سؤال

أحاول قذف مسار ثلاثي الأبعاد.لا يوجد شيء فاخر حتى الآن، فقط اتبع بعض النقاط واستخدم مضلعًا عاديًا لـ "الأنابيب".أستخدم المعالجة حاليًا لإنشاء نموذج أولي سريعًا، ولكنني سأقوم لاحقًا بتحويل الكود إلى OpenGL.

مشكلتي هي تدوير "المفاصل" في الزوايا الصحيحة.أعتقد أن لدي فكرة تقريبية عن كيفية الحصول على الزوايا، لست متأكدًا.

لقد بدأت من عينة كتبها Simon Greenwold (المعالجة > الملف > الأمثلة > ثلاثي الأبعاد > النموذج > القمم). وإليك محاولتي حتى الآن:

تحديث > كود مُعاد تشكيله/مبسط

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

وهنا فئة النتوء:

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

تحديث

هنا كيف يبدو الرسم الخاص بي:

معالجة البثق http://doc.gold.ac.uk/~ma802gp/extrude.gif

المشكلة هي أن المفاصل ليست في الزاوية الصحيحة، وبالتالي فإن البثق يبدو خاطئًا.هذا ليس مثالًا جيدًا جدًا، حيث يمكن تحقيق ذلك باستخدام مخرطة.إذا تمكنت من الحصول على مخرطة للعمل مع مجموعة عشوائية من النقاط والمحور فسيكون ذلك رائعًا.أنا أستخدم البثق لأنني أحاول إنشاء أجسام هندسية على أساس فن Liviu Stoicoviciu.

وهنا بعض العينات:

لوحة النجوم http://doc.gold.ac.uk/~ma802gp/star_painting.jpg

النحت الورقي على شكل نجمة http://doc.gold.ac.uk/~ma802gp/star_paper_culpture.jpg

مثلثات http://doc.gold.ac.uk/~ma802gp/triangles_pencil.jpg

عذرا عن نوعية رديئة.

كما ترون في صورة المثلثات، سيتم تحقيق ذلك باستخدام البثق.

تحديث

هذه محاولتي لاستخدام مساعدة drhirsch في طريقة الرسم:

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

لقد قمت بإعادة بناء الكود، لذا فإن الفئة التي كانت تسمى CShape الآن تسمى Extrude، والكود أقل ونأمل أن يكون بسيطًا، وأنا أستخدم مصفوفة من كائنات PVector بدلاً من Vector of كائنات PVector التي قد تكون مربكة.

إليكم محاولتي الأخرى مع بعض نتائج escher-esque:

رسم محدث

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

تحرير Drhirsch هذا يجب أن يعمل:

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

تحديث

وهذا توضيح بسيط لمشكلتي:

الوصف http://doc.gold.ac.uk/~ma802gp/description.gif

المسار الأزرق يعادل مجموعة النقاط[] PVector في الكود الخاص بي، إذا كانت PointNum = 6.المسار الأحمر هو ما أجد صعوبة في حله، أما المسار الأخضر فهو ما أريد تحقيقه.

تحديث

أعتقد أن بعض المشكلات البسيطة المتعلقة بترتيب القمم.فيما يلي بعض شاشات الطباعة التي تستخدم 6 نقاط ولا توجد حالة نجمة (if/else % 2).

بوينتس1 http://doc.gold.ac.uk/~ma802gp/points1.gif

نص بديل http://doc.gold.ac.uk/~ma802gp/points2.gif

هل كانت مفيدة؟

المحلول

بافتراض أن الشكل الخاص بك يحتوي على ناقل عادي S.في المثال الخاص بك سيكون S هو (0,0,1)، لأن الشكل الخاص بك مسطح في xy.يمكنك استخدام المنتج المتقاطع بين متجه المسار الحالي V (المطبيع) وS للحصول على متجه محور الدوران R.تحتاج إلى تدوير الشكل الخاص بك حول R.يمكن الحصول على زاوية الدوران من حاصل الضرب النقطي بين S وV.لذا:

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

الآن يمكنك إعداد أ مصفوفة الدوران باستخدام R وa وقم بتدوير الشكل به.

يمكنك استخدام glRotate(...) لتدوير المصفوفة الحالية على المكدس، ولكن لا يمكن القيام بذلك بين glBegin() وglEnd().لذلك عليك أن تقوم بضرب المصفوفات بنفسك أو مع المكتبة.

يحرر:بعد إلقاء نظرة سريعة على المكتبة التي تستخدمها، يجب أن تكون قادرًا على إعداد مصفوفة التدوير باستخدامها

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

والآن قم بضرب كل عنصر من عناصر الشكل الخاص بك بالتعفن وترجمته بواسطة متجه المسار الحالي الخاص بك:

PVector rotVec;
rot.mult((PVector)shape[i], rotVec);
rotVec.add(current);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top