7/16/2013

Generating Mesh Shadows On Terrain Using OpenGL


Original post :
http://content.gpwiki.org/index.php/Generating_Mesh_Shadows_On_Terrain_Using_OpenGL


//
// complete function.
//
// unsigned char *lightmap
// int lightmapSize
// unsigned char shadowColor[3]
// float lightdir[3]

 void MeshShadows(unsigned char *lightmap, int lightmapSize, unsigned char shadowColor[3], float lightDir[3])
 {
        // variable initialization
        int lightmapChunkSize = 128;
        if(lightmapSize < lightmapChunkSize) lightmapChunkSize = lightmapSize;
        float terrainDivisions = lightmapSize / lightmapChunkSize;
        int terrainChunkSize = Terrain.size() / terrainDivisions;
 
        unsigned char *chunk = new unsigned char[(lightmapChunkSize)*(lightmapChunkSize)*3];
 
        // create shadow texture
        GLuint shadowChunk;
        glGenTextures(1, &shadowChunk);
        glBindTexture(GL_TEXTURE_2D, shadowChunk);
        glEnable(GL_TEXTURE_2D);
        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, lightmapChunkSize, lightmapChunkSize, 0);
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
 
        int terrainCol = 0;
        int terrainRow = 0;
        float x0 = 0;
        float y0 = 0;
        float x1 = terrainChunkSize;
        float y1 = terrainChunkSize;
 
        for(terrainRow = 0; terrainRow < terrainDivisions; terrainRow++)
        {
                for(terrainCol = 0; terrainCol < terrainDivisions; terrainCol++)
                {
                     // setup orthogonal view
                     glViewport(0, 0, terrainChunkSize * Terrain.size(), terrainChunkSize * Terrain.size());
                     glMatrixMode(GL_PROJECTION);
                     glLoadIdentity();
                     glOrtho(0, terrainChunkSize, 0, terrainChunkSize, -10000, 10000);
                     glMatrixMode(GL_MODELVIEW);
 
                     // apply light's direction to modelview matrix
                     gluLookAt(lightDir[0], lightDir[1], lightDir[2], 0, 0, 0, 0, 1, 0);
 
                     // loop through all vertices in terrain and find min and max points with respect to screen space
                     float minX = 999999, maxX = -999999;
                     float minY = 999999, maxY = -999999;
                     double X, Y, Z;
 
                     // get pointer to terrain vertices
                     float *vertices = Terrain.vertices()->lock();
 
                     for(int i = y0-1; i < y1+1; i++)
                     {
                         if(i < 0) continue;
                         for(int j = x0-1; j < x1+1; j++)
                         {
                              if(j < 0) continue;
                              int index = i * Terrain.size() + j;
 
                              // get screen coordinates for current vertex
                              static GLint viewport[4];
                              static GLdouble modelview[16];
                              static GLdouble projection[16];
                              static GLfloat winX, winY, winZ;
 
                              glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
                              glGetDoublev( GL_PROJECTION_MATRIX, projection );
                              glGetIntegerv( GL_VIEWPORT, viewport );
 
                              gluProject(vertices[index*3+0], vertices[index*3+1], vertices[index*3+2], modelview, projection, viewport, &X, &Y, &Z);
 
                              if(X < minX) minX = X;
                              if(X > maxX) maxX = X;
                              if(Y < minY) minY = Y;
                              if(Y > maxY) maxY = Y;
                         }
                     }
 
                     // clear min and max values
                     static float minX2, minY2, maxX2, maxY2;
                     minX2 = minX;
                     minY2 = minY;
                     maxX2 = maxX;
                     maxY2 = maxY;
 
                     // clear screen
                     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
                     glViewport(0, 0, lightmapChunkSize, lightmapChunkSize);
 
                     // orient viewport so that terrain chunk fits inside
                     glMatrixMode(GL_PROJECTION);
                     glLoadIdentity();
                     glOrtho(minX, maxX, minY, maxY, -10000, 10000);
                     glMatrixMode(GL_MODELVIEW);
 
                     // apply light's direction vector to model view transformation
                     glLoadIdentity();
                     gluLookAt(lightDir[0], lightDir[1], lightDir[2], 0, 0, 0, 0, 1, 0);
 
                     // disable writing to the color buffer
                     glColorMask(false, false, false, false);                   
 
                     // render terrain
                     Terrain.render();
 
                     // enable writing to the color buffer
                     glColorMask(true, true, true, true);
 
                     // render scene meshes '''BLACK'''
                     RenderAllSceneMeshes();
 
                     // bind shadowChunk texture and copy frame buffer data
                     glBindTexture(GL_TEXTURE_2D, shadowChunk);
                     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightmapChunkSize, lightmapChunkSize);
                     glBindTexture(GL_TEXTURE_2D, 0);                   
 
                     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
                     glViewport(0, 0, terrainChunkSize * Terrain.size(), terrainChunkSize * Terrain.size());
 
                     glMatrixMode(GL_PROJECTION);
                     glLoadIdentity();
                     glOrtho(0, 0, terrainChunkSize, terrainChunkSize, -10000, 10000);
                     glMatrixMode(GL_MODELVIEW);
 
                     // rotate view so that xz plane becomes the xy plane
                     glLoadIdentity();
                     glRotatef(90, 1, 0, 0);
 
                     // reset max and min values
                     minX = minY = 999999;
                     maxX = maxY = -999999;
 
                     glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
                     glGetDoublev( GL_PROJECTION_MATRIX, projection );
                     glGetIntegerv( GL_VIEWPORT, viewport );
 
                     // project each corner onto the screen
                     // the corners are represented by the x0, y0, x1 and y1 values
                     gluProject(x0, y0, modelview, projection, viewport, &X, &Y, &Z);
                     if(X < minX) minX = X;
                     if(X > maxX) maxX = X;
                     if(Y < minY) minY = Y;
                     if(Y > maxY) maxY = Y;
 
                     gluProject(x1, y0, modelview, projection, viewport, &X, &Y, &Z);
                     if(X < minX) minX = X;
                     if(X > maxX) maxX = X;
                     if(Y < minY) minY = Y;
                     if(Y > maxY) maxY = Y;
 
                     gluProject(x1, y1, modelview, projection, viewport, &X, &Y, &Z);
                     if(X < minX) minX = X;
                     if(X > maxX) maxX = X;
                     if(Y < minY) minY = Y;
                     if(Y > maxY) maxY = Y;
 
                     gluProject(x0, y1, modelview, projection, viewport, &X, &Y, &Z);
                     if(X < minX) minX = X;
                     if(X > maxX) maxX = X;
                     if(Y < minY) minY = Y;
                     if(Y > maxY) maxY = Y;
 
                     // resize and re-orient the viewport
                     glViewport(0, 0, terrainChunkSize * Terrain.size(), terrainChunkSize * Terrain.size());
 
                     glMatrixMode(GL_PROJECTION);
                     glLoadIdentity();
                     glOrtho(minX, minY, maxX, maxY, -10000, 10000);
                     glMatrixMode(GL_MODELVIEW);
 
                     // rotate view so that xz plane becomes the xy plane
                     glLoadIdentity();
                     glRotatef(90, 1, 0, 0);                     
 
                     // setup projective texturing
                     float PS[] = {1, 0, 0, 0};
                     float PT[] = {0, 1, 0, 0};
                     float PR[] = {0, 0, 1, 0};
                     float PQ[] = {0, 0, 0, 1};
 
                     glTexGenfv(GL_S, GL_EYE_PLANE, PS);
                     glTexGenfv(GL_T, GL_EYE_PLANE, PT);
                     glTexGenfv(GL_R, GL_EYE_PLANE, PR);
                     glTexGenfv(GL_Q, GL_EYE_PLANE, PQ);
 
                     glEnable(GL_TEXTURE_GEN_S);
                     glEnable(GL_TEXTURE_GEN_T);
                     glEnable(GL_TEXTURE_GEN_R);
                     glEnable(GL_TEXTURE_GEN_Q);
                     glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
                     glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
                     glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
                     glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
 
                     // setup texture matrix
                     glBindTexture(GL_TEXTURE_2D, shadowChunk);
 
                     glMatrixMode(GL_TEXTURE);
                     glLoadIdentity();
                     glTranslatef(0.5, 0.5, 0);
                     glScalef(0.5, 0.5, 1);
                     glOrtho(minX2, maxX2, minY2, maxY2, -10000, 10000);
                     gluLookAt(lightDir[0], lightDir[1], lightDir[2], 0, 0, 0, 0, 1, 0);
                     glMatrixMode(GL_MODELVIEW);
 
                     // render the terrain
                     Terrain.render();
 
                     glBindTexture(GL_TEXTURE_2D, shadowChunk);
                     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightmapChunkSize, lightmapChunkSize);
 
                     // disable projective texturing
                     glDisable(GL_TEXTURE_GEN_S);
                     glDisable(GL_TEXTURE_GEN_T);
                     glDisable(GL_TEXTURE_GEN_R);
                     glDisable(GL_TEXTURE_GEN_Q);
 
                     // reset texture matrix
                     glMatrixMode(GL_TEXTURE);
                     glLoadIdentity();
                     glMatrixMode(GL_MODELVIEW);
 
                     // get shadow texture data
                     glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
 
                     for(int a = 0; a < lightmapChunkSize; a++)
                     {
                          for(int b = 0; b < lightmapChunkSize; b++)
                          {
                               int a2 = a + lightmapChunkSize * terrainRow;
                               int b2 = b + lightmapChunkSize * terrainCol;
 
                               lightmap[(a2 * lightmapSize + b2) * 3 + 0] = pixels[(a * lightmapChunkSize + b) * 3 + 0];
                               lightmap[(a2 * lightmapSize + b2) * 3 + 1] = pixels[(a * lightmapChunkSize + b) * 3 + 1];
                               lightmap[(a2 * lightmapSize + b2) * 3 + 2] = pixels[(a * lightmapChunkSize + b) * 3 + 2];
                          }
                     }
                 }
             }
 
             // increment which section on the terrain we are looking at
             x0 += terrainChunkSize;
             x1 += terrainChunkSize;
         }
 
         x0 = 0;
         x1 = terrainChunkSize;
 
         y0 += terrainChunkSize;
         y1 += terrainChunkSize;
     }
 
     // free memory
     glDeleteTextures(1, &shadowTexture);
     delete [] pixels;
 }

댓글 없음: