如何挤压在3D路径? [英] how to extrude a path in 3d?

查看:159
本文介绍了如何挤压在3D路径?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图挤出在3D的路径。没什么特别的是,只是下面的一些要点,并使用正多边形的'管道'。我使用的处理目前快速原型,但稍后会转code到OpenGL的。

我的问题是旋转的关节处直角。我想我有一个大概的了解如何获得角度,不能确定。

我从一个样品由西蒙Greenwold(处理>文件>例子> 3D>表>顶点)。这里是我的尝试,到目前为止开始

更新>重构/简体code

 以下是主要的草图code:
INT pointsNum = 10;
挤出明星;

INT变焦= 0;

无效设置(){
  大小(500,500,P3D);

  PVector []点=新PVector [pointsNum + 1];
  的for(int i = 0; I< = pointsNum;我++){
    浮动角= TWO_PI / pointsNum *我;
    如果(我%2 == 0)
      点[i] =新PVector(COS(角)* 100,罪(角)* 100,0);
    其他
      点[i] =新PVector(COS(角)* 50,罪(角)* 50,0)​​;
  }

  星级=新的挤压(10,10,分,3);
}

无效的draw(){
  背景(0);
  灯();
  平移(宽度/ 2,高度/ 2,变焦);
  rotateY(地图(mouseX,0,宽度,0,PI));
  rotateX(地图(mouseY的,0,高度,0,PI));
  rotateZ(-HALF_PI);
  noStroke();
  补(255,255,255);
  翻译(0,-40,0);
  star.draw();
}

无效键pressed(){
  如果(关键=='A')变焦+ = 5;
  如果(关键=='S')变焦 -  = 5;
}
 

这里是挤出类:

进口processing.core.PMatrix3D;

 类挤出{

  浮topRadius,bottomRadius,身材高大,两侧;
  INT pointsNum;
  PVector []分;

  挤压(){}

  挤压(浮topRadius,浮bottomRadius,PVector []点,诠释侧){
    this.topRadius = topRadius;
    this.bottomRadius = bottomRadius;
    this.points =分;
    this.pointsNum = points.length;
    this.sides =两侧;
  }

  无效的draw(){
    如果(pointsNum> = 2){
      浮动角= 0;
      浮angleIncrement = TWO_PI /侧面;

      //开始盖之间的平局段
      角= 0;
      的for(int i = 1; I< pointsNum ++我){
        beginShape(QUAD_STRIP);
        对于(INT J = 0; J<侧面+ 1; J ++){
          顶点(点[I-1]的.x + COS(角)* topRadius,分〔I-1] .Y,点[I-1] .Z +罪(角度)* topRadius);
          顶点(点[I] .X + COS(角)* bottomRadius,点[I] .Y,点[I] .Z +罪(角)* bottomRadius);

          角+ = angleIncrement;
          }
        endShape();
      }
      //开始盖之间的平局段
    }其他的println(不够分:+ pointsNum);
  }
}
 

更新

下面是如何我素描是这样的:

问题是接头不在直角,所以拉伸看上去错误的。 这不是一个很好的例子,因为这可能与一台车床来实现。如果我能得到一个车床用任意一组点和一个轴,这将是伟大的工作。我使用的挤压 因为我想根据利维乌·Stoicoviciu的艺术创造几何体。

下面是一些示例:

很抱歉的质量较差。

正如你可以在三角形图像看,这将是与型材实现。

更新

