three.js 使用geometry.merge() 优化

第一段是原本画网格的代码 第二段我使用geometry.merge()方法的代码 不知道哪里写错了 不报错 也出不来 请前辈指教

function initObject() {
                //1.在x轴上定义两个点p1 p2
                var geometry = new THREE.Geometry();
                geometry.vertices.push(new THREE.Vector3(-500, 0, 0));
                geometry.vertices.push(new THREE.Vector3(500, 0, 0));
                //2.主要在于这里的算法,从右、下角开始画
                for (var i = 0; i <= 20; i++) {
                    //画横线
                    var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({ color: 0x000000, opacity: 0.2 }));
                    line.position.z = (i * 50) - 500;
                    scene.add(line);


                    var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({ color: 0x000000, opacity: 0.2 }));
                    line.position.x = (i * 50) - 500;
                    line.rotation.y = 90 * Math.PI / 180;   //转90度
                    scene.add(line);

                }
            }
function initObject() {  
                var geometry = new THREE.Geometry();  
                var allLine=new THREE.Geometry();
                geometry.vertices.push( new THREE.Vector3( - 500, 0, 0 ) );  
                geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ) ); 
                for ( var i = 0; i <= 20; i ++ ) { 
                    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
                    line.position.z = ( i * 50 ) - 500;  
                    allLine.merge(line.geometry,line.matrix) 
                    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
                    line.position.x = ( i * 50 ) - 500;  
                    line.rotation.y = 90 * Math.PI / 180;  
                    allLine.merge(line.geometry,line.matrix)
                }  
                allLineMesh=new THREE.Mesh(allLine,new THREE.MeshBasicMaterial({color:0x000000,side:THREE.DoubleSide}))
                scene.add( allLineMesh );  
            }  
阅读 7k
1 个回答

(1) 要使用正确的对象类型

这里不能用Mesh,因为这里geometry的点数不满足Mesh的规范,图形是渲染不出来的,Mesh是由小三角面构成,顶点数必须是3的倍数。所以,这里应该用THREE.Line

将:

allLineMesh=new THREE.Mesh(allLine,new THREE.MeshBasicMaterial({color:0x000000,side:THREE.DoubleSide}))

改成:

allLineMesh=new THREE.Line(allLine,new THREE.MeshBasicMaterial({color:0x000000,side:THREE.DoubleSide}))

你会发现有图像出来了,但只有一条直线,下面讲这个问题。

(2)对对象使用变换之后,要手动更新对象变换矩阵

在three.js中,考虑到性能,框架在做变换的时候不会自动更新变换矩阵(其实还有很多东西都不会自动更新,可以参考文档里面定义的xxxNeedsUpdate,computeXXX,updateXXX之类的属性),所以,如果你对对象做了变换之后要用到对象的矩阵,那么你首先需要更新对象的变换矩阵,可以使用Object3D.updateMatrix()方法。

所以,像下面这种写法是不能看到geometry有任何改变的:

var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
line.position.z = ( i * 50 ) - 500; // 这里做了变换,但是没更新变换矩阵
allLine.merge(line.geometry,line.matrix)//使用原始的变换矩阵,于是对象的变换并没有应用到geometry上

可以改成:

var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
line.position.z = ( i * 50 ) - 500;
line.updateMatrix(); // 加了这句
allLine.merge(line.geometry,line.matrix)

现在可以看到图像了,但是你会发现图像很奇怪:

图片描述

这是什么鬼?为什么有那么多交叉线?

其实这和Line类型的绘制策略有关,Line是把vertices的点一个一个连起来的,比如vertices里有四个点[A,B,C,D],那么Line在画的时候,就是A-->B-->C--D,而你想的可能是A-->B,C-->D,简单验证一下,使用下面的函数:

            function initObject(){
                var material = new THREE.LineBasicMaterial({
                    color: 0x0000ff
                });
                var geometry = new THREE.Geometry();
                geometry.vertices.push(
                    new THREE.Vector3( -500, 0, 0 ),
                    new THREE.Vector3( 500, 0, 0 ),
                    new THREE.Vector3( 0, 0, -500 ),
                    new THREE.Vector3( 0, 0, 500 )
                );
                var line = new THREE.Line( geometry, material );
                scene.add( line );
            }

运行的结果如下图:

图片描述

确实是A-->B-->C--D这样连的

(3)利用吸附算法使中间连线吸附到边缘

对于Line的A-->B-->C--D这种画法我们是没办法改变,但是,在这个例子中,我们可以人为的将B-->C边吸附到边缘。比如有个上面四个点的坐标如下:

A:[1,0,0]
B:[-1,0,0]
C:[0,0,1]
D:[0,0,-1]

我们可以人为的插一个点E:
A:[1,0,0]
B:[-1,0,0]
E:[-1,0,1]
C:[0,0,1]
D:[0,0,-1]
使得B-->C由斜线变成了沿着边缘走的斜线:

图片描述

吸附算法如下:

 // 吸附算法
            function adsorb(geometry,compares){
                var vertices =  geometry.vertices;
                var cdt1 = compares[0];
                var cdt2 = compares[1];
                for (var i = 0 ; i < vertices.length-1; i++) {
                    var vertice = vertices[i];
                    var nextVertice = vertices[i+1];
                    if(Math.round(vertice[cdt1]) !== Math.round(nextVertice[cdt1])
                        && Math.round(vertice[cdt2]) !== Math.round(nextVertice[cdt2])){ // 差异超过两个维度
                        var vector = new THREE.Vector3();
                        vector[cdt1] = vertice[cdt1];
                        vector[cdt2] = nextVertice[cdt2];
                        vertices.splice(i+1, 0,vector); // 插入一个点
                        i++;
                    }
                }
                geometry.vertices = vertices;
            }

将吸附算法加入到创建过程中:

 function initObject() {
                var geometry = new THREE.Geometry();
                var allLine=new THREE.Geometry();
                geometry.vertices.push( new THREE.Vector3( - 500, 0, 0 ) );
                geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ) );
                for ( var i = 0; i <= 20; i ++ ) {
                    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
                    line.position.z = ( i * 50 ) - 500;
                    line.updateMatrix();
                    allLine.merge(line.geometry,line.matrix)
                    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
                    line.position.x = ( i * 50 ) - 500;
                    line.rotation.y = 90 * Math.PI / 180;
                    line.updateMatrix();
                    allLine.merge(line.geometry,line.matrix)
                }
                adsorb(allLine,["x","z"]);  // 添加这一行
                allLine.verticesNeedUpdate = true;
                allLineMesh=new THREE.Line(allLine,new THREE.MeshBasicMaterial({color:0x000000,side:THREE.DoubleSide}))
                scene.add( allLineMesh );
            }

这样看起来就正确了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题