I have an OBJ that uses four textures. The UVs defined in the file range from (0, 0) to (2, 2), such that (0.5, 0.5) refers to a coordinate in the first texture, (0.5, 1.5) is a UV coordinate in the second texture, (1.5, 0.5) is a coordinate in the third texture, and (1.5, 1.5) is a coordinate in the last texture.
I already have the correct three.js geometry or object. However, I now need to be able to apply the correct texture maps to these objects.
In code:
I have a THREE.Mesh
with the correct geometry (with UVs coords such that U = [0, 2], V = [0, 2]) and a dummy placeholder material. I currently load a single texture like so:
var texture = new THREE.TextureLoader().load('tex_u1_v1.png', function() {
object.material.map = texture;
object.material.map.needsUpdate = true;
});
As expected, one fourth of the mesh is textured correctly. I have three more texture files, tex_u1_v2.png
, tex_u2_v1.png
, and tex_u2_v2.png
. I want to be able to apply these textures as well to object
(the THREE.js mesh), such that there is a texture for every valid UV in the mesh.
However, I do not know how to add multiple materials to object
after it has been created. Moreover, I do not know how to specify to the mesh that tex_u1_v2.png
, for example, should be used for UVs in range (U = [0, 2], V = [1, 2]).
Multiple UV Maps You are not limited to one UV map per mesh. You can have multiple UV maps for parts of the mesh by creating new UV maps. This can be done by clicking the Add button next to UV maps list (in Object Data tab in the Properties Editor) and unwrapping a different part of the mesh.
To add the Convert UV to Mesh node, click Add... at the top of the viewport, then click Mesh Operations > UV, and double-click Convert UV to Mesh. Connect the mesh you want to convert to the Source Mesh input of the Convert UV to Mesh operator. This places the converted mesh to the same mesh layer as the original mesh.
Textures are often the part of a three. js app that use the most memory. It's important to understand that in general, textures take width * height * 4 * 1.33 bytes of memory. That image will take 60 MEG OF MEMORY! in three.
The standard materials in Three will only accept a single texture object for the various map-parameters (and the texture objects will only hold a single image), so in order to use multiple textures on your object you will have to use multiple materials or create your own multi-texture-material. If you have experience with shader programming you will probably get the best performance with the latter approach (assuming you have enough video memory for your large textures) as you can draw the entire mesh in a single draw call and without having to load new shaders or textures.
To create your own shader you can use the ShaderMaterial
or RawShaderMaterial
, give it one texture uniform for every texture you will need (four in your case) and then in the shader code pick the correct one to sample depending on the coordinates.
To make an object use more than one material you can set the material
property to an array of materials (either during creation with the constructor parameter, or just replace it manually at a later stage).
const myMaterials = [tex1Material, tex2Material, tex3Material, tex4Material];
const myMesh = new THREE.Mesh(myGeometry, myMaterials);
//Or:
myMesh.materials = myMaterials;
Then, to make the different parts of your mesh use the appropriate materials you will have to create groups
if it is a BufferGeometry
; or set the materialIndex
of the faces if you are using a Geometry
. The material index (both in the group and the face) is the index of the material in the mesh.material
array shown above.
Now that you have different parts of the mesh with different materials, you can just give each material their own textures.
If you don't want to modify your already existing coordinates there are two alternative approaches:
Set the texture wrapping to THREE.RepeatWrapping
:
myTexture.wrapS = THREE.RepeatWrapping;
myTexture.wrapT = THREE.RepeatWrapping;
This will make the texture repeat beyond the standard [0-1] uv interval.
The other way is to use the offset
property of the texture to
push it back into the [0-1] interval. For a texture to be placed in
the u[0,1], v[1,2] interval you would set the offset the v-coordinate
by -1:
myTexture.offset = new THREE.Vector2(0, -1);
Here is a link to a jsfiddle that demonstrate these methods: https://jsfiddle.net/xfehvmb4/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With