analysis of ShadowMapping Sample with GLSL

来源:互联网 发布:手绘板绘图软件 编辑:程序博客网 时间:2024/04/29 20:56

This example is from http://www.fabiensanglard.net/shadowmapping/index.php

 

#ifdef _WIN32
#include "windows.h"
#endif

#include "GLUT/glut.h"

#ifdef _WIN32
#include "glext.h"
#endif


#include <stdio.h>


#ifdef _WIN32
// As microsoft did not maintain openGL after version 1.1, Windows platform need to go throught this crap ; macosX and Linux are fine.
// This block simply retries openGL function needed for this example.
// I recommend to use GLEW instead of going this way. This is done this way only to ease beginner's compilation and portability


PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;

// FrameBuffer (FBO) gen, bin and texturebind
PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT ;
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT ;
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT ;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT ;


// Shader functions
PFNGLCREATEPROGRAMOBJECTARBPROC  glCreateProgramObjectARB ;
PFNGLUSEPROGRAMOBJECTARBPROC     glUseProgramObjectARB   ;
PFNGLCREATESHADEROBJECTARBPROC   glCreateShaderObjectARB ;
PFNGLSHADERSOURCEARBPROC         glShaderSourceARB        ;
PFNGLCOMPILESHADERARBPROC        glCompileShaderARB       ;
PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
PFNGLATTACHOBJECTARBPROC         glAttachObjectARB        ;
PFNGLLINKPROGRAMARBPROC          glLinkProgramARB         ;
PFNGLGETUNIFORMLOCATIONARBPROC   glGetUniformLocationARB  ;
PFNGLUNIFORM1IARBPROC            glUniform1iARB           ;
PFNGLACTIVETEXTUREARBPROC    glActiveTextureARB;
PFNGLGETINFOLOGARBPROC           glGetInfoLogARB          ;

void getOpenGLFunctionPointers(void)
{
 // FBO
 glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
 glGenFramebuffersEXT  = (PFNGLGENFRAMEBUFFERSEXTPROC)  wglGetProcAddress("glGenFramebuffersEXT");
 glBindFramebufferEXT  = (PFNGLBINDFRAMEBUFFEREXTPROC)  wglGetProcAddress("glBindFramebufferEXT");
 glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)wglGetProcAddress("glFramebufferTexture2DEXT");
 glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddress("glCheckFramebufferStatusEXT");
 
 //Shaders
 glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)wglGetProcAddress("glCreateProgramObjectARB");
 glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)wglGetProcAddress("glUseProgramObjectARB");
 glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)wglGetProcAddress("glCreateShaderObjectARB");
 glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)wglGetProcAddress("glShaderSourceARB");
 glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)wglGetProcAddress("glCompileShaderARB");
 glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)wglGetProcAddress("glGetObjectParameterivARB");
 glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)wglGetProcAddress("glAttachObjectARB");
 glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)wglGetProcAddress("glGetInfoLogARB");
 glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)wglGetProcAddress("glLinkProgramARB");
 glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)wglGetProcAddress("glGetUniformLocationARB");
 glUniform1iARB = (PFNGLUNIFORM1IARBPROC)wglGetProcAddress("glUniform1iARB");
 
}
#endif

// Expressed as float so gluPerspective division returns a float and not 0 (640/480 != 640.0/480.0).
#define RENDER_WIDTH 640.0
#define RENDER_HEIGHT 480.0
#define SHADOW_MAP_RATIO 2


//Camera position
float p_camera[3] = {32,20,0};

//Camera lookAt
float l_camera[3] = {2,0,-10};

//Light position
float p_light[3] = {3,20,0};

//Light lookAt
float l_light[3] = {0,0,-5};


//Light mouvement circle radius
float light_mvnt = 30.0f;

// Hold id of the framebuffer for light POV rendering
GLuint fboId;

// Z values will be rendered to this texture when using fboId framebuffer
GLuint depthTextureId;

// Use to activate/disable shadowShader
GLhandleARB shadowShaderId;
GLuint shadowMapUniform;

 

// Loading shader function
GLhandleARB loadShader(char* filename, unsigned int type)
{
 FILE *pfile;
 GLhandleARB handle;
 const GLcharARB* files[1];
 
 // shader Compilation variable
 GLint result;    // Compilation code result
 GLint errorLoglength ;
 char* errorLogText;
 GLsizei actualErrorLogLength;
 
 char buffer[400000];
 memset(buffer,0,400000);
 
 // This will raise a warning on MS compiler
 pfile = fopen(filename, "rb");
 if(!pfile)
 {
  printf("Sorry, can't open file: '%s'.\n", filename);
  exit(0);
 }
 
 fread(buffer,sizeof(char),400000,pfile);
 //printf("%s\n",buffer);
 
 
 fclose(pfile);
 
 handle = glCreateShaderObjectARB(type);
 if (!handle)
 {
  //We have failed creating the vertex shader object.
  printf("Failed creating vertex shader object from file: %s.",filename);
  exit(0);
 }
 
 files[0] = (const GLcharARB*)buffer;
 glShaderSourceARB(
       handle, //The handle to our shader
       1, //The number of files.
       files, //An array of const char * data, which represents the source code of theshaders
       NULL);
 
 glCompileShaderARB(handle);
 
 //Compilation checking.
 glGetObjectParameterivARB(handle, GL_OBJECT_COMPILE_STATUS_ARB, &result);
 
 // If an error was detected.
 if (!result)
 {
  //We failed to compile.
  printf("Shader '%s' failed compilation.\n",filename);
  
  //Attempt to get the length of our error log.
  glGetObjectParameterivARB(handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &errorLoglength);
  
  //Create a buffer to read compilation error message
  errorLogText = malloc(sizeof(char) * errorLoglength);
  
  //Used to get the final length of the log.
  glGetInfoLogARB(handle, errorLoglength, &actualErrorLogLength, errorLogText);
  
  // Display errors.
  printf("%s\n",errorLogText);
  
  // Free the buffer malloced earlier
  free(errorLogText);
 }
 
 return handle;
}

void loadShadowShader()
{
 GLhandleARB vertexShaderHandle;
 GLhandleARB fragmentShaderHandle;
 
 vertexShaderHandle   = loadShader("VertexShader.c",GL_VERTEX_SHADER);
 fragmentShaderHandle = loadShader("FragmentShader.c",GL_FRAGMENT_SHADER);
 
 shadowShaderId = glCreateProgramObjectARB();
 
 glAttachObjectARB(shadowShaderId,vertexShaderHandle);
 glAttachObjectARB(shadowShaderId,fragmentShaderHandle);
 glLinkProgramARB(shadowShaderId);
 

  // get locatin of uniform variable in fragment shader
 shadowMapUniform = glGetUniformLocationARB(shadowShaderId,"ShadowMap");
}

void generateShadowFBO()
{
 int shadowMapWidth = RENDER_WIDTH * SHADOW_MAP_RATIO;
 int shadowMapHeight = RENDER_HEIGHT * SHADOW_MAP_RATIO;
 
 //GLfloat borderColor[4] = {0,0,0,0};
 
 GLenum FBOstatus;
 
 // Try to use a texture depth component
 glGenTextures(1, &depthTextureId);
 glBindTexture(GL_TEXTURE_2D, depthTextureId);
 
 // GL_LINEAR does not make sense for depth texture. However, next tutorial shows usage of GL_LINEAR and PCF
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
 // Remove artefact on the edges of the shadowmap
 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
 
 //glTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor );
 
 
 
 // No need to force GL_DEPTH_COMPONENT24, drivers usually give you the max precision if available
 glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadowMapWidth, shadowMapHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
 glBindTexture(GL_TEXTURE_2D, 0);
 
 // create a framebuffer object
 glGenFramebuffersEXT(1, &fboId);
 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);
 
 // Instruct openGL that we won't bind a color texture with the currently binded FBO
 glDrawBuffer(GL_NONE);
 glReadBuffer(GL_NONE);
 
 // attach the texture to FBO depth attachment point
 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D, depthTextureId, 0);
 
 // check FBO status
 FBOstatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
 if(FBOstatus != GL_FRAMEBUFFER_COMPLETE_EXT)
  printf("GL_FRAMEBUFFER_COMPLETE_EXT failed, CANNOT use FBO\n");
 
 // switch back to window-system-provided framebuffer
 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

void setupMatrices(float position_x,float position_y,float position_z,float lookAt_x,float lookAt_y,float lookAt_z)
{
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 gluPerspective(45,RENDER_WIDTH/RENDER_HEIGHT,10,40000);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 gluLookAt(position_x,position_y,position_z,lookAt_x,lookAt_y,lookAt_z,0,1,0);
}


