处理OBJ提取顶点

Processing OBJ extract vertex

如何在处理时获取并打印 OBJ 的顶点?

PShape x;

void setup(){ size(600,600,P3D); x = loadShape("x.obj");

} void draw(){

   for (int i = 0; i < x.getVertexCount(); i++) {   PVector v =
x.getVertex(i);

translate(width/2,height/2); shape(x,0,0); }

}

来自the Processing forum

根据文档,getVertexCount()getVertex() 函数仅适用于您通过调用 vertex() 函数添加的顶点,不适用于您从文件。

但是有一种方法(至少有时)可以获取形状文件中的顶点:您首先必须遍历形状文件的子项,然后从这些子项中获取顶点。

PShape shape = loadShape("x.obj");
PShape child = shape.getChild(0);
PVector vertex = child.getVertex(0);

请参阅 the reference 以了解允许您遍历每个子项 PShape,然后遍历每个子项的顶点的函数。

我建议先看看 OBJ format and at your mesh.(More details on Paul Bourke's site)

您应该能够使用免费的 3D 编辑器(例如 Blender, Wings3D 等)轻松检查拓扑。 (例如 mesh -> triangles or quads -> vervices

主要目的是清楚了解您的文件结构(是否使用三角形、四边形面或组合,是否有任何嵌套结构等)

一旦了解模型的结构,访问每个面及其顶点就会容易得多。正如 Kevin 提到的,只需使用 Processing 的 PShape 函数来遍历网格。例如:

  • getChildCount() 统计 PShape child 实例的数量(便于遍历深度嵌套的树结构)
  • getChild() 在给定实例中检索 PShape child 实例
  • getVertexCount() 计算 PShape 实例中的顶点数
  • getVertex() 获取给定(有效索引)处的 PShape 实例顶点

务必始终检查遍历前有多少个PShape children可用,有多少个顶点可用以避免NullPointerReference错误。

这是来自 Examples > Basics > Shape > LoadDisplayOBJ

示例的修改版本
/**
 * Load and Display an OBJ Shape. 
 * 
 * The loadShape() command is used to read simple SVG (Scalable Vector Graphics)
 * files and OBJ (Object) files into a Processing sketch. This example loads an
 * OBJ file of a rocket and displays it to the screen. 
 */


PShape rocket;

float ry;

int startFaceIndex = 0;
int stopFaceIndex;

int maxFaceIndex;

public void setup() {
  size(640, 360, P3D);

  rocket = loadShape("rocket.obj");

  maxFaceIndex = rocket.getChildCount();
  stopFaceIndex = maxFaceIndex;

  println("total faces:",rocket.getChildCount());
  println("faces[0] vertices count:",rocket.getChild(0).getVertexCount());
  println("faces[0] vertices[0]",rocket.getChild(0).getVertex(0));
  println("faces[0] vertices[1]",rocket.getChild(0).getVertex(1));
  println("faces[0] vertices[2]",rocket.getChild(0).getVertex(2));
}

public void draw() {
  background(0);
  lights();

  translate(width/2, height/2 + 100, -200);
  rotateZ(PI);
  rotateY(ry);
  //shape(rocket);
  drawFaceSelection();

  ry += 0.02;
}

void drawFaceSelection(){
  beginShape(TRIANGLES);
  for(int i = startFaceIndex; i < stopFaceIndex; i++){
    PShape face = rocket.getChild(i);
    int numVertices = face.getVertexCount();
    for(int j = 0; j < numVertices; j++){
      vertex(face.getVertexX(j),face.getVertexY(j),face.getVertexZ(j));
    }
  }
  endShape();
}

void mouseDragged(){
  if(keyPressed){
    startFaceIndex = (int)map(mouseX,0,width,0,maxFaceIndex-1);
    startFaceIndex = constrain(startFaceIndex,0,maxFaceIndex-1);
  }else{
    stopFaceIndex = (int)map(mouseX,0,width,1,maxFaceIndex-1);
    stopFaceIndex = constrain(stopFaceIndex,0,maxFaceIndex-1);
  }
}

运行演示中可以在X轴上拖动鼠标来控制绘制.obj网格的面数:

如果您不关心 faces/structure 并且只想访问顶点(将它们渲染为四边形或您喜欢的任何形状),您可以编写一个递归函数来遍历 PShape,它是children 并将所有顶点附加到平面列表中:

/**
 * Load and Display an OBJ Shape. 
 * 
 * The loadShape() command is used to read simple SVG (Scalable Vector Graphics)
 * files and OBJ (Object) files into a Processing sketch. This example loads an
 * OBJ file of a rocket and displays it to the screen. 
 */


PShape rocket;

float ry;

ArrayList<PVector> vertices = new ArrayList<PVector>();
int startVertexIndex = 0;

public void setup() {
  size(640, 360, P3D);
  strokeWeight(9);

  rocket = loadShape("rocket.obj");

  getVertices(rocket,vertices);
  println(vertices);
}

/*
* recursively retrieves vertices from a PShape
* @arg PShape shape - the PShape instance to traverse (must be not null)
* @arg ArrayList<PVector> vertices - the list of vertices to add values to
*/
void getVertices(PShape shape,ArrayList<PVector> vertices){
  //for each face in current mesh
  for(int i = 0 ; i < shape.getChildCount(); i++){
    //get each child element
    PShape child = shape.getChild(i);
    int numChildren = child.getChildCount();
    //if has nested elements, recurse
    if(numChildren > 0){
      for(int j = 0 ; j < numChildren; j++){
        getVertices(child.getChild(j),vertices);
      } 
    }
    //otherwise append child's vertices
    else{
      //get each vertex and append it
      for(int j = 0 ; j < child.getVertexCount(); j++){
        vertices.add(child.getVertex(j));
      }
    }
  }
}

public void draw() {
  background(255);
  lights();

  translate(width/2, height/2 + 100, -200);
  rotateZ(PI);
  rotateY(ry);
  //shape(rocket);
  drawVerticesSelection();

  ry += 0.02;
}

void drawVerticesSelection(){
  beginShape(POINTS);
  for(int i = startVertexIndex; i < vertices.size(); i++){
    PVector v = vertices.get(i);
    vertex(v.x,v.y,v.z);
  }
  endShape();
}

void mouseDragged(){
  startVertexIndex = (int)map(mouseX,0,width,0,vertices.size()-1);
  startVertexIndex = constrain(startVertexIndex,0,vertices.size()-1);
}

这是网格中 showing/hiding 顶点的预览:

切记这会忽略 vertexCodes()

此外,如果您不想更改 .obj 文件本身以及它的呈现方式,您应该查看 GLSL 并阅读 Processing PShader tutorial。它的级别较低,但效率更高,并且您在渲染过程中将拥有更大的灵活性。