部分球体的Three.JS UV Mapping

时间:2018-04-24 15:05:27

标签: javascript 3d three.js

a previous question我希望将立体投影映射到球体上,以便直播虚拟现实事件。

我最终学到了很多关于UV映射的知识,并且能够构建一个看起来令人难以置信的非常精确的映射。然而,我不喜欢这种映射方法的一件事:有一个黑客,其中球体的底部必须映射到“无”,所以我将它映射到纹理的一角。

为了改进此解决方案,我尝试通过调整Three.JS documentation on SphereGeometry的θ长度来创建仅部分球体。

虽然我得到了球体的形状,但我注意到UV映射的一些奇怪之处:<​​/ p>

var fov = 270;
var geometry = new THREE.SphereGeometry(
    1, // Radius
    50, // Horizontal segments
    50, // Vertical segments
    0, // Phi start
    2 * Math.PI, // Phi length
    Math.acos((360 - fov) * Math.PI / 180 / 2), // Theta start
    Math.PI - Math.acos((360 - fov) * Math.PI / 180 / 2) // Theta length
);
var minX, minY, minZ, maxX, maxY, maxZ;
var faceVertexUvs = geometry.faceVertexUvs[0];
for ( var i = 0; i < faceVertexUvs.length; i++ ) {
    var face = geometry.faces[i];
    for ( var j = 0; j < 3; j ++ ) {
        var x = face.vertexNormals[j].x;
        var y = face.vertexNormals[j].y;
        var z = face.vertexNormals[j].z;

        // Capture the upper and lower bounds for all points
        if (!minX || x < minX) minX = x;
        if (!maxX || x > maxX) maxX = x;
        if (!minY || y < minY) minY = y;
        if (!maxY || y > maxX) maxY = y;
        if (!minZ || z < minZ) minZ = z;
        if (!maxZ || z > maxZ) maxZ = z;
    }
}
console.log("minX: " + minX + ", maxX: " + maxX);
console.log("minY: " + minY + ", maxY: " + maxY);
console.log("minZ: " + minZ + ", maxZ: " + maxZ);

我之前在执行UV映射时了解到xyz值的范围从-11 - 无论实际大小如何网格。如果球体的半径为1或半径为100,则x值为1表示“球体的最右侧”,y值为1表示“球体的顶部” 。但是当我有一个不完整的球体(使用thetaStartthetaLength在球体顶部切出一个洞)时,突然maxY等于约0.7854。

为什么这个网格结束于0.7854而不是从-1缩放到1?我希望通过改变球体的形状,我可以简化我的UV绘图逻辑(从我之前链接的问题中移除scaledY术语)但是改变球体的形状似乎已经 no 影响UV地图。

有没有办法告诉Three.JS这个部分球体是完整的形状,它的坐标应该是-1到1?

1 个答案:

答案 0 :(得分:1)

我相信您在描述和代码段中将Normals与UV混淆。您可以在以下行中读取上面的法线值:

var fov = 270;
var geometry:THREE.SphereGeometry = new THREE.SphereGeometry(
    2, // Radius
    50, // Horizontal segments
    50, // Vertical segments
    0, // Phi start
    2 * Math.PI, // Phi length
    Math.acos((360 - fov) * Math.PI / 180 / 2), // Theta start
    Math.PI - Math.acos((360 - fov) * Math.PI / 180 / 2) // Theta length
);
var minX, minY, minZ, maxX, maxY, maxZ;
var faceVertexUvs = geometry.faceVertexUvs[0];

for ( var i = 0; i < faceVertexUvs.length; i++ ) {
    var vertUV = faceVertexUvs[i];
    for ( var j = 0; j < 3; j ++ ) {
        var x = vertUV[j].x;
        var y = vertUV[j].y;

        // Capture the upper and lower bounds for all points
        if (!minX || x < minX) minX = x;
        if (!maxX || x > maxX) maxX = x;
        if (!minY || y < minY) minY = y;
        if (!maxY || y > maxX) maxY = y;
    }
}
console.log("minX: " + minX + ", maxX: " + maxX);
console.log("minY: " + minY + ", maxY: " + maxY);

使用SphereGeometry属性,最小和最大y 法线与预期结果匹配:enter image description here

您要做的是查看最小和最大 UV 值。我已更新代码以获取UV值:

[0, 1]

运行此代码时,您会发现范围始终为[-1, 1],而不是{{1}}。另外,请记住,紫外线不具有Z值;只有X和Y,因为它们用于映射二维图像。

<强>法线:

  • x:(-1,1)
  • y:(-1,1)
  • z:(-1,1)

<强>的UV:

  • x:[0,1]
  • y:[0,1]

你可以看到ThreeJS如何在this code中构建球体UV,特别是在第90,94和111行中。