下面是我尝试使用抽奖方法drhirsch的帮助:

 无效平局(){
    如果(pointsNum> = 2){
      浮动角= 0;
      浮angleIncrement = TWO_PI /侧面;

      //开始盖之间的平局段
      角= 0;
      的for(int i = 1; I< pointsNum ++我){
        beginShape(QUAD_STRIP);
        对于(INT J = 0; J<侧面+ 1; J ++){

          PVector S =新PVector(0,0,1);
          PVector CN =新PVector();
          点[I] .normalize(CN);
          PVector R = s.cross(CN);
          浮起= ACOS(s.dot(CN));
          PMatrix3D腐=新PMatrix3D(1,0,0,0,
                                        0,1,0,0,
                                        0,0,1,0,
                                        0,0,0,1);
          rot.rotate(一个,r.x,r.y,r.z);
          PVector rotVec =新PVector();
          rot.mult(点[I],rotVec);
          rotVec.add(新PVector(COS(角)* topRadius,0,罪(角)* topRadius));

          顶点(点[I-1]的.x + COS(角)* topRadius,分〔I-1] .Y,点[I-1] .Z +罪(角度)* topRadius);
          顶点(rotVec.x,rotVec.y,rotVec.y);

          //vertex(points[i-1].x + COS(角)* topRadius,分〔I-1] .Y,点[I-1] .Z +罪(角度)* topRadius);
          //vertex(points[i].x + COS(角)* bottomRadius,点[I] .Y,点[I] .Z +罪(角)* bottomRadius);

          角+ = angleIncrement;
          }
        endShape();
      }
      //开始盖之间的平局段
    }其他的println(不够分:+ pointsNum);
  }
 

我已经重构了code所以现在是曾经被称为CShape该类称为拉伸时,code是越来越希望simples,我用PVector对象的数组的载体,而不是PVector对象这可能会造成混淆。

下面是我还与一些埃舍尔式的结果另一种尝试:

更新过的平局

 无效平局(){
    如果(pointsNum> = 2){
      浮动角= 0;
      浮angleIncrement = TWO_PI /侧面;

      //开始盖之间的平局段
      角= 0;
      的for(int i = 1; I< pointsNum ++我){
        beginShape(QUAD_STRIP);
        浮angleBetweenNextAnd previous = 0.0;
        如果(ⅰ&所述; pointsNum  -  1)angleBetweenNextAnd previous = PVector.angleBetween(点[I],点[I + 1]);

        对于(INT J = 0; J<侧面+ 1; J ++){

          PVector S =新PVector(0,0,1);
          PVector S2 =新PVector(0,0,1);
          PVector CN =新PVector();
          PVector CN2 =新PVector();
          分〔I-1] .normalize(CN);
          点[I] .normalize(CN);
          PVector R = s.cross(CN);
          PVector R2 = s.cross(CN2);
          PMatrix3D腐=新PMatrix3D(1,0,0,0,
                                        0,1,0,0,
                                        0,0,1,0,
                                        0,0,0,1);
          PMatrix3D ROT2 =新PMatrix3D(1,0,0,0,
                                        0,1,0,0,
                                        0,0,1,0,
                                        0,0,0,1);

          rot.rotate(angleBetweenNextAnd previous,RX,RY,RZ);
          rot2.rotate(angleBetweenNextAnd previous,R2.X,r2.y,拷贝到R2.z);

          PVector rotVec =新PVector();
          rot.mult(点[Ⅰ-1],rotVec);
          rotVec.add(新PVector(COS(角)* topRadius,0,罪(角)* topRadius));
          PVector rotVec2 =新PVector();
          rot2.mult(点[I],rotVec2);
          rotVec2.add(新PVector(COS(角)* topRadius,0,罪(角)* topRadius));

          顶点(rotVec.x,rotVec.y,rotVec.z);
          顶点(rotVec2.x,rotVec2.y,rotVec2.z);
          //vertex(points[i-1].x + COS(角)* topRadius,分〔I-1] .Y,点[I-1] .Z +罪(角度)* topRadius);
          //vertex(points[i].x + COS(角)* bottomRadius,点[I] .Y,点[I] .Z +罪(角)* bottomRadius);

          角+ = angleIncrement;
          }
        endShape();
      }
      //开始盖之间的平局段
    }其他的println(不够分:+ pointsNum);
  }
}
 

