如何在three.js中计算闭合形状的法线?

时间:2017-11-08 13:40:59

标签: javascript three.js normals

我正在尝试为自己的文件格式编写自己的网格导入器。在我的文件格式中没有正常数据。所以我试图计算一个接近形状的法线并将这些法线应用于网格。

我的解决方案是为几何体的每个面计算法线向量,并在法向量方向上从这些面的中间创建一个光线投影。如果那个光线投射击中某个东西(另一个平面),则意味着这个方向在里面。在那种情况下,我翻转正常,如果它没有击中某些东西,我就这样离开。

虽然我用这种逻辑写了一个函数,但是法线根本没有改变。

        function calculateNormals(object){

            for (var i = 0; i < object.geometry.faces.length; i++) {
                var vertices= object.geometry.vertices;
                var face=object.geometry.faces[i];



                var a=vertices[face.a];
                var b=vertices[face.b];
                var c=vertices[face.c];

                console.log(face.a+" "+face.b+" "+face.c+" "+face.normal.z);
                console.log(face);
                console.log(face[4]);

                var edge0=new THREE.Vector3(0,0,0);
                edge0.subVectors(a,b);

                var edge1=new THREE.Vector3(0,0,0);
                edge1.subVectors(b,c);

                var planeNormal=new THREE.Vector3(0,0,0)
                planeNormal.crossVectors(edge0,edge1);

                // console.log(planeNormal);

                //Raycast from middle point towards plane nrmal direction
                //If it hits anything it means normal direction is wrong
                var midPoint=calculateMiddlePoint([a,b,c]);
                var raycaster = new THREE.Raycaster(midPoint,planeNormal);

                var intersects = raycaster.intersectObjects([object]);
                if(intersects.length==0){
                    console.log("Normal is true");
                    face.normal=planeNormal;
                }else{
                    console.log("Normal is wrong, you should flip normal direction, length: "+intersects.length);

                    console.log("Old face");
                    console.log(face.normal);

                    var newNormal=new THREE.Vector3(-1*planeNormal.x,-1*planeNormal.y,-1*planeNormal.z);
                    console.log(newNormal);
                    face.normal=newNormal;



                    console.log("new face");
                    console.log(face.normal);
                    console.log(face);
                }

                object.geometry.faces[i]=face;


                // console.log(object.geometry.faces);

            };


            return object;


        }

1 个答案:

答案 0 :(得分:0)

Matey提出了一个很好的观点。绕线顺序决定了面部法线,意味着哪一面被认为是正面。&#34;顶点法线用于着色(例如,使用MeshPhongMaterial)。如果你的顶点法线指向与法线正面相反的方向,你最终会得到意想不到的结果(从不良阴影到完全黑色的面孔)。

所有这一切,Geometry都有辅助函数来计算法线。

Geometry.computeFaceNormals(基于蜿蜒的顺序)

Geometry.computeFlatVertexNormals(将顶点法线设置为与关联的法线法线相同)

Geometry.computeVertexNormals(将顶点法线设置为其周围法线法线的平均值)

一旦你计算了法线,就可以通过重新排序顶点(纠正面法线)或者自己重新计算顶点法线来进行第二次尝试来纠正它们。