如何将 SuperShape3D 绘制为网格?

发布于 2024-10-14 17:42:25 字数 4001 浏览 6 评论 0原文

我想绘制一个 3D Superformula 网格,但不知道应该如何组织面(是它们是三角形或四边形)。

我已经安装了八度并尝试了示例代码。我不知道 Gnuplot 的 mesh() 函数是如何工作的,但我想我需要类似的东西。

维基百科条目有一个指向处理演示的链接。 我查看了来源,发现它只得出点。 我试图将这段代码包装在 beginShape()/endShape() 中 打电话,但按我希望的方式工作。

我还尝试检查点数是否可以被 3 整除 或 4 并使用三角形或四边形,但这不是正确的方法, 如下所示: SuperShape Processing

如何使用三角形/四边形绘制 SuperShape3D? 我想象顶点位于正确的位置,但它们 需要对使用绘制脸部的调用进行排序 顶点索引。

我目前还没有固定使用某种特定的语言,但是 我的目标是将顶点放在数组中,然后 使用顶点索引推面(3 或 4 点)。

有什么提示吗?

更新:

这是用于获取处理示例代码中的点的函数:

import toxi.geom.*;
import controlP5.*;

ControlP5 controlP5;
ArrayList points = new ArrayList();
ArrayList faces = new ArrayList();

float a1=1,a2=1,b=1,xx,step = 0.05,yy,zz,n1=4,n2=12,n3=15,n4=15,r,raux1,r1,raux2,r2;
int N_X = int(2*PI/step);
int N_Y = int(PI/step);


void setup() {
  size(800,800,P3D);
  //hint(ENABLE_DEPTH_SORT);

  controlP5 = new ControlP5(this);

  controlP5.addSlider("a1value",0,3,1,20,0,200,10);
  controlP5.addSlider("a2value",0,3,1,20,20,200,10);
  controlP5.addSlider("bvalue",0,3,1,20,40,200,10);
  controlP5.addSlider("n1value",0,20,8,20,60,200,10);
  controlP5.addSlider("n2value",0,5,0.5,20,80,200,10);
  controlP5.addSlider("n3value",0,5,0.5,20,100,200,10);
  controlP5.addSlider("n4value",0,20,8,20,120,200,10);
  controlP5.addSlider("stepvalue",0.02,0.9,0.05,20,140,200,10);
  controlP5.setAutoDraw(false);
  draw_super_formula();
}

void draw() {
  background(0);
  fill(255);
  controlP5.draw();
  lights();
  translate(width / 2, height / 2, 0);
  rotateX(mouseY * 0.01f);
  rotateY(mouseX * 0.01f);
  // connect 4 points into quads:
  Vec3D pt;
  for(int x=0;x<N_X-1;x++)
  {
    for(int y=0;y<N_Y-1;y++)
    {
      beginShape(QUADS);
      pt = (Vec3D)points.get( x*N_Y + y );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( x*N_Y + y+1 );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( (x+1)*N_Y + y+1 );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( (x+1)*N_Y + y);
      vertex(pt.x,pt.y,pt.z);
      endShape();
    }
  }
}

void vertex(Vec3D v) {
  vertex(v.x,v.y,v.z);
}

void draw_super_formula() {
  for(int i = points.size()-1; i>0;i--){
    points.remove(i);
  }

  for(int x=0;x<N_X;x++)
  {
    float i = -PI + x*step;
    for(int y=0;y<N_Y;y++)
    {
      float j = -PI/2.0 + y*step;
      raux1=pow(abs(1/a1*abs(cos(n1*i/4))),n3)+pow(abs(1/a2*abs(sin(n1*i/4))),n4);
      r1=pow(abs(raux1),(-1/n2));
      raux2=pow(abs(1/a1*abs(cos(n1*j/4))),n3)+pow(abs(1/a2*abs(sin(n1*j/4))),n4);
      r2=pow(abs(raux2),(-1/n2));
      xx=r1*cos(i)*r2*cos(j)*100;
      yy=r1*sin(i)*r2*cos(j)*100;
      zz=r2*sin(j)*100;

      Vec3D test1 = new Vec3D(xx,yy,zz);
      points.add(test1);
    }
  }
}

