首页 > 解决方案 > 无法使用三个 js 渲染网格

问题描述

这段代码应该在三个 js 中生成一个圆环网格。我很确定数学是正确的。但是,如果我更改某些参数,它只会渲染一块圆环或奇怪的东西。我的 THREE.Mesh 练习有什么不好的地方吗?

// the vertices of the mesh and the vertex normals ----------------
        var nx = 64;
        var ny = 32;
        var R = 10; var r = 3;
        var Vertices = new Array(nx);
        var Normals = new Array(nx);
        for (var i = 0; i < nx; i++) {
            Vertices[i] = new Array(ny);
            Normals[i] = new Array(ny);
            var u = i / nx * 2 * Math.PI;
            var cos_u = Math.cos(u);
            var sin_u = Math.sin(u);
            var cx = R * cos_u;
            var cy = R * sin_u;
            for (var j = 0; j < ny; j++) {
                var v = j / ny * 2 * Math.PI;
                var rcos_v = r * Math.cos(v);
                var rsin_v = r * Math.sin(v);
                Vertices[i][j] = new THREE.Vector3(
                    cx + rcos_v * cos_u,
                    cy + rcos_v * sin_u,
                    rsin_v
                );
                Normals[i][j] = new THREE.Vector3(
                    rcos_v * cos_u,
                    rcos_v * sin_u,
                    rsin_v
                );
            }
        }

// vertices as a dot cloud ----------------------------------------
        var dotGeometry = new THREE.Geometry();
        for (var i = 0; i < nx; i++) {
            for (var j = 0; j < ny; j++) {
                dotGeometry.vertices.push(Vertices[i][j]);
            }
        }
        var dotMaterial =
            new THREE.PointsMaterial({ size: 1, sizeAttenuation: false });
        var cloud = new THREE.Points(dotGeometry, dotMaterial);

// mesh -----------------------------------------------------------
        var geom = new THREE.Geometry();
        for (var i = 0; i < nx; i++) {
            var ip1 = (i == nx - 1 ? 0 : i + 1);
            for (var j = 0; j < ny; j++) {
                var jp1 = (j == ny - 1 ? 0 : j + 1);
                geom.vertices.push(Vertices[i][j]);
                geom.vertices.push(Vertices[i][jp1]);
                geom.vertices.push(Vertices[ip1][j]);
                var vnormals1 = 
                    [Normals[i][j], Normals[i][jp1], Normals[ip1][j]];
                geom.faces.push(new THREE.Face3(
                    i * ny + j,
                    i * ny + jp1,
                    ip1 * ny + j,
                    vnormals1
                ));
                geom.vertices.push(Vertices[i][jp1]);
                geom.vertices.push(Vertices[ip1][jp1]);
                geom.vertices.push(Vertices[ip1][j]);
                var vnormals2 = 
                    [Normals[i][jp1], Normals[ip1][jp1], Normals[ip1][j]];
                geom.faces.push(new THREE.Face3(
                    i * ny + jp1,
                    ip1 * ny + jp1,
                    ip1 * ny + j,
                    vnormals2
                ));
            }
        }

        var torusMesh = new THREE.Mesh(
            geom, 
            new THREE.MeshNormalMaterial({ wireframe: false }));

// three js scene -------------------------------------------------
        var scene = new THREE.Scene();

        var aspect = window.innerWidth / window.innerHeight;
        var camera = new THREE.PerspectiveCamera(50, aspect, 1, 10000);
        camera.position.z = 30;
        scene.add(camera);

        var renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        var object = new THREE.Object3D();
        object.add(torusMesh);
        object.add(cloud);
        scene.add(object);
        renderer.render(scene, camera);

// animation ---------------------------------------------------------
        var isDragging = false;
        var previousMousePosition = {
            x: 0,
            y: 0
        };
        $(renderer.domElement).on('mousedown', function (e) {
            isDragging = true;
        }).on('mousemove', function (e) {
            var deltaMove = {
                x: e.offsetX - previousMousePosition.x,
                y: e.offsetY - previousMousePosition.y
            };
            if (isDragging) {
                var deltaRotationQuaternion = new THREE.Quaternion()
                    .setFromEuler(new THREE.Euler(
                        Math.PI / 180 * (deltaMove.y * 1),
                        Math.PI / 180 * (deltaMove.x * 1),
                        0,
                        'XYZ'
                    ));
                object.quaternion.multiplyQuaternions(deltaRotationQuaternion,
                    object.quaternion);
            }
            previousMousePosition = {
                x: e.offsetX,
                y: e.offsetY
            };
        });

        $(document).on('mouseup', function (e) {
            isDragging = false;
        });

        window.requestAnimFrame = (function () {
            return window.requestAnimationFrame ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame ||
                function (callback) {
                    window.setTimeout(callback, 1000 / 60);
                };
        })();

        function render() {
            renderer.render(scene, camera);
            requestAnimFrame(render);
        }

        render();
