strange rendering of PolygonGeometry in Primitive with modelMatrix

1. A concise explanation of the problem you're experiencing.
I am attempting to render a PolygonGeometry specified in ENU. The polygon is in a Primitive with a modelMatrix of Transforms.eastNorthUpToFixedFrame. The polygon renders in the correct location about the specified origin, but at an extremely large altitude. I am trying to understand why I am getting such behavior, as the DebugModelMatrixPrimitive is in the correct location and I can perform the same transformation on a PointPrimitiveCollection without issue.

2. A minimal code example. If you've found a bug, this helps us reproduce and repair it.

var viewer = new Cesium.Viewer('cesiumContainer');
var pts = [1, 0, 5, 0, 1, 5, -1, 0, 5, 0, -1, 5];

var center = Cesium.Cartesian3.fromDegrees(-105.637313, 40.593446);
var instance = new Cesium.GeometryInstance({
  id : 'TEST',
  geometry : new Cesium.PolygonGeometry({
    polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.unpackArray(pts)),
    vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
    height: 2
  }),
  attributes : {
    show : new Cesium.ShowGeometryInstanceAttribute(true)
  }
});

var primitive = new Cesium.Primitive({
  geometryInstances : [instance],
  modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(center),
  appearance : new Cesium.EllipsoidSurfaceAppearance(
                     {
                       flat : true,
                       material : new Cesium.Material({fabric : {
                                                  type : 'Color',
                                                  uniforms : { color : new Cesium.Color(0.0, 0.0, 1.0, 0.2) }
                                                }})
                     }),
  shadows : Cesium.ShadowMode.DISABLED,
  show: true
});

var collection = new Cesium.PrimitiveCollection();
collection.add(primitive);
viewer.scene.primitives.add(collection);
viewer.scene.primitives.add(new Cesium.DebugModelMatrixPrimitive({
  modelMatrix : primitive.modelMatrix,
  length : 100000.0,
  width : 5.0
}));

3. Context. Why do you need to do this? We might know a better way to accomplish your goal.

I am attempting to render thousands of polygons. I can accomplish my goals using ECEF specified locations, but am wishing to be able to specify the polygon points in ENU in order to be able to transform the collection through manipulation of the modelMatrix.

4. The Cesium version you're using, your operating system and browser.

1.46, Mac OS Sierra v.10.12.6, Chrome

Looking a little deeper into this I find that when I apply the transforms manually and use the resulting points then I obtain the correct polygon location. The following code was used to do this:

var viewer = new Cesium.Viewer('cesiumContainer');

var center = Cesium.Cartesian3.fromDegrees(-105.637313, 40.593446);
var mM = Cesium.Transforms.eastNorthUpToFixedFrame(center);
console.log('Model Matrix: ' + mM);
var enuPts = Cesium.Cartesian3.unpackArray([1, 0, 5, 0, 1, 5, -1, 0, 5, 0, -1, 5]);
var ecefPts = ;
for(var i=0;i<enuPts.length;i+=1)
{
    var p = enuPts[i];
    console.log('Point before transform: ' + p);
    var res = new Cesium.Cartesian3();
    Cesium.Matrix4.multiplyByPoint(mM, p, res);
    console.log('After transform: ' + res);
    ecefPts.push(res);
}
console.log(ecefPts);
var instance = new Cesium.GeometryInstance({
  id : 'TEST',
  geometry : new Cesium.PolygonGeometry({
    polygonHierarchy: new Cesium.PolygonHierarchy(ecefPts),
    vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
    height: 2
  }),
  attributes : {
    show : new Cesium.ShowGeometryInstanceAttribute(true)
  }
});

var primitive = new Cesium.Primitive({
  geometryInstances : [instance],
  //modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(center),
  appearance : new Cesium.EllipsoidSurfaceAppearance(
                     {
                       flat : true,
                       material : new Cesium.Material({fabric : {
                                                  type : 'Color',
                                                  uniforms : { color : new Cesium.Color(0.0, 0.0, 1.0, 0.2) }
                                                }})
                     }),
  shadows : Cesium.ShadowMode.DISABLED,
  show: true
});

var collection = new Cesium.PrimitiveCollection();
collection.add(primitive);
viewer.scene.primitives.add(collection);
viewer.scene.primitives.add(new Cesium.DebugModelMatrixPrimitive({
  modelMatrix : mM,
  length : 100000.0,
  width : 5.0
}));

Using this, the polygon renders in the correct location. To me this is showing that the modelMatrix listed in the primitive is not correctly being applied to the points that constitute the PolygonGeometry. Any thoughts?

Bump. Any thoughts?

I would recommend the second solution where you transform your positions to ECF first before constructing the primitives. I think for the first example, you need to inverse transform. Instead of the matrix you need which transforms ECF -> ENU, you have one that transforms ENU -> ECF.

Ideally I would not have to do the second solution- as this is what the modelMatrix should be for so that I can simply update the modelMatrix without changing the underlying points. Also, the transformation I am attempting to apply is in fact ENU->ECEF, note that the positions I am providing are in ENU. Simply using the inverse transform in the first example does not work.

While I appreciate your attention to this matter- it does not solve the problem.

So it looks like this is happening because when you specify a height to PolygonGeometry, it sets it as “distance in meters between the polygon and the ellipsoid surface”. To do this, Cesium will move the points given to the surface, and then offset it by this height.

So in the first case, we have an original set of points P, which get moved to the surface of the globe, and then get transformed by the modelMatrix.

In the second case, we have an original set of points P, which get transformed by the matrix manually, and then moved to the surface of the globe.

I think since the modelMatrix you have correctly transforms the points to the position you want, you want to disable Cesium’s automatic moving of points to the surface. To do that, simply set perPositionHeight: true on the PolygonGeometry instead of height: 2.

So a complete working example would be:

var viewer = new Cesium.Viewer(‘cesiumContainer’);
var pts = [1, 0, 5, 0, 1, 5, -1, 0, 5, 0, -1, 5];

var center = Cesium.Cartesian3.fromDegrees(-105.637313, 40.593446);
var instance = new Cesium.GeometryInstance({
id : ‘TEST’,
geometry : new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.unpackArray(pts)),
vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
perPositionHeight: true
}),
attributes : {
show : new Cesium.ShowGeometryInstanceAttribute(true)
}
});

var primitive = new Cesium.Primitive({
geometryInstances : [instance],
modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(center),
appearance : new Cesium.EllipsoidSurfaceAppearance(
{
flat : true,
material : new Cesium.Material({fabric : {
type : ‘Color’,
uniforms : { color : new Cesium.Color(0.0, 0.0, 1.0, 0.2) }
}})
}),
shadows : Cesium.ShadowMode.DISABLED,
show: true
});

var collection = new Cesium.PrimitiveCollection();
collection.add(primitive);
viewer.scene.primitives.add(collection);
viewer.scene.primitives.add(new Cesium.DebugModelMatrixPrimitive({
modelMatrix : primitive.modelMatrix,
length : 100000.0,
width : 5.0
}));

``