2009-11-30 13 views
12

Estoy tratando de extruir un camino en 3d. No es nada lujoso aún, solo sigue algunos puntos y usa un polígono regular para 'tubos'. Estoy usando Processing por ahora para hacer un prototipo rápido, pero luego convertiré el código en OpenGL.cómo extruir un camino en 3D?

Mi problema es girar las "articulaciones" en los ángulos correctos. Creo que tengo una idea aproximada de cómo obtener los ángulos, no estoy seguro.

He empezado a partir de una muestra de Simon Greenwold (producción> Archivo> Ejemplos> 3D> Formulario> Vértices) .Aquí de mi intento hasta el momento:

ACTUALIZACIÓN> refactorizado/código simplificado

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

Y aquí está la clase Extrusion:

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

ACTUALIZACIÓN

Aquí es cómo mi bosquejo parece:

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

El problema es que las articulaciones no están en el ángulo derecho, por lo que la extrusión se ve mal. Este no es un muy buen ejemplo, ya que esto podría lograrse con un torno. Si puedo obtener un torno para trabajar con un conjunto arbitrario de puntos y un eje que será genial. Estoy utilizando la extrusión porque estoy tratando de crear cuerpos geométricos basados ​​en el arte de Liviu Stoicoviciu.

He aquí algunos ejemplos:

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

Lo siento por la mala calidad.

Como puede ver en la imagen de triángulos, eso se lograría con extrusiones.

ACTUALIZACIÓN

Aquí está mi intento de utilizar la ayuda de drhirsch en el método 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); 
     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); 
    } 

He refactorizado el código por lo que ahora la clase que solía ser llamado CShape se llama Extrusión, el código es menos y, con suerte, simple, y utilizo una matriz de objetos de PVector en lugar de un Vector de objetos de PVector que puede ser confuso.

Aquí está mi otro intento con algunos resultados de Escher-esque:

upated dibujar

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

Editar por drhirsch Esto debería funcionar:

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

ACTUALIZACIÓN

Aquí es una simple ilustración de mi problema:

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

El camino azul es equivalente a los puntos [] array PVector en mi código, si pointsNum = 6. El camino rojo es lo que estoy luchando por resolver, el camino verde es lo que quiero lograr.

ACTUALIZACIÓN

Algunos problemas menores con el fin de vértices que pienso. Aquí hay algunas pantallas de impresión que usan 6 puntos y ninguna condición de estrella (si/else% 2).

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

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

+0

La única razón para calcular los ángulos sería generar normales. ¿Por qué no haces la extrusión por una traducción a lo largo del eje z? Y podrías usar un QUAD_STRIP a los lados. – hirschhornsalz

+0

¿O desea hacer una extrusión a lo largo de un camino con una rotación automática para que coincida con la inclinación en la tangente de esta ruta? – hirschhornsalz

+0

@drhirsch Gracias por el consejo sobre QUAD_STRIP, lo usaré. Quiero una extrusión a lo largo de un camino con una rotación automática para que coincida con la inclinación en la tangente de la ruta. Creo que lo resolví en 2d, teniendo problemas al pasar a 3d.para obtener la inclinación para un segundo punto, uso el atan2 de la diferencia entre el 3er punto y el 1er punto y agrego 90 grados (una perpendicular). No estoy seguro de cómo aplicar eso en 3d. –

Respuesta

3

Asumiendo que su forma tiene un vector normal S. En su ejemplo S sería (0,0,1), debido a que su forma es plana en xy. Puede usar el producto cruzado entre el vector V de trayectoria actual (normalizado) y S para obtener el vector R de eje de rotación. Debe girar su forma alrededor de R. El ángulo de rotación puede obtenerse del producto de puntos entre S y V. por lo tanto:

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

Ahora se puede configurar un rotation matrix con R y a y girar la forma por ella.

Puede usar glRotate (...) para rotar la matriz actual en la pila, pero esto no puede hacerse entre glBegin() y glEnd(). Entonces usted tiene que hacer la multiplicación de la matriz usted mismo o con una biblioteca.

Editar: Después de un breve vistazo a la biblioteca que está utilizando, usted debe ser capaz de configurar la matriz de rotación con

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

y ahora multiplicar cada elemento de su forma con la putrefacción y traducirlo por su actual vector de ruta:

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

Estoy tratando de usar su ayuda, y hasta ahora probé esto: PVector s = new PVector (0,0,1); s.normalize(); // forma el vector normal PVector r = s .contracorriente); float a = acos (s.dot (actual)); ¿Tengo un derecho? a es igual al arco coseno del producto escalar entre S y V? –

+0

Sí, lo tienes exactamente correcto. El producto cruzado es siempre perpendicular a ambos vectores. Hay un caso especial si ambos vectores tienen la misma dirección (probablemente al principio de su camino), pero es fácil de manejar. – hirschhornsalz

+0

He agregado el código con mi intento de usar tus explicaciones. Todavía hay algunas cosas con las que estoy perdido. Intento entender "multiplicar cada elemento de tu forma con podredumbre". cada celemento, significa cada vector, o cada componente de cada vector? Es esta última parte de la concatenación de las rotaciones que me da dolores de cabeza. traducir debería ser simplemente obtener los vértices girados y agregar un vector de traducción a eso. Gracias por toda la paciencia drhirsch! –

Cuestiones relacionadas