Three.js Material which lets you do Texture Projection on a 3d Model.
After having installed three.js, install it from npm with:
npm install three-projected-material
or
yarn add three-projected-material
You can also use it from the CDN, just make sure to put this after the three.js script:
<script src="https://unpkg.com/three-projected-material"></script>
You can import it like this
import ProjectedMaterial from 'three-projected-material'
or, if you're using CommonJS
const ProjectedMaterial = require('three-projected-material').default
Instead, if you install it from the CDN, its exposed under window.projectedMaterial
, and you use it like this
const ProjectedMaterial = window.projectedMaterial.default
Then, you can use it like this:
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, // scale down the texture a bit
textureOffset: new THREE.Vector2(0.1, 0.1), // you can translate the texture if you want
cover: true, // enable background-size: cover behaviour, by default it's like background-size: contain
color: '#ccc', // the color of the object if it's not projected on
roughness: 0.3, // you can pass any other option that belongs to MeshPhysicalMaterial
})
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)
ProjectedMaterial also supports instanced meshes via three.js' InstancedMesh, and even multiple projections. Check out the examples below for a detailed guide!
Create a new material to later use for a mesh.
Option | Default | Description |
---|---|---|
camera |
The PerspectiveCamera the texture will be projected from. | |
texture |
The Texture being projected. | |
textureScale |
1 | Make the texture bigger or smaller. |
textureOffset |
new THREE.Vector2() |
Offset the texture in a x or y direction. The unit system goes from 0 to 1, from the bottom left corner to the top right corner of the projector camera frustum. |
cover |
false | Wheter the texture should act like background-size: cover on the projector frustum. By default it works like background-size: contain . |
...options |
Other options you pass to any three.js material like color , opacity , envMap and so on. The material is built from a MeshPhysicalMaterial, so you can pass any property of that material and of its parent MeshStandardMaterial. |
These properties are exposed as properties of the material, so you can change them later.
For example, to update the material texture and change its scale:
material.texture = newTexture
material.textureScale = 0.8
Project the texture from the camera on the mesh. With this method we "take a snaphot" of the current mesh and camera position in space. The After calling this method, you can move the mesh or the camera freely.
Option | Description |
---|---|
mesh |
The mesh that has a ProjectedMaterial as material. |
Allocate the data that will be used when projecting on an InstancedMesh. Use this on the geometry that will be used in pair with a ProjectedMaterial
when initializing InstancedMesh
.
This needs to be called before .projectInstanceAt()
.
Option | Description |
---|---|
geometry |
The geometry that will be passed to the InstancedMesh . |
instancesCount |
The number of instances, the same that will be passed to the InstancedMesh . |
Do the projection for an InstancedMesh. Don't forget to call updateMatrix()
like you do before calling InstancedMesh.setMatrixAt()
.
To do projection an an instanced mesh, the geometry needs to be prepared with allocateProjectionData()
beforehand.
dummy.updateMatrix()
projectInstanceAt(i, instancedMesh, dummy.matrix)
Link to the full example about instancing.
Option | Description |
---|---|
index |
The index of the instanced element to project. |
instancedMesh |
The InstancedMesh with a projected material. |
matrix |
The matrix of the dummy you used to position the instanced mesh element. Be sure to call .updateMatrix() beforehand. |