canvas {
            width: 100%;
            height: 100%
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.js"></script>

标签: javascripthtmlthree.js

解决方案


我认为您的代码存在两个问题:

  • 使用时,您只需将类型的对象添加到数组中即可Geometry定义面。几何的顶点只定义一次。在你的情况下,你可以这样做:Face3faces

    geom.vertices = dotGeometry.vertices;
    
  • 此外,你的脸的缠绕顺序不正确。您必须切换第一个和第三个索引。

// the vertices of the mesh and the vertex normals ----------------
        var nx = 64;
        var ny = 32;
        var R = 10; var r = 3;
        var Vertices = new Array(nx);
        var Normals = new Array(nx);
        for (var i = 0; i < nx; i++) {
            Vertices[i] = new Array(ny);
            Normals[i] = new Array(ny);
            var u = i / nx * 2 * Math.PI;
            var cos_u = Math.cos(u);
            var sin_u = Math.sin(u);
            var cx = R * cos_u;
            var cy = R * sin_u;
            for (var j = 0; j < ny; j++) {
                var v = j / ny * 2 * Math.PI;
                var rcos_v = r * Math.cos(v);
                var rsin_v = r * Math.sin(v);
                Vertices[i][j] = new THREE.Vector3(
                    cx + rcos_v * cos_u,
                    cy + rcos_v * sin_u,
                    rsin_v
                );
                Normals[i][j] = new THREE.Vector3(
                    rcos_v * cos_u,
                    rcos_v * sin_u,
                    rsin_v
                );
            }
        }

// vertices as a dot cloud ----------------------------------------
        var dotGeometry = new THREE.Geometry();
        for (var i = 0; i < nx; i++) {
            for (var j = 0; j < ny; j++) {
                dotGeometry.vertices.push(Vertices[i][j]);
            }
        }
        var dotMaterial =
            new THREE.PointsMaterial({ size: 1, sizeAttenuation: false });
        var cloud = new THREE.Points(dotGeometry, dotMaterial);

// mesh -----------------------------------------------------------
        var geom = new THREE.Geometry();
        geom.vertices = dotGeometry.vertices;
        for (var i = 0; i < nx; i++) {
            var ip1 = (i == nx - 1 ? 0 : i + 1);
            for (var j = 0; j < ny; j++) {
                var jp1 = (j == ny - 1 ? 0 : j + 1);

                var vnormals1 = 
                    [Normals[i][j], Normals[i][jp1], Normals[ip1][j]];
                geom.faces.push(new THREE.Face3(
                    ip1 * ny + j,
                    i * ny + jp1,
                    i * ny + j,
                    vnormals1
                ));
 
                var vnormals2 = 
                    [Normals[i][jp1], Normals[ip1][jp1], Normals[ip1][j]];
                geom.faces.push(new THREE.Face3(
                    ip1 * ny + j,
                    ip1 * ny + jp1,
                    i * ny + jp1,
                    vnormals2
                ));
            }
        }

        var torusMesh = new THREE.Mesh(
            geom, 
            new THREE.MeshNormalMaterial({ wireframe: false }));

// three js scene -------------------------------------------------
        var scene = new THREE.Scene();

        var aspect = window.innerWidth / window.innerHeight;
        var camera = new THREE.PerspectiveCamera(50, aspect, 1, 10000);
        camera.position.z = 30;
        scene.add(camera);

        var renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        var object = new THREE.Object3D();
        object.add(torusMesh);
        object.add(cloud);
        scene.add(object);
        renderer.render(scene, camera);

// animation ---------------------------------------------------------
        var isDragging = false;
        var previousMousePosition = {
            x: 0,
            y: 0
        };
        $(renderer.domElement).on('mousedown', function (e) {
            isDragging = true;
        }).on('mousemove', function (e) {
            var deltaMove = {
                x: e.offsetX - previousMousePosition.x,
                y: e.offsetY - previousMousePosition.y
            };
            if (isDragging) {
                var deltaRotationQuaternion = new THREE.Quaternion()
                    .setFromEuler(new THREE.Euler(
                        Math.PI / 180 * (deltaMove.y * 1),
                        Math.PI / 180 * (deltaMove.x * 1),
                        0,
                        'XYZ'
                    ));
                object.quaternion.multiplyQuaternions(deltaRotationQuaternion,
                    object.quaternion);
            }
            previousMousePosition = {
                x: e.offsetX,
                y: e.offsetY
            };
        });

        $(document).on('mouseup', function (e) {
            isDragging = false;
        });

        window.requestAnimFrame = (function () {
            return window.requestAnimationFrame ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame ||
                function (callback) {
                    window.setTimeout(callback, 1000 / 60);
                };
        })();

        function render() {
            renderer.render(scene, camera);
            requestAnimFrame(render);
        }

        render();
canvas {
            width: 100%;
            height: 100%
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.js"></script>
<script
  src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
  integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E="
  crossorigin="anonymous"></script>

此外,考虑使用 的方法TorusBufferGeometryBufferGeometry此外,使用 生成几何图形比使用生成几何图形要快得多Geometry


推荐阅读