void bvalue(float new_value){
  b = new_value;
  draw_super_formula();
}
void a1value(float new_value){
  a1 = new_value;
  draw_super_formula();
}
void a2value(float new_value){
  a2 = new_value;
  draw_super_formula();
}
void n1value(float new_value){
  n1 = new_value;
  draw_super_formula();
}
void n2value(float new_value){
  n2 = new_value;
  draw_super_formula();
}
void n3value(float new_value){
  n3 = new_value;
  draw_super_formula();
}
void n4value(float new_value){
  n4 = new_value;
  draw_super_formula();
}

void stepvalue(float new_value){
  step = new_value;
  draw_super_formula();
  println("% 3: "+(points.size()%3));
  println("% 4: "+(points.size()%4));
}
class F4{
  int a,b,c,d;
  F4(int a,int b,int c,int d){
    this.a = a;
    this.b = b;
    this.c = c;
    this.d = d;
  }
}

@tim_hutton 的解决方案很棒,但它看起来索引关闭,试图找出它在哪里。

superformula 问题

I would like to draw a 3D Superformula mesh but not sure how I should organize the faces(be them triangles or quads).

I've installed octave and tried the sample code. I have no clue how Gnuplot's mesh() function works, but I imagine I would need something similar.

The Wikipedia entry has a link to a Processing demo.
I had a look at the source and noticed it only draws points.
I tried to wrap that segment of code within beginShape()/endShape()
calls but work the way I hoped.

I also tried to check if the number of points is divisible by 3
or 4 and used TRIANGLES or QUADS, but this is not the right way to do this,
as you can see below:
SuperShape Processing

How can I draw a SuperShape3D using triangles/quads ?
I imagine the vertices are in the right positions, but they
need to be sorted to calls that would draw the faces using
the vertex indices.

I'm not fixed to a particular language at the moment, but
my goal would be to have the vertices in an array, then
push faces(3 or 4 points) using vertex indices.

Any hints ?

Update:

Here is the function used to get the points in the Processing sample code:

import toxi.geom.*;
import controlP5.*;

ControlP5 controlP5;
ArrayList points = new ArrayList();
ArrayList faces = new ArrayList();

float a1=1,a2=1,b=1,xx,step = 0.05,yy,zz,n1=4,n2=12,n3=15,n4=15,r,raux1,r1,raux2,r2;
int N_X = int(2*PI/step);
int N_Y = int(PI/step);


void setup() {
  size(800,800,P3D);
  //hint(ENABLE_DEPTH_SORT);

  controlP5 = new ControlP5(this);

  controlP5.addSlider("a1value",0,3,1,20,0,200,10);
  controlP5.addSlider("a2value",0,3,1,20,20,200,10);
  controlP5.addSlider("bvalue",0,3,1,20,40,200,10);
  controlP5.addSlider("n1value",0,20,8,20,60,200,10);
  controlP5.addSlider("n2value",0,5,0.5,20,80,200,10);
  controlP5.addSlider("n3value",0,5,0.5,20,100,200,10);
  controlP5.addSlider("n4value",0,20,8,20,120,200,10);
  controlP5.addSlider("stepvalue",0.02,0.9,0.05,20,140,200,10);
  controlP5.setAutoDraw(false);
  draw_super_formula();
}

void draw() {
  background(0);
  fill(255);
  controlP5.draw();
  lights();
  translate(width / 2, height / 2, 0);
  rotateX(mouseY * 0.01f);
  rotateY(mouseX * 0.01f);
  // connect 4 points into quads:
  Vec3D pt;
  for(int x=0;x<N_X-1;x++)
  {
    for(int y=0;y<N_Y-1;y++)
    {
      beginShape(QUADS);
      pt = (Vec3D)points.get( x*N_Y + y );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( x*N_Y + y+1 );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( (x+1)*N_Y + y+1 );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( (x+1)*N_Y + y);
      vertex(pt.x,pt.y,pt.z);
      endShape();
    }
  }
}

void vertex(Vec3D v) {
  vertex(v.x,v.y,v.z);
}

void draw_super_formula() {
  for(int i = points.size()-1; i>0;i--){
    points.remove(i);
  }

  for(int x=0;x<N_X;x++)
  {
    float i = -PI + x*step;
    for(int y=0;y<N_Y;y++)
    {
      float j = -PI/2.0 + y*step;
      raux1=pow(abs(1/a1*abs(cos(n1*i/4))),n3)+pow(abs(1/a2*abs(sin(n1*i/4))),n4);
      r1=pow(abs(raux1),(-1/n2));
      raux2=pow(abs(1/a1*abs(cos(n1*j/4))),n3)+pow(abs(1/a2*abs(sin(n1*j/4))),n4);
      r2=pow(abs(raux2),(-1/n2));
      xx=r1*cos(i)*r2*cos(j)*100;
      yy=r1*sin(i)*r2*cos(j)*100;
      zz=r2*sin(j)*100;

      Vec3D test1 = new Vec3D(xx,yy,zz);
      points.add(test1);
    }
  }
}

void bvalue(float new_value){
  b = new_value;
  draw_super_formula();
}
void a1value(float new_value){
  a1 = new_value;
  draw_super_formula();
}
void a2value(float new_value){
  a2 = new_value;
  draw_super_formula();
}
void n1value(float new_value){
  n1 = new_value;
  draw_super_formula();
}
void n2value(float new_value){
  n2 = new_value;
  draw_super_formula();
}
void n3value(float new_value){
  n3 = new_value;
  draw_super_formula();
}
void n4value(float new_value){
  n4 = new_value;
  draw_super_formula();
}

void stepvalue(float new_value){
  step = new_value;
  draw_super_formula();
  println("% 3: "+(points.size()%3));
  println("% 4: "+(points.size()%4));
}
class F4{
  int a,b,c,d;
  F4(int a,int b,int c,int d){
    this.a = a;
    this.b = b;
    this.c = c;
    this.d = d;
  }
}

@tim_hutton's solution is great, but it looks an index off, trying to figure out where that is.

superformula issue

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

霞映澄塘 2024-10-21 17:42:25

超级公式为您提供每个采样角度的半径。在 3D 中,您需要两个角度:theta 和 phi。通过保持 theta 固定并改变 phi(反之亦然),您将沿着一个大圆进行采样。

制作曲面的一种方法是通过根据角度 a 和 b 采样四个点来制作四边形:(a,b)、(a+da,b)、(a+da,b+db)、(a,b) +db)。对 a: 0,da,2*da... 和 b: 0,db,2*db... 执行此操作,直到覆盖整个表面。使用小 da 和 db 得到小四边形。

(另一种方法是使用通用表面重建算法 (1,2)但这对于这样的问题来说有点过分了。)

更新:

我认为代码下面是你想要的东西:


import toxi.geom.*;
import controlP5.*;

ControlP5 controlP5;
ArrayList points = new ArrayList();
ArrayList faces = new ArrayList();

float a1=1,a2=1,b=1,xx,step = 0.05,yy,zz,n1=4,n2=12,n3=15,n4=15,r,raux1,r1,raux2,r2;
int N_X = int(2*PI/step);
int N_Y = int(PI/step);


void setup() {
  size(800,800,P3D);
  //hint(ENABLE_DEPTH_SORT);

  controlP5 = new ControlP5(this);

  controlP5.addSlider("a1value",0,3,1,20,0,200,10);
  controlP5.addSlider("a2value",0,3,1,20,20,200,10);
  controlP5.addSlider("bvalue",0,3,1,20,40,200,10);
  controlP5.addSlider("n1value",0,20,8,20,60,200,10);
  controlP5.addSlider("n2value",0,5,0.5,20,80,200,10);
  controlP5.addSlider("n3value",0,5,0.5,20,100,200,10);
  controlP5.addSlider("n4value",0,20,8,20,120,200,10);
  controlP5.addSlider("stepvalue",0.02,0.9,0.05,20,140,200,10);
  controlP5.setAutoDraw(false);
  draw_super_formula();
}

void draw() {
  background(0);
  fill(255);

  controlP5.draw();

  translate(width / 2, height / 2, 0);
  rotateX(mouseY * 0.01f);
  rotateY(mouseX * 0.01f);
  drawAxes(300);
  beginShape(POINTS);
  for(int i = 0; i < points.size();i++){
    Vec3D k = (Vec3D)points.get(i); 
    stroke(color(k.x+110,k.y+110,k.z+110));
    vertex(k.x,k.y,k.z);
  }
  endShape();

  // connect 4 points into quads:
  Vec3D pt;
  noFill();
  for(int x=0;x<N_X-1;x++)
  {
    for(int y=0;y<N_Y-1;y++)
    {
      beginShape();
      pt = (Vec3D)points.get( x*N_Y + y );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( x*N_Y + y+1 );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( (x+1)*N_Y + y+1 );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( (x+1)*N_Y + y);
      vertex(pt.x,pt.y,pt.z);
      endShape();
    }
  }
}

