在THREEJS网格中将共面三角形分组的方法? [英] Way to group coplanar triangles in THREEJS mesh?

查看:652
本文介绍了在THREEJS网格中将共面三角形分组的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用一种建模工具,可以让您直接操纵网格。例如,您可以抓住一张脸并将其拖动。用户对面部的感知可能超过一个共面三角形。例如,一个立方体的顶部面实际上是两个三角形,它们被拖在一起成为一个正方形。



为实现这一点,我想收集所有在拖动时使用的,与任何特定三角形相邻的共面,相邻面。我看过 Simplifier 以及此帖子为例,但我想保留基础三角形,而不是缩小/删除它们。



在美好的日子里,您将构建一个边缘模型ala Mantlya ,您可以在其中行走每条边以查看相邻的面孔并检查法线。



我希望已经有一些代码了为THREEJS写的某个地方,将共面三角形组合在一起。如果我从头开始编写此代码,我能想到的最佳算法是O(n ^ 2),类似于:


  1. 构建边缘哈希(双向)通过行走所有面的所有顶点。每个条目都是2个面指针的数组。创建或修改网格时,只需执行一次此步骤。

  2. 当用户选择要操作的面时,创建空的评估堆栈并将拾取的面放入该堆栈中。另外,创建一个空的共面的面数组。

  3. 弹出面离开评估堆栈,并遍历该面的边缘。在边哈希中查找与该边相邻的所有面。如果面是共面的,则将该面推到评估堆栈上并存储在共面的面阵列中。

  4. 重复步骤3-4,直到评估堆栈为空。

此算法完成后,您应具有一个共面且与开始的面相邻的所有面的数组。



任何人都欢迎所有建议/指针!

解决方案

您的想法有效。



我添加了一个角度阈值,这样您就可以抓取稍微非共面的地形。我必须进行onEvent来确定不确定的递归时间。应该修改它以将vertexHash放在mesh.userData中。



// edit。我已经更新了该类,以利用夹紧参数,当设置为true时,可以将maxAngle夹紧到原始面。

  faceUtils = function(){};设置为false时,它将比较每张脸和下一张脸。 
faceUtils.vertexHash = function(geometry){
geometry.vertexHash = [];
varfaces = geometry.faces;
var vLen = geometry.vertices.length;
for(var i = 0; i< vLen; i ++){
geometry.vertexHash [i] = [];
for(在面孔中变f){
if(faces [f] .a == i || faces [f] .b == i || faces [f] .c == i) {
geometry.vertexHash [i] .push(faces [f]);
}
}
}
}

faceUtils.prototype.getCoplanar = function(maxAngle,geometry,face,clip,out,originFace){
if(clamp == undefined){
lamp = true;
}
if(this.originFace == undefined){
this.originFace = face;
}
if(this.pendingRecursive == undefined){
this.pendingRecursive = 0;
}
this.result = out;
if(out == undefined){
this.result = {count:0};
}
if(geometry.vertexHash == undefined){
faceUtils.vertexHash(geometry);
}
this.pendingRecursive ++;
var vertexs = [ a, b, c];
for(顶点中的var i){
var vertexIndex = face [vertexes [i]];
var neighborFaces = geometry.vertexHash [vertexIndex];
for(var a in neighborFaces){
var newface = neighborFaces [a];
var testF = this.originFace;
if(clamp == false){
testF = face
}
if(testF.normal.angleTo(newface.normal)*(180 / Math.PI)< = maxAngle){
if(this.result [ f + newface.a + newface.b + newface.c] ==未定义){
this.result [ f + newface.a + newface.b + newface.c] = newface;
this.result.count ++;
this.getCoplanar(maxAngle,geometry,newface,clip,this.result,this.originFace);
}
}
}
}
this.pendingRecursive--;

if(this.pendingRecursive == 0& this.onCoplanar!=未定义){
删除this.result.count;
this.onCoplanar(this.result);
}
}

用法很简单:

  var faceTools = new faceUtils(); 
faceTools.onCoplanar = function(rfaces){
for(var i in rfaces){
rfaces [i] .color.setHex(0xff0000);
相交[0] .object.geometry.colorsNeedUpdate = true;
}
}
//参数:最大角度,几何形状,拾取面
faceTools.getCoplanar(13,geometry,face);

我将该课程添加到其他人的提琴中,并且效果很好。 http://jsfiddle.net/fnuaw44r/



我更新了小提琴以使用钳制选项: http://jsfiddle.net/ta0g3mLc/



我想像您所建议的那样,它的效率极低,但这取决于网格。我添加了一个 pendingRecursive变量。只要它不等于零,您就可以放置一个gif,然后在该值再次为零时将其删除。



