three-projected-material

repository·master·Indexed 20 days ago

https://github.com/marcofugaro/three-projected-material

A Three.js material extension that enables projective texture mapping, allowing textures to be projected onto 3D models from the perspective of a camera. Built on top of MeshPhysicalMaterial, it provides the ProjectedMaterial class for standard meshes and specialized methods like projectInstanceAt and allocateProjectionData for use with InstancedMesh.

Tokens
2.4K
Snippets
11
Records
12
Agent score
22%

What's inside three-projected-material

  1. Project on InstancedMesh

    master

    To use ProjectedMaterial with InstancedMesh, you must follow a specific workflow to prepare the geometry and individual instances:

    1. Prepare Geometry: Call allocateProjectionData(geometry, instancesCount) on the geometry intended for the InstancedMesh. This must be done before calling projectInstanceAt.
    2. Project Instances: Use material.projectInstanceAt(index, instancedMesh, matrix) to project onto a specific instance.
    3. Matrix Update: Ensure you call matrix.updateMatrix() on your dummy/transform object before passing it to projectInstanceAt.
    // 1. Prepare
    allocateProjectionData(geometry, instancesCount)
    
    // 2. Project
    dummy.updateMatrix()
    material.projectInstanceAt(i, instancedMesh, dummy.matrix)
  2. Install three-projected-material via CDN

    master

    You can use the library from a CDN. Ensure you use a three.js import map in your HTML.

    <script type="importmap">
      {
        "imports": {
          "three": "https://unpkg.com/three/build/three.module.js"
        }
      }
    </script>
    <script type="module">
      import ProjectedMaterial from 'https://unpkg.com/three-projected-material/build/ProjectedMaterial.module.js'
      // ...
    </script>
  3. Get started with ProjectedMaterial

    master

    Import the material and apply it to a Three.js mesh. After setting up the mesh and camera, call material.project(mesh) to capture the current spatial relationship between the camera and the mesh for the projection.

    import ProjectedMaterial from 'three-projected-material'
    
    const geometry = new THREE.BoxGeometry(1, 1, 1)
    const material = new ProjectedMaterial({
      camera, // the camera that acts as a projector
      texture, // the texture being projected
      textureScale: 0.8,
      textureOffset: new THREE.Vector2(0.1, 0.1),
      cover: true,
      color: '#ccc',
      roughness: 0.3,
    })
    const box = new THREE.Mesh(geometry, material)
    webgl.scene.add(box)
    
    // move the mesh any way you want!
    box.rotation.y = -Math.PI / 4
    
    // and when you're ready project the texture on the box!
    material.project(box)
  4. Project texture on a mesh with material.project()

    master
    Call material.project(mesh) to 'take a snapshot' of the current mesh and camera position in space. Once this method is called, you can move the mesh or the camera freely and the projection will remain fixed relative to the snapshot taken.
    material.project(mesh)
  5. Configure ProjectedMaterial options

    master

    The ProjectedMaterial constructor accepts several options to control the projection behavior. It is built on top of MeshPhysicalMaterial, so you can also pass any property supported by MeshPhysicalMaterial or MeshStandardMaterial (e.g., color, opacity, envMap).

    OptionDefaultDescription
    cameraThe PerspectiveCamera the texture will be projected from.
    textureThe Texture being projected.
    textureScale1Scale the texture.
    textureOffsetnew THREE.Vector2()Offset the texture (0 to 1 range) from the bottom-left to top-right of the projector frustum.
    coverfalseIf true, uses background-size: cover behavior; otherwise uses contain behavior.
    backgroundOpacity1Opacity of the mesh part not covered by the projected texture. Set to 0 to hide non-projected parts.
    ...optionsAny MeshPhysicalMaterial or MeshStandardMaterial properties.
  6. Reference: InstancedMesh projection methods

    master

    Methods for handling projection data in instanced scenarios.

    ### allocateProjectionData(geometry, instancesCount)
    Allocate the data used when projecting on an `InstancedMesh`. Must be called before `.projectInstanceAt()`.
    - `geometry`: The geometry passed to the `InstancedMesh`.
    - `instancesCount`: The number of instances (must match `InstancedMesh`).
    
    ### material.projectInstanceAt(index, instancedMesh, matrix)
    Performs projection for a specific instance in an `InstancedMesh`.
    - `index`: The index of the instanced element.
    - `instancedMesh`: The `InstancedMesh` using a `ProjectedMaterial`.
    - `matrix`: The matrix of the element (ensure `.updateMatrix()` was called on the source object).
  7. Create a ProjectedMaterial

    master

    The ProjectedMaterial class extends MeshPhysicalMaterial and allows you to project a texture onto a mesh using a specific camera. You can initialize it by passing a configuration object of type ProjectedMaterialParameters to the constructor.

    Available parameters include:

    • camera: A PerspectiveCamera or OrthographicCamera used for the projection.
    • texture: The Texture to be projected.
    • textureScale: A number to scale the texture.
    • textureOffset: A Vector2 to offset the texture.
    • cover: A boolean determining if the texture should cover the projected area.
    • backgroundOpacity: A number controlling the opacity of the non-projected parts of the material.
    • Any other standard MeshPhysicalMaterialParameters.
    import ProjectedMaterial from 'three-projected-material';
    
    const material = new ProjectedMaterial({
      camera: myCamera,
      texture: myTexture,
      textureScale: 1.0,
      textureOffset: new THREE.Vector2(0, 0),
      cover: true,
      backgroundOpacity: 0.5
    });
  8. Reference: ProjectedMaterial uniforms

    master

    The ProjectedMaterial exposes a uniforms object used by the underlying shader. These values are updated by the class methods during the projection process.

    uniforms: {
      projectedTexture: { value: Texture }
      isTextureLoaded: { value: boolean }
      isTextureProjected: { value: boolean }
      backgroundOpacity: { value: number }
      viewMatrixCamera: { value: Matrix4 }
      projectionMatrixCamera: { value: Matrix4 }
      projPosition: { value: Vector3 }
      projDirection: { value: Vector3 }
      savedModelMatrix: { value: Matrix4 }
      widthScaled: { value: number }
      heightScaled: { value: number }
      textureOffset: { value: Vector2 }
    }
  9. Allocate projection data with allocateProjectionData()

    master

    Use the allocateProjectionData(geometry, instancesCount) function to prepare the necessary buffer data for projection. This is required when working with geometries that will be used with projected materials, especially in instanced scenarios.

    import { allocateProjectionData } from 'three-projected-material';
    
    allocateProjectionData(myBufferGeometry, 100);
  10. Project an instance in an InstancedMesh using projectInstanceAt()

    master

    To project a specific instance within an InstancedMesh, use projectInstanceAt. This method requires the index of the instance, the InstancedMesh itself, and the world matrix of that instance.

    Parameters:

    • index: The index of the instance to project.
    • instancedMesh: The InstancedMesh containing the instance.
    • matrixWorld: The Matrix4 representing the instance's world transform.
    • options (optional): An object containing forceCameraSave (boolean) to force the camera state to be saved.
    material.projectInstanceAt(
      0, 
      myInstancedMesh, 
      instanceMatrix, 
      { forceCameraSave: true }
    );