custom rendering question

Hi,

First let me congratulate you all for the Cesium project. I think this
is really marvelous!!!!

I'd like to use Cesium to display aviation related constructs, like
airspaces. Thus, I have a custom rendering question. I looked at the
'Box' custom rendering example, and started to modify it at first to
display a simple airspace, which is a rectangle, with the following
corners in degrees:

47.5225 18.93888888888889
47.531666666666666 18.965555555555554

and with a lower bound of ground level and an upper bound of 3500ft AMSL
(about 1066m AMSL)

now I started to edit the Box2 sample object from the custom rendering
sample, by replacing the 'position' constructor parameter to
(ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(0, 0,
0)), and then by trying to define the following corners:

            var c = Cesium.Cartographic.fromDegrees(47.5225,
18.93888888888889, 0);
            var d = Cesium.Cartographic.fromDegrees(47.531666666666666,
18.965555555555554, 1066);
            var minimumCorner = this._ellipsoid.cartographicToCartesian(c);
            var maximumCorner = this._ellipsoid.cartographicToCartesian(d);

but, unfortunately this doesn't have the desired effect - the created
box is floating high up above the stratosphere. I also tried to manually
set the z coordinate to the desired elevation, but the effect is about
the same.

thus, I wonder, what would be the proper approach to render a box like this?

best regards,

Akos

Hi Ákos,

To get your code to work in the Box sample (Box2 should be similar), just comment out this line:

this._colorCommand.modelMatrix = this._pickCommand.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);

The original box was drawn in a local coordinate system using the original center point as the origin, with x pointing towards east, y pointing north, and z pointing up. The positions you computed with cartographicToCartesian were drawn in this coordinate system; however, cartographicToCartesian returns positions in WGS84 coordinates where the center of Earth is the origin, and x points to longitude/latitude 0/0, y points to 90/0, and z points to the north pole. Since this is the default - or world - coordinate system for rendering, we can just leave the modelMatrix undefined.

Also, for defining custom geometry, in many cases it should be as simple as building on the Box examples and replacing the BoxTessellator with new code that creates a Mesh for your geometry. We have plans to make it easier to use a custom mesh like this, but just working off of the Box example is perfectly reasonable for now.

Regards,

Patrick

yes, this is what I thought, that it’s all in relative coordinates,
and I need absolute coordinates.
but it doesn’t seem to work for me, see here:
basically the code contains the Box2 sample (renamed to Box), and
the corresponding part changed:
/*
this._modelMatrix =
Cesium.Transforms.eastNorthUpToFixedFrame(this._position);

        var dimensions = new Cesium.Cartesian3(500000.0,

500000.0, 500000.0);
var maximumCorner = dimensions.multiplyByScalar(0.5);
var minimumCorner = maximumCorner.negate();
*/

        var c = Cesium.Cartographic.fromDegrees(south, west,

lower);
var d = Cesium.Cartographic.fromDegrees(north, east,
upper);
var minimumCorner =
this._ellipsoid.cartographicToCartesian©;
var maximumCorner =
this._ellipsoid.cartographicToCartesian(d);

where north, south, east, west, upper & lower are defined in the
beginning. for clarity, I exaggerated the size of the area, by
extending it with 1 degree or latitude and longitude each, and I
also increased the height.
I also added a polygon drawing call with the same coordinates, which
seems to show fine (see the end of the javascript code). you should
see an area in East Europe that is of cyan color.
but the box itself is not drawn :frowning:
I wonder what I’m doing still wrong :slight_smile:
thanks, I was thinking along the same lines.
moreover, I can get this simple case working, I’ll need to draw a
special case of airspace, which is defined relative to the ground
level at that particular location. basically this would be an offset
to the elevation (terrain) data that is drawn by cesium (say, 1000ft
above ground level). I wonder how easy would be to do this?
Akos

Hi Ákos,

It looks like your box is being culled by the view frustum. You need to compute the correct bounding sphere for correct frustum culling or set the bounding volume to be undefined to disable it.

Regards,

Dan

thanks for pointing this out. indeed, this was one of the prolbems,
which I’ve solved now. See the result here:
now the issue is, that the box’s orientation is wrong. if you look
at the result, the 2D polygon drawn is correct, while the
orientation of the box is wrong :frowning:
the code to generate the box tesselation didn’t change:
var c = Cesium.Cartographic.fromDegrees(west, south,
lower);
var d = Cesium.Cartographic.fromDegrees(east, north,
upper);
var minimumCorner =
this._ellipsoid.cartographicToCartesian©;
var maximumCorner =
this._ellipsoid.cartographicToCartesian(d);
var mesh =
Cesium.MeshFilters.toWireframeInPlace(Cesium.BoxTessellator.compute({
minimumCorner : minimumCorner,
maximumCorner : maximumCorner
}));
mesh.attributes.position3D = mesh.attributes.position;
delete mesh.attributes.position;
I wonder what’s wrong with this approach.
Akos

Akos,

