Code re-work: shadow mapping.

This commit is contained in:
Joey de Vries
2017-04-23 12:52:47 +02:00
parent c8431d9498
commit 919084ba39
19 changed files with 561 additions and 677 deletions

View File

@@ -106,59 +106,59 @@ public:
} }
// utility uniform functions // utility uniform functions
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setBool(std::string name, bool value) const void setBool(const std::string &name, bool value) const
{ {
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setInt(std::string name, int value) const void setInt(const std::string &name, int value) const
{ {
glUniform1i(glGetUniformLocation(ID, name.c_str()), value); glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setFloat(std::string name, float value) const void setFloat(const std::string &name, float value) const
{ {
glUniform1f(glGetUniformLocation(ID, name.c_str()), value); glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setVec2(std::string name, const glm::vec2 &value) const void setVec2(const std::string &name, const glm::vec2 &value) const
{ {
glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
} }
void setVec2(std::string name, float x, float y) const void setVec2(const std::string &name, float x, float y) const
{ {
glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setVec3(std::string name, const glm::vec3 &value) const void setVec3(const std::string &name, const glm::vec3 &value) const
{ {
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
} }
void setVec3(std::string name, float x, float y, float z) const void setVec3(const std::string &name, float x, float y, float z) const
{ {
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setVec4(std::string name, const glm::vec4 &value) const void setVec4(const std::string &name, const glm::vec4 &value) const
{ {
glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
} }
void setVec4(std::string name, float x, float y, float z, float w) void setVec4(const std::string &name, float x, float y, float z, float w)
{ {
glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setMat2(std::string name, const glm::mat2 &mat) const void setMat2(const std::string &name, const glm::mat2 &mat) const
{ {
glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setMat3(std::string name, const glm::mat3 &mat) const void setMat3(const std::string &name, const glm::mat3 &mat) const
{ {
glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setMat4(std::string name, const glm::mat4 &mat) const void setMat4(const std::string &name, const glm::mat4 &mat) const
{ {
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
} }

View File

@@ -80,59 +80,59 @@ public:
} }
// utility uniform functions // utility uniform functions
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setBool(std::string name, bool value) const void setBool(const std::string &name, bool value) const
{ {
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setInt(std::string name, int value) const void setInt(const std::string &name, int value) const
{ {
glUniform1i(glGetUniformLocation(ID, name.c_str()), value); glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setFloat(std::string name, float value) const void setFloat(const std::string &name, float value) const
{ {
glUniform1f(glGetUniformLocation(ID, name.c_str()), value); glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setVec2(std::string name, const glm::vec2 &value) const void setVec2(const std::string &name, const glm::vec2 &value) const
{ {
glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
} }
void setVec2(std::string name, float x, float y) const void setVec2(const std::string &name, float x, float y) const
{ {
glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setVec3(std::string name, const glm::vec3 &value) const void setVec3(const std::string &name, const glm::vec3 &value) const
{ {
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
} }
void setVec3(std::string name, float x, float y, float z) const void setVec3(const std::string &name, float x, float y, float z) const
{ {
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setVec4(std::string name, const glm::vec4 &value) const void setVec4(const std::string &name, const glm::vec4 &value) const
{ {
glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
} }
void setVec4(std::string name, float x, float y, float z, float w) const void setVec4(const std::string &name, float x, float y, float z, float w) const
{ {
glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setMat2(std::string name, const glm::mat2 &mat) const void setMat2(const std::string &name, const glm::mat2 &mat) const
{ {
glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setMat3(std::string name, const glm::mat3 &mat) const void setMat3(const std::string &name, const glm::mat3 &mat) const
{ {
glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setMat4(std::string name, const glm::mat4 &mat) const void setMat4(const std::string &name, const glm::mat4 &mat) const
{ {
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
} }

View File

@@ -78,17 +78,17 @@ public:
} }
// utility uniform functions // utility uniform functions
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setBool(std::string name, bool value) const void setBool(const std::string &name, bool value) const
{ {
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setInt(std::string name, int value) const void setInt(const std::string &name, int value) const
{ {
glUniform1i(glGetUniformLocation(ID, name.c_str()), value); glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setFloat(std::string name, float value) const void setFloat(const std::string &name, float value) const
{ {
glUniform1f(glGetUniformLocation(ID, name.c_str()), value); glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
} }

View File

@@ -0,0 +1,61 @@
#version 330 core
out vec4 FragColor;
in VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} fs_in;
uniform sampler2D diffuseTexture;
uniform samplerCube depthMap;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform float far_plane;
uniform bool shadows;
float ShadowCalculation(vec3 fragPos)
{
// get vector between fragment position and light position
vec3 fragToLight = fragPos - lightPos;
// ise the fragment to light vector to sample from the depth map
float closestDepth = texture(depthMap, fragToLight).r;
// it is currently in linear range between [0,1], let's re-transform it back to original depth value
closestDepth *= far_plane;
// now get current linear depth as the length between the fragment and light position
float currentDepth = length(fragToLight);
// test for shadows
float bias = 0.05; // we use a much larger bias since depth is now in [near_plane, far_plane] range
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
// display closestDepth as debug (to visualize depth cubemap)
// FragColor = vec4(vec3(closestDepth / far_plane), 1.0);
return shadow;
}
void main()
{
vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb;
vec3 normal = normalize(fs_in.Normal);
vec3 lightColor = vec3(0.3);
// Ambient
vec3 ambient = 0.3 * color;
// Diffuse
vec3 lightDir = normalize(lightPos - fs_in.FragPos);
float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = diff * lightColor;
// Specular
vec3 viewDir = normalize(viewPos - fs_in.FragPos);
vec3 reflectDir = reflect(-lightDir, normal);
float spec = 0.0;
vec3 halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
vec3 specular = spec * lightColor;
// Calculate shadow
float shadow = shadows ? ShadowCalculation(fs_in.FragPos) : 0.0;
vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;
FragColor = vec4(lighting, 1.0f);
}

View File

@@ -0,0 +1,29 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out vec2 TexCoords;
out VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} vs_out;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform bool reverse_normals;
void main()
{
vs_out.FragPos = vec3(model * vec4(aPos, 1.0));
if(reverse_normals) // a slight hack to make sure the outer large cube displays lighting from the 'inside' instead of the default 'outside'.
vs_out.Normal = transpose(inverse(mat3(model))) * (-1.0 * aNormal);
else
vs_out.Normal = transpose(inverse(mat3(model))) * aNormal;
vs_out.TexCoords = aTexCoords;
gl_Position = projection * view * model * vec4(aPos, 1.0);
}

View File

@@ -11,6 +11,6 @@ void main()
// map to [0;1] range by dividing by far_plane // map to [0;1] range by dividing by far_plane
lightDistance = lightDistance / far_plane; lightDistance = lightDistance / far_plane;
// Write this as modified depth // write this as modified depth
gl_FragDepth = lightDistance; gl_FragDepth = lightDistance;
} }

View File

@@ -2,7 +2,7 @@
layout (triangles) in; layout (triangles) in;
layout (triangle_strip, max_vertices=18) out; layout (triangle_strip, max_vertices=18) out;
uniform mat4 shadowTransforms[6]; uniform mat4 shadowMatrices[6];
out vec4 FragPos; // FragPos from GS (output per emitvertex) out vec4 FragPos; // FragPos from GS (output per emitvertex)
@@ -14,7 +14,7 @@ void main()
for(int i = 0; i < 3; ++i) // for each triangle's vertices for(int i = 0; i < 3; ++i) // for each triangle's vertices
{ {
FragPos = gl_in[i].gl_Position; FragPos = gl_in[i].gl_Position;
gl_Position = shadowTransforms[face] * FragPos; gl_Position = shadowMatrices[face] * FragPos;
EmitVertex(); EmitVertex();
} }
EndPrimitive(); EndPrimitive();

View File

@@ -0,0 +1,9 @@
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
void main()
{
gl_Position = model * vec4(aPos, 1.0);
}

View File

@@ -20,11 +20,12 @@ void processInput(GLFWwindow *window);
unsigned int loadTexture(const char *path); unsigned int loadTexture(const char *path);
void renderScene(const Shader &shader); void renderScene(const Shader &shader);
void renderCube(); void renderCube();
void renderQuad();
// settings // settings
const unsigned int SCR_WIDTH = 1280; const unsigned int SCR_WIDTH = 1280;
const unsigned int SCR_HEIGHT = 720; const unsigned int SCR_HEIGHT = 720;
bool shadows = true;
bool shadowsKeyPressed = false;
// camera // camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
@@ -36,9 +37,6 @@ bool firstMouse = true;
float deltaTime = 0.0f; float deltaTime = 0.0f;
float lastFrame = 0.0f; float lastFrame = 0.0f;
// meshes
unsigned int planeVAO;
int main() int main()
{ {
// glfw: initialize and configure // glfw: initialize and configure
@@ -76,38 +74,12 @@ int main()
// configure global opengl state // configure global opengl state
// ----------------------------- // -----------------------------
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
// build and compile shaders // build and compile shaders
// ------------------------- // -------------------------
Shader shader("3.2.1.point_shadows.vs", "3.2.1.point_shadows.fs"); Shader shader("3.2.1.point_shadows.vs", "3.2.1.point_shadows.fs");
Shader simpleDepthShader("3.2.1.point_shadows_depth.vs", "3.2.1.point_shadows_depth.fs"); Shader simpleDepthShader("3.2.1.point_shadows_depth.vs", "3.2.1.point_shadows_depth.fs", "3.2.1.point_shadows_depth.gs");
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float planeVertices[] = {
// positions // normals // texcoords
25.0f, -0.5f, 25.0f, 0.0f, 1.0f, 0.0f, 25.0f, 0.0f,
-25.0f, -0.5f, 25.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-25.0f, -0.5f, -25.0f, 0.0f, 1.0f, 0.0f, 0.0f, 25.0f,
25.0f, -0.5f, 25.0f, 0.0f, 1.0f, 0.0f, 25.0f, 0.0f,
-25.0f, -0.5f, -25.0f, 0.0f, 1.0f, 0.0f, 0.0f, 25.0f,
25.0f, -0.5f, -25.0f, 0.0f, 1.0f, 0.0f, 25.0f, 25.0f
};
// plane VAO
unsigned int planeVBO;
glGenVertexArrays(1, &planeVAO);
glGenBuffers(1, &planeVBO);
glBindVertexArray(planeVAO);
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glBindVertexArray(0);
// load textures // load textures
// ------------- // -------------
@@ -118,20 +90,20 @@ int main()
const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024; const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
unsigned int depthMapFBO; unsigned int depthMapFBO;
glGenFramebuffers(1, &depthMapFBO); glGenFramebuffers(1, &depthMapFBO);
// create depth texture // create depth cubemap texture
unsigned int depthMap; unsigned int depthCubemap;
glGenTextures(1, &depthMap); glGenTextures(1, &depthCubemap);
glBindTexture(GL_TEXTURE_2D, depthMap); glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); for (unsigned int i = 0; i < 6; ++i)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
GLfloat borderColor[] = { 1.0, 1.0, 1.0, 1.0 }; glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
// attach depth texture as FBO's depth buffer // attach depth texture as FBO's depth buffer
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0);
glDrawBuffer(GL_NONE); glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE); glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -141,13 +113,11 @@ int main()
// -------------------- // --------------------
shader.use(); shader.use();
shader.setInt("diffuseTexture", 0); shader.setInt("diffuseTexture", 0);
shader.setInt("shadowMap", 1); shader.setInt("depthMap", 1);
debugDepthQuad.use();
debugDepthQuad.setInt("depthMap", 0);
// lighting info // lighting info
// ------------- // -------------
glm::vec3 lightPos(-2.0f, 4.0f, -1.0f); glm::vec3 lightPos(0.0f, 0.0f, 0.0f);
// render loop // render loop
// ----------- // -----------
@@ -163,43 +133,42 @@ int main()
// ----- // -----
processInput(window); processInput(window);
// change light position over time // move light position over time
//lightPos.x = sin(glfwGetTime()) * 3.0f; lightPos.z = sin(glfwGetTime() * 0.5) * 3.0;
//lightPos.z = cos(glfwGetTime()) * 2.0f;
//lightPos.y = 5.0 + cos(glfwGetTime()) * 1.0f;
// render // render
// ------ // ------
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 1. render depth of scene to texture (from light's perspective) // 0. create depth cubemap transformation matrices
// -------------------------------------------------------------- // -----------------------------------------------
glm::mat4 lightProjection, lightView; float near_plane = 1.0f;
glm::mat4 lightSpaceMatrix; float far_plane = 25.0f;
float near_plane = 1.0f, far_plane = 7.5f; glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), (float)SHADOW_WIDTH / (float)SHADOW_HEIGHT, near_plane, far_plane);
//lightProjection = glm::perspective(glm::radians(45.0f), (GLfloat)SHADOW_WIDTH / (GLfloat)SHADOW_HEIGHT, near_plane, far_plane); // note that if you use a perspective projection matrix you'll have to change the light position as the current light position isn't enough to reflect the whole scene std::vector<glm::mat4> shadowTransforms;
lightProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3( 1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0, 1.0, 0.0)); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
lightSpaceMatrix = lightProjection * lightView; shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3( 0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)));
// render scene from light's point of view shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3( 0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)));
simpleDepthShader.use(); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3( 0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
simpleDepthShader.setMat4("lightSpaceMatrix", lightSpaceMatrix); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3( 0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
// 1. render scene to depth cubemap
// --------------------------------
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0); simpleDepthShader.use();
glBindTexture(GL_TEXTURE_2D, woodTexture); for (unsigned int i = 0; i < 6; ++i)
renderScene(simpleDepthShader); simpleDepthShader.setMat4("shadowMatrices[" + std::to_string(i) + "]", shadowTransforms[i]);
simpleDepthShader.setFloat("far_plane", far_plane);
simpleDepthShader.setVec3("lightPos", lightPos);
renderScene(simpleDepthShader);
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
// reset viewport // 2. render scene as normal
glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); // -------------------------
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 2. render scene as normal using the generated depth/shadow map
// --------------------------------------------------------------
glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.use(); shader.use();
@@ -207,36 +176,23 @@ int main()
glm::mat4 view = camera.GetViewMatrix(); glm::mat4 view = camera.GetViewMatrix();
shader.setMat4("projection", projection); shader.setMat4("projection", projection);
shader.setMat4("view", view); shader.setMat4("view", view);
// set light uniforms // set lighting uniforms
shader.setVec3("viewPos", camera.Position);
shader.setVec3("lightPos", lightPos); shader.setVec3("lightPos", lightPos);
shader.setMat4("lightSpaceMatrix", lightSpaceMatrix); shader.setVec3("viewPos", camera.Position);
shader.setInt("shadows", shadows); // enable/disable shadows by pressing 'SPACE'
shader.setFloat("far_plane", far_plane);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, woodTexture); glBindTexture(GL_TEXTURE_2D, woodTexture);
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depthMap); glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap);
renderScene(shader); renderScene(shader);
// render Depth map to quad for visual debugging
// ---------------------------------------------
debugDepthQuad.use();
debugDepthQuad.setFloat("near_plane", near_plane);
debugDepthQuad.setFloat("far_plane", far_plane);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthMap);
//renderQuad();
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents(); glfwPollEvents();
} }
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &planeVAO);
glDeleteBuffers(1, &planeVBO);
glfwTerminate(); glfwTerminate();
return 0; return 0;
} }
@@ -245,31 +201,44 @@ int main()
// -------------------- // --------------------
void renderScene(const Shader &shader) void renderScene(const Shader &shader)
{ {
// floor // room cube
glm::mat4 model; glm::mat4 model;
model = glm::scale(model, glm::vec3(5.0f));
shader.setMat4("model", model); shader.setMat4("model", model);
glBindVertexArray(planeVAO); glDisable(GL_CULL_FACE); // note that we disable culling here since we render 'inside' the cube instead of the usual 'outside' which throws off the normal culling methods.
glDrawArrays(GL_TRIANGLES, 0, 6); shader.setInt("reverse_normals", 1); // A small little hack to invert normals when drawing cube from the inside so lighting still works.
renderCube();
shader.setInt("reverse_normals", 0); // and of course disable it
glEnable(GL_CULL_FACE);
// cubes // cubes
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(0.0f, 1.5f, 0.0)); model = glm::translate(model, glm::vec3(4.0f, -3.5f, 0.0));
model = glm::scale(model, glm::vec3(0.5f)); model = glm::scale(model, glm::vec3(0.5f));
shader.setMat4("model", model); shader.setMat4("model", model);
renderCube(); renderCube();
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 1.0)); model = glm::translate(model, glm::vec3(2.0f, 3.0f, 1.0));
model = glm::scale(model, glm::vec3(0.75f));
shader.setMat4("model", model);
renderCube();
model = glm::mat4();
model = glm::translate(model, glm::vec3(-3.0f, -1.0f, 0.0));
model = glm::scale(model, glm::vec3(0.5f)); model = glm::scale(model, glm::vec3(0.5f));
shader.setMat4("model", model); shader.setMat4("model", model);
renderCube(); renderCube();
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, 2.0)); model = glm::translate(model, glm::vec3(-1.5f, 1.0f, 1.5));
model = glm::scale(model, glm::vec3(0.5f));
shader.setMat4("model", model);
renderCube();
model = glm::mat4();
model = glm::translate(model, glm::vec3(-1.5f, 2.0f, -3.0));
model = glm::rotate(model, glm::radians(60.0f), glm::normalize(glm::vec3(1.0, 0.0, 1.0))); model = glm::rotate(model, glm::radians(60.0f), glm::normalize(glm::vec3(1.0, 0.0, 1.0)));
model = glm::scale(model, glm::vec3(0.25)); model = glm::scale(model, glm::vec3(0.75f));
shader.setMat4("model", model); shader.setMat4("model", model);
renderCube(); renderCube();
} }
// renderCube() renders a 1x1 3D cube in NDC. // renderCube() renders a 1x1 3D cube in NDC.
// ------------------------------------------------- // -------------------------------------------------
unsigned int cubeVAO = 0; unsigned int cubeVAO = 0;
@@ -282,46 +251,46 @@ void renderCube()
float vertices[] = { float vertices[] = {
// back face // back face
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, // top-left -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, // top-left
// front face // front face
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
// left face // left face
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
// right face // right face
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left
// bottom face // bottom face
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left
-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
// top face // top face
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left
1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right 1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left
}; };
glGenVertexArrays(1, &cubeVAO); glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &cubeVBO); glGenBuffers(1, &cubeVBO);
@@ -345,37 +314,6 @@ void renderCube()
glBindVertexArray(0); glBindVertexArray(0);
} }
// renderQuad() renders a 1x1 XY quad in NDC
// -----------------------------------------
unsigned int quadVAO = 0;
unsigned int quadVBO;
void renderQuad()
{
if (quadVAO == 0)
{
float quadVertices[] = {
// positions // texture Coords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
};
// setup plane VAO
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
}
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// --------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window) void processInput(GLFWwindow *window)
@@ -392,6 +330,16 @@ void processInput(GLFWwindow *window)
camera.ProcessKeyboard(LEFT, deltaTime); camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime); camera.ProcessKeyboard(RIGHT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS && !shadowsKeyPressed)
{
shadows = !shadows;
shadowsKeyPressed = true;
}
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_RELEASE)
{
shadowsKeyPressed = false;
}
} }
// glfw: whenever the window size changed (by OS or user resize) this callback function executes // glfw: whenever the window size changed (by OS or user resize) this callback function executes

View File

@@ -1,29 +0,0 @@
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoords;
out vec2 TexCoords;
out VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} vs_out;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform bool reverse_normals;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
vs_out.FragPos = vec3(model * vec4(position, 1.0));
if(reverse_normals) // A slight hack to make sure the outer large cube displays lighting from the 'inside' instead of the default 'outside'.
vs_out.Normal = transpose(inverse(mat3(model))) * (-1.0 * normal);
else
vs_out.Normal = transpose(inverse(mat3(model))) * normal;
vs_out.TexCoords = texCoords;
}

View File

@@ -1,16 +0,0 @@
#version 330 core
in vec4 FragPos;
uniform vec3 lightPos;
uniform float far_plane;
void main()
{
float lightDistance = length(FragPos.xyz - lightPos);
// map to [0;1] range by dividing by far_plane
lightDistance = lightDistance / far_plane;
// Write this as modified depth
gl_FragDepth = lightDistance;
}

View File

@@ -1,22 +0,0 @@
#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices=18) out;
uniform mat4 shadowTransforms[6];
out vec4 FragPos; // FragPos from GS (output per emitvertex)
void main()
{
for(int face = 0; face < 6; ++face)
{
gl_Layer = face; // built-in variable that specifies to which face we render.
for(int i = 0; i < 3; ++i) // for each triangle's vertices
{
FragPos = gl_in[i].gl_Position;
gl_Position = shadowTransforms[face] * FragPos;
EmitVertex();
}
EndPrimitive();
}
}

View File

@@ -1,9 +0,0 @@
#version 330 core
layout (location = 0) in vec3 position;
uniform mat4 model;
void main()
{
gl_Position = model * vec4(position, 1.0);
}

View File

@@ -29,16 +29,16 @@ vec3 gridSamplingDisk[20] = vec3[]
float ShadowCalculation(vec3 fragPos) float ShadowCalculation(vec3 fragPos)
{ {
// Get vector between fragment position and light position // get vector between fragment position and light position
vec3 fragToLight = fragPos - lightPos; vec3 fragToLight = fragPos - lightPos;
// Use the fragment to light vector to sample from the depth map // use the fragment to light vector to sample from the depth map
// float closestDepth = texture(depthMap, fragToLight).r; // float closestDepth = texture(depthMap, fragToLight).r;
// It is currently in linear range between [0,1]. Let's re-transform it back to original depth value // it is currently in linear range between [0,1], let's re-transform it back to original depth value
// closestDepth *= far_plane; // closestDepth *= far_plane;
// Now get current linear depth as the length between the fragment and light position // now get current linear depth as the length between the fragment and light position
float currentDepth = length(fragToLight); float currentDepth = length(fragToLight);
// Now test for shadows // test for shadows
// float bias = 0.05; // We use a much larger bias since depth is now in [near_plane, far_plane] range // float bias = 0.05; // we use a much larger bias since depth is now in [near_plane, far_plane] range
// float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; // float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
// PCF // PCF
// float shadow = 0.0; // float shadow = 0.0;
@@ -51,7 +51,7 @@ float ShadowCalculation(vec3 fragPos)
// { // {
// for(float z = -offset; z < offset; z += offset / (samples * 0.5)) // for(float z = -offset; z < offset; z += offset / (samples * 0.5))
// { // {
// float closestDepth = texture(depthMap, fragToLight + vec3(x, y, z)).r; // Use lightdir to lookup cubemap // float closestDepth = texture(depthMap, fragToLight + vec3(x, y, z)).r; // use lightdir to lookup cubemap
// closestDepth *= far_plane; // Undo mapping [0;1] // closestDepth *= far_plane; // Undo mapping [0;1]
// if(currentDepth - bias > closestDepth) // if(currentDepth - bias > closestDepth)
// shadow += 1.0; // shadow += 1.0;
@@ -67,16 +67,15 @@ float ShadowCalculation(vec3 fragPos)
for(int i = 0; i < samples; ++i) for(int i = 0; i < samples; ++i)
{ {
float closestDepth = texture(depthMap, fragToLight + gridSamplingDisk[i] * diskRadius).r; float closestDepth = texture(depthMap, fragToLight + gridSamplingDisk[i] * diskRadius).r;
closestDepth *= far_plane; // Undo mapping [0;1] closestDepth *= far_plane; // undo mapping [0;1]
if(currentDepth - bias > closestDepth) if(currentDepth - bias > closestDepth)
shadow += 1.0; shadow += 1.0;
} }
shadow /= float(samples); shadow /= float(samples);
// Display closestDepth as debug (to visualize depth cubemap) // display closestDepth as debug (to visualize depth cubemap)
// FragColor = vec4(vec3(closestDepth / far_plane), 1.0); // FragColor = vec4(vec3(closestDepth / far_plane), 1.0);
// return shadow;
return shadow; return shadow;
} }
@@ -85,20 +84,20 @@ void main()
vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb; vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb;
vec3 normal = normalize(fs_in.Normal); vec3 normal = normalize(fs_in.Normal);
vec3 lightColor = vec3(0.3); vec3 lightColor = vec3(0.3);
// Ambient // ambient
vec3 ambient = 0.3 * color; vec3 ambient = 0.3 * color;
// Diffuse // diffuse
vec3 lightDir = normalize(lightPos - fs_in.FragPos); vec3 lightDir = normalize(lightPos - fs_in.FragPos);
float diff = max(dot(lightDir, normal), 0.0); float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = diff * lightColor; vec3 diffuse = diff * lightColor;
// Specular // specular
vec3 viewDir = normalize(viewPos - fs_in.FragPos); vec3 viewDir = normalize(viewPos - fs_in.FragPos);
vec3 reflectDir = reflect(-lightDir, normal); vec3 reflectDir = reflect(-lightDir, normal);
float spec = 0.0; float spec = 0.0;
vec3 halfwayDir = normalize(lightDir + viewDir); vec3 halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0); spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
vec3 specular = spec * lightColor; vec3 specular = spec * lightColor;
// Calculate shadow // calculate shadow
float shadow = shadows ? ShadowCalculation(fs_in.FragPos) : 0.0; float shadow = shadows ? ShadowCalculation(fs_in.FragPos) : 0.0;
vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color; vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;

