Question

J'essaie d'extruder un chemin en 3D. Rien de spécial pour le moment, il suffit de suivre quelques points et d’utiliser un polygone régulier pour «tube». J'utilise actuellement Traitement en cours pour réaliser rapidement un prototype, mais le code deviendra plus tard OpenGL.

Mon problème est de faire tourner les "joints" à angle droit. Je pense avoir une idée approximative de la manière d’obtenir les angles, mais je ne suis pas sûr.

J'ai commencé à partir d'un échantillon de Simon Greenwold (Traitement> Fichier> Exemples> 3D> Formulaires> Sommets). Voici ma tentative jusqu'à présent:

MISE À JOUR > CODE REFACTORÉ / SIMPLIFIÉ

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

Et voici la classe d'extrusion:

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

MISE À JOUR

Voici à quoi ressemble mon croquis:

traitement de l'extrusion http://doc.gold.ac.uk/~ma802gp/extrude.gif

Le problème est que les joints ne sont pas au bon angle et que l'extrusion ne semble pas être bonne. Ce n'est pas un très bon exemple, car cela pourrait être réalisé avec un tour. Si je peux obtenir un tour pour travailler avec un ensemble arbitraire de points et un axe, ce sera génial. J'utilise l'extrusion J'essaie de créer des corps géométriques basés sur l'art de Liviu Stoicoviciu.

Voici quelques exemples:

peinture d'étoile http://doc.gold.ac.uk/~ma802gp/star_painting.jpg

sculpture en papier étoiles http://doc.gold.ac.uk/~ma802gp/star_paper_sculpture.jpg

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

Désolé pour la qualité médiocre.

Comme vous pouvez le voir dans l'image des triangles, cela serait réalisé avec des extrusions.

MISE À JOUR

Voici ma tentative d'utiliser l'aide de drhirsch dans la méthode de tirage au sort:

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

J'ai refactoré le code et la classe qui s'appelait auparavant CShape s'appelle Extrude, le code est inférieur et, espérons-le, simple, et j'utilise un tableau d'objets PVector au lieu d'un vecteur d'objets PVector, ce qui peut prêter à confusion. .

Voici une autre tentative avec quelques résultats escher-esque:

tirage amélioré

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

Modifier de drhirsch Cela devrait fonctionner:

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

MISE À JOUR

Voici une illustration simple de mon problème:

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

Le chemin bleu est équivalent au tableau PVector de points [] dans mon code, si pointsNum = 6. Le chemin rouge est ce que j'ai du mal à résoudre, le chemin vert est ce que je veux réaliser.

MISE À JOUR

Je pense que quelques problèmes mineurs avec l’ordre des vertices. Voici quelques écrans d’impression utilisant 6 points et aucune condition d’étoile (si / 2%).

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

texte alternatif http://doc.gold.ac.uk/~ma802gp/points2.gif

Était-ce utile?

La solution

En supposant que votre forme a un vecteur normal S. Dans votre exemple, S serait (0,0,1), car votre forme est plate dans xy. Vous pouvez utiliser le produit croisé entre le vecteur de chemin actuel V (normalisé) et S pour obtenir le vecteur d'axe de rotation R. Vous devez faire pivoter votre forme autour de R. L'angle de rotation peut être obtenu à partir du produit scalaire entre S et V. Donc:

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

Vous pouvez maintenant configurer une matrice de rotation avec R et a et faire pivoter la forme par celle-ci. .

Vous pouvez utiliser glRotate (...) pour faire pivoter la matrice actuelle sur la pile, mais cela ne peut pas être fait entre glBegin () et glEnd (). Donc, vous devez faire la multiplication de matrice par vous-même ou avec une bibliothèque.

Modifier: après un bref aperçu de la bibliothèque que vous utilisez, vous devriez pouvoir configurer la matrice de rotation avec

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

et multipliez maintenant chaque élément de votre forme avec rot et traduisez-le par votre vecteur de chemin actuel:

PVector rotVec;
rot.mult((PVector)shape[i], rotVec);
rotVec.add(current);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top