【问题标题】:Three.JS UV Mapping for partial spheres三.JS UV Mapping for partial spheres
【发布时间】:2023-04-02 09:51:01
【问题描述】:

a previous question 中,我希望将立体投影映射到球体上,以便实时流式传输虚拟现实事件。

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

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

虽然我得到了正确的球体形状,但我注意到 UV 映射有些奇怪:

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 的范围内?

【问题讨论】:

    标签: javascript 3d three.js


    【解决方案1】:

    我相信您在描述和代码 sn-p 中将法线与 UV 混淆了。您正在以下几行中阅读上述 Normals 的值:

        var x = face.vertexNormals[j].x;
        var y = face.vertexNormals[j].y;
        var z = face.vertexNormals[j].z;
    

    使用您的 SphereGeometry 属性,最小和最大 y 法线与预期结果相匹配:

    您要做的是查看最小和最大 UV 值。我已经更新了获取 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);
    

    运行此代码时,您会看到范围始终为[0, 1],而不是[-1, 1]。此外,请记住 UV 没有 Z 值;只有 X 和 Y,因为它们用于映射二维图像。

    法线:

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

    UV:

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

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

    【讨论】:

    • 我可能很困惑,因为我对 UV 映射的概念还很陌生。我知道法线指的是 3D 空间中多边形上的点,而 UV 指的是 2D 空间中纹理上的点。我还知道 UV 的范围是 [0, 1]。但是我认为法线总是的范围是[-1, 1]。当我制作一个半径为 100 的球体时,法线的范围仍为 [-1, 1] - 这表明它与网格的物理尺寸无关。所以我认为1 的意思是“网格的顶部”,无论形状或大小如何。
    • 创建球体时,X,Y,Z 空间中的法线为perpendicular to the face。但是由于您的球体没有“北极”,因此您不会遇到法线指向正上方。这就是您发现最大 y 值是 0.7854 的原因。
    • 这是有道理的,但提出了一些新问题,即人们应该如何为两个面指向同一方向的网格创建 UV 贴图(就像一个甜甜圈,内环和外环都有面指向所有基本方向)。感谢您的解释。
    • This example 擅长说明 ThreeJS 如何通过将this image 映射到其标准几何图形(包括甜甜圈(A.K.A. torus))来定义其 UV。现在,要映射您自己的纹理,这取决于您使用的软件。
    猜你喜欢
    • 2013-07-15
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 2017-04-19
    • 2013-03-21
    • 2019-08-08
    • 2013-02-14
    • 1970-01-01
    相关资源
    最近更新 更多