Implement basic shadows
Still shadow acne, but working in principle
This commit is contained in:
parent
5f30873f23
commit
0254b81882
@ -15,7 +15,7 @@ struct MouseLook {
|
|||||||
|
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
|
|
||||||
bool is_active;
|
bool is_active = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //ECSGAME_MOUSELOOK_H
|
#endif //ECSGAME_MOUSELOOK_H
|
||||||
|
@ -14,7 +14,7 @@ struct Movement {
|
|||||||
|
|
||||||
glm::vec3 velocity;
|
glm::vec3 velocity;
|
||||||
|
|
||||||
bool is_active;
|
bool is_active = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //ECSGAME_MOVEMENT_H
|
#endif //ECSGAME_MOVEMENT_H
|
||||||
|
@ -35,7 +35,7 @@ struct PathMove {
|
|||||||
|
|
||||||
PathMove(double speed, Path path, Views views) : speed(speed), path(path), views(views) {}
|
PathMove(double speed, Path path, Views views) : speed(speed), path(path), views(views) {}
|
||||||
|
|
||||||
bool is_active;
|
bool is_active = false;
|
||||||
double speed;
|
double speed;
|
||||||
float time_passed = 0.0;
|
float time_passed = 0.0;
|
||||||
int current_point_index = 0;
|
int current_point_index = 0;
|
||||||
|
@ -18,6 +18,38 @@
|
|||||||
|
|
||||||
using namespace ECS;
|
using namespace ECS;
|
||||||
|
|
||||||
|
// For debugging:
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
class RenderSystem : public EntitySystem {
|
class RenderSystem : public EntitySystem {
|
||||||
public:
|
public:
|
||||||
struct RenderObject {
|
struct RenderObject {
|
||||||
@ -36,9 +68,11 @@ public:
|
|||||||
|
|
||||||
// 0 can't be a valid texture name, so we use it for meshes without textures here
|
// 0 can't be a valid texture name, so we use it for meshes without textures here
|
||||||
if (texture_id != 0) {
|
if (texture_id != 0) {
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(GL_TEXTURE_2D, texture_id);
|
glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Not always required (not when rendering shadows) - make functions separate?
|
||||||
shader.setFloat("diffuseStrength", material.diffuse);
|
shader.setFloat("diffuseStrength", material.diffuse);
|
||||||
shader.setFloat("specularStrength", material.specular);
|
shader.setFloat("specularStrength", material.specular);
|
||||||
|
|
||||||
@ -125,40 +159,113 @@ public:
|
|||||||
return renderObjects;
|
return renderObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
void render(World *pWorld, Shader shader) {
|
RenderSystem() {
|
||||||
|
// Configure depth map
|
||||||
|
glGenFramebuffers(1, &depthMapFBO);
|
||||||
|
// create depth texture
|
||||||
|
glGenTextures(1, &depthMap);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, depthMap);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadow_width, shadow_height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
// attach depth texture as FBO's depth buffer
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);
|
||||||
|
glDrawBuffer(GL_NONE);
|
||||||
|
glReadBuffer(GL_NONE);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void render(World *pWorld, Shader normalShader, Shader shadowShader, Shader debugShader) {
|
||||||
pWorld->each<Camera, Transform>([&](Entity *ent, ComponentHandle<Camera> camera, ComponentHandle<Transform> cameraTransform) {
|
pWorld->each<Camera, Transform>([&](Entity *ent, ComponentHandle<Camera> camera, ComponentHandle<Transform> cameraTransform) {
|
||||||
|
// Common
|
||||||
glClearColor(0.6f, 0.9f, 0.9f, 1.0f);
|
glClearColor(0.6f, 0.9f, 0.9f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
shader.use();
|
std::vector<std::vector<RenderObject>> allRenderObjects = getRenderObjects(pWorld, cameraTransform->get_origin());
|
||||||
|
std::vector<RenderObject> renderObjects = allRenderObjects[0];
|
||||||
|
std::vector<RenderObject> transparentRenderObjects = allRenderObjects[1];
|
||||||
|
|
||||||
|
// Calculate matrix for lighting
|
||||||
|
// Get light direction
|
||||||
|
// TODO: Currently only the last light is used!
|
||||||
|
glm::vec3 lightDirection;
|
||||||
|
pWorld->each<DirectionalLight>([&](Entity *ent, ComponentHandle<DirectionalLight> light) {
|
||||||
|
lightDirection = light->direction;
|
||||||
|
});
|
||||||
|
float near_plane = 1.0f, far_plane = 100.0f;
|
||||||
|
glm::mat4 lightProjection = glm::ortho(-20.0f, 20.0f, -20.0f, 20.0f, near_plane, far_plane);
|
||||||
|
glm::mat4 lightView = glm::lookAt(lightDirection * 40.0f, -lightDirection, glm::vec3(0.0, 1.0, 0.0));
|
||||||
|
glm::mat4 lightSpaceMatrix = lightProjection * lightView;
|
||||||
|
|
||||||
|
// Render shadows
|
||||||
|
shadowShader.use();
|
||||||
|
|
||||||
|
shadowShader.setMat4("lightSpaceMatrix", lightSpaceMatrix);
|
||||||
|
|
||||||
|
glViewport(0, 0, shadow_width, shadow_height);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
|
||||||
|
for (const RenderObject &obj : renderObjects) {
|
||||||
|
obj.render(shadowShader);
|
||||||
|
}
|
||||||
|
for (const RenderObject &obj : transparentRenderObjects) {
|
||||||
|
obj.render(shadowShader);
|
||||||
|
}
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
// reset viewport
|
||||||
|
glViewport(0, 0, screen_width, screen_height);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
|
||||||
|
// Render normal
|
||||||
|
normalShader.use();
|
||||||
|
|
||||||
// Lighting
|
// Lighting
|
||||||
// TODO: Currently only the last light is used!
|
normalShader.setVec3("lightDirection", lightDirection);
|
||||||
pWorld->each<DirectionalLight>([&](Entity *ent, ComponentHandle<DirectionalLight> light) {
|
normalShader.setMat4("lightSpaceMatrix", lightSpaceMatrix);
|
||||||
shader.setVec3("lightDirection", light->direction);
|
|
||||||
});
|
|
||||||
|
|
||||||
glm::vec3 cameraPos = cameraTransform->get_origin();
|
glm::vec3 cameraPos = cameraTransform->get_origin();
|
||||||
|
|
||||||
glm::mat4 view = cameraTransform->matrix;
|
glm::mat4 view = cameraTransform->matrix;
|
||||||
view[3] = glm::vec4(cameraPos, 1.0);
|
view[3] = glm::vec4(cameraPos, 1.0);
|
||||||
|
|
||||||
shader.setMat4("projection", camera->projection);
|
normalShader.setMat4("projection", camera->projection);
|
||||||
shader.setMat4("view", glm::inverse(view));
|
normalShader.setMat4("view", glm::inverse(view));
|
||||||
shader.setVec3("cameraPosition", cameraTransform->get_origin());
|
normalShader.setVec3("cameraPosition", cameraTransform->get_origin());
|
||||||
|
|
||||||
std::vector<std::vector<RenderObject>> allRenderObjects = getRenderObjects(pWorld, cameraPos);
|
// Bind shadow texture
|
||||||
std::vector<RenderObject> renderObjects = allRenderObjects[0];
|
glActiveTexture(GL_TEXTURE0);
|
||||||
std::vector<RenderObject> transparentRenderObjects = allRenderObjects[1];
|
glBindTexture(GL_TEXTURE_2D, depthMap);
|
||||||
|
|
||||||
for (const RenderObject &obj : renderObjects) {
|
for (const RenderObject &obj : renderObjects) {
|
||||||
obj.render(shader);
|
obj.render(normalShader);
|
||||||
}
|
}
|
||||||
for (const RenderObject &obj : transparentRenderObjects) {
|
for (const RenderObject &obj : transparentRenderObjects) {
|
||||||
obj.render(shader);
|
obj.render(normalShader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render the light's depth map to a quad for debugging
|
||||||
|
debugShader.use();
|
||||||
|
debugShader.setFloat("near_plane", near_plane);
|
||||||
|
debugShader.setFloat("far_plane", far_plane);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, depthMap);
|
||||||
|
//renderQuad(); // TODO: Add actual code switch instead of commenting
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int screen_width = 1280;
|
||||||
|
int screen_height = 720;
|
||||||
|
|
||||||
|
int shadow_width = 1024;
|
||||||
|
int shadow_height = 1024;
|
||||||
|
|
||||||
|
unsigned int depthMap;
|
||||||
|
unsigned int depthMapFBO;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //ECSGAME_RENDERSYSTEM_H
|
#endif //ECSGAME_RENDERSYSTEM_H
|
||||||
|
23
Shaders/debug-fragment.fs
Normal file
23
Shaders/debug-fragment.fs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#version 330 core
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
in vec2 TexCoords;
|
||||||
|
|
||||||
|
uniform sampler2D depthMap;
|
||||||
|
uniform float near_plane;
|
||||||
|
uniform float far_plane;
|
||||||
|
|
||||||
|
// required when using a perspective projection matrix
|
||||||
|
float LinearizeDepth(float depth)
|
||||||
|
{
|
||||||
|
float z = depth * 2.0 - 1.0; // Back to NDC
|
||||||
|
return (2.0 * near_plane * far_plane) / (far_plane + near_plane - z * (far_plane - near_plane));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float depthValue = texture(depthMap, TexCoords).r;
|
||||||
|
// FragColor = vec4(vec3(LinearizeDepth(depthValue) / far_plane), 1.0); // perspective
|
||||||
|
FragColor = vec4(vec3(depthValue), 1.0); // orthographic
|
||||||
|
}
|
||||||
|
|
12
Shaders/debug-vertex.vs
Normal file
12
Shaders/debug-vertex.vs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#version 330 core
|
||||||
|
layout (location = 0) in vec3 aPos;
|
||||||
|
layout (location = 1) in vec2 aTexCoords;
|
||||||
|
|
||||||
|
out vec2 TexCoords;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
TexCoords = aTexCoords;
|
||||||
|
gl_Position = vec4(aPos, 1.0);
|
||||||
|
}
|
||||||
|
|
@ -4,14 +4,38 @@ out mediump vec4 FragColor;
|
|||||||
in mediump vec2 TexCoord;
|
in mediump vec2 TexCoord;
|
||||||
in mediump vec3 Normal;
|
in mediump vec3 Normal;
|
||||||
in mediump vec3 FragPos;
|
in mediump vec3 FragPos;
|
||||||
|
in mediump vec4 FragPosLightSpace;
|
||||||
|
|
||||||
|
layout(binding=0) uniform sampler2D shadowMap;
|
||||||
|
layout(binding=1) uniform sampler2D tex;
|
||||||
|
|
||||||
uniform sampler2D tex;
|
|
||||||
uniform mediump vec3 lightDirection;
|
uniform mediump vec3 lightDirection;
|
||||||
uniform mediump vec3 cameraPosition;
|
uniform mediump vec3 cameraPosition;
|
||||||
|
|
||||||
uniform mediump float diffuseStrength;
|
uniform mediump float diffuseStrength;
|
||||||
uniform mediump float specularStrength;
|
uniform mediump float specularStrength;
|
||||||
|
|
||||||
|
mediump float ShadowCalculation(vec4 fragPosLightSpace)
|
||||||
|
{
|
||||||
|
// perform perspective divide
|
||||||
|
mediump vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||||
|
// transform to [0,1] range
|
||||||
|
projCoords = projCoords * 0.5 + 0.5;
|
||||||
|
|
||||||
|
// If we're outside of [0.0, 1.0] in the coordinates, return 0
|
||||||
|
if (projCoords.x < 0.0 || projCoords.y < 0.0 || projCoords.x > 1.0 || projCoords.y > 1.0) return 0.0;
|
||||||
|
|
||||||
|
// get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
|
||||||
|
mediump float closestDepth = texture(shadowMap, projCoords.xy).r;
|
||||||
|
// get depth of current fragment from light's perspective
|
||||||
|
mediump float currentDepth = projCoords.z;
|
||||||
|
// check whether current frag pos is in shadow
|
||||||
|
mediump float shadow = currentDepth > closestDepth ? 1.0 : 0.0;
|
||||||
|
|
||||||
|
return shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
mediump vec4 texColor = texture(tex, TexCoord);
|
mediump vec4 texColor = texture(tex, TexCoord);
|
||||||
@ -33,8 +57,11 @@ void main()
|
|||||||
|
|
||||||
mediump float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0);
|
mediump float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0);
|
||||||
|
|
||||||
|
// Shadow
|
||||||
|
mediump float shadow = ShadowCalculation(FragPosLightSpace);
|
||||||
|
|
||||||
// Total
|
// Total
|
||||||
mediump float light = min(diff * diffuseStrength + ambient + spec * specularStrength, 1.0);
|
mediump float light = min(diff * diffuseStrength + ambient + spec * specularStrength - shadow * 0.5 + 0.5, 2.0);
|
||||||
|
|
||||||
// Assign resulting color
|
// Assign resulting color
|
||||||
mediump vec3 color = texColor.xyz * light;
|
mediump vec3 color = texColor.xyz * light;
|
||||||
|
@ -6,10 +6,12 @@ layout (location = 2) in vec2 UV;
|
|||||||
out vec2 TexCoord;
|
out vec2 TexCoord;
|
||||||
out vec3 Normal;
|
out vec3 Normal;
|
||||||
out vec3 FragPos;
|
out vec3 FragPos;
|
||||||
|
out vec4 FragPosLightSpace;
|
||||||
|
|
||||||
uniform mat4 model;
|
uniform mat4 model;
|
||||||
uniform mat4 view;
|
uniform mat4 view;
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
|
uniform mat4 lightSpaceMatrix;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
@ -17,4 +19,5 @@ void main()
|
|||||||
TexCoord = UV;
|
TexCoord = UV;
|
||||||
Normal = NORMAL;
|
Normal = NORMAL;
|
||||||
FragPos = vec3(model * vec4(aPos, 1.0));
|
FragPos = vec3(model * vec4(aPos, 1.0));
|
||||||
|
FragPosLightSpace = lightSpaceMatrix * vec4(FragPos, 1.0);
|
||||||
}
|
}
|
7
Shaders/shadow-fragment.fs
Normal file
7
Shaders/shadow-fragment.fs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// This happens implicitly anyways
|
||||||
|
// gl_FragDepth = gl_FragCoord.z;
|
||||||
|
}
|
10
Shaders/shadow-vertex.vs
Normal file
10
Shaders/shadow-vertex.vs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#version 330 core
|
||||||
|
layout (location = 0) in vec3 aPos;
|
||||||
|
|
||||||
|
uniform mat4 lightSpaceMatrix;
|
||||||
|
uniform mat4 model;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = lightSpaceMatrix * model * vec4(aPos, 1.0);
|
||||||
|
}
|
5
main.cpp
5
main.cpp
@ -112,6 +112,7 @@ int main() {
|
|||||||
glm::angleAxis(glm::radians(180.f), glm::vec3(0.f, 1.f, 0.f))
|
glm::angleAxis(glm::radians(180.f), glm::vec3(0.f, 1.f, 0.f))
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
player->get<Transform>()->set_origin(glm::vec3(0.0, 3.0, 4.0));
|
||||||
|
|
||||||
Entity *monkey = world->create();
|
Entity *monkey = world->create();
|
||||||
monkey->assign<Transform>();
|
monkey->assign<Transform>();
|
||||||
@ -172,6 +173,8 @@ int main() {
|
|||||||
sun->assign<DirectionalLight>(glm::normalize(glm::vec3(1.0, 1.0, 1.0)));
|
sun->assign<DirectionalLight>(glm::normalize(glm::vec3(1.0, 1.0, 1.0)));
|
||||||
|
|
||||||
Shader defaultShader("Shaders/default-vertex.vs", "Shaders/default-fragment.fs");
|
Shader defaultShader("Shaders/default-vertex.vs", "Shaders/default-fragment.fs");
|
||||||
|
Shader shadowShader("Shaders/shadow-vertex.vs", "Shaders/shadow-fragment.fs");
|
||||||
|
Shader debugShader("Shaders/debug-vertex.vs", "Shaders/debug-fragment.fs");
|
||||||
|
|
||||||
double timeInLastFrame = glfwGetTime();
|
double timeInLastFrame = glfwGetTime();
|
||||||
double elapsed_time = 0.0;
|
double elapsed_time = 0.0;
|
||||||
@ -184,7 +187,7 @@ int main() {
|
|||||||
elapsed_time += delta;
|
elapsed_time += delta;
|
||||||
|
|
||||||
world->tick(delta);
|
world->tick(delta);
|
||||||
renderSystem->render(world, defaultShader);
|
renderSystem->render(world, defaultShader, shadowShader, debugShader);
|
||||||
|
|
||||||
/* Swap front and back buffers */
|
/* Swap front and back buffers */
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user