English 中文(简体)
how to extrude a path in 3d?
原标题:

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:

processing extrude http://doc.gold.ac.uk/~ma802gp/extrude.gif

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:

star painting http://doc.gold.ac.uk/~ma802gp/star_painting.jpg

star paper sculpture http://doc.gold.ac.uk/~ma802gp/star_paper_sculpture.jpg

triangles http://doc.gold.ac.uk/~ma802gp/triangles_pencil.jpg

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);
  }
}

fix_test http://doc.gold.ac.uk/~ma802gp/extrude2.gif

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:

description http://doc.gold.ac.uk/~ma802gp/description.gif

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.

points1 http://doc.gold.ac.uk/~ma802gp/points1.gif

alt text http://doc.gold.ac.uk/~ma802gp/points2.gif

最佳回答

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);
问题回答

暂无回答




相关问题
Bounding ellipse

I have been given an assignement for a graphics module, one part of which is to calculate the minimum bounding ellipse of a set of arbitrary shapes. The ellipse doesn t have to be axis aligned. This ...

Line segment in a triangle

How can we check if a line segment falls partially or fully inside a triangle? Cheers.

Line Segments from a point

I have a point p, and 2 line segments in a 2D plane. Point p is a location of view from where camera is looking towards the line segments. I want to check if line segment 1 is partially or fully ...

Creating a surface of triangles from a set of 2D points

I have a set of points and I need to convert the set to (non-overlapping) triangles (or a big polygon if equivalent)... The application: I have a list of locations (latitude,longitude) from a country,...

Radial plotting algorithm

I have to write an algorithm in AS3.0 that plots the location of points radially. I d like to input a radius and an angle at which the point should be placed. Obviously I remember from geometry ...

Delete holes in a Polygon

I have a polygon determined by an Array of Points. This polygon is crossing itself making some holes in the polygon itself. My questions is: How can I omit this holes and just get the exterior ...

Finding cycle of 3 nodes ( or triangles) in a graph

I am working with complex networks. I want to find group of nodes which forms a cycle of 3 nodes (or triangles) in a given graph. As my graph contains about million edges, using a simple iterative ...

热门标签