Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: Opengl Surface normals in Chromadepth terrain

  1. #1
    Newbie Newbie
    Join Date
    Nov 2012
    Posts
    2

    Opengl Surface normals in Chromadepth terrain

    Hi All,

    I am creating a chromadepth terrain using Opengl. I am loading a PGM(Portable grey map) file and then I am creating vertices for that. But I am not able to understand how would I get surface normals for the terrain? Here is my code snippet. I am using triangle strip Please help me. I am using VBO to load my buffers.
    Code :
     
    double getNormalizedX(unsigned long x){
    	return ((double)x/((width-1)) * 2.0 - 1.0);
      }
     
      double getNormalizedY(unsigned long y){
    	return ((double)(height - 1 - y) /( (height - 1))* 2.0 - 1.0);
      }
     
      double getNormalizedZ(unsigned long x,unsigned long y){
    	unsigned long yPrime = (height - 1) - y;
    	return   (0.25 * gridData[yPrime][x]/ (double)maxVal);	
      }
     
     void loadPGMFile(){
        FILE *pgmFile;
        char pgm_name[10000];
        size_t x,y;
        unsigned long vertexIndex = 0;
     
     
        pgmFile = fopen("sample.pgm","r");
     
        fgets(pgm_name,10000,pgmFile);
     
        fscanf(pgmFile,"%d", &width);
        fscanf(pgmFile,"%d", &height);
        fscanf(pgmFile,"%d", &maxVal);
     
        gridData = malloc(height * sizeof(int *));
     
        for( x = 0; x < height; x++){
           gridData[x] = malloc(width * sizeof(int));
             for(y = 0; y < width; y++){
                fscanf(pgmFile, "%d", &gridData[x][y]);
             }
     
        }
     
    // XXX Change this allocation once everything is finished.
     
        indicesArray = malloc(width * height * 6 * sizeof(GLuint));
        verticesArray = malloc(width * height * 3 * sizeof(GLfloat));
        normalsArray = malloc(width * height * 3 * sizeof(GLfloat));
     
        int vertsI = 0, indicesI=0, normalsI = 0;
        unsigned long i=0,j=0;
        for(i = 0; i < width; i++){
          if(i > 1){
    	indicesArray[indicesI++] = vertexIndex;
    	indicesArray[indicesI++] = vertexIndex;
          } 
     
          for(j = 0; j < height; j++){
    	verticesArray[vertsI++] = getNormalizedX(i);
    	verticesArray[vertsI++] = getNormalizedY(j);
    	verticesArray[vertsI++] = getNormalizedZ(i,j);
    	if(i > 0){
    	  indicesArray[indicesI++] = vertexIndex;
    	  indicesArray[indicesI++] = vertexIndex - height;
    	}
    	vertexIndex++;
     
          } 
     
          if(i > 0){
    	indicesArray[indicesI++] = vertexIndex - height -1;
    	indicesArray[indicesI++] = vertexIndex - height -1;
          }
    /**
    ** Trying to create Normals*
    **/
        }
     
    void generateTerrain(){
     static GLuint indexBuffer;
     static GLuint vertexBuffer;
        static GLuint normalsBuffer;
     
     static GLboolean first = GL_TRUE;
     
     
    if(first){ 
    glGenBuffers(1, &vertexBuffer);
     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
     glBufferData(GL_ARRAY_BUFFER, totalVertices * sizeof(GLfloat),
    &verticesArray[0], GL_STATIC_DRAW);
     
     glGenBuffers(1, &indexBuffer);
     glBindBuffer(GL_ARRAY_BUFFER,indexBuffer);
     glBufferData(GL_ARRAY_BUFFER, totalIndices * sizeof(GLuint),
    &indicesArray[0], GL_STATIC_DRAW);
    first = GL_FALSE;
     
     }
     
    // loadUniforms();
     glEnableVertexAttribArray(vertexPositionAttr);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexAttribPointer(vertexPositionAttr,3, GL_FLOAT,GL_FALSE, 0, (GLvoid*) 0);
     
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
     
    glDrawElements(GL_TRIANGLE_STRIP, totalIndices, GL_UNSIGNED_INT, (GLvoid*) 0);
     
     }

  2. #2
    Junior Member Regular Contributor
    Join Date
    Jan 2011
    Location
    Paris, France
    Posts
    248
    You have to compute yourself normals using verticesArray[] and computing/averaging dots products between edges AB and AC for alls triangles ABC that share the same vertex A
    (I see that you use triangle strips so a lot of computations can be shared between connected triangles for to minimize computations)

    Have you please a more complete basis of your code source for that I can test to add the necessary code to it ?
    (if not, I think to can complete your code sample for to have a full fonctionnal OpenGL program code source but this can really economize a lot of time ...)
    Last edited by The Little Body; 12-11-2012 at 04:24 PM.
    @+
    Yannoo

  3. #3
    Junior Member Regular Contributor
    Join Date
    Jan 2011
    Location
    Paris, France
    Posts
    248
    I have begin to convert a simple NeHe tutorial for to make the base of the chromadepth program

    Code :
    // YLP 12/12/12 : transformation of a basic NeHe OpenGL code source sample (http://nehe.gamedev.net/tutorial/3d_shapes/10035/) 
    // for to handle chromadepth PGM pictures
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
     
    #include <GL/glut.h>    // Header File For The GLUT Library 
    #include <GL/gl.h>    // Header File For The OpenGL32 Library
    #include <GL/glu.h>    // Header File For The GLu32 Library
    #include <unistd.h>     // needed to sleep
     
    /* ASCII code for the escape key. */
    #define ESCAPE 27
     
    /* The number of our GLUT window */
    int window; 
     
    /* specifics variables used for the PGM chromadepth */
    int    width = 0, height = 0, maxVal = 0;
    int  **gridData = NULL;
     
    int   *indicesArray = NULL;
    float *verticesArray = NULL;
    float *normalsArray = NULL;
     
    int    totalVertices = 0;
    int    totalIndices = 0;
    int    totalNormals = 0;
     
    int vertexPositionAttr = 0;
     
    GLuint indexBuffer = 0;
    GLuint vertexBuffer = 0;
    GLuint normalsBuffer = 0;
     
    float rarray = 0;
     
     
    /* A general OpenGL initialization function.  Sets all of the initial parameters. */
    void InitGL(int Width, int Height)            // We call this right after our OpenGL window is created.
    {
      glClearColor(0.0f, 0.0f, 0.0f, 0.0f);        // This Will Clear The Background Color To Black
      glClearDepth(1.0);                // Enables Clearing Of The Depth Buffer
      glDepthFunc(GL_LESS);                    // The Type Of Depth Test To Do
      glEnable(GL_DEPTH_TEST);                // Enables Depth Testing
      glShadeModel(GL_SMOOTH);            // Enables Smooth Color Shading
     
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();                // Reset The Projection Matrix
     
      gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);    // Calculate The Aspect Ratio Of The Window
     
      glMatrixMode(GL_MODELVIEW);
    }
     
    /* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
    void ReSizeGLScene(int Width, int Height)
    {
      if (Height==0)                // Prevent A Divide By Zero If The Window Is Too Small
        Height=1;
     
      glViewport(0, 0, Width, Height);        // Reset The Current Viewport And Perspective Transformation
     
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
     
      gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
      glMatrixMode(GL_MODELVIEW);
    }
     
    /*  Init into the drawing function. */
    void InitGLScene()
    {
      glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);    // Clear The Screen And The Depth Buffer
      glLoadIdentity();                // Reset The View
    }
     
    /* The function called whenever a key is pressed. */
    void keyPressed(unsigned char key, int x, int y) 
    {
        /* avoid thrashing this call */
        usleep(100);
     
        /* If escape is pressed, kill everything. */
        if (key == ESCAPE) 
        { 
          /* shut down our window */
          glutDestroyWindow(window); 
     
          /* exit the program...normal termination. */
          exit(0);                   
        }
    }
     
     
    // Here are located specifics Chromadepth funcs
     
    double getNormalizedX(unsigned long x)
    {
        return ((double)x/((width-1)) * 2.0 - 1.0);
    }
     
    double getNormalizedY(unsigned long y)
    {
        return ((double)(height - 1 - y) /( (height - 1))* 2.0 - 1.0);
    }
     
    double getNormalizedZ(unsigned long x,unsigned long y)
    {
        unsigned long yPrime = (height - 1) - y;
     
        // return   (0.25 * gridData[yPrime][x]) / (double)maxVal;
        return -fabs(gridData[yPrime][x]) / 20.0f;
    }
     
    void loadPGMFile(char *filename)
    {
        FILE *pgmFile;
        int x, y;
        char pgm_name[10000];
        unsigned char temp[4];
     
        // pgmFile = fopen("sample.pgm","r");
        pgmFile = fopen(filename,"r");
     
        if( pgmFile == NULL )
        {
        printf("Canot open the %s file :(\n", filename);
        return;
        }
     
        fgets(pgm_name,10000,pgmFile);
     
        fscanf(pgmFile,"%d", &width);
        fscanf(pgmFile,"%d", &height);
        fscanf(pgmFile,"%d", &maxVal);
     
        printf("%s : width=%d height=%d maxVal=%d \n", filename, width, height, maxVal);
     
        gridData = (int **)malloc(height * sizeof(int *));
     
        for( y = 0; y < height; y++)
        {
        gridData[y] = malloc(width * sizeof(int));
        for(x = 0; x < width; x++)
        {
                // fscanf(pgmFile, "%d", &gridData[y][x]);
            fscanf(pgmFile, "%c", temp);
            gridData[y][x] = temp[0];
            // printf("gridData[%d][%d] = %d \n", y, x, gridData[y][x] );
            }
        }
    }
     
    void InitTerrain()
    {
           size_t x,y;
         unsigned long vertexIndex = 0;
     
           // XXX Change this allocation once everything is finished.
     
            indicesArray = malloc(width * height * 6 * sizeof(GLuint));
            verticesArray = malloc(width * height * 3 * sizeof(GLfloat));
            normalsArray = malloc(width * height * 3 * sizeof(GLfloat));
     
            int vertsI = 0, indicesI=0, normalsI = 0;
            unsigned long i=0,j=0;
     
            for(i = 0; i < width; i++)
            {
                  if(i > 1)
                  {
                indicesArray[indicesI++] = vertexIndex;
                indicesArray[indicesI++] = vertexIndex;
                  }     
     
                  for(j = 0; j < height; j++)
                  {
                verticesArray[vertsI++] = getNormalizedX(i);
                verticesArray[vertsI++] = getNormalizedY(j);
                verticesArray[vertsI++] = getNormalizedZ(i,j);
     
                if(i > 0)
                    {
                      indicesArray[indicesI++] = vertexIndex;
                      indicesArray[indicesI++] = vertexIndex - height;
                }
     
                vertexIndex++;
                  } 
     
                  if(i > 0)
                  {
                indicesArray[indicesI++] = vertexIndex - height -1;
                indicesArray[indicesI++] = vertexIndex - height -1;
                  }
     
     
            /**
            ** Trying to create Normals*
            **/
        }
     
        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLOAT, 0, verticesArray);
     
        // glEnableClientState(GL_NORMAL_ARRAY);
        // glVertexPointer(3, GL_FLOAT, 0, normalsArray);
     
        totalVertices = vertsI / 3;
        totalIndices = indicesI;
        totalNormals = normalsI;
     
        printf("%d vertices, %d indices, %d normals \n", totalVertices, totalIndices, totalNormals);
     
    /*
        for( i = 0 ; i < totalVertices ; i++)
        {
            printf("chromadepth(%f,%f) = %f \n", verticesArray[i*3], verticesArray[i*3+1], verticesArray[i*3+2]);
        }
    */             
    }
     
    void DrawTerrain()
    { 
        glLoadIdentity();
        // glRotatef(rarray, 0.0f,1.0f,0.0f);        // Rotate The Terrain On The Y axis
        glScalef(0.02f, 0.02f, 0.02f);
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        glColor3f(1.0f,1.0f,1.0f);
        glDrawElements(GL_TRIANGLE_STRIP, totalIndices, GL_UNSIGNED_INT, indicesArray);
     
        rarray += 1.0f;
    }
     
    void DrawGLScene()
    {
       InitGLScene();
     
       DrawTerrain();
     
       glutSwapBuffers();
    }
     
    int main(int argc, char **argv) 
    {  
      /* Initialize GLUT state - glut will take any command line arguments that pertain to it or 
         X Windows - look at its documentation at http://reality.sgi.com/mjk/spec3/spec3.html */  
      glutInit(&argc, argv);  
     
      /* Select type of Display mode:   
         Double buffer 
         RGBA color
         Alpha components supported 
         Depth buffered for automatic clipping */  
      glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);  
     
      /* get a 640 x 480 window */
      glutInitWindowSize(640, 480);  
     
      /* the window starts at the upper left corner of the screen */
      glutInitWindowPosition(0, 0);  
     
      /* Open a window */  
      window = glutCreateWindow("Chromadepth PGM by YLP v0.0 (12/12/12) ");  
     
      /* Register the function to do all our OpenGL drawing. */
      glutDisplayFunc(&DrawGLScene);  
     
      /* Go fullscreen.  This is as soon as possible. */
      // glutFullScreen();
     
      /* Even if there are no events, redraw our gl scene. */
      glutIdleFunc(&DrawGLScene);
     
      /* Register the function called when our window is resized. */
      glutReshapeFunc(&ReSizeGLScene);
     
      /* Register the function called when the keyboard is pressed. */
      glutKeyboardFunc(&keyPressed);
     
      /* Initialize our window. */
      InitGL(640, 480);
     
      /* Chromadepth loading */
      loadPGMFile("sample.pgm");
      InitTerrain();
     
     
      /* Start Event Processing Engine */  
      glutMainLoop();  
     
      return 1;
    }

    I compile this using gcc on my Linux box
    Code :
    gcc chromadepth.c -o chromadepth -lX11 -lglut -lGL -lGLU -lm


    The important functions are loadPGMFile(), getNormalized*(), InitTerrain() and DrawTerrain()
    (I have a little modify your source for to can use a variable filename of the .pgm picture and read unsigned bytes instead ints [this is perhaps for this that I have a problem with the format ...])


    I have found a depth picture at http://dev.bukkit.org/profiles/thedeadlytao/, converted it to a grayscale picture, resample to 30x30 (for to have an array that I can speedly analyze) and save it to sample.pgm http://dl.free.fr/jrfxBUpAf

    I have discover a problem with the reading of the pgm file because GIMP/ImageMagick store a label on the header
    => I have suppress this line and it can read the file

    But I think that the data isn't really loaded at the good format
    (I read pixels data from disk as unsigned chars and have modified the getNormalizedZ() function for to have something displayed)


    PS : I add the computation of normals as soon as I can properly read/decode .pgm files
    (and/or can properly handle the scaling of the depth)
    Last edited by The Little Body; 12-11-2012 at 09:30 PM.
    @+
    Yannoo

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •