3D C/C++ tutorials -> OpenGL 2.1 -> GLSL shadow cube mapping
Use for personal or educational purposes only. Commercial and other profit uses strictly prohibited. Exploitation of content on a website or in a publication prohibited.
opengl_tutorials_win32_framework.h
...
#define SHADOW_CUBE_MAP_SIZE 512
class COpenGLRenderer
{
protected:
int Width, Height;
mat4x4 Model, View, Projection, ProjectionBiasInverse;
int ObjectsCount, LightObjectID;
CObject *Objects;
CShaderProgram ShadowCubeMapping;
GLuint ShadowCubeMap, FBO;
mat4x4 LightView[6], LightProjection, LightTexture[6];
int SelectedObject;
float PlaneD;
vec3 SelectedPoint, PlaneNormal;
public:
COpenGLRenderer();
~COpenGLRenderer();
bool Init();
void Render(float FrameTime);
void Resize(int Width, int Height);
void Destroy();
void MoveSelectedObject(int x, int y);
void SelectObject(int x, int y);
protected:
void RenderShadowCubeMap();
};
...
opengl_tutorials_win32_framework.cpp
...
COpenGLRenderer::COpenGLRenderer()
{
SelectedObject = -1;
Camera.SetViewMatrixPointer(&View);
}
COpenGLRenderer::~COpenGLRenderer()
{
}
bool COpenGLRenderer::Init()
{
if(gl_version < 21)
{
ErrorLog.Set("OpenGL 2.1 not supported!");
return false;
}
bool Error = false;
if(!GLEW_ARB_depth_texture)
{
ErrorLog.Append("GL_ARB_depth_texture not supported!\r\n");
Error = true;
}
if(!GLEW_EXT_texture_array)
{
ErrorLog.Append("GL_EXT_texture_array not supported!\r\n");
Error = true;
}
if(!GLEW_ARB_framebuffer_object)
{
ErrorLog.Append("GL_ARB_framebuffer_object not supported!\r\n");
Error = true;
}
ObjectsCount = 7;
Objects = new CObject[ObjectsCount];
Error |= !Objects[0].Load("Models\\", "room.obj");
Error |= !Objects[1].Load("Models\\Thor\\", "thor.obj");
Error |= !Objects[2].Load("Models\\Spongebob\\", "spongebob_bind.obj");
Error |= !Objects[3].Load("Models\\Alien2\\", "alien2.obj");
Error |= !Objects[4].Load("Models\\Teapot\\", "teapot.obj");
Error |= !Objects[5].Texture.LoadTexture2D("earthmap.jpg");
Error |= !ShadowCubeMapping.Load("shadow_cube_mapping.vs", "shadow_cube_mapping.fs");
if(Error)
{
return false;
}
Objects[0].Movable = false;
Objects[1].Rotate(-90.0f, vec3(0.0f, 1.0f, 0.0f));
Objects[1].Scale(1.75f / (Objects[1].Max.y - Objects[1].Min.y));
Objects[1].Translate(vec3(-(Objects[1].Min.x + Objects[1].Max.x) / 2.0f, -Objects[1].Min.y, -(Objects[1].Min.z + Objects[1].Max.z) / 2.0f));
Objects[1].Position = vec3(1.0f, 0.0f, -1.0f);
Objects[2].Scale(0.875f / (Objects[2].Max.y - Objects[2].Min.y));
Objects[2].Translate(vec3(-(Objects[2].Min.x + Objects[2].Max.x) / 2.0f, -Objects[2].Min.y, -(Objects[2].Min.z + Objects[2].Max.z) / 2.0f));
Objects[2].Position = vec3(-1.0f, 0.0f, -1.0f);
Objects[3].Scale(1.0f / (Objects[3].Max.y - Objects[3].Min.y));
Objects[3].Translate(vec3(-(Objects[3].Min.x + Objects[3].Max.x) / 2.0f, -Objects[3].Min.y, -(Objects[3].Min.z + Objects[3].Max.z) / 2.0f));
Objects[3].Position = vec3(0.0f, 0.0f, -2.5f);
Objects[4].Color = vec3(1.0f, 0.5f, 0.0f);
Objects[4].CullFace = false;
Objects[4].FrontFace = GL_CW;
Objects[4].Scale(0.25f / (Objects[4].Max.y - Objects[4].Min.y));
Objects[4].Translate(vec3(-(Objects[4].Min.x + Objects[4].Max.x) / 2.0f, -Objects[4].Min.y, -(Objects[4].Min.z + Objects[4].Max.z) / 2.0f));
Objects[4].Position = vec3(0.0f, 0.0f, 0.5f);
Objects[5].CreateSphere(0.5f, 32);
Objects[5].Position = vec3(1.0f, 0.5f, 1.0f);
Objects[6].CreateSphere(0.03125f, 16, true);
Objects[6].Position = vec3(0.0f, 1.0f, 0.0f);
LightObjectID = 6;
for(int i = 0; i < ObjectsCount; i++)
{
Objects[i].InitVertexBuffers();
}
ShadowCubeMapping.UniformLocations = new GLuint[3];
ShadowCubeMapping.UniformLocations[0] = glGetUniformLocation(ShadowCubeMapping, "Model");
ShadowCubeMapping.UniformLocations[1] = glGetUniformLocation(ShadowCubeMapping, "Texturing");
ShadowCubeMapping.UniformLocations[2] = glGetUniformLocation(ShadowCubeMapping, "LightTexture");
glUseProgram(ShadowCubeMapping);
glUniform1i(glGetUniformLocation(ShadowCubeMapping, "Texture"), 0);
glUniform1i(glGetUniformLocation(ShadowCubeMapping, "ShadowCubeMap"), 1);
glUseProgram(0);
glGenTextures(1, &ShadowCubeMap);
glBindTexture(GL_TEXTURE_2D_ARRAY, ShadowCubeMap);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32, SHADOW_CUBE_MAP_SIZE, SHADOW_CUBE_MAP_SIZE, 6, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glDrawBuffers(0, NULL);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
LightProjection = PerspectiveProjectionMatrix(90.0f, SHADOW_CUBE_MAP_SIZE, SHADOW_CUBE_MAP_SIZE, 0.125f, 512.0f);
vec3 LightColor = vec3(1.0f, 1.0f, 1.0f);
glLightfv(GL_LIGHT0, GL_AMBIENT, &vec4(LightColor * 0.25f, 1.0f));
glLightfv(GL_LIGHT0, GL_DIFFUSE, &vec4(LightColor * 0.75f, 1.0f));
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0f / 128.0f);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 1.0f / 256.0f);
Camera.LookAt(vec3(0.0f, 0.875f, 0.0f), vec3(0.0f, 0.875f, 2.5f), true);
RenderShadowCubeMap();
return true;
}
void COpenGLRenderer::Render(float FrameTime)
{
glViewport(0, 0, Width, Height);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(&Projection);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLightfv(GL_LIGHT0, GL_POSITION, &vec4(Objects[LightObjectID].Position, 1.0f));
glLoadMatrixf(&View);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D_ARRAY, ShadowCubeMap);
glActiveTexture(GL_TEXTURE0);
glUseProgram(ShadowCubeMapping);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
for(int i = 0; i < ObjectsCount; i++)
{
if(Objects[i].TrianglesCount <= 0) continue;
Model = TranslationMatrix(Objects[i].Position.x, Objects[i].Position.y, Objects[i].Position.z);
glUniformMatrix4fv(ShadowCubeMapping.UniformLocations[0], 1, GL_FALSE, &Model);
if(Objects[i].CullFace)
{
glEnable(GL_CULL_FACE);
}
glColor3fv(&Objects[i].Color);
if(Objects[i].Texture)
{
glBindTexture(GL_TEXTURE_2D, Objects[i].Texture);
}
glUniform1i(ShadowCubeMapping.UniformLocations[1], Objects[i].Texture ? 1 : 0);
glBindBuffer(GL_ARRAY_BUFFER, Objects[i].VBO[0]);
glTexCoordPointer(2, GL_FLOAT, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, Objects[i].VBO[1]);
glNormalPointer(GL_FLOAT, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, Objects[i].VBO[2]);
glVertexPointer(3, GL_FLOAT, 0, NULL);
glFrontFace(Objects[i].FrontFace);
glDrawArrays(GL_TRIANGLES, 0, Objects[i].TrianglesCount * 3);
if(Objects[i].Texture)
{
glBindTexture(GL_TEXTURE_2D, 0);
}
if(Objects[i].CullFace)
{
glDisable(GL_CULL_FACE);
}
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glUseProgram(0);
glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glActiveTexture(GL_TEXTURE0);
glDisable(GL_DEPTH_TEST);
}
void COpenGLRenderer::Resize(int Width, int Height)
{
this->Width = Width;
this->Height = Height;
Projection = PerspectiveProjectionMatrix(45.0f, (float)Width, (float)Height, 0.125f, 512.0f);
ProjectionBiasInverse = PerspectiveProjectionMatrixInverse(Projection) * BiasMatrixInverse();
}
void COpenGLRenderer::Destroy()
{
for(int i = 0; i < ObjectsCount; i++)
{
Objects[i].Destroy();
}
delete [] Objects;
if(gl_version >= 21)
{
ShadowCubeMapping.Delete();
}
glDeleteTextures(1, &ShadowCubeMap);
if(GLEW_ARB_framebuffer_object)
{
glDeleteFramebuffers(1, &FBO);
}
}
...
void COpenGLRenderer::MoveSelectedObject(int x, int y)
{
...
if(NdotR != 0.0f)
{
...
RenderShadowCubeMap();
}
}
...
void COpenGLRenderer::RenderShadowCubeMap()
{
// calculate light matrices -----------------------------------------------------------------------------------------------
LightView[0] = ViewMatrix(vec3( 0.0f, 0.0f, 1.0f), vec3(0.0f, 1.0f, 0.0f), vec3(-1.0f, 0.0f, 0.0f), Objects[LightObjectID].Position);
LightView[1] = ViewMatrix(vec3( 0.0f, 0.0f,-1.0f), vec3(0.0f, 1.0f, 0.0f), vec3( 1.0f, 0.0f, 0.0f), Objects[LightObjectID].Position);
LightView[2] = ViewMatrix(vec3( 1.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f), vec3( 0.0f,-1.0f, 0.0f), Objects[LightObjectID].Position);
LightView[3] = ViewMatrix(vec3( 1.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f,-1.0f), vec3( 0.0f, 1.0f, 0.0f), Objects[LightObjectID].Position);
LightView[4] = ViewMatrix(vec3(-1.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec3( 0.0f, 0.0f,-1.0f), Objects[LightObjectID].Position);
LightView[5] = ViewMatrix(vec3( 1.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec3( 0.0f, 0.0f, 1.0f), Objects[LightObjectID].Position);
LightTexture[0] = BiasMatrix() * LightProjection * LightView[0];
LightTexture[1] = BiasMatrix() * LightProjection * LightView[1];
LightTexture[2] = BiasMatrix() * LightProjection * LightView[2];
LightTexture[3] = BiasMatrix() * LightProjection * LightView[3];
LightTexture[4] = BiasMatrix() * LightProjection * LightView[4];
LightTexture[5] = BiasMatrix() * LightProjection * LightView[5];
glUseProgram(ShadowCubeMapping);
glUniformMatrix4fv(ShadowCubeMapping.UniformLocations[2], 6, GL_FALSE, (GLfloat*)LightTexture);
glUseProgram(0);
// render shadow cube map -------------------------------------------------------------------------------------------------
glViewport(0, 0, SHADOW_CUBE_MAP_SIZE, SHADOW_CUBE_MAP_SIZE);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(&LightProjection);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glEnableClientState(GL_VERTEX_ARRAY);
for(int i = 0; i < 6; i++)
{
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, ShadowCubeMap, 0, i);
glClear(GL_DEPTH_BUFFER_BIT);
for(int ii = 0; ii < ObjectsCount; ii++)
{
if(Objects[ii].TrianglesCount <= 0) continue;
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(&LightView[i]);
glTranslatef(Objects[ii].Position.x, Objects[ii].Position.y, Objects[ii].Position.z);
glBindBuffer(GL_ARRAY_BUFFER, Objects[ii].VBO[2]);
glVertexPointer(3, GL_FLOAT, 0, NULL);
glFrontFace(Objects[ii].FrontFace);
glDrawArrays(GL_TRIANGLES, 0, Objects[ii].TrianglesCount * 3);
}
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glCullFace(GL_BACK);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
}
...
shadow_cube_mapping.vs
#version 120
uniform mat4x4 Model;
varying vec3 Position, Normal;
void main()
{
Position = (Model * gl_Vertex).xyz;
Normal = gl_Normal;
gl_FrontColor = gl_Color;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * vec4(Position, 1.0);
}
shadow_cube_mapping.fs
#version 120
#extension GL_EXT_texture_array : enable
uniform sampler2D Texture;
uniform sampler2DArrayShadow ShadowCubeMap;
uniform int Texturing;
uniform mat4x4 LightTexture[6];
varying vec3 Position, Normal;
void main()
{
vec3 LightDirection = gl_LightSource[0].position.xyz - Position;
float LightDistance2 = dot(LightDirection, LightDirection);
float LightDistance = sqrt(LightDistance2);
LightDirection /= LightDistance;
float Attenuation = gl_LightSource[0].constantAttenuation;
Attenuation += gl_LightSource[0].linearAttenuation * LightDistance;
Attenuation += gl_LightSource[0].quadraticAttenuation * LightDistance2;
float Axis[6];
Axis[0] = -LightDirection.x;
Axis[1] = LightDirection.x;
Axis[2] = -LightDirection.y;
Axis[3] = LightDirection.y;
Axis[4] = -LightDirection.z;
Axis[5] = LightDirection.z;
int MaxAxisID = 0;
for(int i = 1; i < 6; i++)
{
if(Axis[i] > Axis[MaxAxisID])
{
MaxAxisID = i;
}
}
vec4 ShadowTexCoord = LightTexture[MaxAxisID] * vec4(Position, 1.0);
ShadowTexCoord.xyz /= ShadowTexCoord.w;
ShadowTexCoord.w = ShadowTexCoord.z;
ShadowTexCoord.z = float(MaxAxisID);
float Shadow = shadow2DArray(ShadowCubeMap, ShadowTexCoord).r;
float NdotLD = max(dot(normalize(Normal), LightDirection), 0.0) * Shadow;
vec3 Light = (gl_LightSource[0].ambient.rgb + gl_LightSource[0].diffuse.rgb * NdotLD) / Attenuation;
gl_FragColor.rgb = gl_Color.rgb;
if(Texturing == 1) gl_FragColor.rgb *= texture2D(Texture, gl_TexCoord[0].st).rgb;
gl_FragColor.rgb *= Light;
}
Download
|