反正这是一个起点。我敢肯定,一个聪明的人可以在没有嵌套for循环的情况下抛开脸庞。

I'm working on a modeling tool that lets you directly manipulate meshes. For instance, you can grab a face and drag it around. The user's perception of the "face" could be of more than one coplanar triangle. For instance, the top "face" of a cube would actually be two triangles that get dragged together as one square.

To accomplish this, I'd like to collect all coplanar, adjacent faces to any particular triangle for use when dragging. I've looked at Simplifier, as well as this post as examples, but I want to retain the underlying triangles, not reduce/remove them.

In the good ol' days, you'd build an edge model ala Mantlya, where you could walk each edge to see adjacent faces and check normals.

I was hoping there might be some code already written somewhere for THREEJS that groups coplanar triangles together. If I write this from scratch, the best algorithm I can think of is O(n^2), something like:

  1. Build edges hash (both directions) by walking all vertices of all faces. Each entry is an array of 2 face pointers. You only need to do this step once when a mesh is created or modified.
  2. When user picks a face to manipulate, create empty evaluation stack and put picked face into that stack. Also, create empty coplanar face array.
  3. Pop face off evaluation stack, and walk edges of that face. Look up all faces adjacent to that edge in the edges hash. If face is coplanar, push that face onto evaluation stack and store in coplanar face array.
  4. Repeat steps 3-4 until evaluation stack is empty.

When this algorithm finishes, you should have an array of all faces coplanar and adjacent to the face you start with. But it seems relatively inefficient to me.

Any and all suggestions/pointers welcomed!

解决方案

Your idea works.

I added an angle threshold so you can grab slightly non-coplanar topography.I had to make an onEvent to allow for an indeterminate recursion time. It should be modified to put vertexHash in mesh.userData instead.

//edit. I've updated the class to utilize a clamp parameter that allows you to clamp the maxAngle to the original face when set to true. When set to false it will compare each face to next face.

faceUtils = function(){};
faceUtils.vertexHash = function(geometry){
  geometry.vertexHash = [];
  var faces = geometry.faces;
  var vLen = geometry.vertices.length;
  for(var i=0;i<vLen;i++){
    geometry.vertexHash[i] = [];
    for(var f in faces){
         if(faces[f].a == i || faces[f].b == i || faces[f].c == i){
            geometry.vertexHash[i].push(faces[f]);
       }
     }
   }
}

faceUtils.prototype.getCoplanar = function(maxAngle, geometry, face, clamp, out, originFace){
  if(clamp == undefined){
      clamp = true;
  }
  if(this.originFace == undefined){
    this.originFace = face;
  }
  if(this.pendingRecursive == undefined){
    this.pendingRecursive = 0;
  }
    this.result = out;
  if(out == undefined){
       this.result = {count:0};
  }
  if(geometry.vertexHash == undefined){
    faceUtils.vertexHash(geometry);
  }
  this.pendingRecursive++;
  var vertexes = ["a","b","c"];
  for (var i in vertexes){
    var vertexIndex = face[vertexes[i]];
    var adjacentFaces = geometry.vertexHash[vertexIndex];
    for(var a in adjacentFaces){
        var newface = adjacentFaces[a];
        var testF = this.originFace;
        if(clamp == false){
          testF = face
        }
        if(testF.normal.angleTo(newface.normal) * (180/ Math.PI) <= maxAngle){
          if(this.result["f"+newface.a+newface.b+newface.c] == undefined){
            this.result["f"+newface.a+newface.b+newface.c] = newface;
            this.result.count++;
            this.getCoplanar(maxAngle, geometry, newface, clamp, this.result, this.originFace);
          }
        }
    }
  }
  this.pendingRecursive--;

  if(this.pendingRecursive == 0 && this.onCoplanar != undefined){
    delete this.result.count;
    this.onCoplanar(this.result);
  }
}

Usage is simple:

         var faceTools = new faceUtils();
         faceTools.onCoplanar = function(rfaces){
           for(var i in rfaces){
              rfaces[i].color.setHex(0xff0000);
              intersects[0].object.geometry.colorsNeedUpdate = true;
           }
         }
         //params: maxangle, geometry, picked face
         faceTools.getCoplanar(13, geometry, face);

I added the class to someone else's fiddle and it works fine. http://jsfiddle.net/fnuaw44r/

I updated the fiddle to use a clamp option: http://jsfiddle.net/ta0g3mLc/

I imagine its terribly inefficient as you suggest, but it depends on the mesh. I added a "pendingRecursive" variable. So long as it's not equal to zero you could put up a gif and remove it when the value is zero again.

It's a starting point anyways. I am sure someone clever could toss through the faces without a nested for loop.

这篇关于在THREEJS网格中将共面三角形分组的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