3

I want to learn OpenGL, and decided to start with a very simple example - rendering the shape of comet Wild 2 as inferred from measurements from the Stardust spacecraft (details about the data in: http://nssdc.gsfc.nasa.gov/nmc/masterCatalog.do?ds=PSSB-00133). Please keep in mind that I know absolutely NOTHING about OpenGL. Some Google-fu helped me get as far as the code presented below. Despite my best efforts, my comet sucks:

An OpenGL rendering of comet Wild 2

I would like for it to look prettier, and I have no idea how to proceed (besides reading the Red book, or similar). For example:

  • How can I make a very basic "wireframe" rendering of the shape?
  • Suppose the Sun is along the "bottom" direction (i.e., along -Y), how can I add the light and see the shadow on the other side?
  • How can I add "mouse events" so that I can rotate my view by, and zoom in/out?

How can I make this monster look prettier? Any references to on-line tutorials, or code examples?

I placed the source code, data, and makefile (for OS X) in bitbucket:

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

The data consists of 8,761 triplets (the vertices, in a body-fixed frame) and 17,518 triangles (each triangle is a triplet of integers referring to one of the 8,761 vertex triplets).

#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;  
}

EDIT

It is starting to look better, and I have now plenty of resources to look into for the time being. It still sucks, but my questions have been answered!

Another image, which does not suck as much

I added the normals, and can switch back and forth between the "texture" and the wireframe:

With normals

PS. The repository shows the changes made as per SeedmanJ's suggestions.

genpfault
  • 51,148
  • 11
  • 85
  • 139
Escualo
  • 40,844
  • 23
  • 87
  • 135

3 Answers3

3

It's really easy to change to a wireframe rendering in OpenGL, you'll have to use

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

and to switch back to a fill rendering,

glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

About the lights, OpenGL allows you to use at most 8 different lights, generating your final rendering thanks to the normals, and materials. You can activate a lighting mode with:

glEnable(GL_LIGHTING);

and then activate each of your lights with either:

 glEnable(GL_LIGHT0);
 glEnable(GL_LIGHT1);

to change a light property like its position, please look at http://linux.die.net/man/3/gllightfv

You'll have to set up your normals for each vertices you define, if your using the glBegin() method. In VBO rendering it's the same but normals are also contained in the vram. In the glBegin() method, you can use

glNormal3f(x, y, z); for example

for each vertex you define.

And for more information about what you can do, the redbook is a good way to begin.

Moving your "scene" is one more thing OpenGL indirectly allows you to do. As it all works with matrix,

you can either use

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

Managing key events and mouse events has (i'm almost sure about that) nothing to do with OpenGL, it depends on the lib your using, for example glut/SDL/... so you'll have to refer to their own documentations.

Finaly, for more further information about some of the functions you can use, http://www.opengl.org/sdk/docs/man/, and there's also a tutorial part, leading you to different interesting websites.

Hope this helps!

SeedmanJ
  • 444
  • 2
  • 8
1

How can I make a very basic "wireframe" rendering of the shape?

glPolygonMode( GL_FRONT, GL_LINE );

Suppose the Sun is along the "bottom" direction (i.e., along -Y), how can I add the light and see the shadow on the other side?

Good shadows are hard, especially with the fixed-function pipeline.

But before that you need normals to go with your vertices. You can calculate per-face normals pretty easily.

How can I add "mouse events" so that I can rotate my view by, and zoom in/out?

Try the mouse handlers I did here.

Community
  • 1
  • 1
genpfault
  • 51,148
  • 11
  • 85
  • 139
-7

Though I some like to say "Start with something simpler", I think, sometimes you need to "dive in" to get a good understanding, on a small time span! Well done!

Also if you would like an example, please ask... I have written a WELL DOCUMENTED, and efficient, but readable pure Win32 (No .NET, or MFC) OpenGL FPS!

Though it appears other people answered most of you questions... I can help you if you would like, maybe make a cool texture (if you don't have one)...

To answer this question:

    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();

That is rendering the vertices of the 3D Model (in the case the view has changed) and using the DC (Device Context), BitBlt's it- onto the Window! It has to be done repeatedly (in case something has caused the window to clear)...

Mitch
  • 44
  • 6
  • `-1`. Reasoning : "I hope you are using Win32, and NOT glut.h or glew.h or anything like that!" <- that's quite a bad advice; what about cross-platform support? Besides, how are you supposed to get 2.0+ functionality *without* GLEW? Not mentioning that on modern GPUs the approach you have proposed is mostly useless, since the contents of said buffer would change with every mouse movement. – Bartek Banachewicz Feb 22 '13 at 23:41
  • Also though normally it would make cross-platform difficult, the example I offered separates the WinAPI, and makes it easy to apply it to a cross-platform implementation (simply by changing some functions, and removing the WinProc). I just do not like relying on multiple libraries, and header... They often become outdated. – Mitch Feb 22 '13 at 23:53
  • 1
    So basically you suggest reinventing the wheel because "the libraries might get outdated". Also, "removes the low level API by adding abstractions" - that's the whole point of it, don't you think? Are you implying you are calling every function by getting the raw pointer every time? Because anything else would be "an abstraction". Also, there are other libraries than GLEW, such as GLFW. Your proposal is not "advanced", it's plainly unreasonable in modern usages, but you just seem to be stucked in 1998. – Bartek Banachewicz Feb 23 '13 at 00:03
  • 9
    Ahahahahahahahahahahahaha spouting nonsense about performance and using immediate mode at the same time. – Cat Plus Plus Feb 23 '13 at 00:08
  • 1
    @Mitch Libraries become outdated all the time. It doesn't mean they'll catch fire and stop being usable. – Etienne de Martel Feb 23 '13 at 00:08
  • 5
    btw OpenGL removes the low-level device API by adding abstractions – Cat Plus Plus Feb 23 '13 at 00:10
  • 1
    "(though I like to add a loop to prevent hogging CPU)" summarized it nicely. Thanks for making my day! – sehe Feb 23 '13 at 00:30
  • OK... Have any of you ported Glut to Android or iPhone? I am just suggesting to avoid outdated headers... It just seems easier and less time consuming. Glut and Glew are just another thing to learn, and do not port that easily... Also I unintentionally stated "loop" when I should have said "timer"... It's just my preference to avoid these additional dependencies, when apparently everyone else relies so greatly on them. – Mitch Feb 23 '13 at 02:13
  • 4
    I, too, use WinAPI because it's easier to port to Android. – Cat Plus Plus Feb 23 '13 at 02:27
  • @Cat Plus Plus, I Agree :) – Mitch Feb 23 '13 at 02:30
  • Well it is easier, faster too. :| – Mitch Feb 23 '13 at 02:34
  • If the reputation points were accurate, I would be in the negative :( – Mitch Feb 23 '13 at 02:39
  • 3
    Do tell how it's easier to port code using OS-specific API than code using libraries (fyi calling them "headers" doesn't make you very credible) that already support Android (like freeGLUT, which was last updated a year ago) or those that are trivially drop-in replaceable by others (also GLEW supports OpenGL 4.3 just fine, what with last being updated few months ago and all). – Cat Plus Plus Feb 23 '13 at 02:40
  • First, GLUT is mostly just a header, second I cannot explain all of that in a comment... But when you avoid such dependencies you understand what is happening more... It's just easier. I doubt you would know, you probably use managed code, and I am guessing you always use freeGLUT. – Mitch Feb 23 '13 at 02:44
  • And before someone comments (probably you) and says "then what is Glut32.lib" I will just say I am aware of it. – Mitch Feb 23 '13 at 02:44
  • Wrong on all accounts, but thanks for participating in this highly amusing thread~ – Cat Plus Plus Feb 23 '13 at 02:45
  • @Mitch Well, why aren't you writing in assembly, then? – Etienne de Martel Feb 23 '13 at 02:54
  • I do write assembly... MASM, and 6502 (That one is just for fun). – Mitch Feb 23 '13 at 02:55
  • It isn't always faster (compilers are REALLY good)... I don't understand why nobody else prefers not to uses silly wrappers for OpenGL (yeah that is what I think). – Mitch Feb 23 '13 at 02:56
  • @Etienne you are really good at french... It's you native language isn't it? You are also good at English! :) – Mitch Feb 23 '13 at 03:02
  • At least Bartek Banachewicz explained his reason for down voting... Others didn't :( How am I supposed to know where the problem is if people don't explain? I realize that everyone likes Glut etc (so do I), I just prefer not to use them (for most projects)... I might change my mind later, but currently I don't see many reason to use them. I assume it is because I said that "I prefer not to use Glut". – Mitch Feb 23 '13 at 03:17
  • 2
    You can safely assume everyone is just agreeing to the comments. This is especially apparent from the upvotes on the comments. If they don't render for you, here is a screencap: http://i.imgur.com/9ZoeFyb.png – sehe Feb 23 '13 at 03:22
  • Supposedly Stack Overflow if for people who "write code because they love it"... Yet people seem to like to avoid writing code as much as they can. They like to use small libraries (instead of just making the stuff themselves), and saying "stop reinventing the wheel"... Even though I find it quite fun (to reinvent/modify existing stuff)! – Mitch Feb 23 '13 at 03:31
  • 2
    @Mitch I downvoted because you're recommending wheel reinvention _to a beginner_. – Etienne de Martel Feb 23 '13 at 06:16
  • He didn't ask about optimizations, he just mentioned in the code, why it has to re-draw... I simply explained why (the Window needs to refresh etc), and the only way to avoid such, is to -refresh ONLY when needed, IE changes were made- I know, it's silly! :) – Mitch Feb 23 '13 at 20:41