Description
I’m experiencing a consistent error when merging multiple GeometryInstance objects into a single Primitive. The error only occurs with a very specific combination of rotation and translation values:
Error Message:
Reproducible Scenario
I’m building a 3D gizmo (translation widget) with arrows pointing in all six directions (±X, ±Y, ±Z). I reuse the same CylinderGeometry instances for all directions with different modelMatrix transformations.
Code
function calTransModelMatrix(axis, translate) {
const modelMatrix = Matrix4.IDENTITY.clone();
if (Cartesian3.equals(axis, Cartesian3.UNIT_X)) {
// ✅ Works fine
const rotation = Matrix3.fromRotationY(CesiumMath.toRadians(90));
const translation = Cartesian3.fromElements(translate, 0, 0);
Matrix4.setTranslation(modelMatrix, translation, modelMatrix);
Matrix4.setRotation(modelMatrix, rotation, modelMatrix);
}
else if (Cartesian3.equals(axis, Cartesian3.negate(Cartesian3.UNIT_X, new Cartesian3()))) {
// ❌ FAILS with error
const rotation = Matrix3.fromRotationY(CesiumMath.toRadians(-90));
const translation = Cartesian3.fromElements(-translate, 0, 0); // FAILS
// const translation = Cartesian3.fromElements(-translate, 0.00001, 0); // WORKS!
Matrix4.setTranslation(modelMatrix, translation, modelMatrix);
Matrix4.setRotation(modelMatrix, rotation, modelMatrix);
}
else if (Cartesian3.equals(axis, Cartesian3.negate(Cartesian3.UNIT_Y, new Cartesian3()))) {
// ✅ Works fine
const rotation = Matrix3.fromRotationX(CesiumMath.toRadians(90));
const translation = Cartesian3.fromElements(0, -translate, 0);
Matrix4.setTranslation(modelMatrix, translation, modelMatrix);
Matrix4.setRotation(modelMatrix, rotation, modelMatrix);
}
else if (Cartesian3.equals(axis, Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()))) {
// ✅ Works fine
const rotation = Matrix3.fromRotationY(CesiumMath.toRadians(180));
const translation = Cartesian3.fromElements(0, 0, -translate);
Matrix4.setTranslation(modelMatrix, translation, modelMatrix);
Matrix4.setRotation(modelMatrix, rotation, modelMatrix);
}
return modelMatrix;
}
// Create geometries (reused for multiple instances)
const arrowGeometry = new CylinderGeometry({
length: 0.2,
topRadius: 0,
bottomRadius: 0.06,
});
const lineGeometry = new CylinderGeometry({
length: 0.8,
topRadius: 0.01,
bottomRadius: 0.01,
});
// Create instances with different transformations
const xArrowNegModelMatrix = calTransModelMatrix(
Cartesian3.negate(Cartesian3.UNIT_X, new Cartesian3()),
0.9 // translate value
);
const xArrowNegInstance = new GeometryInstance({
id: 'xAxisNeg',
geometry: arrowGeometry,
modelMatrix: xArrowNegModelMatrix,
attributes: {
color: ColorGeometryInstanceAttribute.fromColor(new Color(1.0, 0.0, 0.0, 0.99)),
},
});
// Similar instances for xLineNeg, xArrow, xLine...
// Merge into Primitive - THIS FAILS
const xTransPrimitive = new Primitive({
geometryInstances: [xArrowInstance, xLineInstance, xArrowNegInstance, xLineNegInstance],
appearance: new PerInstanceColorAppearance({
flat: true,
translucent: true,
}),
asynchronous: false,
});
The Strange Behavior
FAILS:
-
Rotation:
Matrix3.fromRotationY(-90°) -
Translation:
(-0.9, 0, 0)
WORKS:
-
Rotation:
Matrix3.fromRotationY(-90°) -
Translation:
(-0.9, 0.00001, 0)
-
Translation:
(-0.9, -0.00001, 0)
Also WORKS (other axes):
-
Rotation:
Matrix3.fromRotationX(90°), Translation:(0, -0.9, 0)
-
Rotation:
Matrix3.fromRotationY(180°), Translation:(0, 0, -0.9)
-
Rotation:
Matrix3.fromRotationY(90°), Translation:(0.9, 0, 0)
Key Observations
-
Only fails for negative X-axis with the specific combination of:
-
Y-axis rotation of -90 degrees
-
Translation with Y and Z components exactly 0
-
-
Adding any tiny offset (even
1e-5) to the Y or Z component fixes the issue -
Other negative axes (Y, Z) work fine with zero components in their translations
-
The error occurs during
Primitivecreation when merging multipleGeometryInstanceobjects that share the same base geometry
Questions
-
Is this a known issue with geometry instance merging when certain transformation matrices are applied?
-
Is there a better workaround than adding a tiny epsilon offset?
-
Should I create separate geometry instances instead of reusing the same geometry?
Environment
-
CesiumJS Version: [1.135.0]
-
Browser: Chrome[142.0.7444.60]
-
OS: [win10]