void vertex(Vec3D v) {
  vertex(v.x,v.y,v.z);
}

void draw_super_formula() {
  for(int i = points.size()-1; i>0;i--){
    points.remove(i);
  }

  for(int x=0;x<N_X;x++)
  {
    float i = -PI + x*step;
    for(int y=0;y<N_Y;y++)
    {
      float j = -PI/2.0 + y*step;
      raux1=pow(abs(1/a1*abs(cos(n1*i/4))),n3)+pow(abs(1/a2*abs(sin(n1*i/4))),n4);
      r1=pow(abs(raux1),(-1/n2));
      raux2=pow(abs(1/a1*abs(cos(n1*j/4))),n3)+pow(abs(1/a2*abs(sin(n1*j/4))),n4);
      r2=pow(abs(raux2),(-1/n2));
      xx=r1*cos(i)*r2*cos(j)*100;
      yy=r1*sin(i)*r2*cos(j)*100;
      zz=r2*sin(j)*100;

      Vec3D test1 = new Vec3D(xx,yy,zz);
      points.add(test1);
    }
  }
}

void drawAxes(float l) {
  stroke(255, 0, 0);
  line(0, 0, 0, l, 0, 0);
  line(l, 0, 0, l-10, 10, 0);
  line(l, 0, 0, l-10, -10, 0);

  stroke(0, 255, 0);
  line(0, 0, 0, 0, l, 0);
  line(0, l, 0, 10, l-10, 0);
  line(0, l, 0, -10, l-10, 0);

  stroke(0, 0, 255);

  line(0, 0, 0, 0, 0, l);
  line(0, 0, l, 0, 10, l-10);
  line(0, 0, l, 0, -10, l-10);

}

void bvalue(float new_value){
  b = new_value;
  draw_super_formula();
}
void a1value(float new_value){
  a1 = new_value;
  draw_super_formula();
}
void a2value(float new_value){
  a2 = new_value;
  draw_super_formula();
}
void n1value(float new_value){
  n1 = new_value;
  draw_super_formula();
}
void n2value(float new_value){
  n2 = new_value;
  draw_super_formula();
}
void n3value(float new_value){
  n3 = new_value;
  draw_super_formula();
}
void n4value(float new_value){
  n4 = new_value;
  draw_super_formula();
}

void stepvalue(float new_value){
  step = new_value;
  draw_super_formula();
  println("% 3: "+(points.size()%3));
  println("% 4: "+(points.size()%4));
}
class F4{
  int a,b,c,d;
  F4(int a,int b,int c,int d){
    this.a = a;
    this.b = b;
    this.c = c;
    this.d = d;
  }
}

The superformula gives you a radius for each angle sampled. In 3D you need two angles: theta and phi. By keeping theta fixed and varying phi (or vice versa) you will sample along a great circle.

One way to make a surface is to make quads by sampling four points based on the angles a and b: (a,b), (a+da,b), (a+da,b+db), (a,b+db). Do this for a: 0,da,2*da... and for b: 0,db,2*db... until the whole surface is covered. Use a small da and db to get small quads.

(The alternative is to use a generic surface reconstruction algorithm (1,2) but this is overkill for a problem like this.)

Update:

I think the code below is something like what you want:


import toxi.geom.*;
import controlP5.*;

ControlP5 controlP5;
ArrayList points = new ArrayList();
ArrayList faces = new ArrayList();

float a1=1,a2=1,b=1,xx,step = 0.05,yy,zz,n1=4,n2=12,n3=15,n4=15,r,raux1,r1,raux2,r2;
int N_X = int(2*PI/step);
int N_Y = int(PI/step);


