I have successfully applied an image texture to a cube via UV mapping (to produce a photo-sphere viewer). Although the texture is perfectly aligned with cube faces, the lines at which faces join are visible as thin straight lines.
The same problem does not happen if texture tiles are split via Canvas and applied to cube via MultiMaterial.
The following image compares results of the two methods of applying a texture (click for larger image):
Live example can be found at CodePen.io
The image used for the texture can be found here
Here's the code which does the UV mapping (it's pretty straightforward):
function mapCubeUV(geometry, cubeH) {
// converting all vertices into polar coordinates
geometry.faceVertexUvs[0] = []; // This clears out any UV mapping that may have already existed on the object
// walking through all the faces defined by the object
// ... we need to define a UV map for each of them
geometry.faces.forEach(function(face) {
var uvs = [];
var ids = [ 'a', 'b', 'c'],
faceSign = face.normal.x+'.'+face.normal.y+'.'+face.normal.z;
for( var i = 0; i < ids.length; i++ ) {
// using the point to access the vertice
var vertexIndex = face[ ids[ i ] ],
vertex = geometry.vertices[ vertexIndex ],
tileIx,
uvY, uvX;
// face order in the image: West, East, Up, Down, South, North
switch(faceSign) {
case '1.0.0': // West
uvY = vertex.y;
uvX = -vertex.z;
tileIx = 0;
break;
case '-1.0.0': // East
uvY = vertex.y;
uvX = vertex.z;
tileIx = 1;
break;
case '0.1.0': // Up
uvY = -vertex.z;
uvX = vertex.x;
tileIx = 2;
break;
case '0.-1.0': // Down
uvY = vertex.z;
uvX = vertex.x;
tileIx = 3;
break;
case '0.0.1': // South
uvY = vertex.y;
uvX = vertex.x;
tileIx = 4;
break;
case '0.0.-1': // North
uvY = vertex.y;
uvX = -vertex.x;
tileIx = 5;
break;
}
// coordinate values range from [-cubeH/2, +cubeH/2]
// here we're fixing moving the range to [0, +cubeH]
uvY = uvY+cubeH/2;
uvX = uvX+cubeH/2;
// each UV coordinate represents decimal range [0, +1]
uvY = uvY/cubeH;
uvX = uvX/cubeH;
// since the image contains multiple texture tiles (8 of them = 6 with
// images + 2 dummy, which were added so that the width is a multiple of 2),
// [uvX] must be adjusted to point to the part of the image
// containing current tile
uvX = (uvX+tileIx)/8;
uvs.push( new THREE.Vector2( uvX, uvY ) );
}
geometry.faceVertexUvs[ 0 ].push( uvs );
});
geometry.uvsNeedUpdate = true;
return(geometry);
}
I have double-checked the values produced by the above function and everything looks good - the UV values when multiplied with the image width and height produce the correct values in pixel. Here's the dump:
Face VerticeA VerticeB VerticeC
0: ( 0,1), ( 0,0), (0.125,1)
1: ( 0,0), (0.125,0), (0.125,1)
2: (0.125,1), (0.125,0), ( 0.25,1)
3: (0.125,0), ( 0.25,0), ( 0.25,1)
4: ( 0.25,1), ( 0.25,0), (0.375,1)
5: ( 0.25,0), (0.375,0), (0.375,1)
6: (0.375,1), (0.375,0), ( 0.5,1)
7: (0.375,0), ( 0.5,0), ( 0.5,1)
8: ( 0.5,1), ( 0.5,0), (0.625,1)
9: ( 0.5,0), (0.625,0), (0.625,1)
10: (0.625,1), (0.625,0), ( 0.75,1)
11: (0.625,0), ( 0.75,0), ( 0.75,1)
Am I doing something wrong or is there some problem with Three.js?
P.S. the test was based on an example found on Three.js website
P.P.S
a very similar question can be found HERE (although it doesn't deal with manually calculating the UV map)