// This update only change the position of the light.
//int elapsedTimeCounter = 0;
void update(void)
{
 
 p_light[0] = light_mvnt * cos(glutGet(GLUT_ELAPSED_TIME)/1000.0);
 p_light[2] = light_mvnt * sin(glutGet(GLUT_ELAPSED_TIME)/1000.0);
 
 //p_light[0] = light_mvnt * cos(3652/1000.0);
 //p_light[2] = light_mvnt * sin(3652/1000.0);
}


void setTextureMatrix(void)
{
 static double modelView[16];
 static double projection[16];
 
 // This is matrix transform every coordinate x,y,z
 // x = x* 0.5 + 0.5
 // y = y* 0.5 + 0.5
 // z = z* 0.5 + 0.5
 // Moving from unit cube [-1,1] to [0,1] 
 const GLdouble bias[16] = { // transform [-1, 1] to [0, 1]
  0.5, 0.0, 0.0, 0.0,
  0.0, 0.5, 0.0, 0.0,
  0.0, 0.0, 0.5, 0.0,
 0.5, 0.5, 0.5, 1.0};
 
 // Grab modelview and transformation matrices
 glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
 glGetDoublev(GL_PROJECTION_MATRIX, projection);
 
 
 glMatrixMode(GL_TEXTURE);    // 切换到texture matrix stack
 glActiveTextureARB(GL_TEXTURE7); // 激活 Texture7

  // save (bias * project * modelview) product of below matrices into texture7 
 glLoadIdentity(); 
 glLoadMatrixd(bias);
 
 // concatating all matrice into one.
 glMultMatrixd (projection);
 glMultMatrixd (modelView);
 
 // Go back to normal matrix mode
 glMatrixMode(GL_MODELVIEW);
}

// During translation, we also have to maintain the GL_TEXTURE8, used in the shadow shader
// to determine if a vertex is in the shadow.
void startTranslate(float x,float y,float z)
{
 glPushMatrix();
 glTranslatef(x,y,z);
 
 glMatrixMode(GL_TEXTURE);
 glActiveTextureARB(GL_TEXTURE7);
 glPushMatrix();
 glTranslatef(x,y,z);
}

void endTranslate()
{
 glPopMatrix();
 glMatrixMode(GL_MODELVIEW);
 glPopMatrix();
}

void drawObjects(void)
{
 // Ground
 glColor4f(0.3f,0.3f,0.3f,1);
 glBegin(GL_QUADS);
 glVertex3f(-35,2,-35);
 glVertex3f(-35,2, 15);
 glVertex3f( 15,2, 15);
 glVertex3f( 15,2,-35);
 glEnd();
 
 glColor4f(0.9f,0.9f,0.9f,1);
 
 // Instead of calling glTranslatef, we need a custom function that also maintain the light matrix
 startTranslate(0,4,-16);
 glutSolidCube(4);
 endTranslate();
 
 startTranslate(0,4,-5);
 glutSolidCube(4);
 endTranslate();
 
 
}

