THREE.js generate UV coordinate THREE.js generate UV coordinate javascript javascript

THREE.js generate UV coordinate


To my knowledge there is no automatic way to calculate UV.

You must calculate yourself. Calculate a UV for a plane is quite easy, this site explains how: calculating texture coordinates

For a complex shape, I don't know how. Maybe you could detect planar surface.

EDIT

Here is a sample code for a planar surface (x, y, z) where z = 0:

geometry.computeBoundingBox();var max = geometry.boundingBox.max,    min = geometry.boundingBox.min;var offset = new THREE.Vector2(0 - min.x, 0 - min.y);var range = new THREE.Vector2(max.x - min.x, max.y - min.y);var faces = geometry.faces;geometry.faceVertexUvs[0] = [];for (var i = 0; i < faces.length ; i++) {    var v1 = geometry.vertices[faces[i].a],         v2 = geometry.vertices[faces[i].b],         v3 = geometry.vertices[faces[i].c];    geometry.faceVertexUvs[0].push([        new THREE.Vector2((v1.x + offset.x)/range.x ,(v1.y + offset.y)/range.y),        new THREE.Vector2((v2.x + offset.x)/range.x ,(v2.y + offset.y)/range.y),        new THREE.Vector2((v3.x + offset.x)/range.x ,(v3.y + offset.y)/range.y)    ]);}geometry.uvsNeedUpdate = true;


The other answers here were a great help but didn't quite fit my requirements to apply a repeating pattern texture to all sides of a shape with mostly flat surfaces. The problem is that using only the x and y components as u and v results in weird stretched textures on vertical surfaces.

My solution below uses surface normals to pick which two components (x, y and z) to map to u and v. It's still pretty crude but it works quite well.

function assignUVs(geometry) {    geometry.faceVertexUvs[0] = [];    geometry.faces.forEach(function(face) {        var components = ['x', 'y', 'z'].sort(function(a, b) {            return Math.abs(face.normal[a]) > Math.abs(face.normal[b]);        });        var v1 = geometry.vertices[face.a];        var v2 = geometry.vertices[face.b];        var v3 = geometry.vertices[face.c];        geometry.faceVertexUvs[0].push([            new THREE.Vector2(v1[components[0]], v1[components[1]]),            new THREE.Vector2(v2[components[0]], v2[components[1]]),            new THREE.Vector2(v3[components[0]], v3[components[1]])        ]);    });    geometry.uvsNeedUpdate = true;}

This function doesn't normalise the UVs to the size of the object. This works better when applying the same texture to different sized objects in the same scene. However depending on the size of your world coordinate system, you'll probably need to scale and repeat the texture as well:

texture.repeat.set(0.1, 0.1);texture.wrapS = texture.wrapT = THREE.MirroredRepeatWrapping;


The answers here are brilliant and helped me a lot. Only one thing: If you are updating vertices, do not re-assign uvs, but set them, as in (scope is my geometry):

scope.updateUVs = (copy=true) => {    scope.computeBoundingBox();    var max     = scope.boundingBox.max;    var min     = scope.boundingBox.min;    var offset  = new THREE.Vector2(0 - min.x, 0 - min.y);    var range   = new THREE.Vector2(max.x - min.x, max.y - min.y);    if (!copy) {        scope.faceVertexUvs[0] = [];    }    var faces = scope.faces;    for (i = 0; i < scope.faces.length ; i++) {      var v1 = scope.vertices[faces[i].a];      var v2 = scope.vertices[faces[i].b];      var v3 = scope.vertices[faces[i].c];      var uv0 = new THREE.Vector2( ( v1.x + offset.x ) / range.x , ( v1.y + offset.y ) / range.y );      var uv1 = new THREE.Vector2( ( v2.x + offset.x ) / range.x , ( v2.y + offset.y ) / range.y );      var uv2 = new THREE.Vector2( ( v3.x + offset.x ) / range.x , ( v3.y + offset.y ) / range.y );      if (copy) {          var uvs =scope.faceVertexUvs[0][i];          uvs[0].copy(uv0);          uvs[1].copy(uv1);          uvs[2].copy(uv2);      } else {          scope.faceVertexUvs[0].push([uv0, uv1, uv2]);      }    }    scope.uvsNeedUpdate = true;}