如何在OpenGL场景中创建新对象?OpenGL新手求助
嘿,作为OpenGL新手能从示例代码入手尝试扩展已经超棒啦!我来帮你捋捋怎么在现有环境里添加其他3D对象~
从你给出的代码片段看,你应该是用显示列表(BoxList就是显示列表的ID)来复用立方体的绘制逻辑,那添加其他对象的思路其实和这个类似,核心就是「定义对象的绘制指令 → 用矩阵变换把它放到场景里 → 调用绘制」。下面给你几种实用的方法,结合代码示例来讲:
1. 用OpenGL内置函数快速绘制基础对象
OpenGL和GLU库提供了不少现成的基础形状绘制函数,新手可以先从这些入手,不用自己写复杂的顶点计算:
示例:绘制球体
GLU库的gluSphere可以直接生成球体,只需要先创建一个二次曲面对象:
// 初始化阶段(比如在setup函数里) GLUquadric* sphereQuad = gluNewQuadric(); // 创建二次曲面对象 // 绘制阶段(比如在display函数里) glPushMatrix(); // 保存当前矩阵状态,避免影响其他对象 glTranslatef(2.0f, 0.0f, 0.0f); // 把球体平移到立方体右侧 gluSphere(sphereQuad, 1.0f, 20, 20); // 参数:二次曲面、半径、经度分段数、纬度分段数 glPopMatrix(); // 恢复矩阵状态 // 程序结束前记得释放资源 gluDeleteQuadric(sphereQuad);
示例:绘制金字塔
如果想自己用基本图元(三角形)拼简单形状,比如金字塔:
glPushMatrix(); glTranslatef(-2.0f, 0.0f, 0.0f); // 平移到立方体左侧 glBegin(GL_TRIANGLES); // 前侧面 glVertex3f(0.0f, 1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glVertex3f(1.0f, -1.0f, 1.0f); // 后侧面 glVertex3f(0.0f, 1.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // 左侧面 glVertex3f(0.0f, 1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // 右侧面 glVertex3f(0.0f, 1.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.0f); glEnd(); glPopMatrix();
2. 用显示列表复用自定义对象(和你的立方体逻辑一致)
既然你已经用BoxList来存立方体的绘制指令,那可以用同样的方式创建其他对象的显示列表,方便重复调用:
// 全局变量,和BoxList一起定义 unsigned SphereList; // 初始化阶段 void init() { // 先初始化你的BoxList... // 然后创建球体的显示列表 SphereList = glGenLists(1); glNewList(SphereList, GL_COMPILE); // GL_COMPILE表示只编译不立即执行 GLUquadric* quad = gluNewQuadric(); gluSphere(quad, 1.0f, 20, 20); gluDeleteQuadric(quad); glEndList(); } // 绘制阶段 void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); // 绘制你的立方体 glPushMatrix(); glCallList(BoxList); glPopMatrix(); // 绘制球体 glPushMatrix(); glTranslatef(3.0f, 0.0f, 0.0f); glCallList(SphereList); glPopMatrix(); glutSwapBuffers(); }
3. 自定义复杂形状:手动定义顶点数据
如果要绘制OpenGL没有内置的形状(比如圆环、不规则模型),就得自己计算顶点坐标。比如下面是一个简单的圆环绘制示例:
glPushMatrix(); glTranslatef(0.0f, 0.0f, 3.0f); // 放到立方体前方 float outerRadius = 1.5f; // 圆环外半径 float innerRadius = 0.5f; // 圆环内半径 int slices = 20; // 圆环圆周方向分段数 int stacks = 20; // 圆环截面方向分段数 for (int i = 0; i < slices; i++) { float theta1 = i * 2 * PI / slices; float theta2 = (i + 1) * 2 * PI / slices; glBegin(GL_QUAD_STRIP); for (int j = 0; j <= stacks; j++) { float phi = j * 2 * PI / stacks; // 计算第一个顶点 float x1 = (outerRadius + innerRadius * cos(phi)) * cos(theta1); float y1 = (outerRadius + innerRadius * cos(phi)) * sin(theta1); float z1 = innerRadius * sin(phi); glVertex3f(x1, y1, z1); // 计算第二个顶点 float x2 = (outerRadius + innerRadius * cos(phi)) * cos(theta2); float y2 = (outerRadius + innerRadius * cos(phi)) * sin(theta2); float z2 = innerRadius * sin(phi); glVertex3f(x2, y2, z2); } glEnd(); } glPopMatrix();
几个新手必注意的关键点:
- 矩阵变换顺序:OpenGL的矩阵变换是「逆序生效」的,比如你先写
glTranslate再写glRotate,实际是先旋转再平移,这点很容易搞混,记得多测试调整。 glPushMatrix/glPopMatrix必须成对用:每次绘制新对象前用glPushMatrix保存当前矩阵状态,绘制完用glPopMatrix恢复,这样不同对象的变换不会互相干扰。- 光照与材质:如果你的场景开启了光照(
glEnable(GL_LIGHTING)),记得给新对象设置材质属性(glMaterial),不然可能会出现物体发黑或者看不到的情况。
内容的提问来源于stack exchange,提问作者Yu Yu
相关产品推荐
相关产品推荐

