【问题标题】:Applying OpenGL Depth Test to Orbiting Spheres将 OpenGL 深度测试应用于轨道球体
【发布时间】:2014-09-08 12:34:58
【问题描述】:

我正在用 C++ 编写一个引力 n 体模拟,它使用 OpenGL 和 GLUT 进行动画处理(这是一个爱好项目)。大部分情况下,动画效果都很好,但是我遇到了两个无法解决的主要问题:

  • 虽然启用了深度测试,但它没有按预期工作,并且
  • 表面……嗯,很乱。

我的问题是,我该如何解决这些问题?

这两个问题都可以在以下图片中看到(对链接表示歉意,但我没有足够的代表来发布图片)。这些是简单轨道模拟的快照,从边缘观察。

Here 黄色球体绘制在紫色球体前面,应该是这样。

After half an orbit黄色球体仍然绘制在前面,即使它更远。

用于创建动画的代码如下。

#include <GL/glut.h>
#include "Cluster.h" // My own class.

// Scale for animation.  Each unit in the animation = 1/SCALE m.
const double SCALE = 1e-10;
// Size of spheres for animation.
const double SPHERE_SIZE = 2e10*SCALE;

// Cluster object contains bodies and updates their positions.
Cluster cluster();

// Array of rgb colors for spheres.
GLfloat colorArr[4][4] =
{ 
   {0.7, 0.7, 0.0, 1.0},
   {0.73, 0.24, 0.95, 1.0},
}

void display()
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt( 0.0*SCALE, 5e11*SCALE, 0.0*SCALE  // eye is on y-axis outside orbit.
            , 0.0, 0.0, 0.0 
            , 0.0, 0.0, 1.0 ); 

   for (int i=0; i<N; i++) // N is the number of bodies in cluster.
   { 
      glPushMatrix(); 
      glTranslated( SCALE*cluster.getX(i)     // Get coordinate of ith body.
                  , SCALE*cluster.getY(i)
                  , SCALE*cluster.getZ(i) );
      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colorArr[i]);
      glutSolidSphere(SPHERE_SIZE, 50, 50);
      glCullFace(GL_BACK);
      glPopMatrix();
   } 

   glutSwapBuffers();
} 

void reshape(GLint w, GLint h) 
{ 
   glViewport(0, 0, w, h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(30.0, (GLfloat)w/(GLfloat)h, SCALE, 5e11*SCALE);
   glMatrixMode(GL_MODELVIEW);
} 

void animate() 
{ 
   // Update positions and redraw.
   cluster.update();
   display();
} 

void init() 
{ 
   GLfloat black[] = {0.0, 0.0, 0.0, 1.0};
   GLfloat white[] = {1.0, 1.0, 1.0, 0.5};
   GLfloat direction[] = {1.0, 1.0, 1.0, 0.0};

   glMaterialfv(GL_FRONT, GL_SPECULAR, white);
   glMaterialf(GL_FRONT, GL_SHININESS, 10);

   glLightfv(GL_LIGHT0, GL_AMBIENT, black);
   glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
   glLightfv(GL_LIGHT0, GL_SPECULAR, white);
   glLightfv(GL_LIGHT0, GL_POSITION, direction);

   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_DEPTH_TEST);
} 

int main(int argc, char** argv) 
{
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize(800, 600);
   glutCreateWindow("Test Orbit");
   glutDisplayFunc(display);
   glutReshapeFunc(reshape);
   glutIdleFunc(animate);
   init();
   glutMainLoop();
}

【问题讨论】:

  • 在这里查看我关于深度战斗的回答:stackoverflow.com/questions/25580397/…
  • 谢谢,一个很好的答案,为我解决了一些问题。但是,我已经在我的代码中包含了缩放以避免深度冲突;球体的半径为 2.0,相机位于 y=50,近端和远端剪裁平面分别为 1e-10 和 50.0。当我写这篇文章时,我意识到远/近比率太高了!我会修复它并回复你。
  • 我将剪裁平面的远/近比率降低到

标签: c++ opengl depth-buffer


【解决方案1】:

OpenGL 的深度缓冲区具有有限的精度,并且您使用的数字足够大,您可能会遇到该精度限制。您可能想阅读this article about depth-buffer optimization,或者干脆使用比米更大的单位来表示天文距离。

【讨论】:

  • 是的,精度是问题;在动画之前我已经缩小了所有距离,但是我也缩小了我的近剪裁平面使其变小。这导致我的远/近口粮仍然太大,导致深度战斗。谢谢你的回答。
猜你喜欢
  • 2015-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-28
  • 1970-01-01
  • 2018-07-21
  • 1970-01-01
相关资源
最近更新 更多