void setup() {
  size(800,800,P3D);
  //hint(ENABLE_DEPTH_SORT);

  controlP5 = new ControlP5(this);

  controlP5.addSlider("a1value",0,3,1,20,0,200,10);
  controlP5.addSlider("a2value",0,3,1,20,20,200,10);
  controlP5.addSlider("bvalue",0,3,1,20,40,200,10);
  controlP5.addSlider("n1value",0,20,8,20,60,200,10);
  controlP5.addSlider("n2value",0,5,0.5,20,80,200,10);
  controlP5.addSlider("n3value",0,5,0.5,20,100,200,10);
  controlP5.addSlider("n4value",0,20,8,20,120,200,10);
  controlP5.addSlider("stepvalue",0.02,0.9,0.05,20,140,200,10);
  controlP5.setAutoDraw(false);
  draw_super_formula();
}

void draw() {
  background(0);
  fill(255);

  controlP5.draw();

  translate(width / 2, height / 2, 0);
  rotateX(mouseY * 0.01f);
  rotateY(mouseX * 0.01f);
  drawAxes(300);
  beginShape(POINTS);
  for(int i = 0; i < points.size();i++){
    Vec3D k = (Vec3D)points.get(i); 
    stroke(color(k.x+110,k.y+110,k.z+110));
    vertex(k.x,k.y,k.z);
  }
  endShape();

  // connect 4 points into quads:
  Vec3D pt;
  noFill();
  for(int x=0;x<N_X-1;x++)
  {
    for(int y=0;y<N_Y-1;y++)
    {
      beginShape();
      pt = (Vec3D)points.get( x*N_Y + y );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( x*N_Y + y+1 );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( (x+1)*N_Y + y+1 );
      vertex(pt.x,pt.y,pt.z);
      pt = (Vec3D)points.get( (x+1)*N_Y + y);
      vertex(pt.x,pt.y,pt.z);
      endShape();
    }
  }
}

void vertex(Vec3D v) {
  vertex(v.x,v.y,v.z);
}

void draw_super_formula() {
  for(int i = points.size()-1; i>0;i--){
    points.remove(i);
  }

  for(int x=0;x<N_X;x++)
  {
    float i = -PI + x*step;
    for(int y=0;y<N_Y;y++)
    {
      float j = -PI/2.0 + y*step;
      raux1=pow(abs(1/a1*abs(cos(n1*i/4))),n3)+pow(abs(1/a2*abs(sin(n1*i/4))),n4);
      r1=pow(abs(raux1),(-1/n2));
      raux2=pow(abs(1/a1*abs(cos(n1*j/4))),n3)+pow(abs(1/a2*abs(sin(n1*j/4))),n4);
      r2=pow(abs(raux2),(-1/n2));
      xx=r1*cos(i)*r2*cos(j)*100;
      yy=r1*sin(i)*r2*cos(j)*100;
      zz=r2*sin(j)*100;

      Vec3D test1 = new Vec3D(xx,yy,zz);
      points.add(test1);
    }
  }
}

void drawAxes(float l) {
  stroke(255, 0, 0);
  line(0, 0, 0, l, 0, 0);
  line(l, 0, 0, l-10, 10, 0);
  line(l, 0, 0, l-10, -10, 0);

  stroke(0, 255, 0);
  line(0, 0, 0, 0, l, 0);
  line(0, l, 0, 10, l-10, 0);
  line(0, l, 0, -10, l-10, 0);

  stroke(0, 0, 255);

  line(0, 0, 0, 0, 0, l);
  line(0, 0, l, 0, 10, l-10);
  line(0, 0, l, 0, -10, l-10);

}

void bvalue(float new_value){
  b = new_value;
  draw_super_formula();
}
void a1value(float new_value){
  a1 = new_value;
  draw_super_formula();
}
void a2value(float new_value){
  a2 = new_value;
  draw_super_formula();
}
void n1value(float new_value){
  n1 = new_value;
  draw_super_formula();
}
void n2value(float new_value){
  n2 = new_value;
  draw_super_formula();
}
void n3value(float new_value){
  n3 = new_value;
  draw_super_formula();
}
void n4value(float new_value){
  n4 = new_value;
  draw_super_formula();
}

void stepvalue(float new_value){
  step = new_value;
  draw_super_formula();
  println("% 3: "+(points.size()%3));
  println("% 4: "+(points.size()%4));
}
class F4{
  int a,b,c,d;
  F4(int a,int b,int c,int d){
    this.a = a;
    this.b = b;
    this.c = c;
    this.d = d;
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文