The BoxTesselator creates vertex positions in world space when the xy-plane intersects the equator and the north pole is on the z-axis. You need to use the model matrix to orient the box correctly.

Try something like:

var center = this._ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(center_lon, center_lat, center_vert));

// reference frame relative to the center of the extent

this._modelMatrix = Transforms.eastNorthUpToFixedFrame(center, this._ellipsoid);

// corners relative to the center

var minimumCorner = this._ellipsoid.cartographicToCartesian©.subtract(center);

var maximumCorner = this._ellipsoid.cartographicToCartesian(d).subtract(center);

I haven’t tried that, but I hope it helps.

If you don’t mind me asking, what kind of app are you making?

Dan

actually I went for a different approach - I deferred creation of
the box edges from cartographic coordinates into the BoxTessellator.
see my results here: the modified BoxTessellator is here:
my updated Box object is here: (it has hardcoded values for now)
for clarity (and debugging), I put spheres at each corner of the
box.
I also added my own tiles to double check for precision.
now, I’d like to color the vertices in the box, as opposed to
showing a wireframe. I see that there is a vertexArray property of
the color command, and also there is a
context.createVertexArrayFromMesh() call, but this doesn’t seem to
have an effect. would I have to add a material and change the GLSL
code so that the vertices are colored?
I’m trying to visualize aviation related spacial data like
airspaces, etc. this would be part of the Open Aviaton Map project,
which currently has 2D (tileset) renderings. see here:
what I’d need is to be able to draw ‘bodies’ that have a footprint
of a polygon or a circle, or a combination of these, and they have
lower and upper bounds. these would be the airspaces that affect
aircraft navigation. some have upper or lower bound definitions in
relation to the ground level at that particular location - for this
I’d need to work from the elevation database that cesium already
uses.
additionally ground features would need to be shown (navigation
aids, airports, etc.)
and then flight paths (traffic circuits, published flight
procedures) would be shown as well.
moreover, re-playing recorded GPS tracks (flights) would be needed
as well.
Akos

Akos,

If you want to add per-vertex colors, you need to add another attribute to the mesh with an array of the color components. You would also need to modify the GLSL to use the color vertex attribute instead of the u_color uniform.

Changing the box to render filled triangles instead of wireframe should be as simple as changing the primitive type to TRIANGLES and removing the line:

var mesh = Cesium.MeshFilters.toWireframeInPlace(mesh);

Dan

thanks - but no, I don’t need per-vertex colors, a single color for
the whole box is just fine.
actually it is already producing TRIANGLES:
// 12 triangles: 6 faces, 2 triangles each.
mesh.indexLists.push({
primitiveType : Cesium.PrimitiveType.TRIANGLES,
values : [
4, 5, 6, // Top: plane z = corner.Z
4, 6, 7,
1, 0, 3, // Bottom: plane z = -corner.Z
1, 3, 2,
1, 6, 5, // Side: plane x = corner.X
1, 2, 6,
2, 3, 7, // Side: plane y = corner.Y
2, 7, 6,
3, 0, 4, // Side: plane x = -corner.X
3, 4, 7,
0, 1, 5, // Side: plane y = -corner.Y
0, 5, 4
]
});
I tried this, but I get the same, although with fewer lines
(triangles)
Akos

Akos,

thanks - but no, I don’t need per-vertex colors, a single color for the whole box is just fine.

You can change the value returned by the u_color function in the uniform map in the constructor.

actually it is already producing TRIANGLES:

I meant change this line to TRIANGLES:

this._colorCommand.primitiveType = this._pickCommand.primitiveType = Cesium.PrimitiveType.LINES;

The primitive type of the color command is the type that gets rendered.

Dan

indeed - thanks. nos I can draw a solid brick:
I wonder why it’s not transparent, as I’ve set the alpha value for
the color:
this._colorCommand.uniformMap = {
u_color : function() {
var color = Cesium.Color.LIME;
color.alpha = 0.2;
return color;
},
and the u_color uniform in the shader expects a vec4, so it should
take the alpha value into account, shouldn’t it?
moreover, is there a way to have the terrain ‘win’ over such a
custom 3D object? now this brick is showing even ‘below ground’,
where it would be better if it blended in.
sorry for all the lame questions :frowning:
Akos

Cesium.Color.LIME is a frozen object (i.e. read-only) If you want to modify it you need to copy it first. Unfortunately, the standard says its perfectly okay to fail silently when modifying a readonly object. var color = Cesium.Color.LIME.clone(); will do the trick.

For the terrain issue, try setting:

widget.centralBody.depthTestAgainstTerrain = true;

(Kevin can correct me here if I’m wrong.

this doesn’t seem to work :frowning:
I also tried var color = new Cesium.Color(1, 0, 0, 0.5); &
similar, but it’s still opaque :frowning:
thanks - this did the trick fine!
Akos

Enable alpha blending for translucency:

renderState = context.createRenderState({

blending : BlendingState.ALPHA_BLEND

});

oh, thank you, works splendidly!