编辑由drhirsch 这应该工作:

 无效平局(){
    如果(pointsNum> = 2){
      浮动角= 0;
      浮angleIncrement = TWO_PI /侧面;

      //开始盖之间的平局段
      角= 0;
      的for(int i = 1; I< pointsNum ++我){
        beginShape(QUAD_STRIP);
        浮angleBetweenNextAnd previous = 0.0;
        如果(ⅰ&所述; pointsNum  -  1)angleBetweenNextAnd previous = PVector.angleBetween(点[I],点[I + 1]);
        PVector S =新PVector(0,0,1);
        PVector S2 =新PVector(0,0,1);
        PVector CN =新PVector();
        PVector CN2 =新PVector();
        分〔I-1] .normalize(CN);
        点[I] .normalize(CN2);
        PVector R = s.cross(CN);
        PVector R2 = s.cross(CN2);
        PMatrix3D腐=新PMatrix3D(1,0,0,0,
                                      0,1,0,0,
                                      0,0,1,0,
                                      0,0,0,1);
        PMatrix3D ROT2 =新PMatrix3D(1,0,0,0,
                                       0,1,0,0,
                                       0,0,1,0,
                                       0,0,0,1);

        rot.rotate(angleBetweenNextAnd previous,RX,RY,RZ);
        rot2.rotate(angleBetweenNextAnd previous,R2.X,r2.y,拷贝到R2.z);
        PVector rotVec =新PVector();
        PVector rotVec2 =新PVector();

        对于(INT J = 0; J<侧面+ 1; J ++){
          //我现在还不能确定这一点。应的形状是在xy平面内
          //如果挤出主要是沿z轴?如果形状是现在在
          // XZ平面,你需要使用(0,1,0)作为形状的法向量
          //(这将是S和S2上面,不要使用短名我有
          //使用,抱歉)
          PVector形状=新PVector(COS(角)* topRadius,0,罪(角)* topRadius);

          rot.mult(形状,rotVec);
          rot2.mult(形状,rotVec2);

          rotVec.add(点[I-1]);
          rotVec2.add(点[i]);

          顶点(rotVec.x,rotVec.y,rotVec.z);
          顶点(rotVec2.x,rotVec2.y,rotVec2.z);
          //vertex(points[i-1].x + COS(角)* topRadius,分〔I-1] .Y,点[I-1] .Z +罪(角度)* topRadius);
          //vertex(points[i].x + COS(角)* bottomRadius,点[I] .Y,点[I] .Z +罪(角)* bottomRadius);

          角+ = angleIncrement;
          }
        endShape();
      }
      //开始盖之间的平局段
    }其他的println(不够分:+ pointsNum);
  }
}
 

更新

下面是我的问题的一个简单的例子:

蓝色路径相当于点[] PVector阵列中我code,如果pointsNum = 6。 红色的路径是什么,我在努力解决,绿色路径就是我想要达到的。

更新

顶点我认为,为了一些小问题。 下面是使用6分一些打印屏幕和没有(的if / else%2)明星的条件。

解决方案

假设你的形状有一个正常的向量S在您的例子S。将(0,0,1),因为你的形状是平XY。您可以使用跨产品的当前路径矢量V(标准化)和S之间获得的旋转轴矢量R.您需要旋转你的形状R.左右旋转的角度可以从S和V之间的点积得到所以:

 研究= S x垂直
A =弧COS(S,V)
 

现在,你可以设置一个旋转矩阵与R和旋转的形状它。

您可以使用glRotate(...)旋转堆栈中的当前矩阵,但不能在glBegin()和glEnd()之间进行。所以,你必须通过自己或与库做矩阵乘法。

编辑:经过短暂的看你使用该库,你应该能够设置与旋转矩阵

  PVector S =新PVector(0,0,1); //已经标准化(意思是长度为1)
PVector CN;
current.normalize(CN);
PVector R = s.cross(CN);
浮起= ACOS(s.dot(CN));
PMatrix腐=新PMatrix(1,0,0,0,
                          0,1,0,0,
                          0,0,1,0,
                          0,0,0,1);
