Geo*_*nza 12 opengl 3d processing geometry trigonometry
我正试图在3d中挤出一条路径.没什么好看的,只是遵循一些要点并使用正常的多边形来表示"管道".我现在正在使用Processing来快速原型化,但稍后会将代码转换为OpenGL.
我的问题是以正确的角度旋转"关节".我想我对如何获得角度有一个粗略的想法,不确定.
我从Simon Greenwold的一个样本开始(处理>文件>示例> 3D>表格>顶点).这是我迄今为止的尝试:
更新>改进/简化代码
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;
}
Run Code Online (Sandbox Code Playgroud)
这是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);
}
}
Run Code Online (Sandbox Code Playgroud)
UPDATE
这是我的草图的样子:
处理挤出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_sculpture.jpg
三角形http://doc.gold.ac.uk/~ma802gp/triangles_pencil.jpg
抱歉质量很差.
正如您在三角形图像中看到的那样,这可以通过挤压来实现.
UPDATE
这是我尝试在draw方法中使用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);
}
Run Code Online (Sandbox Code Playgroud)
我已经重构了代码,所以现在以前被称为CShape的类被称为Extrude,代码更少,希望简单,我使用PVector对象的数组而不是PVector对象的Vector,这可能会令人困惑.
这是我的另一种尝试,有一些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);
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
UPDATE
这是我的问题的简单说明:
说明http://doc.gold.ac.uk/~ma802gp/description.gif
如果pointsNum = 6,蓝色路径相当于我的代码中的points [] PVector数组.红色路径是我正在努力解决的问题,绿色路径是我想要实现的.
UPDATE
我认为顶点顺序的一些小问题.以下是一些使用6点且没有(if/else%2)星条件的打印屏幕.
假设您的形状具有法线向量 S。在您的示例中,S 将为 (0,0,1),因为您的形状在 xy 方向上是平坦的。您可以使用当前路径向量 V(归一化)和 S 之间的叉积来获得旋转轴向量 R。您需要围绕 R 旋转您的形状。旋转角度可以通过 S 和 V 之间的点积获得。所以:
R = S x V
a = arc cos(S . V)
Run Code Online (Sandbox Code Playgroud)
现在您可以使用 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);
Run Code Online (Sandbox Code Playgroud)
现在将形状的每个元素与 rot 相乘,并将其平移为当前的路径向量:
PVector rotVec;
rot.mult((PVector)shape[i], rotVec);
rotVec.add(current);
Run Code Online (Sandbox Code Playgroud)