You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL立方体显示异常求助:远层面覆盖近层面

OpenGL立方体抛掷模拟显示异常问题

问题现象

实现了立方体抛掷模拟的OpenGL代码,但立方体显示逻辑错误,远层面出现在近层面上方。尝试调整Z缓冲相关函数与参数后,要么出现黑屏,要么显示问题依旧,立方体深度层级完全错乱。

相关代码

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <math.h>
#include <GL/glut.h>
float z = 7.0f, y = 0, x = 0;
float v0 = 0.2;
float alfa = 5;
float fi = 5;
float r = 1;
float dt = 0.01;
float g = 9.80665f;
float t = 0;
float omega = 0;
float vY = 0, vX = 0, vZ = 0, Y = 0, X = 0, Z = 0;
float ymax = 0, xmax = 0, zmax = 0, tD = 0, tm = 0;
void display()
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();
gluLookAt(xmax + 10, zmax, ymax+10, 
    0.0, 0.0, 0.0,    
    0.0, 2, 0.0);   

glPushMatrix();
glColor3f(0.0f, 0.0f, 1.0f);
glBegin(GL_LINES);
glVertex2f(0.0f, 0.0f);
glVertex2f(333, 0.0f);
glEnd();

glBegin(GL_LINES);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex2f(0.001f, 0.0f);
glVertex2f(0.001f, 333);
glEnd();

glBegin(GL_LINES);
glColor3f(0.0f, 1.0f, 1.0f);
glVertex3f(0.001f, 0.001f, 0.0f);
glVertex3f(0.001f, 0.001f, 333);
glEnd();
glPopMatrix();

glPushMatrix();
static float angle = 0.0f;
angle += omega;

// glTranslatef(X-xmax-r, Z-zmax, Y-(xmax+ymax+zmax));
glTranslatef(X, Z, Y);
glRotatef(angle, 0.0f, 1.0f, 0.0f);
glScalef(r, r, r);
glBegin(GL_QUADS);

glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(-0.5f, -0.5f, 0.5f);
glVertex3f(0.5f, -0.5f, 0.5f);
glVertex3f(0.5f, 0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);

glColor3f(0.5f, 1.0f, 0.5f);
glVertex3f(-0.5f, -0.5f, -0.5f);
glVertex3f(-0.5f, -0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f(-0.5f, 0.5f, -0.5f);

glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.5f, -0.5f, -0.5f);
glVertex3f(-0.5f, -0.5f, -0.5f);
glVertex3f(-0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, 0.5f, -0.5f);

glColor3f(1.0f, 1.0f, 0.0f);
glVertex3f(-0.5f, 0.5f, 0.5f);
glVertex3f(0.5f, 0.5f, 0.5f);
glVertex3f(0.5f, 0.5f, -0.5f);
glVertex3f(-0.5f, 0.5f, -0.5f);

glColor3f(1.0f, 0.0f, 1.0f);
glVertex3f(-0.5f, -0.5f, -0.5f);
glVertex3f(0.5f, -0.5f, -0.5f);
glVertex3f(0.5f, -0.5f, 0.5f);
glVertex3f(-0.5f, -0.5f, 0.5f);

glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.5f, -0.5f, 0.5f);
glVertex3f(0.5f, -0.5f, -0.5f);
glVertex3f(0.5f, 0.5f, -0.5f);
glVertex3f(0.5f, 0.5f, 0.5f);

glEnd();
//   glPopMatrix();
glutSwapBuffers();
}

void timer(int value)
{
glutPostRedisplay();
glutTimerFunc(15, timer, 0);
if (Z >= 0) {
    vX = v0 * cos(alfa * (3.14 / 180)) * cos(fi * (3.14 / 180));
    vY = v0 * cos(alfa * (3.14 / 180)) * sin(fi * (3.14 / 180));
    vZ = v0 * sin(alfa * (3.14 / 180))- g * t;
    Z = z + (v0 * sin(alfa * (3.14 / 180))) * t - 1 / 2.0 * g * t * t; 
    X = t * vX;
    Y = t * vY;
}
t += dt;

}
void obsluhaReshape(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (width == 0) width++;
const float aspect_ratio = (float)(width) / (height);
gluPerspective(100, aspect_ratio, 0, zmax + 10);
}
int main(int argc, char** argv)
{
z = atof(argv[1]);
v0 = atof(argv[2]);
alfa = atof(argv[3]);
fi = atof(argv[4]);
r = atof(argv[5]);
omega = atof(argv[6]);

tD = (v0 * sin(alfa * (3.14 / 180)) + sqrt(pow(v0 * sin(alfa * (3.14 / 180)), 2) + 2 * g * z)) / g;
vX = v0 * cos(alfa * (3.14 / 180)) * cos(fi * (3.14 / 180));
vY = v0 * cos(alfa * (3.14 / 180)) * sin(fi * (3.14 / 180));
zmax = z + (v0* v0* sin(alfa * (3.141592 / 180))* sin(alfa * (3.141592 / 180))) / (2 * g);
xmax = tD*vX;
ymax = tD * vY;

printf("tD = %.2fs\nxmax = %.2fm\nymax = %.2fm\nzmax = %.2fm\n", tD, xmax, zmax, ymax);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(640, 640);
glutCreateWindow("DU6");
glClearDepth(100.0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glutDisplayFunc(display);
glutTimerFunc(0, timer, 0);
glutReshapeFunc(obsluhaReshape);
glutMainLoop();
return 0;
}

问题分析与修复方案

1. 投影矩阵近裁剪面参数错误

gluPerspective的近裁剪面不能设为0,这会直接导致深度缓冲精度丢失,引发深度测试逻辑混乱。将近裁剪面改为极小正值:

gluPerspective(100, aspect_ratio, 0.1, zmax + 10);

2. 显示模式与缓冲交换不匹配

代码使用glutSwapBuffers()双缓冲交换,但初始化时设置的是GLUT_SINGLE单缓冲模式,这会导致缓冲逻辑冲突,引发黑屏。修改显示模式为双缓冲:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

3. 矩阵栈未正确弹出

display函数中调用glPushMatrix()后未执行glPopMatrix(),会导致矩阵栈溢出,后续绘制的变换矩阵完全错乱。取消注释对应的弹出代码:

glEnd();
glPopMatrix();
glutSwapBuffers();

4. 额外优化:开启面剔除

如果修复后仍有层级问题,可以开启背面剔除,避免背面与正面的深度冲突:

// 在main函数的初始化部分添加
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);

内容的提问来源于stack exchange,提问作者srgerh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 14:27:06