The projectionMatrix seems to have caused a loss of accuracy

Description

After adding the mesh of the gltf model to THREE.InstancedMesh, I modified the scaling, and the rendered effect seems to have lost some vertices

Reproduction steps

  1. Adding custom layers using mapboxgl
  2. Load the model using three gltfloader in the mapboxgl custom layer
  3. Adding gltf mesh using THREE.InstancedMesh

Code

loader.load(
        "https://threejs.org/examples/models/gltf/Flower/Flower.glb",
        function (gltf) {
          const p = projectToWorld(origin);

          const model = gltf.scene;

          const _stemMesh = model.getObjectByName("Stem");
          const _blossomMesh = model.getObjectByName("Blossom");

          const stemGeometry = _stemMesh.geometry.clone();
          const blossomGeometry = _blossomMesh.geometry.clone();

          const stemMaterial = _stemMesh.material;
          const blossomMaterial = _blossomMesh.material;

          const stemMesh = new THREE.InstancedMesh(
            stemGeometry,
            stemMaterial,
            1
          );
          const blossomMesh = new THREE.InstancedMesh(
            blossomGeometry,
            blossomMaterial,
            1
          );

          stemMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
          blossomMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);

          const defaultTransform = new THREE.Matrix4()
            .makeRotationX(Math.PI)
            .multiply(new THREE.Matrix4().makeScale(1, 1, 1));

          stemGeometry.applyMatrix4(defaultTransform);
          blossomGeometry.applyMatrix4(defaultTransform);

          stemMesh.instanceMatrix.needsUpdate = true;
          blossomMesh.instanceMatrix.needsUpdate = true;

          const dummy = new THREE.Object3D();

          let pos = projectToWorld([118.61113, 32.06318, 0]);

          for (let i = 0; i < 1; i++) {
            dummy.position.copy(pos);
            dummy.scale.set(10, 10, 10);
            // dummy.scale.set(100, 100, 100);
            dummy.updateMatrix();
            stemMesh.setMatrixAt(i, dummy.matrix);
            blossomMesh.setMatrixAt(i, dummy.matrix);
          }

          const group = new THREE.Group();

          group.add(stemMesh);
          group.add(blossomMesh);

          world.add(group);

          map.triggerRepaint(); }
      );

Live example

Screenshots

normal
2
abnormal
1

Version

all

God save me, this problem has been bothering me for two weeks now

You’re setting the position of the instance to a huge value meaning floating point matrix math with large values is happening on the GPU resulting in precision loss:

x: -3373827.697777778
y: -963723.9676581315
z: 0
2 Likes

Thank you for pointing out the problem. How can I solve the problem? I haven’t found a solution without changing the shaders. It should be related to my custom projection matrix, but I don’t know how to solve it.

You need to adjust your transformations such that no matrices with large values make it to the GPU. Ie set the origin of the InstancedMesh to the center of all the instance positions and set the instance positions relative to that mesh.

1 Like

Oh, my goodness. Thank you. But I don’t fully understand why this can solve it. Mesh is also set to a large number with double precision. Can you explain to me that I am a beginner in this field. Thank you again

Three.js premultiplies each mesh’s matrixWorld with the camera transformation on the CPU which uses 64-bit floats which is higher precision so performing operations with large values is less of a big deal. Transforming objects into the camera frame results in a smaller values since it’s relative to the view position. These pre-transformed matrices are then uploaded to the GPU as uniforms.

If you perform this kind of math on the GPU it means you’re using lower precision floats to perform these large value calculations. This results in the kind of jitter and apparent “merging” of vertices during rendering. The instance matrices have to be multiplied on GPU for the sake of performance.

Bottom line is you want to keep as much important matrix computation on the CPU as you can when large values will be involved.

2 Likes

Thank you very much