void renderScene(void)
{
 update();
 

 // render to depth to texture(depthTextureId)
 //First step: Render from the light POV to a FBO, story depth values only
 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fboId); //Rendering offscreen
 
 //Using the fixed pipeline to render to the depthbuffer
 glUseProgramObjectARB(0);
 
 // In the case we render the shadowmap to a higher resolution, the viewport must be modified accordingly.
 glViewport(0,0,RENDER_WIDTH * SHADOW_MAP_RATIO,RENDER_HEIGHT* SHADOW_MAP_RATIO);
 
 // Clear previous frame values
 glClear( GL_DEPTH_BUFFER_BIT);
 
 //Disable color rendering, we only want to write to the Z-Buffer, only render depth
 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 

 // 建立以光源位置和方向向量为向量基确定的light_modelviewmatrix 和

 // light_projectmatrix  in setupMatrices
 setupMatrices(p_light[0],p_light[1],p_light[2],l_light[0],l_light[1],l_light[2]);
 
 // Culling switching, rendering only backface, this is done to avoid self-shadowing
 glCullFace(GL_FRONT);
 drawObjects();
 
 //Save modelview/projection matrice into texture7, also add a biais
 setTextureMatrix();     // save T = biasM * light_ProjM * light_ModelViewM into texture7
 
 
 // Now rendering from the camera POV, using the FBO to generate shadows
 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
 
 glViewport(0,0,RENDER_WIDTH,RENDER_HEIGHT);
 
 //Enabling color write (previously disabled for light POV z-buffer rendering)

 // enable color render
 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 
 // Clear previous frame values
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 //Using the shadow shader
 glUseProgramObjectARB(shadowShaderId);

 //  Specify the value of a uniform variable for the current program object
 glUniform1iARB(shadowMapUniform, 7);

 glActiveTextureARB(GL_TEXTURE7);

  // bind texture object (depthTextureId) into texture unit 7, sampler will sample from

   // texture7 by above glUniform1iARB(shadowMapUniform, 7);
 glBindTexture(GL_TEXTURE_2D,  depthTextureId);
 
 
 
  

 // 建立相机的modelview_matrix 和 project_matrix
 setupMatrices(p_camera[0],p_camera[1],p_camera[2],l_camera[0],l_camera[1],l_camera[2]);
 
 glCullFace(GL_BACK);
 drawObjects();
 
 // DEBUG only. this piece of code draw the depth buffer onscreen
 /*
  glUseProgramObjectARB(0);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-RENDER_WIDTH/2,RENDER_WIDTH/2,-RENDER_HEIGHT/2,RENDER_HEIGHT/2,1,20);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glColor4f(1,1,1,1);
  glActiveTextureARB(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D,depthTextureId);
  glEnable(GL_TEXTURE_2D);
  glTranslated(0,0,-1);
  glBegin(GL_QUADS);
  glTexCoord2d(0,0);glVertex3f(0,0,0);
  glTexCoord2d(1,0);glVertex3f(RENDER_WIDTH/2,0,0);
  glTexCoord2d(1,1);glVertex3f(RENDER_WIDTH/2,RENDER_HEIGHT/2,0);
  glTexCoord2d(0,1);glVertex3f(0,RENDER_HEIGHT/2,0);
 
 
  glEnd();
  glDisable(GL_TEXTURE_2D);
  */
 
 glutSwapBuffers();
}

void processNormalKeys(unsigned char key, int x, int y) {
 
 if (key == 27)
  exit(0);
}


int main(int argc, char** argv)
{
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
 glutInitWindowPosition(100,100);
 glutInitWindowSize(RENDER_WIDTH,RENDER_HEIGHT);
 glutCreateWindow("GLSL Shadow mapping");
 
 // This call will grab openGL extension function pointers.
 // This is not necessary for macosx and linux
#ifdef _WIN32
 getOpenGLFunctionPointers();
#endif
 generateShadowFBO();
 loadShadowShader();
 
 // This is important, if not here, FBO's depthbuffer won't be populated.
 glEnable(GL_DEPTH_TEST);
 glClearColor(0,0,0,1.0f);
 
 glEnable(GL_CULL_FACE);
 
 glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
 
 
 
 
 glutDisplayFunc(renderScene);
 glutIdleFunc(renderScene);
 
 glutKeyboardFunc(processNormalKeys);
 
 glutMainLoop();
}

 

 

// VertexShader.c

// Used for shadow lookup
varying vec4 ShadowCoord;

 

void main()
{

      // the texture Matrix ( bias * light_project_matrix * light_modelview_matrix ) was saved into texture7 

      // here we got it.

      // calc its coord in light of light_space
      ShadowCoord= gl_TextureMatrix[7] * gl_Vertex;
 
  gl_Position = ftransform();

  gl_FrontColor = gl_Color;
}

 

 

 

// FragmentShader.c

uniform sampler2D ShadowMap;  // texture7 sampler by set above glUniform1iARB(shadowMapUniform, 7);

varying vec4 ShadowCoord;

void main()

 // do perspective division against vertex coord based light_space.
 vec4 shadowCoordinateWdivide = ShadowCoord / ShadowCoord.w ;
 
 // Used to lower moiré pattern and self-shadowing
 shadowCoordinateWdivide.z += 0.0005;
 
 // get depth rendered from sampler
 float distanceFromLight = texture2D(ShadowMap,shadowCoordinateWdivide.st).z;
 
 
  float shadow = 1.0;
  if (ShadowCoord.w > 0.0)    // determine color factor in light of depth value comparision.
   shadow = distanceFromLight < shadowCoordinateWdivide.z ? 0.5 : 1.0 ;
   
 
   gl_FragColor =  shadow * gl_Color;
 
}

 

 

原创粉丝点击