3

我想学习 OpenGL,并决定从一个非常简单的例子开始——根据星尘航天器的测量结果来渲染彗星 Wild 2 的形状(有关数据的详细信息,请参见:http: //nssdc.gsfc.nasa.gov/ nmc/masterCatalog.do?ds=PSSB-00133)。请记住,我对 OpenGL 一无所知。一些 Google-fu 帮助我了解了下面提供的代码。尽管我尽了最大的努力,我的彗星还是很糟糕

彗星 Wild 2 的 OpenGL 渲染

我希望它看起来更漂亮,但我不知道如何进行(除了阅读红皮书或类似书籍)。例如:

  • 如何对形状进行非常基本的“线框”渲染?
  • 假设太阳沿着“底部”方向(即,沿着-Y),我如何添加光线并看到另一侧的阴影?
  • 如何添加“鼠标事件”以便我可以旋转视图并放大/缩小?

我怎样才能让这个怪物看起来更漂亮?对在线教程或代码示例的任何引用?

我将源代码、数据和 makefile(对于 OS X)放在 bitbucket 中:

hg 克隆https://arrieta@bitbucket.org/arrieta/learning-opengl

数据由 8,761 个三元组(顶点,在身体固定框架中)和 17,518 个三角形(每个三角形是一个整数三元组,指的是 8,761 个顶点三元组之一)组成。

#include<stdio.h>
#include<stdlib.h>

#include<OpenGL/gl.h>
#include<OpenGL/glu.h> 
// I added this in case you want to "copy/paste" the program into a
// non-Mac computer
#ifdef __APPLE__
#  include <GLUT/glut.h>
#else
#  include <GL/glut.h>
#endif

/* I hardcoded the data and use globals. I know it sucks, but I was in
   a hurry. */
#define NF 17518
#define NV 8761
unsigned int fs[3 * NF];
float vs[3 * NV];
float angle = 0.0f;

/* callback when the window changes size (copied from Internet example) */
void changeSize(int w, int h) {
  if (h == 0) h = 1;  
  float ratio =  w * 1.0 / h;
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glViewport(0, 0, w, h);
  gluPerspective(45.0f, ratio, 0.2f, 50000.0f); /*  45 degrees fov in Y direction; 50km z-clipping*/
  glMatrixMode(GL_MODELVIEW);
}

/* this renders and updates the scene (mostly copied from Internet examples) */
void renderScene() {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
  glLoadIdentity();
  gluLookAt(0.0f, 0.0f,  10000.0f, /* eye is looking down along the Z-direction at 10km */
            0.0f, 0.0f,  0.0f,     /* center at (0, 0, 0) */
            0.0f, 1.0f,  0.0f);    /* y direction along natural y-axis */

  /* just add a simple rotation */
  glRotatef(angle, 0.0f, 0.0f, 1.0f);    
  /* use the facets and vertices to insert triangles in the buffer */
  glBegin(GL_TRIANGLES);
  unsigned int counter;
  for(counter=0; counter<3 * NF; ++counter) {
    glVertex3fv(vs + 3 * fs[counter]); /* here is where I'm loading
                                          the data - why do I need to
                                          load it every time? */
  }
  glEnd();  
  angle += 0.1f;                /* update the rotation angle */
  glutSwapBuffers();  
}


int main(int argc, char* argv[]) {
  FILE *fp;
  unsigned int counter;


  /* load vertices */
  fp = fopen("wild2.vs", "r");
  counter = 0;
  while(fscanf(fp, "%f", &vs[counter++]) > 0);
  fclose(fp);

  /* load facets */
  fp = fopen("wild2.fs", "r");
  counter = 0;
  while(fscanf(fp, "%d", &fs[counter++]) > 0);
  fclose(fp);

  /* this initialization and "configuration" is mostly copied from Internet */
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
  glutInitWindowPosition(0, 0);
  glutInitWindowSize(1024, 1024);
  glutCreateWindow("Wild-2 Shape");

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

  GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
  GLfloat mat_shininess[] = { 30.0 };
  GLfloat light_position[] = {3000.0, 3000.0, 3000.0, 0.0 };
  glClearColor (0.0, 0.0, 0.0, 0.0);
  glShadeModel (GL_SMOOTH);
  glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
  glLightfv(GL_LIGHT0, GL_POSITION, light_position);

  glutDisplayFunc(renderScene);
  glutReshapeFunc(changeSize);
  glutIdleFunc(renderScene);

  glutMainLoop();
  return 0;  
}

编辑

它开始看起来更好了,我现在有很多资源可以暂时研究。它仍然很烂,但我的问题已得到解答!

另一个图像,它没有那么糟糕

我添加了法线,并且可以在“纹理”和线框之间来回切换:

有法线

PS。存储库显示了根据 SeedmanJ 的建议所做的更改。

4

3 回答 3

3

在OpenGL中更改为线框渲染真的很容易,你必须使用

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

并切换回填充渲染,

glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

关于灯光,OpenGL 允许您使用最多 8 种不同的灯光,通过法线和材质生成最终渲染。您可以通过以下方式激活照明模式:

glEnable(GL_LIGHTING);

然后使用以下任一方法激活您的每个灯:

 glEnable(GL_LIGHT0);
 glEnable(GL_LIGHT1);

要更改像它的位置这样的光属性,请查看 http://linux.die.net/man/3/gllightfv

如果您使用 glBegin() 方法,则必须为您定义的每个顶点设置法线。在 VBO 渲染中它是相同的,但法线也包含在 vram 中。在 glBegin() 方法中,您可以使用

glNormal3f(x, y, z); for example

对于您定义的每个顶点。

有关您可以做什么的更多信息,红皮书是一个很好的开始。

移动你的“场景”是 OpenGL 间接允许你做的另一件事。因为这一切都适用于矩阵,

你可以使用

glTranslate3f(x, y, z);
glRotate3f(num, x, y, z);
....

管理键事件和鼠标事件(我几乎可以肯定)与 OpenGL 无关,这取决于您使用的库,例如 glut/SDL/... 所以您必须参考他们自己的文档.

最后,有关您可以使用的一些功能的更多信息,http://www.opengl.org/sdk/docs/man/,还有一个教程部分,带您访问不同的有趣网站。

希望这可以帮助!

于 2013-02-22T23:04:28.910 回答
1

如何对形状进行非常基本的“线框”渲染?

glPolygonMode( GL_FRONT, GL_LINE );

假设太阳沿着“底部”方向(即,沿着-Y),我如何添加光线并看到另一侧的阴影?

好的阴影很难,尤其是在固定功能的管道中。

但在此之前,您需要法线与顶点一起使用。您可以很容易地计算每个面的法线

如何添加“鼠标事件”以便我可以旋转视图并放大/缩小?

试试我在这里做的鼠标处理程序。

于 2013-02-22T23:03:15.627 回答
-7

尽管我有些人喜欢说“从更简单的事情开始”,但我认为,有时您需要在很短的时间内“潜入”以获得良好的理解!做得好!

另外,如果您想要一个示例,请询问... 我已经编写了一个文档完善、高效但可读的纯 Win32(无 .NET 或 MFC)OpenGL FPS!

虽然看起来其他人回答了你们大多数问题......如果你愿意,我可以帮助你,也许可以制作一个很酷的纹理(如果你没有的话)......

要回答这个问题:

    glBegin(GL_TRIANGLES);
    unsigned int counter;
    for(counter=0; counter<3 * NF; ++counter) {
    glVertex3fv(vs + 3 * fs[counter]); /*   here is where I'm loading
                                            the data - why do I need to
                                            load it every time? */
}
glEnd();

那就是渲染 3D 模型的顶点(在视图发生变化的情况下)并使用 DC(设备上下文),BitBlt 的它 - 到窗口上!它必须重复进行(以防某些事情导致窗口清除)......

于 2013-02-22T23:18:10.800 回答