在 OpenGL 中绘制绕 Y 轴旋转的 Cog
Drawing a Cog which rotates around the Y axis in OpenGL
如标题所述:我想创建一个 3D 齿轮,它有 10 个齿,围绕其中心旋转(就像齿轮一样)。齿轮有方齿,为了简单起见,齿之间的边是平的——这个齿轮没有曲线。
齿轮一侧的可视化效果。请注意,角度并非 100% 完美。
根据上图,每个嵌齿轮齿都必须是 8 边多边形,而齿之间的每一边都必须是 4 边多边形。然而,现在,牙齿绘图执行以下操作:
- 尽管没有应用初始旋转,但应该面向相机的侧齿旋转到地板上。
- 牙齿的宽度是高度的两倍,尽管缩放和顶点创建是使用统一数字完成的(它在 x、y、z 方向上按
s
缩放,并使用 0
或 0.5
作为顶点坐标)。
完全可重现的示例:
import java.awt.Dimension;
import javax.swing.JFrame;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.awt.GLJPanel;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;
public class SpinCog3D implements GLEventListener {
JFrame jf;
GLJPanel gljpanel;
Dimension dim = new Dimension(800, 600);
FPSAnimator animator;
float rotation;
float speed;
// set up the OpenGL Panel within a JFrame
public SpinCog3D() {
jf = new JFrame();
gljpanel = new GLJPanel();
gljpanel.addGLEventListener(this);
gljpanel.requestFocusInWindow();
jf.getContentPane().add(gljpanel);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
jf.setPreferredSize(dim);
jf.pack();
animator = new FPSAnimator(gljpanel, 20);
rotation = 0.0f;
speed = 0.1f;
animator.start();
}
public static void main(String[] args) {
new SpinCog3D();
}
public void init(GLAutoDrawable dr) {
GL2 gl2 = dr.getGL().getGL2();
GLU glu = new GLU();
gl2.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
gl2.glEnable(GL2.GL_DEPTH_TEST);
gl2.glMatrixMode(GL2.GL_PROJECTION);
gl2.glLoadIdentity();
glu.gluPerspective(60.0, 1.0, 100.0, 800.0);
}
public void display(GLAutoDrawable dr) {
GL2 gl2 = dr.getGL().getGL2();
GLU glu = new GLU();
gl2.glMatrixMode(GL2.GL_MODELVIEW);
gl2.glLoadIdentity();
glu.gluLookAt(0.0, 200.0, 500.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
gl2.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
// Draw 1 Cog Tooth + 1 Side
drawTooth(gl2, 100.0, 1.0f, 0.0f, 0.0f, 0.0, 0.0, 1.0, 0.0, 0);
drawSide(gl2, 100.0, 0.0f, 1.0f, 0.0f, 0.0, 0.0, 1.0, 0.0, 10);
// Draw Floor
sideRotatedColorScaledFloor(gl2, 300.0, 0.0f, 0.0f, 0.0f, 90.0, 1.0, 0.0, 0.0, 0.0);
gl2.glFlush();
rotation += speed;
if (rotation > 360.9f)
rotation = 0.0f;
}
// draw a single side with a set color and orientation
private void drawTooth(GL2 gl2, double s, float r, float g, float b, double a, double ax, double ay,
double az, double zoffset) {
gl2.glPushMatrix();
gl2.glRotated(a, ax, ay, az);
gl2.glColor3f(r, g, b);
gl2.glTranslated(0.0, 0.0, zoffset);
gl2.glScaled(s, s, s);
tooth(gl2);
gl2.glPopMatrix();
}
private void drawSide(GL2 gl2, double s, float r, float g, float b, double a, double ax, double ay,
double az, double zoffset) {
gl2.glPushMatrix();
gl2.glRotated(a, ax, ay, az);
gl2.glColor3f(r, g, b);
gl2.glTranslated(0.0, 0.0, zoffset);
gl2.glScaled(s, s, s);
side(gl2);
gl2.glPopMatrix();
}
private void sideRotatedColorScaledFloor(GL2 gl2, double s, float r, float g, float b, double a, double ax, double ay,
double az, double zoffset) {
gl2.glPushMatrix();
gl2.glRotated(a, ax, ay, az);
gl2.glColor3f(r, g, b);
gl2.glTranslated(0.0, 0.0, zoffset);
gl2.glScaled(s, s, s);
side(gl2);
gl2.glPopMatrix();
}
private void tooth(GL2 gl2) {
gl2.glBegin(GL2.GL_POLYGON);
gl2.glVertex3d(-0.5, -0.5, 0.0);
gl2.glVertex3d(-0.5, 0.5, 0.0);
gl2.glVertex3d(0.5, 0.5, 0.0);
gl2.glVertex3d(0.5, -0.5, 0.0);
gl2.glVertex3d(-0.5, -0.5, 0.5);
gl2.glVertex3d(-0.5, 0.5, 0.5);
gl2.glVertex3d(0.5, 0.5, 0.5);
gl2.glVertex3d(0.5, -0.5, 0.5);
gl2.glEnd();
}
private void side(GL2 gl2) {
gl2.glBegin(GL2.GL_POLYGON);
gl2.glVertex3d(-0.5, -0.5, 0.0);
gl2.glVertex3d(-0.5, 0.5, 0.0);
gl2.glVertex3d(0.5, 0.5, 0.0);
gl2.glVertex3d(0.5, -0.5, 0.0);
gl2.glEnd();
}
}
是的,我知道 glBegin()
和 glEnd()
已被永远弃用,但这不是重点。如何让我的牙齿正确拔牙并与两侧正确对齐?
tooth drawing does all sorts of weird things...
不是很好的问题描述。我敢打赌你的网格有很多间隙和重叠,因为你使用的是硬编码形状,没有对 Cog 的实际尺寸进行任何修正。就像必须有多大的牙齿才能适合 n
个牙齿才能准确覆盖整个圆圈...
改用参数圆方程如何?
这将摆脱矩阵混乱,我认为会更简单。
所以我会简单地将齿轮分成三角形切片,每个切片都有几个边缘点。因此,将它们与 QUAD
s 连接起来,并将其放入 for
循环中执行所有切片。
我不在 JAVA 中编写代码,但这里使用旧 GL api 的小 C++ 示例,没有花哨的 C++ 内容,因此您应该能够轻松移植它:
void glCog(float r0,float r1,float r2,float w,int n) // shaft/inner/outer radiuses, width, tooths
{
int i;
float a,da,x,y,c,s;
float p[6][3],q[6][3]; // slice points
// set z for slice points
a=-0.5*w; for (i=0;i<3;i++){ p[i][2]=a; q[i][2]=a; }
a=+0.5*w; for (i=3;i<6;i++){ p[i][2]=a; q[i][2]=a; }
// init first slice
q[0][0]= r0; q[5][0]= r0;
q[0][1]=0.0; q[5][1]=0.0;
q[1][0]= r1; q[4][0]= r1;
q[1][1]=0.0; q[4][1]=0.0;
q[2][0]= r2; q[3][0]= r2;
q[2][1]=0.0; q[3][1]=0.0;
// divide circle to 2*n slices
da=2.0*M_PI/float(4*n);
glBegin(GL_QUADS);
for (a=0.0,i=0;i<=n;i++)
{
// points on circles at angle a
c=cos(a); s=sin(a); a+=da;
x=r0*c; y=r0*s; p[0][0]=x; p[5][0]=x;
p[0][1]=y; p[5][1]=y;
x=r1*c; y=r1*s; p[1][0]=x; p[4][0]=x;
p[1][1]=y; p[4][1]=y;
x=r2*c; y=r2*s; p[2][0]=x; p[3][0]=x;
p[2][1]=y; p[3][1]=y;
// render tooth
c=cos(a); s=sin(a); a+=da;
glNormal3f(0.0,0.0,-1.0); // -Z base
glVertex3fv(p[0]);
glVertex3fv(p[2]);
glVertex3fv(q[2]);
glVertex3fv(q[0]);
glNormal3f(0.0,0.0,+1.0); // +Z base
glVertex3fv(p[3]);
glVertex3fv(p[5]);
glVertex3fv(q[5]);
glVertex3fv(q[3]);
glNormal3f(-c,-s,0.0); // shaft circumference side
glVertex3fv(p[5]);
glVertex3fv(p[0]);
glVertex3fv(q[0]);
glVertex3fv(q[5]);
glNormal3f(c,s,0.0); // outter circumference side
glVertex3fv(p[2]);
glVertex3fv(p[3]);
glVertex3fv(q[3]);
glVertex3fv(q[2]);
glNormal3f(-s,c,0.0);
glVertex3fv(p[4]);
glVertex3fv(p[3]);
glVertex3fv(p[2]);
glVertex3fv(p[1]);
glNormal3f(s,-c,0.0);
glVertex3fv(q[1]);
glVertex3fv(q[2]);
glVertex3fv(q[3]);
glVertex3fv(q[4]);
// points on circles at angle a
c=cos(a); s=sin(a); a+=da;
x=r0*c; y=r0*s; q[0][0]=x; q[5][0]=x;
q[0][1]=y; q[5][1]=y;
x=r1*c; y=r1*s; q[1][0]=x; q[4][0]=x;
q[1][1]=y; q[4][1]=y;
x=r2*c; y=r2*s; q[2][0]=x; q[3][0]=x;
q[2][1]=y; q[3][1]=y;
// render gap
c=cos(a); s=sin(a); a+=da;
glNormal3f(0.0,0.0,-1.0); // -Z base
glVertex3fv(q[0]);
glVertex3fv(q[1]);
glVertex3fv(p[1]);
glVertex3fv(p[0]);
glNormal3f(0.0,0.0,+1.0); // +Z base
glVertex3fv(q[4]);
glVertex3fv(q[5]);
glVertex3fv(p[5]);
glVertex3fv(p[4]);
glNormal3f(-c,-s,0.0); // shaft circumference side
glVertex3fv(q[5]);
glVertex3fv(q[0]);
glVertex3fv(p[0]);
glVertex3fv(p[5]);
glNormal3f(c,s,0.0); // outter circumference side
glVertex3fv(q[1]);
glVertex3fv(q[4]);
glVertex3fv(p[4]);
glVertex3fv(p[1]);
}
glEnd();
}
这里是 glCog(0.1,0.5,0.6,0.1,10);
的预览:
这里是 glCog(0.2,0.5,0.52,0.2,50);
的预览:
但是要注意牙齿并不是完全长方形的。齿数越少误差越大。如果你想要完全矩形的牙齿,你需要平移最外面的点而不是旋转(或更正它们计算的角度)
使用翻译来解决这个问题:
void glCog(float r0,float r1,float r2,float w,int n) // shaft/inner/outer radiuses, width, tooths
{
int i,j;
float a,da,dr,x,y,c,s;
float p[6][3],q[6][3]; // slice points
// divide circle to 2*n slices
da=2.0*M_PI/float(4*n);
dr=r2-r1;
// set z for slice points
a=-0.5*w; for (i=0;i<3;i++){ p[i][2]=a; q[i][2]=a; }
a=+0.5*w; for (i=3;i<6;i++){ p[i][2]=a; q[i][2]=a; }
// init first slice
q[0][0]= r0; q[5][0]= r0;
q[0][1]=0.0; q[5][1]=0.0;
q[1][0]= r1; q[4][0]= r1;
q[1][1]=0.0; q[4][1]=0.0;
x=r1+dr*cos(-da); y=dr*sin(-da);
q[2][0]= x; q[3][0]= x;
q[2][1]= y; q[3][1]= y;
glBegin(GL_QUADS);
for (a=0.0,i=0;i<=n;i++)
{
// points on circles at angle a
c=cos(a); s=sin(a);
x=r0*c; y=r0*s; p[0][0]=x; p[5][0]=x;
p[0][1]=y; p[5][1]=y;
x=r1*c; y=r1*s; p[1][0]=x; p[4][0]=x;
p[1][1]=y; p[4][1]=y;
c=cos(a-da); s=sin(a-da); a+=da;
x+=dr*c;y+=dr*s;p[2][0]=x; p[3][0]=x;
p[2][1]=y; p[3][1]=y;
c=cos(a); s=sin(a); a+=da;
// render tooth
glNormal3f(0.0,0.0,-1.0); // -Z base
glVertex3fv(p[0]);
glVertex3fv(p[1]);
glVertex3fv(q[1]);
glVertex3fv(q[0]);
glVertex3fv(p[1]);
glVertex3fv(p[2]);
glVertex3fv(q[2]);
glVertex3fv(q[1]);
glNormal3f(0.0,0.0,+1.0); // +Z base
glVertex3fv(p[3]);
glVertex3fv(p[4]);
glVertex3fv(q[4]);
glVertex3fv(q[3]);
glVertex3fv(p[4]);
glVertex3fv(p[5]);
glVertex3fv(q[5]);
glVertex3fv(q[4]);
glNormal3f(-c,-s,0.0); // shaft circumference side
glVertex3fv(p[5]);
glVertex3fv(p[0]);
glVertex3fv(q[0]);
glVertex3fv(q[5]);
glNormal3f(c,s,0.0); // outter circumference side
glVertex3fv(p[2]);
glVertex3fv(p[3]);
glVertex3fv(q[3]);
glVertex3fv(q[2]);
glNormal3f(-s,c,0.0);
glVertex3fv(p[4]);
glVertex3fv(p[3]);
glVertex3fv(p[2]);
glVertex3fv(p[1]);
glNormal3f(s,-c,0.0);
glVertex3fv(q[1]);
glVertex3fv(q[2]);
glVertex3fv(q[3]);
glVertex3fv(q[4]);
// points on circles at angle a
c=cos(a); s=sin(a);;
x=r0*c; y=r0*s; q[0][0]=x; q[5][0]=x;
q[0][1]=y; q[5][1]=y;
x=r1*c; y=r1*s; q[1][0]=x; q[4][0]=x;
q[1][1]=y; q[4][1]=y;
c=cos(a+da); s=sin(a+da); a+=da;
x+=dr*c;y+=dr*s;q[2][0]=x; q[3][0]=x;
q[2][1]=y; q[3][1]=y;
c=cos(a); s=sin(a); a+=da;
// render gap
glNormal3f(0.0,0.0,-1.0); // -Z base
glVertex3fv(q[0]);
glVertex3fv(q[1]);
glVertex3fv(p[1]);
glVertex3fv(p[0]);
glNormal3f(0.0,0.0,+1.0); // +Z base
glVertex3fv(q[4]);
glVertex3fv(q[5]);
glVertex3fv(p[5]);
glVertex3fv(p[4]);
glNormal3f(-c,-s,0.0); // shaft circumference side
glVertex3fv(q[5]);
glVertex3fv(q[0]);
glVertex3fv(p[0]);
glVertex3fv(p[5]);
glNormal3f(c,s,0.0); // outter circumference side
glVertex3fv(q[1]);
glVertex3fv(q[4]);
glVertex3fv(p[4]);
glVertex3fv(p[1]);
}
glEnd();
}
所以只是点 p[2],q[2],p[3],q[3]
略有变化,基础侧必须用更多的 QUADS 来补偿 ...
这里是 glCog(0.2,0.5,0.6,0.2,10);
的预览:
如标题所述:我想创建一个 3D 齿轮,它有 10 个齿,围绕其中心旋转(就像齿轮一样)。齿轮有方齿,为了简单起见,齿之间的边是平的——这个齿轮没有曲线。
齿轮一侧的可视化效果。请注意,角度并非 100% 完美。
根据上图,每个嵌齿轮齿都必须是 8 边多边形,而齿之间的每一边都必须是 4 边多边形。然而,现在,牙齿绘图执行以下操作:
- 尽管没有应用初始旋转,但应该面向相机的侧齿旋转到地板上。
- 牙齿的宽度是高度的两倍,尽管缩放和顶点创建是使用统一数字完成的(它在 x、y、z 方向上按
s
缩放,并使用0
或0.5
作为顶点坐标)。
完全可重现的示例:
import java.awt.Dimension;
import javax.swing.JFrame;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.awt.GLJPanel;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;
public class SpinCog3D implements GLEventListener {
JFrame jf;
GLJPanel gljpanel;
Dimension dim = new Dimension(800, 600);
FPSAnimator animator;
float rotation;
float speed;
// set up the OpenGL Panel within a JFrame
public SpinCog3D() {
jf = new JFrame();
gljpanel = new GLJPanel();
gljpanel.addGLEventListener(this);
gljpanel.requestFocusInWindow();
jf.getContentPane().add(gljpanel);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
jf.setPreferredSize(dim);
jf.pack();
animator = new FPSAnimator(gljpanel, 20);
rotation = 0.0f;
speed = 0.1f;
animator.start();
}
public static void main(String[] args) {
new SpinCog3D();
}
public void init(GLAutoDrawable dr) {
GL2 gl2 = dr.getGL().getGL2();
GLU glu = new GLU();
gl2.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
gl2.glEnable(GL2.GL_DEPTH_TEST);
gl2.glMatrixMode(GL2.GL_PROJECTION);
gl2.glLoadIdentity();
glu.gluPerspective(60.0, 1.0, 100.0, 800.0);
}
public void display(GLAutoDrawable dr) {
GL2 gl2 = dr.getGL().getGL2();
GLU glu = new GLU();
gl2.glMatrixMode(GL2.GL_MODELVIEW);
gl2.glLoadIdentity();
glu.gluLookAt(0.0, 200.0, 500.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
gl2.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
// Draw 1 Cog Tooth + 1 Side
drawTooth(gl2, 100.0, 1.0f, 0.0f, 0.0f, 0.0, 0.0, 1.0, 0.0, 0);
drawSide(gl2, 100.0, 0.0f, 1.0f, 0.0f, 0.0, 0.0, 1.0, 0.0, 10);
// Draw Floor
sideRotatedColorScaledFloor(gl2, 300.0, 0.0f, 0.0f, 0.0f, 90.0, 1.0, 0.0, 0.0, 0.0);
gl2.glFlush();
rotation += speed;
if (rotation > 360.9f)
rotation = 0.0f;
}
// draw a single side with a set color and orientation
private void drawTooth(GL2 gl2, double s, float r, float g, float b, double a, double ax, double ay,
double az, double zoffset) {
gl2.glPushMatrix();
gl2.glRotated(a, ax, ay, az);
gl2.glColor3f(r, g, b);
gl2.glTranslated(0.0, 0.0, zoffset);
gl2.glScaled(s, s, s);
tooth(gl2);
gl2.glPopMatrix();
}
private void drawSide(GL2 gl2, double s, float r, float g, float b, double a, double ax, double ay,
double az, double zoffset) {
gl2.glPushMatrix();
gl2.glRotated(a, ax, ay, az);
gl2.glColor3f(r, g, b);
gl2.glTranslated(0.0, 0.0, zoffset);
gl2.glScaled(s, s, s);
side(gl2);
gl2.glPopMatrix();
}
private void sideRotatedColorScaledFloor(GL2 gl2, double s, float r, float g, float b, double a, double ax, double ay,
double az, double zoffset) {
gl2.glPushMatrix();
gl2.glRotated(a, ax, ay, az);
gl2.glColor3f(r, g, b);
gl2.glTranslated(0.0, 0.0, zoffset);
gl2.glScaled(s, s, s);
side(gl2);
gl2.glPopMatrix();
}
private void tooth(GL2 gl2) {
gl2.glBegin(GL2.GL_POLYGON);
gl2.glVertex3d(-0.5, -0.5, 0.0);
gl2.glVertex3d(-0.5, 0.5, 0.0);
gl2.glVertex3d(0.5, 0.5, 0.0);
gl2.glVertex3d(0.5, -0.5, 0.0);
gl2.glVertex3d(-0.5, -0.5, 0.5);
gl2.glVertex3d(-0.5, 0.5, 0.5);
gl2.glVertex3d(0.5, 0.5, 0.5);
gl2.glVertex3d(0.5, -0.5, 0.5);
gl2.glEnd();
}
private void side(GL2 gl2) {
gl2.glBegin(GL2.GL_POLYGON);
gl2.glVertex3d(-0.5, -0.5, 0.0);
gl2.glVertex3d(-0.5, 0.5, 0.0);
gl2.glVertex3d(0.5, 0.5, 0.0);
gl2.glVertex3d(0.5, -0.5, 0.0);
gl2.glEnd();
}
}
是的,我知道 glBegin()
和 glEnd()
已被永远弃用,但这不是重点。如何让我的牙齿正确拔牙并与两侧正确对齐?
tooth drawing does all sorts of weird things...
不是很好的问题描述。我敢打赌你的网格有很多间隙和重叠,因为你使用的是硬编码形状,没有对 Cog 的实际尺寸进行任何修正。就像必须有多大的牙齿才能适合 n
个牙齿才能准确覆盖整个圆圈...
改用参数圆方程如何?
这将摆脱矩阵混乱,我认为会更简单。
所以我会简单地将齿轮分成三角形切片,每个切片都有几个边缘点。因此,将它们与 QUAD
s 连接起来,并将其放入 for
循环中执行所有切片。
我不在 JAVA 中编写代码,但这里使用旧 GL api 的小 C++ 示例,没有花哨的 C++ 内容,因此您应该能够轻松移植它:
void glCog(float r0,float r1,float r2,float w,int n) // shaft/inner/outer radiuses, width, tooths
{
int i;
float a,da,x,y,c,s;
float p[6][3],q[6][3]; // slice points
// set z for slice points
a=-0.5*w; for (i=0;i<3;i++){ p[i][2]=a; q[i][2]=a; }
a=+0.5*w; for (i=3;i<6;i++){ p[i][2]=a; q[i][2]=a; }
// init first slice
q[0][0]= r0; q[5][0]= r0;
q[0][1]=0.0; q[5][1]=0.0;
q[1][0]= r1; q[4][0]= r1;
q[1][1]=0.0; q[4][1]=0.0;
q[2][0]= r2; q[3][0]= r2;
q[2][1]=0.0; q[3][1]=0.0;
// divide circle to 2*n slices
da=2.0*M_PI/float(4*n);
glBegin(GL_QUADS);
for (a=0.0,i=0;i<=n;i++)
{
// points on circles at angle a
c=cos(a); s=sin(a); a+=da;
x=r0*c; y=r0*s; p[0][0]=x; p[5][0]=x;
p[0][1]=y; p[5][1]=y;
x=r1*c; y=r1*s; p[1][0]=x; p[4][0]=x;
p[1][1]=y; p[4][1]=y;
x=r2*c; y=r2*s; p[2][0]=x; p[3][0]=x;
p[2][1]=y; p[3][1]=y;
// render tooth
c=cos(a); s=sin(a); a+=da;
glNormal3f(0.0,0.0,-1.0); // -Z base
glVertex3fv(p[0]);
glVertex3fv(p[2]);
glVertex3fv(q[2]);
glVertex3fv(q[0]);
glNormal3f(0.0,0.0,+1.0); // +Z base
glVertex3fv(p[3]);
glVertex3fv(p[5]);
glVertex3fv(q[5]);
glVertex3fv(q[3]);
glNormal3f(-c,-s,0.0); // shaft circumference side
glVertex3fv(p[5]);
glVertex3fv(p[0]);
glVertex3fv(q[0]);
glVertex3fv(q[5]);
glNormal3f(c,s,0.0); // outter circumference side
glVertex3fv(p[2]);
glVertex3fv(p[3]);
glVertex3fv(q[3]);
glVertex3fv(q[2]);
glNormal3f(-s,c,0.0);
glVertex3fv(p[4]);
glVertex3fv(p[3]);
glVertex3fv(p[2]);
glVertex3fv(p[1]);
glNormal3f(s,-c,0.0);
glVertex3fv(q[1]);
glVertex3fv(q[2]);
glVertex3fv(q[3]);
glVertex3fv(q[4]);
// points on circles at angle a
c=cos(a); s=sin(a); a+=da;
x=r0*c; y=r0*s; q[0][0]=x; q[5][0]=x;
q[0][1]=y; q[5][1]=y;
x=r1*c; y=r1*s; q[1][0]=x; q[4][0]=x;
q[1][1]=y; q[4][1]=y;
x=r2*c; y=r2*s; q[2][0]=x; q[3][0]=x;
q[2][1]=y; q[3][1]=y;
// render gap
c=cos(a); s=sin(a); a+=da;
glNormal3f(0.0,0.0,-1.0); // -Z base
glVertex3fv(q[0]);
glVertex3fv(q[1]);
glVertex3fv(p[1]);
glVertex3fv(p[0]);
glNormal3f(0.0,0.0,+1.0); // +Z base
glVertex3fv(q[4]);
glVertex3fv(q[5]);
glVertex3fv(p[5]);
glVertex3fv(p[4]);
glNormal3f(-c,-s,0.0); // shaft circumference side
glVertex3fv(q[5]);
glVertex3fv(q[0]);
glVertex3fv(p[0]);
glVertex3fv(p[5]);
glNormal3f(c,s,0.0); // outter circumference side
glVertex3fv(q[1]);
glVertex3fv(q[4]);
glVertex3fv(p[4]);
glVertex3fv(p[1]);
}
glEnd();
}
这里是 glCog(0.1,0.5,0.6,0.1,10);
的预览:
这里是 glCog(0.2,0.5,0.52,0.2,50);
的预览:
但是要注意牙齿并不是完全长方形的。齿数越少误差越大。如果你想要完全矩形的牙齿,你需要平移最外面的点而不是旋转(或更正它们计算的角度)
使用翻译来解决这个问题:
void glCog(float r0,float r1,float r2,float w,int n) // shaft/inner/outer radiuses, width, tooths
{
int i,j;
float a,da,dr,x,y,c,s;
float p[6][3],q[6][3]; // slice points
// divide circle to 2*n slices
da=2.0*M_PI/float(4*n);
dr=r2-r1;
// set z for slice points
a=-0.5*w; for (i=0;i<3;i++){ p[i][2]=a; q[i][2]=a; }
a=+0.5*w; for (i=3;i<6;i++){ p[i][2]=a; q[i][2]=a; }
// init first slice
q[0][0]= r0; q[5][0]= r0;
q[0][1]=0.0; q[5][1]=0.0;
q[1][0]= r1; q[4][0]= r1;
q[1][1]=0.0; q[4][1]=0.0;
x=r1+dr*cos(-da); y=dr*sin(-da);
q[2][0]= x; q[3][0]= x;
q[2][1]= y; q[3][1]= y;
glBegin(GL_QUADS);
for (a=0.0,i=0;i<=n;i++)
{
// points on circles at angle a
c=cos(a); s=sin(a);
x=r0*c; y=r0*s; p[0][0]=x; p[5][0]=x;
p[0][1]=y; p[5][1]=y;
x=r1*c; y=r1*s; p[1][0]=x; p[4][0]=x;
p[1][1]=y; p[4][1]=y;
c=cos(a-da); s=sin(a-da); a+=da;
x+=dr*c;y+=dr*s;p[2][0]=x; p[3][0]=x;
p[2][1]=y; p[3][1]=y;
c=cos(a); s=sin(a); a+=da;
// render tooth
glNormal3f(0.0,0.0,-1.0); // -Z base
glVertex3fv(p[0]);
glVertex3fv(p[1]);
glVertex3fv(q[1]);
glVertex3fv(q[0]);
glVertex3fv(p[1]);
glVertex3fv(p[2]);
glVertex3fv(q[2]);
glVertex3fv(q[1]);
glNormal3f(0.0,0.0,+1.0); // +Z base
glVertex3fv(p[3]);
glVertex3fv(p[4]);
glVertex3fv(q[4]);
glVertex3fv(q[3]);
glVertex3fv(p[4]);
glVertex3fv(p[5]);
glVertex3fv(q[5]);
glVertex3fv(q[4]);
glNormal3f(-c,-s,0.0); // shaft circumference side
glVertex3fv(p[5]);
glVertex3fv(p[0]);
glVertex3fv(q[0]);
glVertex3fv(q[5]);
glNormal3f(c,s,0.0); // outter circumference side
glVertex3fv(p[2]);
glVertex3fv(p[3]);
glVertex3fv(q[3]);
glVertex3fv(q[2]);
glNormal3f(-s,c,0.0);
glVertex3fv(p[4]);
glVertex3fv(p[3]);
glVertex3fv(p[2]);
glVertex3fv(p[1]);
glNormal3f(s,-c,0.0);
glVertex3fv(q[1]);
glVertex3fv(q[2]);
glVertex3fv(q[3]);
glVertex3fv(q[4]);
// points on circles at angle a
c=cos(a); s=sin(a);;
x=r0*c; y=r0*s; q[0][0]=x; q[5][0]=x;
q[0][1]=y; q[5][1]=y;
x=r1*c; y=r1*s; q[1][0]=x; q[4][0]=x;
q[1][1]=y; q[4][1]=y;
c=cos(a+da); s=sin(a+da); a+=da;
x+=dr*c;y+=dr*s;q[2][0]=x; q[3][0]=x;
q[2][1]=y; q[3][1]=y;
c=cos(a); s=sin(a); a+=da;
// render gap
glNormal3f(0.0,0.0,-1.0); // -Z base
glVertex3fv(q[0]);
glVertex3fv(q[1]);
glVertex3fv(p[1]);
glVertex3fv(p[0]);
glNormal3f(0.0,0.0,+1.0); // +Z base
glVertex3fv(q[4]);
glVertex3fv(q[5]);
glVertex3fv(p[5]);
glVertex3fv(p[4]);
glNormal3f(-c,-s,0.0); // shaft circumference side
glVertex3fv(q[5]);
glVertex3fv(q[0]);
glVertex3fv(p[0]);
glVertex3fv(p[5]);
glNormal3f(c,s,0.0); // outter circumference side
glVertex3fv(q[1]);
glVertex3fv(q[4]);
glVertex3fv(p[4]);
glVertex3fv(p[1]);
}
glEnd();
}
所以只是点 p[2],q[2],p[3],q[3]
略有变化,基础侧必须用更多的 QUADS 来补偿 ...
这里是 glCog(0.2,0.5,0.6,0.2,10);
的预览: