Three.js

  • WebGL Hardware limitation, Tips

  • Render(scene,renderer,camera)
    • depthTest
      • WebGLRenderer.logarithmicDepthBuffer and camera.near/far may cause weird depthTest.
      • when using transparent and renderOrder to clip something
  • Material :
    • Max TextureSize : 4096*4096
    • sovle z-fighting by polygon offset
        const material = new THREE.Material({
            polygonOffset: true,
            polygonOffsetFactor: 1.0,
            polygonOffsetUnits: 4.0
        })
      
    • shaderMaterial : calculate normal in shader
        const shadermat = new THREE.ShaderMaterial(...);
      
        // enable dFdx,dFdy
        shadermat.extensions.derivatives = true
      
        // in vertex shader
        pos =  position;
      
        // in fragment shader
        vec3 normal = normalize(cross(dFdx(pos), dFdy(pos)));
      
    • discard pixel instead write it transparent in fragmentShader
      • remove all transparent pixel avoid weird occlusion
          THREE.Material.prototype.onBeforeCompile = function ( shader )
          {
          function insert( str, index, value )
          {
              return str.substr( 0, index ) + value + str.substr( index );
          }
                    
          const mainEndIndex = shader.fragmentShader.lastIndexOf( '}' );
        
          const addOnshader = [
              `if(gl_FragColor.a < 0.1){`,
              `   discard;`,
              `}`,
              ``
          ].join( "\n" );
        
          shader.fragmentShader = insert( shader.fragmentShader, mainEndIndex, addOnshader )
          }
        
  • Object :

    • Billboard : Obejct3D.onAfterRender/.onBeforeRender is usefull, function is called with the following parameters: renderer, scene, camera, geometry, material, group.

    • local-axis aligned bounding box :

        this.boxHelper?.parent?.remove( this.boxHelper )
        const quaternion = this.object.quaternion.clone();
        this.object.quaternion.set( 0, 0, 0, 1 );
        this.boxHelper = new THREE.BoxHelper( this.object, 0x0077ff );
        this.object.quaternion.copy( quaternion );
        this.boxHelper.applyMatrix4( this.object.matrixWorld.invert() )
        this.object.add( this.boxHelper )
      
  • Interact :

    • Raycaster : face normal
        private intersect2rot4( intersect: THREE.Intersection ): THREE.Matrix4
        {
            if ( intersect )
            {
                const n = intersect.face.normal.clone();
                intersect.object.updateMatrixWorld( true )
                n.transformDirection( intersect.object.matrixWorld );
                const mat4 = new THREE.Matrix4().lookAt( n, new THREE.Vector3( 0, 0, 0 ), this.camera.up );
                return mat4;
            }
        }
      
    • project 3d point to screen coordinate
        function createVector(x, y, z, camera, width, height) {
            var p = new THREE.Vector3(x, y, z);
            var vector = p.project(camera);
      
            vector.x = (vector.x + 1) / 2 * width;
            vector.y = -(vector.y - 1) / 2 * height;
      
            return vector;
        }
      

Reference