如何将 SuperShape3D 绘制为网格?
我想绘制一个 3D Superformula 网格,但不知道应该如何组织面(是它们是三角形或四边形)。
我已经安装了八度并尝试了示例代码。我不知道 Gnuplot 的 mesh() 函数是如何工作的,但我想我需要类似的东西。
维基百科条目有一个指向处理演示的链接。 我查看了来源,发现它只得出点。 我试图将这段代码包装在 beginShape()/endShape() 中 打电话,但按我希望的方式工作。
我还尝试检查点数是否可以被 3 整除 或 4 并使用三角形或四边形,但这不是正确的方法, 如下所示:
如何使用三角形/四边形绘制 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 的解决方案很棒,但它看起来索引关闭,试图找出它在哪里。
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:
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
超级公式为您提供每个采样角度的半径。在 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)但这对于这样的问题来说有点过分了。)
更新:
我认为代码下面是你想要的东西:
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: