我已成功通过UV贴图将图像纹理应用于立方体(以生成照片球体查看器)。尽管纹理与立方体面完美对齐,但面连接的线条可以看作细直线。
如果纹理贴图通过Canvas分割并通过MultiMaterial应用于多维数据集,则不会发生同样的问题。
下图比较了两种应用纹理的方法的结果(点击查看大图):
可以在CodePen.io
找到实例可以找到用于纹理的图像here
这里是执行UV映射的代码(它非常简单):
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);
}
我仔细检查了上述函数产生的值,一切看起来都很好 - 与图像宽度和高度相乘时的UV值会产生像素中的正确值。这是转储:
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)
我做错了什么或者Three.js有问题吗?
P.S。 测试基于example found on Three.js website
P.P.S
可以找到一个非常相似的问题HERE(尽管它并不涉及手动计算UV地图)
答案 0 :(得分:1)
在摆弄了一段时间的问题并睡个好觉后,我发现问题是由相邻瓷砖的像素引起的,这些像素在面边缘处会泄漏。这不会发生,图像被切割成较小的独立部分(即通过画布),因为相邻图块的像素不会被复制。
问题可以通过(重新)在源图像中排列图块来解决,这样当它们应用于立方体时,它们就会被放置在下一个图块旁边。这样,如果像素在边缘处发光,那将是正确的。
在上述问题的示例所使用的图像中,瓷砖按以下方式排序:西 - 东 - 上 - 下 - 南 - 北。正确的顺序应该是东 - 西 - 北 - 北+上/下。
这个序列边缘的瓷砖仍然存在问题,谁的边缘仍然与错误的瓷砖相邻: * 北 - 它的右边缘应与East连接 * 顶部 - 它的左边缘应与East连接,右边缘与West连接 * 底部 - 左边缘为西边,右边缘为东边
要解决此问题,我们需要在North,Top和Bottom之间放置一些空格。然后我们可以从East&amp;的边缘复制粘贴一个狭窄的垂直条带。西方瓷砖将它们粘贴在North,Top&amp;的边缘旁边。底部。这样可以防止出现错误的像素。
下图显示了原始图像以及最终结果应该是什么样的(添加到图块的条带用蓝色字母标记):
需要注意的另外两件事是:
function mapCubeUV_v2(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: East, South, West, North, Up, Down
switch(faceSign) {
case '-1.0.0': // East
uvY = vertex.y;
uvX = vertex.z;
tileIx = 0;
break;
case '0.0.1': // South
uvY = vertex.y;
uvX = vertex.x;
tileIx = 1;
break;
case '1.0.0': // West
uvY = vertex.y;
uvX = -vertex.z;
tileIx = 2;
break;
case '0.0.-1': // North
uvY = vertex.y;
uvX = -vertex.x;
tileIx = 3;
break;
case '0.1.0': // Up
uvY = -vertex.z;
uvX = vertex.x;
tileIx = 4.5; // "up" is 1.5 tile width distance from "north"
break;
case '0.-1.0': // Down
uvY = vertex.z;
uvX = vertex.x;
tileIx = 6; // "down" if further 1.5 widths distance from "up"
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),
// [uvX] must be adjusted to point to the part of the image
// containing current tile
uvX = (uvX+tileIx)/8;
console.log(uvX);
// if(faceSign!=='1.0.0') {
// uvY = uvX = 0;
// }
uvs.push( new THREE.Vector2( uvX, uvY ) );
}
geometry.faceVertexUvs[ 0 ].push( uvs );
});
geometry.uvsNeedUpdate = true;
return(geometry);
}