rot.rotate(一个,r.x,r.y,r.z);
 

和现在乘以你的形状的每个元素腐烂和你目前的路径向量它翻译:

  PVector rotVec;
rot.mult((PVector)形状[I],rotVec);
rotVec.add(电流);
 

I'm trying to extrude a path in 3d. Nothing fancy yet, just following some points and using a regular polygon for 'tubing'. I'm using Processing for now to quickly prototype, but will later turn the code into OpenGL.

My problem is rotating the 'joints' at the right angles. I think I have a rough idea how to get the angles, not sure.

I've started from a sample by Simon Greenwold(Processing > File > Examples > 3D > Form > Vertices).Here's my attempt so far:

UPDATE > REFACTORED/SIMPLIFIED CODE

Here is the main sketch code:
int pointsNum = 10;
Extrusion star;

int zoom = 0;

void setup() {
  size(500, 500, P3D);

  PVector[] points = new PVector[pointsNum+1];
  for(int i = 0 ; i <= pointsNum ; i++){
    float angle = TWO_PI/pointsNum * i;
    if(i % 2 == 0)
      points[i] = new PVector(cos(angle) * 100,sin(angle) * 100,0);
    else
      points[i] = new PVector(cos(angle) * 50,sin(angle) * 50,0);
  }

  star = new Extrusion(10,10,points,3);
}

void draw() {
  background(0);
  lights();
  translate(width / 2, height / 2,zoom);
  rotateY(map(mouseX, 0, width, 0, PI));
  rotateX(map(mouseY, 0, height, 0, PI));
  rotateZ(-HALF_PI);
  noStroke();
  fill(255, 255, 255);
  translate(0, -40, 0);
  star.draw();
}

void keyPressed(){
  if(key == 'a') zoom += 5;
  if(key == 's') zoom -= 5;
}

And here is the Extrusion class:

import processing.core.PMatrix3D;

class Extrusion{

  float topRadius,bottomRadius,tall,sides;
  int pointsNum;
  PVector[] points;

  Extrusion(){}

  Extrusion(float topRadius, float bottomRadius, PVector[] points, int sides) {
    this.topRadius = topRadius;
    this.bottomRadius = bottomRadius;
    this.points = points;
    this.pointsNum = points.length;
    this.sides = sides;
  }

  void draw() {
    if(pointsNum >= 2){  
      float angle = 0;
      float angleIncrement = TWO_PI / sides;

      //begin draw segments between caps
      angle = 0;
      for(int i = 1; i < pointsNum ; ++i){
        beginShape(QUAD_STRIP);
        for(int j = 0; j < sides + 1; j++){
          vertex(points[i-1].x + cos(angle) * topRadius, points[i-1].y, points[i-1].z + sin(angle) * topRadius);
          vertex(points[i].x + cos(angle) * bottomRadius, points[i].y, points[i].z + sin(angle) * bottomRadius);

          angle += angleIncrement;
          }
        endShape();
      }
      //begin draw segments between caps
    }else println("Not enough points: " + pointsNum);
  }
}

UPDATE

Here is how my sketch looks like:

The problem is the joints aren't at the right angle, so the extrude looks wrong. This isn't a very good example, as this could be achieved with a lathe. If I can get a lathe to work with an arbitrary set of points and an axis that will be great. I am using extrusion because I am trying to create geometric bodies based on the art of Liviu Stoicoviciu.

Here are some samples:

Sorry about the poor quality.

As you can see in the triangles image, that would be achieved with extrusions.

UPDATE

Here's my attempt to use drhirsch's help in the draw method:

void draw() {
    if(pointsNum >= 2){  
      float angle = 0;
      float angleIncrement = TWO_PI / sides;

      //begin draw segments between caps
      angle = 0;
      for(int i = 1; i < pointsNum ; ++i){
        beginShape(QUAD_STRIP);
        for(int j = 0; j < sides + 1; j++){

          PVector s = new PVector(0,0,1);
          PVector cn = new PVector();
          points[i].normalize(cn);
          PVector r = s.cross(cn);
          float a = acos(s.dot(cn));
          PMatrix3D rot = new PMatrix3D(1,0,0,0,
                                        0,1,0,0,
                                        0,0,1,0,
                                        0,0,0,1);
          rot.rotate(a,r.x,r.y,r.z);
          PVector rotVec = new PVector();
          rot.mult(points[i],rotVec);
          rotVec.add(new PVector(cos(angle) * topRadius,0,sin(angle) * topRadius));

          vertex(points[i-1].x + cos(angle) * topRadius, points[i-1].y, points[i-1].z + sin(angle) * topRadius);
          vertex(rotVec.x,rotVec.y,rotVec.y);

          //vertex(points[i-1].x + cos(angle) * topRadius, points[i-1].y, points[i-1].z + sin(angle) * topRadius);
          //vertex(points[i].x + cos(angle) * bottomRadius, points[i].y, points[i].z + sin(angle) * bottomRadius);

          angle += angleIncrement;
          }
        endShape();
      }
      //begin draw segments between caps
    }else println("Not enough points: " + pointsNum);
  }

I've refactored the code so now the class that used to be called CShape is called Extrude, the code is less and hopefully simples, and I use an array of PVector objects instead of a Vector of PVector objects which might be confusing.

Here is my yet another attempt with some escher-esque results:

upated draw

void draw() {
    if(pointsNum >= 2){  
      float angle = 0;
      float angleIncrement = TWO_PI / sides;

      //begin draw segments between caps
      angle = 0;
      for(int i = 1; i < pointsNum ; ++i){
        beginShape(QUAD_STRIP);
        float angleBetweenNextAndPrevious = 0.0;
        if(i < pointsNum - 1) angleBetweenNextAndPrevious = PVector.angleBetween(points[i],points[i+1]);

        for(int j = 0; j < sides + 1; j++){

          PVector s = new PVector(0,0,1);
          PVector s2 = new PVector(0,0,1);
          PVector cn = new PVector();
          PVector cn2 = new PVector();
          points[i-1].normalize(cn);
          points[i].normalize(cn);
          PVector r = s.cross(cn);
          PVector r2 = s.cross(cn2);
          PMatrix3D rot = new PMatrix3D(1,0,0,0,
                                        0,1,0,0,
                                        0,0,1,0,
                                        0,0,0,1);
          PMatrix3D rot2 = new PMatrix3D(1,0,0,0,
                                        0,1,0,0,
                                        0,0,1,0,
                                        0,0,0,1);

          rot.rotate(angleBetweenNextAndPrevious,r.x,r.y,r.z);
          rot2.rotate(angleBetweenNextAndPrevious,r2.x,r2.y,r2.z);

          PVector rotVec = new PVector();
          rot.mult(points[i-1],rotVec);
          rotVec.add(new PVector(cos(angle) * topRadius,0,sin(angle) * topRadius));
          PVector rotVec2 = new PVector();
          rot2.mult(points[i],rotVec2);
          rotVec2.add(new PVector(cos(angle) * topRadius,0,sin(angle) * topRadius));

          vertex(rotVec.x,rotVec.y,rotVec.z);
          vertex(rotVec2.x,rotVec2.y,rotVec2.z);
          //vertex(points[i-1].x + cos(angle) * topRadius, points[i-1].y, points[i-1].z + sin(angle) * topRadius);
          //vertex(points[i].x + cos(angle) * bottomRadius, points[i].y, points[i].z + sin(angle) * bottomRadius);

          angle += angleIncrement;
          }
        endShape();
      }
      //begin draw segments between caps
    }else println("Not enough points: " + pointsNum);
  }
}

Edit by drhirsch This should work:

void draw() {
    if(pointsNum >= 2){  
      float angle = 0;
      float angleIncrement = TWO_PI / sides;

      //begin draw segments between caps
      angle = 0;
      for(int i = 1; i < pointsNum ; ++i){
        beginShape(QUAD_STRIP);
        float angleBetweenNextAndPrevious = 0.0;
        if(i < pointsNum - 1) angleBetweenNextAndPrevious = PVector.angleBetween(points[i],points[i+1]);
        PVector s = new PVector(0,0,1);
        PVector s2 = new PVector(0,0,1);
        PVector cn = new PVector();
        PVector cn2 = new PVector();
        points[i-1].normalize(cn);
        points[i].normalize(cn2);
        PVector r = s.cross(cn);
        PVector r2 = s.cross(cn2);
        PMatrix3D rot = new PMatrix3D(1,0,0,0,
                                      0,1,0,0,
                                      0,0,1,0,
                                      0,0,0,1);
        PMatrix3D rot2 = new PMatrix3D(1,0,0,0,
                                       0,1,0,0,
                                       0,0,1,0,
                                       0,0,0,1);

        rot.rotate(angleBetweenNextAndPrevious,r.x,r.y,r.z);
        rot2.rotate(angleBetweenNextAndPrevious,r2.x,r2.y,r2.z);
        PVector rotVec = new PVector();
        PVector rotVec2 = new PVector();

        for(int j = 0; j < sides + 1; j++){
          // I am still not sure about this. Should the shape be in the xy plane 
          // if the extrusion is mainly along the z axis? If the shape is now in
          // the xz plane, you need to use (0,1,0) as normal vector of the shape
          // (this would be s and s2 above, don't use the short names I have
          // used, sorry)
          PVector shape = new PVector(cos(angle) * topRadius,0,sin(angle) * topRadius);

          rot.mult(shape, rotVec);
          rot2.mult(shape,rotVec2);

          rotVec.add(points[i-1]);
          rotVec2.add(points[i]);

          vertex(rotVec.x,rotVec.y,rotVec.z);
          vertex(rotVec2.x,rotVec2.y,rotVec2.z);
          //vertex(points[i-1].x + cos(angle) * topRadius, points[i-1].y, points[i-1].z + sin(angle) * topRadius);
          //vertex(points[i].x + cos(angle) * bottomRadius, points[i].y, points[i].z + sin(angle) * bottomRadius);

          angle += angleIncrement;
          }
        endShape();
      }
      //begin draw segments between caps
    }else println("Not enough points: " + pointsNum);
  }
}

UPDATE

Here is a simple illustration of my problem:

The blue path is equivalent to the points[] PVector array in my code, if pointsNum = 6. The red path is what I'm struggling to solve, the green path is what I want to achieve.

UPDATE

Some minor issues with the order of vertices I think. Here are some print screens using 6 points and no (if/else % 2) star condition.

解决方案

Assuming your shape has a normal vector S. In your example S would be (0,0,1), because your shape is flat in xy. You can use the cross product between the current path vector V (normalized) and S to obtain the rotation axis vector R. You need to rotate your shape around R. The angle of rotation can be obtained from the dot product between S and V. So:

R = S x V
a = arc cos(S . V)

Now you can setup a rotation matrix with R and a and rotate the shape by it.

You can use glRotate(...) to rotate the current matrix on the stack, but this can't be done between glBegin() and glEnd(). So you have to do the matrix multiplication by yourself or with a library.

Edit: After a short look at the library you are using, you should be able to setup the rotation matrix with

PVector s = new PVector(0,0,1);  // is already normalized (meaning is has length 1)
PVector cn;
current.normalize(cn);
PVector r = s.cross(cn);
float a = acos(s.dot(cn));
PMatrix rot = new PMatrix(1, 0, 0, 0,
                          0, 1, 0, 0,
                          0, 0, 1, 0,
                          0, 0, 0, 1);
rot.rotate(a, r.x, r.y, r.z);

and now multiply each element of your shape with rot and translate it by your current path vector:

PVector rotVec;
rot.mult((PVector)shape[i], rotVec);
rotVec.add(current);

这篇关于如何挤压在3D路径?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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