View File

@@ -0,0 +1,29 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out vec2 TexCoords;
out VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} vs_out;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform bool reverse_normals;
void main()
{
vs_out.FragPos = vec3(model * vec4(aPos, 1.0));
if(reverse_normals) // a slight hack to make sure the outer large cube displays lighting from the 'inside' instead of the default 'outside'.
vs_out.Normal = transpose(inverse(mat3(model))) * (-1.0 * aNormal);
else
vs_out.Normal = transpose(inverse(mat3(model))) * aNormal;
vs_out.TexCoords = aTexCoords;
gl_Position = projection * view * model * vec4(aPos, 1.0f);
}

View File

@@ -1,106 +0,0 @@
#version 330 core
out vec4 FragColor;
in VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} fs_in;
uniform sampler2D diffuseTexture;
uniform samplerCube depthMap;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform float far_plane;
uniform bool shadows;
// array of offset direction for sampling
vec3 gridSamplingDisk[20] = vec3[]
(
vec3(1, 1, 1), vec3(1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
vec3(1, 1, -1), vec3(1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
vec3(1, 1, 0), vec3(1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
vec3(1, 0, 1), vec3(-1, 0, 1), vec3(1, 0, -1), vec3(-1, 0, -1),
vec3(0, 1, 1), vec3(0, -1, 1), vec3(0, -1, -1), vec3(0, 1, -1)
);
float ShadowCalculation(vec3 fragPos)
{
// Get vector between fragment position and light position
vec3 fragToLight = fragPos - lightPos;
// Use the fragment to light vector to sample from the depth map
// float closestDepth = texture(depthMap, fragToLight).r;
// It is currently in linear range between [0,1]. Let's re-transform it back to original depth value
// closestDepth *= far_plane;
// Now get current linear depth as the length between the fragment and light position
float currentDepth = length(fragToLight);
// Now test for shadows
// float bias = 0.05; // We use a much larger bias since depth is now in [near_plane, far_plane] range
// float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
// PCF
// float shadow = 0.0;
// float bias = 0.05;
// float samples = 4.0;
// float offset = 0.1;
// for(float x = -offset; x < offset; x += offset / (samples * 0.5))
// {
// for(float y = -offset; y < offset; y += offset / (samples * 0.5))
// {
// for(float z = -offset; z < offset; z += offset / (samples * 0.5))
// {
// float closestDepth = texture(depthMap, fragToLight + vec3(x, y, z)).r; // Use lightdir to lookup cubemap
// closestDepth *= far_plane; // Undo mapping [0;1]
// if(currentDepth - bias > closestDepth)
// shadow += 1.0;
// }
// }
// }
// shadow /= (samples * samples * samples);
float shadow = 0.0;
float bias = 0.15;
int samples = 20;
float viewDistance = length(viewPos - fragPos);
float diskRadius = (1.0 + (viewDistance / far_plane)) / 25.0;
for(int i = 0; i < samples; ++i)
{
float closestDepth = texture(depthMap, fragToLight + gridSamplingDisk[i] * diskRadius).r;
closestDepth *= far_plane; // Undo mapping [0;1]
if(currentDepth - bias > closestDepth)
shadow += 1.0;
}
shadow /= float(samples);
// Display closestDepth as debug (to visualize depth cubemap)
// FragColor = vec4(vec3(closestDepth / far_plane), 1.0);
// return shadow;
return shadow;
}
void main()
{
vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb;
vec3 normal = normalize(fs_in.Normal);
vec3 lightColor = vec3(0.3);
// Ambient
vec3 ambient = 0.3 * color;
// Diffuse
vec3 lightDir = normalize(lightPos - fs_in.FragPos);
float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = diff * lightColor;
// Specular
vec3 viewDir = normalize(viewPos - fs_in.FragPos);
vec3 reflectDir = reflect(-lightDir, normal);
float spec = 0.0;
vec3 halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
vec3 specular = spec * lightColor;
// Calculate shadow
float shadow = shadows ? ShadowCalculation(fs_in.FragPos) : 0.0;
vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;
FragColor = vec4(lighting, 1.0f);
}

View File

@@ -1,29 +0,0 @@
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoords;
out vec2 TexCoords;
out VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} vs_out;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform bool reverse_normals;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
vs_out.FragPos = vec3(model * vec4(position, 1.0));
if(reverse_normals) // A slight hack to make sure the outer large cube displays lighting from the 'inside' instead of the default 'outside'.
vs_out.Normal = transpose(inverse(mat3(model))) * (-1.0 * normal);
else
vs_out.Normal = transpose(inverse(mat3(model))) * normal;
vs_out.TexCoords = texCoords;
}

View File

@@ -1,9 +0,0 @@
#version 330 core
layout (location = 0) in vec3 position;
uniform mat4 model;
void main()
{
gl_Position = model * vec4(position, 1.0);
}

View File

@@ -1,371 +1,359 @@
// GLEW #include <glad/glad.h>
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <stb_image.h>
// GL includes
#include <learnopengl/shader.h>
#include <learnopengl/camera.h>
// GLM Mathemtics
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
// Other Libs
#include <SOIL.h>
#include <learnopengl/filesystem.h> #include <learnopengl/filesystem.h>
#include <learnopengl/shader.h>
#include <learnopengl/camera.h>
#include <learnopengl/model.h>
// Properties #include <iostream>
const GLuint SCR_WIDTH = 800, SCR_HEIGHT = 600;
// Function prototypes void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_callback(GLFWwindow* window, double xpos, double ypos); void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void Do_Movement(); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
GLuint loadTexture(GLchar const * path); void processInput(GLFWwindow *window);
void RenderScene(Shader &shader); unsigned int loadTexture(const char *path);
void RenderCube(); void renderScene(const Shader &shader);
void RenderQuad(); void renderCube();
// Camera // settings
const unsigned int SCR_WIDTH = 1280;
const unsigned int SCR_HEIGHT = 720;
bool shadows = true;
bool shadowsKeyPressed = false;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = (float)SCR_WIDTH / 2.0;
float lastY = (float)SCR_HEIGHT / 2.0;
bool firstMouse = true;
// Delta // timing
GLfloat deltaTime = 0.0f; float deltaTime = 0.0f;
GLfloat lastFrame = 0.0f; float lastFrame = 0.0f;
// Options
GLboolean shadows = true;
// Global variables
GLuint woodTexture;
GLuint planeVAO;
// The MAIN function, from here we start our application and run our Game loop
int main() int main()
{ {
// Init GLFW // glfw: initialize and configure
// ------------------------------
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr); // Windowed // glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
if (window == NULL)
// Set the required callback functions {
glfwSetKeyCallback(window, key_callback); std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback); glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback); glfwSetScrollCallback(window, scroll_callback);
// Options // tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Initialize GLEW to setup the OpenGL Function pointers // glad: load all OpenGL function pointers
glewExperimental = GL_TRUE; // ---------------------------------------
glewInit(); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// Define the viewport dimensions // configure global opengl state
glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); // -----------------------------
// Setup some OpenGL options
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
// Setup and compile our shaders // build and compile shaders
Shader shader("point_shadows.vs", "point_shadows.frag"); // -------------------------
Shader simpleDepthShader("point_shadows_depth.vs", "point_shadows_depth.frag", "point_shadows_depth.gs"); Shader shader("3.2.2.point_shadows.vs", "3.2.2.point_shadows.fs");
Shader simpleDepthShader("3.2.1.point_shadows_depth.vs", "3.2.1.point_shadows_depth.fs", "3.2.1.point_shadows_depth.gs");
// Set texture samples // load textures
shader.Use(); // -------------
glUniform1i(glGetUniformLocation(shader.Program, "diffuseTexture"), 0); unsigned int woodTexture = loadTexture(FileSystem::getPath("resources/textures/wood.png").c_str());
glUniform1i(glGetUniformLocation(shader.Program, "depthMap"), 1);
// Light source // configure depth map FBO
glm::vec3 lightPos(0.0f, 0.0f, 0.0f); // -----------------------
const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
// Load textures unsigned int depthMapFBO;
woodTexture = loadTexture(FileSystem::getPath("resources/textures/wood.png").c_str());
// Configure depth map FBO
const GLuint SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
GLuint depthMapFBO;
glGenFramebuffers(1, &depthMapFBO); glGenFramebuffers(1, &depthMapFBO);
// Create depth cubemap texture // create depth cubemap texture
GLuint depthCubemap; unsigned int depthCubemap;
glGenTextures(1, &depthCubemap); glGenTextures(1, &depthCubemap);
glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap); glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap);
for (GLuint i = 0; i < 6; ++i) for (unsigned int i = 0; i < 6; ++i)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
// Attach cubemap as depth map FBO's color buffer // attach depth texture as FBO's depth buffer
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0);
glDrawBuffer(GL_NONE); glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE); glReadBuffer(GL_NONE);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "Framebuffer not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
// Game loop // shader configuration
// --------------------
shader.use();
shader.setInt("diffuseTexture", 0);
shader.setInt("depthMap", 1);
// lighting info
// -------------
glm::vec3 lightPos(0.0f, 0.0f, 0.0f);
// render loop
// -----------
while (!glfwWindowShouldClose(window)) while (!glfwWindowShouldClose(window))
{ {
// Set frame time // per-frame time logic
GLfloat currentFrame = glfwGetTime(); // --------------------
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame; deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame; lastFrame = currentFrame;
// Check and call events // input
glfwPollEvents(); // -----
Do_Movement(); processInput(window);
// Move light position over time // move light position over time
//lightPos.z = sin(glfwGetTime() * 0.5) * 3.0; lightPos.z = sin(glfwGetTime() * 0.5) * 3.0;
// 0. Create depth cubemap transformation matrices // render
GLfloat aspect = (GLfloat)SHADOW_WIDTH / (GLfloat)SHADOW_HEIGHT; // ------
GLfloat near = 1.0f; glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
GLfloat far = 25.0f; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 shadowProj = glm::perspective(90.0f, aspect, near, far);
// 0. create depth cubemap transformation matrices
// -----------------------------------------------
float near_plane = 1.0f;
float far_plane = 25.0f;
glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), (float)SHADOW_WIDTH / (float)SHADOW_HEIGHT, near_plane, far_plane);
std::vector<glm::mat4> shadowTransforms; std::vector<glm::mat4> shadowTransforms;
shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3( 1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0))); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0))); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3( 0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, 1.0))); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)));
shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3( 0.0, -1.0, 0.0), glm::vec3(0.0, 0.0, -1.0))); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)));
shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3( 0.0, 0.0, 1.0), glm::vec3(0.0, -1.0, 0.0))); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3( 0.0, 0.0, -1.0), glm::vec3(0.0, -1.0, 0.0))); shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
// 1. Render scene to depth cubemap // 1. render scene to depth cubemap
// --------------------------------
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);
simpleDepthShader.Use(); simpleDepthShader.use();
for (GLuint i = 0; i < 6; ++i) for (unsigned int i = 0; i < 6; ++i)
glUniformMatrix4fv(glGetUniformLocation(simpleDepthShader.Program, ("shadowTransforms[" + std::to_string(i) + "]").c_str()), 1, GL_FALSE, glm::value_ptr(shadowTransforms[i])); simpleDepthShader.setMat4("shadowMatrices[" + std::to_string(i) + "]", shadowTransforms[i]);
glUniform1f(glGetUniformLocation(simpleDepthShader.Program, "far_plane"), far); simpleDepthShader.setFloat("far_plane", far_plane);
glUniform3fv(glGetUniformLocation(simpleDepthShader.Program, "lightPos"), 1, &lightPos[0]); simpleDepthShader.setVec3("lightPos", lightPos);
RenderScene(simpleDepthShader); renderScene(simpleDepthShader);
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
// 2. Render scene as normal // 2. render scene as normal
// -------------------------
glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.Use(); shader.use();
glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix(); glm::mat4 view = camera.GetViewMatrix();
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); shader.setMat4("projection", projection);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); shader.setMat4("view", view);
// Set light uniforms // set lighting uniforms
glUniform3fv(glGetUniformLocation(shader.Program, "lightPos"), 1, &lightPos[0]); shader.setVec3("lightPos", lightPos);
glUniform3fv(glGetUniformLocation(shader.Program, "viewPos"), 1, &camera.Position[0]); shader.setVec3("viewPos", camera.Position);
// Enable/Disable shadows by pressing 'SPACE' shader.setInt("shadows", shadows); // enable/disable shadows by pressing 'SPACE'
glUniform1i(glGetUniformLocation(shader.Program, "shadows"), shadows); shader.setFloat("far_plane", far_plane);
glUniform1f(glGetUniformLocation(shader.Program, "far_plane"), far);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, woodTexture); glBindTexture(GL_TEXTURE_2D, woodTexture);
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap); glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap);
RenderScene(shader); renderScene(shader);
// Swap the buffers // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents();
} }
glfwTerminate(); glfwTerminate();
return 0; return 0;
} }
void RenderScene(Shader &shader) // renders the 3D scene
// --------------------
void renderScene(const Shader &shader)
{ {
// Room cube // room cube
glm::mat4 model; glm::mat4 model;
model = glm::scale(model, glm::vec3(10.0)); model = glm::scale(model, glm::vec3(5.0f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shader.setMat4("model", model);
glDisable(GL_CULL_FACE); // Note that we disable culling here since we render 'inside' the cube instead of the usual 'outside' which throws off the normal culling methods. glDisable(GL_CULL_FACE); // note that we disable culling here since we render 'inside' the cube instead of the usual 'outside' which throws off the normal culling methods.
glUniform1i(glGetUniformLocation(shader.Program, "reverse_normals"), 1); // A small little hack to invert normals when drawing cube from the inside so lighting still works. shader.setInt("reverse_normals", 1); // A small little hack to invert normals when drawing cube from the inside so lighting still works.
RenderCube(); renderCube();
glUniform1i(glGetUniformLocation(shader.Program, "reverse_normals"), 0); // And of course disable it shader.setInt("reverse_normals", 0); // and of course disable it
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
// Cubes // cubes
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(4.0f, -3.5f, 0.0)); model = glm::translate(model, glm::vec3(4.0f, -3.5f, 0.0));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); model = glm::scale(model, glm::vec3(0.5f));
RenderCube(); shader.setMat4("model", model);
renderCube();
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(2.0f, 3.0f, 1.0)); model = glm::translate(model, glm::vec3(2.0f, 3.0f, 1.0));
model = glm::scale(model, glm::vec3(1.5)); model = glm::scale(model, glm::vec3(0.75f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shader.setMat4("model", model);
RenderCube(); renderCube();
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(-3.0f, -1.0f, 0.0)); model = glm::translate(model, glm::vec3(-3.0f, -1.0f, 0.0));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); model = glm::scale(model, glm::vec3(0.5f));
RenderCube(); shader.setMat4("model", model);
renderCube();
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(-1.5f, 1.0f, 1.5)); model = glm::translate(model, glm::vec3(-1.5f, 1.0f, 1.5));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); model = glm::scale(model, glm::vec3(0.5f));
RenderCube(); shader.setMat4("model", model);
renderCube();
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(-1.5f, 2.0f, -3.0)); model = glm::translate(model, glm::vec3(-1.5f, 2.0f, -3.0));
model = glm::rotate(model, 60.0f, glm::normalize(glm::vec3(1.0, 0.0, 1.0))); model = glm::rotate(model, glm::radians(60.0f), glm::normalize(glm::vec3(1.0, 0.0, 1.0)));
model = glm::scale(model, glm::vec3(1.5)); model = glm::scale(model, glm::vec3(0.75f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shader.setMat4("model", model);
RenderCube(); renderCube();
} }
// renderCube() renders a 1x1 3D cube in NDC.
// RenderCube() Renders a 1x1 3D cube in NDC. // -------------------------------------------------
GLuint cubeVAO = 0; unsigned int cubeVAO = 0;
GLuint cubeVBO = 0; unsigned int cubeVBO = 0;
void RenderCube() void renderCube()
{ {
// Initialize (if necessary) // initialize (if necessary)
if (cubeVAO == 0) if (cubeVAO == 0)
{ {
GLfloat vertices[] = { float vertices[] = {
// Back face // back face
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // Bottom-left -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,// top-left -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, // top-left
// Front face // front face
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
// Left face // left face
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
// Right face // right face
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left
// Bottom face // bottom face
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,// bottom-left 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
// Top face // top face
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,// top-left -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right 1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,// top-left -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left
}; };
glGenVertexArrays(1, &cubeVAO); glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &cubeVBO); glGenBuffers(1, &cubeVBO);
// Fill buffer // fill buffer
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Link vertex attributes // link vertex attributes
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0); glBindVertexArray(0);
} }
// Render Cube // render Cube
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0); glBindVertexArray(0);
} }
// This function loads a texture from file. Note: texture loading functions like these are usually // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// managed by a 'Resource Manager' that manages all resources (like textures, models, audio). // ---------------------------------------------------------------------------------------------------------
// For learning purposes we'll just define it as a utility function. void processInput(GLFWwindow *window)
GLuint loadTexture(GLchar const * path)
{ {
// Generate texture ID and load texture data if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
GLuint textureID; glfwSetWindowShouldClose(window, true);
glGenTextures(1, &textureID);
int width, height;
unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB);
// Assign texture to ID
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
// Parameters float cameraSpeed = 2.5 * deltaTime;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image);
return textureID;
}
bool keys[1024];
bool keysPressed[1024];
// Moves/alters the camera positions based on user input
void Do_Movement()
{
// Camera controls
if (keys[GLFW_KEY_W])
camera.ProcessKeyboard(FORWARD, deltaTime); camera.ProcessKeyboard(FORWARD, deltaTime);
if (keys[GLFW_KEY_S]) if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime); camera.ProcessKeyboard(BACKWARD, deltaTime);
if (keys[GLFW_KEY_A]) if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime); camera.ProcessKeyboard(LEFT, deltaTime);
if (keys[GLFW_KEY_D]) if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime); camera.ProcessKeyboard(RIGHT, deltaTime);
if (keys[GLFW_KEY_SPACE] && !keysPressed[GLFW_KEY_SPACE]) if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS && !shadowsKeyPressed)
{ {
shadows = !shadows; shadows = !shadows;
keysPressed[GLFW_KEY_SPACE] = true; shadowsKeyPressed = true;
} }
} if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_RELEASE)
GLfloat lastX = 400, lastY = 300;
bool firstMouse = true;
// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
if (key >= 0 && key <= 1024)
{ {
if (action == GLFW_PRESS) shadowsKeyPressed = false;
keys[key] = true;
else if (action == GLFW_RELEASE)
{
keys[key] = false;
keysPressed[key] = false;
}
} }
} }
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos) void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{ {
if (firstMouse) if (firstMouse)
@@ -375,8 +363,8 @@ void mouse_callback(GLFWwindow* window, double xpos, double ypos)
firstMouse = false; firstMouse = false;
} }
GLfloat xoffset = xpos - lastX; float xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos; lastX = xpos;
lastY = ypos; lastY = ypos;
@@ -384,7 +372,48 @@ void mouse_callback(GLFWwindow* window, double xpos, double ypos)
camera.ProcessMouseMovement(xoffset, yoffset); camera.ProcessMouseMovement(xoffset, yoffset);
} }
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{ {
camera.ProcessMouseScroll(yoffset); camera.ProcessMouseScroll(yoffset);
} }
// utility function for loading a 2D texture from file
// ---------------------------------------------------
unsigned int loadTexture(char const * path)
{
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT); // for this tutorial: use GL_CLAMP_TO_EDGE to prevent semi-transparent borders. Due to interpolation it takes texels from next repeat
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}