diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index b36d2448..5259513a 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -66,13 +66,24 @@ add_custom_command(TARGET Editor POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${C file(GLOB_RECURSE ASSETS ${CMAKE_CURRENT_SOURCE_DIR}/assets/* ) -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_Assets - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/assets/ $/assets - COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/_Assets - DEPENDS ${ASSETS} - COMMENT "Copying assets to executable directory" -) + +if (CMAKE_GENERATOR MATCHES "Visual Studio") + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_Assets + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/assets/ $/../assets + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/_Assets + DEPENDS ${ASSETS} + COMMENT "Copying assets to executable directory" + ) +else () + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_Assets + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/assets/ $/assets + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/_Assets + DEPENDS ${ASSETS} + COMMENT "Copying assets to executable directory" + ) +endif () add_custom_target(CopyAssets DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_Assets) add_dependencies(Editor CopyAssets) diff --git a/Editor/assets/shaders/depth.glsl b/Editor/assets/shaders/depth.glsl new file mode 100644 index 00000000..602f3588 --- /dev/null +++ b/Editor/assets/shaders/depth.glsl @@ -0,0 +1,24 @@ +#type vertex +#version 330 core +// depth.glsl +layout(location = 0) in vec3 a_Position; +layout(location = 1) in vec4 a_Color; +layout(location = 2) in vec3 a_Normal; +layout(location = 3) in vec2 a_Texcoord; + +uniform mat4 u_lightSpaceMatrix; +uniform mat4 u_transform; + +void main() +{ + gl_Position = u_lightSpaceMatrix * u_transform * vec4(a_Position, 1.0); +} + +#type fragment +#version 330 core +//depth.glsl + +void main() +{ + // gl_FragDepth = gl_FragCoord.z; +} \ No newline at end of file diff --git a/Editor/assets/shaders/depthCube.glsl b/Editor/assets/shaders/depthCube.glsl new file mode 100644 index 00000000..93c1a1c4 --- /dev/null +++ b/Editor/assets/shaders/depthCube.glsl @@ -0,0 +1,56 @@ +#type vertex +#version 330 core +// depth.glsl +layout(location = 0) in vec3 a_Position; +layout(location = 1) in vec4 a_Color; +layout(location = 2) in vec3 a_Normal; +layout(location = 3) in vec2 a_Texcoord; + +uniform mat4 u_transform; + +void main() +{ + gl_Position = u_transform * vec4(a_Position, 1.0); +} + +#type fragment +#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; +} + +#type geometry +#version 330 core +layout (triangles) in; +layout (triangle_strip, max_vertices=18) out; + +uniform mat4 shadowMatrices[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 = shadowMatrices[face] * FragPos; + EmitVertex(); + } + EndPrimitive(); + } +} diff --git a/Editor/assets/shaders/phong.glsl b/Editor/assets/shaders/phong.glsl index 1a3e1da5..ce906489 100644 --- a/Editor/assets/shaders/phong.glsl +++ b/Editor/assets/shaders/phong.glsl @@ -4,154 +4,214 @@ layout(location = 0) in vec3 a_Position; layout(location = 1) in vec4 a_Color; layout(location = 2) in vec3 a_Normal; -out vec4 v_color; -out vec3 v_normal; +layout(location = 3) in vec2 a_TexCoord; + out vec3 v_worldPos; +out vec3 v_normal; +out vec2 v_texCoord; uniform mat4 u_viewProjectionMatrix; -uniform mat4 u_transform; -uniform mat3 u_normal; +uniform mat4 u_transform; //model + void main() { gl_Position = u_viewProjectionMatrix * u_transform * vec4(a_Position, 1.0); - v_color = a_Color; - v_normal = u_normal * a_Normal; v_worldPos = vec3(u_transform * vec4(a_Position, 1.0)); + v_normal = vec3(mat3(transpose(inverse(u_transform))) * a_Normal); + v_texCoord = a_TexCoord; } #type fragment #version 330 core -in vec3 v_normal; -in vec4 v_color; in vec3 v_worldPos; +in vec3 v_normal; +in vec2 v_texCoord; + layout(location = 0) out vec4 color; layout(location = 1) out int entity; -struct PointLight +struct DirectionalLight { - vec4 position; + sampler2D depthMap; vec4 color; - float range; + vec3 direction; + mat4 lightSpaceMatrix; }; -struct SpotLight + +struct PointLight { - vec4 position; - vec4 color; - vec4 direction; - float innerCutoff; - float outerCutoff; - float range; + samplerCube depthCubemap; + vec4 color; + vec3 position; + float far_plane; }; -struct DirectionalLight +struct SpotLight { - vec4 direction; + samplerCube depthCubemap; vec4 color; - + vec3 position; + vec3 direction; + float far_plane; + float innerCutoff; + float outerCutoff; }; -uniform PointLight u_pointLights[4]; -uniform SpotLight u_spotLights[4]; -uniform DirectionalLight u_directionalLights[4]; -uniform vec3 cameraPosition; -uniform int u_numPointLights; -uniform int u_numSpotLights; -uniform int u_id; -uniform int u_selectionId; -vec4 pointLightCalculate(PointLight light, vec3 norm, vec3 viewDir) +float calculateShadow(DirectionalLight light) { - float distance = length(light.position.xyz - v_worldPos); - vec3 lightDir = (light.position.xyz - v_worldPos) / distance; - - float attentuation = clamp(1 - (distance * distance)/(light.range * light.range), 0.0 , 1.0); - - float diff = max(dot(norm, lightDir), 0.0); - vec4 diffuse = diff * light.color; + vec4 fragPosLightSpace = light.lightSpaceMatrix * vec4(v_worldPos, 1.0); + vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; + + projCoords = projCoords * 0.5 + 0.5; + float closestDepth = texture(light.depthMap, projCoords.xy).r; + + float currentDepth = projCoords.z; + + float bias = 0.005; + + float shadow = (currentDepth - bias > closestDepth ) ? 1.0 : 0.0; + + if(projCoords.z > 1.0) + shadow = 0.0; + + return shadow; +} - //specular - vec3 halfwayDir = normalize(lightDir + viewDir); - float spec = pow(max(dot(norm, viewDir), 0.0), 64); - vec4 specular = spec * light.color; - diffuse = diffuse * attentuation; - specular = specular * attentuation; - vec4 result = diffuse + specular; - return result; +float calculateShadow(PointLight light) +{ + // get vector between fragment position and light position + vec3 fragToLight = v_worldPos - light.position; + // use the light to fragment vector to sample from the depth map + float closestDepth = texture(light.depthCubemap, fragToLight).r; + // it is currently in linear range between [0,1]. Re-transform back to original value + closestDepth *= light.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; + float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; + + return shadow; +} + +float calculateShadow(SpotLight light) +{ + // get vector between fragment position and light position + vec3 fragToLight = v_worldPos - light.position; + // use the light to fragment vector to sample from the depth map + float closestDepth = texture(light.depthCubemap, fragToLight).r; + // it is currently in linear range between [0,1]. Re-transform back to original value + closestDepth *= light.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; + float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; + + return shadow; } -vec4 directionalLightCalculate(DirectionalLight light, vec3 norm, vec3 viewDir) +vec4 calculateShading(DirectionalLight light, vec3 viewDir) { vec4 color = vec4(light.color); - vec3 lightDir = normalize(vec3(light.direction)); - float diff = max(dot(norm, lightDir), 0.0); + vec3 lightDir = -normalize(light.direction); + float diff = max(dot(v_normal, lightDir), 0.0); vec4 diffuse = diff * color; //specular vec3 halfwayDir = normalize(lightDir + viewDir); - float spec = pow(max(dot(halfwayDir, norm), 0.0), 64); + //TODO: make sure it is facing light + float spec = pow(max(dot(halfwayDir, v_normal), 0.0), 32); vec4 specular = spec * color; + float shadow = calculateShadow(light); + vec4 result = (1.0f - shadow)*(diffuse + specular); +// vec4 result = (1.0f - shadow) * vec4(1, 1, 1, 1); - vec4 result = diffuse + specular; return result; } -vec4 spotLightCalculate(SpotLight light, vec3 norm, vec3 viewDir) +vec4 calculateShading(PointLight light, vec3 viewDir) { float distance = length(light.position.xyz - v_worldPos); - vec3 lightDir = normalize(light.position.xyz - v_worldPos); - vec4 result; + vec3 lightDir = (light.position.xyz - v_worldPos) / distance; + + float attentuation = clamp(1 - (distance * distance)/(light.far_plane * light.far_plane), 0.0 , 1.0); + + float diff = max(dot(v_normal, lightDir), 0.0); + vec4 diffuse = diff * light.color; + + //specular + vec3 halfwayDir = normalize(lightDir + viewDir); + float spec = pow(max(dot(v_normal, viewDir), 0.0), 64); + vec4 specular = spec * light.color; + diffuse = diffuse * attentuation; + specular = specular * attentuation; + float shadow = calculateShadow(light); + vec4 result = (1.0f - shadow)*(diffuse + specular); + return result; +// return vec4(1.0 , 0.0 , 0.0 , 0.0); +} - - float attentuation = clamp(1 - distance/light.range, 0.0 , 1.0); - float theta = dot(lightDir, light.direction.xyz); +vec4 calculateShading(SpotLight light, vec3 viewDir) +{ + float distance = length(light.position - v_worldPos); + vec3 lightDir = normalize(light.position - v_worldPos); + vec4 result; +// +// + float attentuation = clamp(1 - distance/light.far_plane, 0.0 , 1.0); + float theta = dot(lightDir, -light.direction); if (theta > light.outerCutoff) { float intensity = clamp((theta - light.outerCutoff) / (light.innerCutoff - light.outerCutoff), 0.0, 1.0); - float diff = max(dot(norm, lightDir), 0.0); + float diff = max(dot(v_normal, lightDir), 0.0); vec4 diffuse = diff * light.color; vec3 halfwayDir = normalize(lightDir + viewDir); - float spec = pow(max(dot(halfwayDir, norm), 0.0), 64); + float spec = pow(max(dot(halfwayDir, v_normal), 0.0), 64); vec4 specular = spec * light.color; - diffuse = diffuse * intensity * attentuation; - specular = specular * intensity * attentuation; - result = diffuse + specular; - } else + float shadow = calculateShadow(light); +// diffuse = diffuse * intensity * attentuation; +// specular = specular * intensity * attentuation; + result = (diffuse + specular) * attentuation * intensity * (1.0f - shadow); + } + else { - result = vec4(0.0 , 0.0 , 0.0 , 0.0); + result = vec4(0.0 , 0.0 , 0.0 , 1.0); } - - - return result; +// return vec4(lightDir * attentuation, 1.0); } +uniform int u_id; +uniform int u_n_dLights; +uniform int u_n_pLights; +uniform int u_n_sLights; +uniform vec3 cameraPos; +//uniform sampler2D diffuseTexture; +uniform DirectionalLight u_dirLights[4]; +uniform PointLight u_pointLights[4]; +uniform SpotLight u_spotLights[4]; + void main() { - - vec3 norm = normalize(v_normal); - vec3 viewDir = normalize(cameraPosition - v_worldPos); - color = vec4(0.3, 0.3, 0.3, 1.0); - // for (int i = 0; i < u_numPointLights; i++) - // { - // color += vec4(pointLightCalculate(u_pointLights[i]), 0.0); - // } - color += pointLightCalculate(u_pointLights[0], norm, viewDir); - color += pointLightCalculate(u_pointLights[1], norm, viewDir); - color += pointLightCalculate(u_pointLights[2], norm, viewDir); - color += pointLightCalculate(u_pointLights[3], norm, viewDir); - color += spotLightCalculate(u_spotLights[0], norm, viewDir); - color += spotLightCalculate(u_spotLights[1], norm, viewDir); - color += spotLightCalculate(u_spotLights[2], norm, viewDir); - color += spotLightCalculate(u_spotLights[3], norm, viewDir); - color += directionalLightCalculate(u_directionalLights[0], norm, viewDir); - color += directionalLightCalculate(u_directionalLights[1], norm, viewDir); - color += directionalLightCalculate(u_directionalLights[2], norm, viewDir); - color += directionalLightCalculate(u_directionalLights[3], norm, viewDir); +// color = vec4(texture(diffuseTexture, v_texCoord)); + color = vec4(1.0, 1.0, 1.0, 1.0); + vec3 viewDir = v_worldPos - cameraPos; + + vec4 lighting = vec4(0.0, 0.0, 0.0, 0.0); + for(int i=0; i closestDepth ) ? 1.0 : 0.0; + + if(projCoords.z > 1.0) + shadow = 0.0; + + return shadow; +} + +float calculateShadow(PointLight light) +{ + // get vector between fragment position and light position + vec3 fragToLight = v_worldPos - light.position; + // use the light to fragment vector to sample from the depth map + float closestDepth = texture(light.depthCubemap, fragToLight).r; + // it is currently in linear range between [0,1]. Re-transform back to original value + closestDepth *= light.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; + float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; + + return shadow; +} + +float calculateShadow(SpotLight light) +{ + // get vector between fragment position and light position + vec3 fragToLight = v_worldPos - light.position; + // use the light to fragment vector to sample from the depth map + float closestDepth = texture(light.depthCubemap, fragToLight).r; + // it is currently in linear range between [0,1]. Re-transform back to original value + closestDepth *= light.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; + float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; + + return shadow; +} + +vec4 calculateShading(DirectionalLight light, vec3 viewDir) +{ + vec3 fragToLightDir = -normalize(light.direction); + float diff = max(dot(v_normal, fragToLightDir), 0.0); + vec4 diffuse = diff * light.emission_color; + + + //specular + vec3 halfwayDir = normalize(fragToLightDir - viewDir); + //TODO: make sure it is facing light + float spec = pow(max(dot(halfwayDir, v_normal), 0.0), 32); + vec4 specular = spec * light.emission_color; + float shadow = calculateShadow(light); + vec4 result = (1.0f - shadow)*(diffuse + specular); +// vec4 result = (1.0f - shadow) * vec4(1, 1, 1, 1); + + return result; +} + +vec4 calculateShading(PointLight light, vec3 viewDir) +{ + float distance = length(light.position - v_worldPos); + vec3 lightDir = (light.position - v_worldPos) / distance; + + float attentuation = clamp(1 - (distance * distance)/(light.far_plane * light.far_plane), 0.0 , 1.0); + + float diff = max(dot(v_normal, lightDir), 0.0); + vec4 diffuse = diff * light.emission_color; + + //specular + vec3 halfwayDir = normalize(lightDir - viewDir); + float spec = pow(max(dot(v_normal, halfwayDir), 0.0), 64); + vec4 specular = spec * light.emission_color; + diffuse = diffuse * attentuation; + specular = specular * attentuation; + float shadow = calculateShadow(light); + vec4 result = (1.0f - shadow)*(diffuse + specular); + return result; +// return vec4(1.0 , 0.0 , 0.0 , 0.0); +} + +vec4 calculateShading(SpotLight light, vec3 viewDir) +{ + float distance = length(light.position - v_worldPos); + vec3 lightDir = normalize(light.position - v_worldPos); + vec4 result; +// +// + float attentuation = clamp(1 - distance/light.far_plane, 0.0 , 1.0); + float theta = dot(lightDir, -light.direction); + if (theta > light.outerCutoff) + { + float intensity = clamp((theta - light.outerCutoff) / (light.innerCutoff - light.outerCutoff), 0.0, 1.0); + float diff = max(dot(v_normal, lightDir), 0.0); + vec4 diffuse = diff * light.emission_color; + vec3 halfwayDir = normalize(lightDir - viewDir); + float spec = pow(max(dot(halfwayDir, v_normal), 0.0), 64); + vec4 specular = spec * light.emission_color; + float shadow = calculateShadow(light); +// diffuse = diffuse * intensity * attentuation; +// specular = specular * intensity * attentuation; + result = (diffuse + specular) * attentuation * intensity * (1.0f - shadow); + } + else + { + result = vec4(0.0 , 0.0 , 0.0 , 1.0); + } + return result; +// return vec4(lightDir * attentuation, 1.0); +} + +uniform int u_id; +uniform int u_n_dLights; +uniform int u_n_pLights; +uniform int u_n_sLights; +uniform vec3 cameraPos; +//uniform sampler2D diffuseTexture; +uniform DirectionalLight u_dirLights[4]; +uniform PointLight u_pointLights[4]; +uniform SpotLight u_spotLights[4]; + + +void main() +{ +// color = vec4(texture(diffuseTexture, v_texCoord)); + color = vec4(1.0, 1.0, 1.0, 1.0); + vec3 viewDir = normalize(v_worldPos - cameraPos); + + vec4 lighting = vec4(0.0, 0.0, 0.0, 0.0); + for(int i=0; iaddEntity("Cube"); entity.addComponent(m_meshLibrary->get("Cube")); - entity.addComponent("assets/shaders/phong.glsl"); + entity.addComponent("assets/shaders/phong_vertex.glsl", "assets/shaders/phong_fragment.glsl"); } ImGui::EndMenu(); } @@ -70,7 +70,7 @@ namespace Light } if(ImGui::MenuItem("Mesh Renderer", nullptr, false, !m_selectionContext.hasComponent())) { - m_selectionContext.addComponent("assets/shaders/phong.glsl"); + m_selectionContext.addComponent("assets/shaders/phong_vertex.glsl", "assets/shaders/phong_fragment.glsl"); } if(ImGui::MenuItem("Light", nullptr, false, !m_selectionContext.hasComponent())) { diff --git a/Editor/src/layers/editorlayer.cpp b/Editor/src/layers/editorlayer.cpp index 51aec54f..583b57dd 100644 --- a/Editor/src/layers/editorlayer.cpp +++ b/Editor/src/layers/editorlayer.cpp @@ -71,13 +71,13 @@ namespace Light m_scene = std::make_shared(); auto cube = m_scene->addEntity("Cube"); - cube.addComponent("assets/shaders/phong.glsl"); + cube.addComponent("assets/shaders/phong_vertex.glsl", "assets/shaders/phong_fragment.glsl"); auto floor = m_scene->addEntity("Floor"); auto& floor_transform = floor.getComponent(); floor_transform.position = glm::vec3(0, -1, 0); floor_transform.scale = glm::vec3(2, 0.1, 2); - floor.addComponent("assets/shaders/phong.glsl"); + floor.addComponent("assets/shaders/phong_vertex.glsl", "assets/shaders/phong_fragment.glsl"); auto light = m_scene->addEntity("Light"); auto& light_transform = light.getComponent(); @@ -195,7 +195,7 @@ namespace Light void EditorLayer::addDefaultMeshes() { - m_meshes->add("None", std::vector(), std::vector(), std::vector(), std::vector()); + m_meshes->add("None", std::vector(), std::vector(), std::vector(), std::vector(), std::vector()); std::vector vertices = { glm::vec3(-0.5f, -0.5f, 0.5f), @@ -263,6 +263,38 @@ namespace Light glm::vec3(0.0f, 0.0f, -1.0f) }; + std::vector texcoords = { + glm::vec2(0.0f, 0.0f), + glm::vec2(1.0f, 0.0f), + glm::vec2(1.0f, 1.0f), + glm::vec2(0.0f, 1.0f), + + glm::vec2(0.0f, 1.0f), + glm::vec2(1.0f, 1.0f), + glm::vec2(1.0f, 0.0f), + glm::vec2(0.0f, 0.0f), + + glm::vec2(0.0f, 1.0f), + glm::vec2(0.0f, 0.0f), + glm::vec2(1.0f, 0.0f), + glm::vec2(1.0f, 1.0f), + + glm::vec2(0.0f, 1.0f), + glm::vec2(1.0f, 1.0f), + glm::vec2(1.0f, 0.0f), + glm::vec2(0.0f, 0.0f), + + glm::vec2(0.0f, 1.0f), + glm::vec2(0.0f, 0.0f), + glm::vec2(1.0f, 0.0f), + glm::vec2(1.0f, 1.0f), + + glm::vec2(0.0f, 0.0f), + glm::vec2(0.0f, 1.0f), + glm::vec2(1.0f, 1.0f), + glm::vec2(1.0f, 0.0f), + }; + std::vector indices = { 0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4, @@ -272,7 +304,7 @@ namespace Light 20, 21, 22, 22, 23, 20 }; - m_meshes->add("Cube", vertices, color, normals, indices); + m_meshes->add("Cube", vertices, color, normals, texcoords, indices); } } diff --git a/Light/include/light/platform/opengl/openglframebuffer.hpp b/Light/include/light/platform/opengl/openglframebuffer.hpp index 3dd1216a..9497cd08 100644 --- a/Light/include/light/platform/opengl/openglframebuffer.hpp +++ b/Light/include/light/platform/opengl/openglframebuffer.hpp @@ -17,7 +17,8 @@ namespace Light void bind() override; void unbind() override; - void invalidate(); + void invalidate2D(); + void invalidateCubemap(); void resize(uint32_t width, uint32_t height) override; int readPixelInt(uint32_t attachmentIndex, uint32_t x, uint32_t y) override; @@ -27,13 +28,17 @@ namespace Light void clearAttachment(uint32_t attachmentIndex, glm::vec4 clearValue) override; void clearDepthAttachment() override; + inline uint32_t getRendererId() const override { return m_rendererId; } inline uint32_t getColorAttachmentRendererId(uint32_t attachmentIndex = 0) const override { return m_colorAttachmentIds[attachmentIndex]; } - inline uint32_t getRendererId() const override { return m_rendererId; } + inline uint32_t getDepthAttachmentRendererId() const override + { + return m_depthAttachmentId; + } virtual void bindAttachmentTexture(uint32_t attachmentIndex, uint32_t slot) override; virtual void bindDepthAttachmentTexture(uint32_t slot) override; diff --git a/Light/include/light/platform/opengl/openglrendererapi.hpp b/Light/include/light/platform/opengl/openglrendererapi.hpp index 948ead29..60bcdcf1 100644 --- a/Light/include/light/platform/opengl/openglrendererapi.hpp +++ b/Light/include/light/platform/opengl/openglrendererapi.hpp @@ -15,6 +15,7 @@ namespace Light void setViewPort(uint32_t x, uint32_t y, uint32_t width, uint32_t height) override; void setClearColor(glm::vec4& color) override; void clear() override; + void clearDepthBit() override; void setBlendFunc(BlendFactor src, BlendFactor dst) override; void setBlendFuncSeperate(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha) override; diff --git a/Light/include/light/platform/opengl/openglshader.hpp b/Light/include/light/platform/opengl/openglshader.hpp index f22592a4..601cf4c6 100644 --- a/Light/include/light/platform/opengl/openglshader.hpp +++ b/Light/include/light/platform/opengl/openglshader.hpp @@ -12,6 +12,8 @@ namespace Light { public: OpenGLShader(const char* shaderPath); + OpenGLShader(const char* VertexShaderPath, const char* FragmentShaderPath); + OpenGLShader(const char* VertexShaderPath, const char* FragmentShaderPath, const char* GeometryShaderPath); ~OpenGLShader(); void bind() override; diff --git a/Light/include/light/rendering/framebuffer.hpp b/Light/include/light/rendering/framebuffer.hpp index 8de8012a..cee85281 100644 --- a/Light/include/light/rendering/framebuffer.hpp +++ b/Light/include/light/rendering/framebuffer.hpp @@ -5,6 +5,14 @@ namespace Light { + enum class FramebufferTextureType + { + None, + + TWO_D, + CUBEMAP + }; + enum class FramebufferTextureFormat { None, @@ -64,7 +72,8 @@ namespace Light struct FramebufferSpec { - uint32_t width, height; + FramebufferTextureType type = FramebufferTextureType::TWO_D; + uint32_t width = 0, height = 0; uint32_t samples = 1; FramebufferAttachmentsSpec attachments; @@ -81,6 +90,7 @@ namespace Light virtual const FramebufferSpec& getSpec() const = 0; virtual uint32_t getColorAttachmentRendererId(uint32_t attachmentIndex = 0) const = 0; + virtual uint32_t getDepthAttachmentRendererId() const =0; virtual uint32_t getRendererId() const = 0; virtual void resize(uint32_t width, uint32_t height) = 0; diff --git a/Light/include/light/rendering/lights.hpp b/Light/include/light/rendering/lights.hpp index 0772f56f..3e05777a 100644 --- a/Light/include/light/rendering/lights.hpp +++ b/Light/include/light/rendering/lights.hpp @@ -2,7 +2,10 @@ #define __LIGHTS_H__ #include "glm/glm.hpp" +#include + #include +#include namespace Light { @@ -17,11 +20,31 @@ namespace Light extern std::string LightTypeStrings[(int)LightType::NumLightTypes]; +// TODO convert these lights to classes struct PointLight { glm::vec3 position; glm::vec3 color; float range; + + std::vector getSpaceMatrices() const + { + glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 25.0f); + std::vector shadowTransforms; + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3( 1.0, 0.0, 0.0), glm::vec3(0.0,-1.0, 0.0))); + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0,-1.0, 0.0))); + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3( 0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, 1.0))); + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3( 0.0,-1.0, 0.0), glm::vec3(0.0, 0.0,-1.0))); + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3( 0.0, 0.0, 1.0), glm::vec3(0.0,-1.0, 0.0))); + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3( 0.0, 0.0,-1.0), glm::vec3(0.0,-1.0, 0.0))); + return shadowTransforms; + } }; struct SpotLight @@ -32,13 +55,46 @@ namespace Light float innerCutoff; float outerCutoff; float range; + + std::vector getSpaceMatrices() const + { + glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 25.0f); + std::vector shadowTransforms; + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3(1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0))); + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0))); + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3(0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, 1.0))); + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3(0.0, -1.0, 0.0), glm::vec3(0.0, 0.0, -1.0))); + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3(0.0, 0.0, 1.0), glm::vec3(0.0, -1.0, 0.0))); + shadowTransforms.push_back(shadowProj * + glm::lookAt(position, position + glm::vec3(0.0, 0.0, -1.0), glm::vec3(0.0, -1.0, 0.0))); + return shadowTransforms; + } }; struct DirectionalLight { + glm::vec3 position; glm::vec3 direction; glm::vec3 color; + // glm::mat4 lightSpaceMatrix; + inline glm::mat4 getViewMatrix() const + { + return glm::lookAt(-10.0f * direction, glm::vec3(0.0f), glm::vec3(0.0,1.0,0.0)); + } + inline glm::mat4 getProjectionMatrix() const + { + return glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 0.0f, 20.0f); + } + inline glm::mat4 getSpaceMatrix() const + { + return getProjectionMatrix() * getViewMatrix(); + } }; } diff --git a/Light/include/light/rendering/mesh.hpp b/Light/include/light/rendering/mesh.hpp index 86f7cca4..e1cb768e 100644 --- a/Light/include/light/rendering/mesh.hpp +++ b/Light/include/light/rendering/mesh.hpp @@ -13,6 +13,7 @@ namespace Light Mesh(const std::vector &vertices, const std::vector &colors, const std::vector &normals, + const std::vector &texcoords, const std::vector &indices); ~Mesh() = default; @@ -22,6 +23,7 @@ namespace Light std::vector m_vertices; std::vector m_colors; std::vector m_normals; + std::vector m_texcoords; std::vector m_indices; std::shared_ptr m_vao; @@ -35,6 +37,7 @@ namespace Light const std::vector &vertices, const std::vector &colors, const std::vector &normals, + const std::vector &texcoords, const std::vector &indices); std::shared_ptr get(const std::string &name); diff --git a/Light/include/light/rendering/rendercommand.hpp b/Light/include/light/rendering/rendercommand.hpp index 2da6539e..96ba0c5f 100644 --- a/Light/include/light/rendering/rendercommand.hpp +++ b/Light/include/light/rendering/rendercommand.hpp @@ -9,7 +9,6 @@ namespace Light { - class RenderCommand { public: @@ -23,6 +22,7 @@ namespace Light inline static void drawIndexed(const std::shared_ptr& vao) { s_rendererApi->drawIndexed(vao); } inline static void clear() { s_rendererApi->clear(); } + inline static void clearDepthBit() { s_rendererApi->clearDepthBit(); } inline static void setClearColor(glm::vec4 color) { s_rendererApi->setClearColor(color); } inline static void setBlendFunc(BlendFactor src, BlendFactor dst) { s_rendererApi->setBlendFunc(src, dst); } inline static void setBlendFuncSeperate(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha) diff --git a/Light/include/light/rendering/renderer.hpp b/Light/include/light/rendering/renderer.hpp index c809cc3b..5c9268de 100644 --- a/Light/include/light/rendering/renderer.hpp +++ b/Light/include/light/rendering/renderer.hpp @@ -17,13 +17,32 @@ namespace Light static void onWindowResize(uint32_t width, uint32_t height); static void beginScene(Camera& camera, glm::mat4 camera_view); + static void beginScene(glm::mat4 viewProjectionMatrix, glm::vec3 position); static void endScene(); static void submitLight(const std::vector& lights); static void submitLight(const std::vector& lights); static void submitLight(const std::vector& lights); - static void submit(const std::shared_ptr& shader, const std::shared_ptr& vao, glm::mat4 transform = glm::mat4(1.0f)); - static void submitID(const std::shared_ptr& shader, const std::shared_ptr& vao, glm::mat4 transform = glm::mat4(1.0f), int id = -1); + static void submit(const std::shared_ptr& shader, + const std::shared_ptr& vao, + glm::mat4 transform = glm::mat4(1.0f)); + static void submitID(const std::shared_ptr& shader, + const std::shared_ptr& vao, + glm::mat4 transform = glm::mat4(1.0f), + int id = -1); + static void submitForDirectionalShadow(const std::shared_ptr& shader, + const std::shared_ptr& vao, + glm::mat4 lightSpaceMatrix = glm::mat4(1.0f), + glm::mat4 transform = glm::mat4(1.0f)); + static void submitForCubeShadow(const std::shared_ptr& shader, + const std::shared_ptr& vao, + PointLight light, + glm::mat4 transform = glm::mat4(1.0f)); + static void submitForCubeShadow(const std::shared_ptr& shader, + const std::shared_ptr& vao, + SpotLight light, + glm::mat4 transform = glm::mat4(1.0f)); + static void submitSkybox(const std::shared_ptr& shader, const std::shared_ptr& vao); private: @@ -31,6 +50,7 @@ namespace Light { glm::mat4 viewProjectionMatrix; glm::mat4 viewProjectionSkyboxMatrix; + glm::mat4 lightSpaceMatrix; glm::vec3 cameraPosition; std::vector pointLights; std::vector spotLights; @@ -42,4 +62,4 @@ namespace Light } -#endif // __RENDERER_H__ \ No newline at end of file +#endif // __RENDERER_H__ diff --git a/Light/include/light/rendering/rendererapi.hpp b/Light/include/light/rendering/rendererapi.hpp index 55f7596f..522c532d 100644 --- a/Light/include/light/rendering/rendererapi.hpp +++ b/Light/include/light/rendering/rendererapi.hpp @@ -35,6 +35,7 @@ namespace Light virtual void setViewPort(uint32_t x, uint32_t y, uint32_t width, uint32_t height) = 0; virtual void setClearColor(glm::vec4& color) = 0; virtual void clear() = 0; + virtual void clearDepthBit() = 0; virtual void setBlendFunc(BlendFactor src, BlendFactor dst) = 0; virtual void setBlendFuncSeperate(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha) = 0; diff --git a/Light/include/light/rendering/shader.hpp b/Light/include/light/rendering/shader.hpp index 0afeebd2..87db2572 100644 --- a/Light/include/light/rendering/shader.hpp +++ b/Light/include/light/rendering/shader.hpp @@ -14,6 +14,8 @@ namespace Light virtual const std::string& getName() const = 0; static std::shared_ptr create(const char* shaderPath); + static std::shared_ptr create(const char* VertexShaderPath, const char* FragmentShaderPath); + static std::shared_ptr create(const char* VertexShaderPath, const char* FragmentShaderPath, const char* GeometryShaderPath); virtual void bind() = 0; virtual void unbind() = 0; @@ -46,4 +48,4 @@ namespace Light } -#endif // __SHADER_H__ \ No newline at end of file +#endif // __SHADER_H__ diff --git a/Light/src/platform/opengl/openglframebuffer.cpp b/Light/src/platform/opengl/openglframebuffer.cpp index 50b1ea98..31704c11 100644 --- a/Light/src/platform/opengl/openglframebuffer.cpp +++ b/Light/src/platform/opengl/openglframebuffer.cpp @@ -89,7 +89,18 @@ namespace Light m_colorAttachmentSpecs.emplace_back(attachmentSpec); } - invalidate(); + if (spec.type == FramebufferTextureType::TWO_D) + { + invalidate2D(); + } + else if (spec.type == FramebufferTextureType::CUBEMAP) + { + invalidateCubemap(); + } + else + { + LIGHT_CORE_ERROR("Unrecognized texture type"); + } } OpenGLFramebuffer::~OpenGLFramebuffer() @@ -108,13 +119,13 @@ namespace Light return; } - m_spec.width = width; - m_spec.height = height; + m_spec.width = width; + m_spec.height = height; - invalidate(); + invalidate2D(); } - void OpenGLFramebuffer::invalidate() + void OpenGLFramebuffer::invalidate2D() { if(m_rendererId != 0) { @@ -122,7 +133,6 @@ namespace Light glDeleteTextures((GLsizei)m_colorAttachmentIds.size(), m_colorAttachmentIds.data()); if(m_depthAttachmentId != 0) glDeleteTextures(1, &m_depthAttachmentId); - m_colorAttachmentIds.clear(); m_depthAttachmentId = 0; } @@ -226,8 +236,138 @@ namespace Light TexFormat2OpenGLType(m_depthAttachmentSpec.textureFormat), nullptr ); + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_R, + TexWrap2OpenGLType(m_depthAttachmentSpec.wrapFormat)); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, + TexWrap2OpenGLType(m_depthAttachmentSpec.wrapFormat)); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, + TexWrap2OpenGLType(m_depthAttachmentSpec.wrapFormat)); } + + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_DEPTH_STENCIL_ATTACHMENT, + textureTarget, + m_depthAttachmentId, + 0 + ); + } + + if(m_colorAttachmentSpecs.size() > 1) + { + LIGHT_CORE_ASSERT(m_colorAttachmentSpecs.size() <= 4, "Only 4 color attachments supported"); + + GLenum buffers[4] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }; + glDrawBuffers((GLsizei)m_colorAttachmentSpecs.size(), buffers); + } + else if(m_colorAttachmentSpecs.empty()) + { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + + LIGHT_CORE_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + void OpenGLFramebuffer::invalidateCubemap() + { + if(m_rendererId != 0) + { + glDeleteFramebuffers(1, &m_rendererId); + glDeleteTextures((GLsizei)m_colorAttachmentIds.size(), m_colorAttachmentIds.data()); + if(m_depthAttachmentId != 0) + glDeleteTextures(1, &m_depthAttachmentId); + m_colorAttachmentIds.clear(); + m_depthAttachmentId = 0; + } + + glGenFramebuffers(1, &m_rendererId); + glBindFramebuffer(GL_FRAMEBUFFER, m_rendererId); + + + if(m_colorAttachmentSpecs.size() > 0) + { + GLenum textureTarget = GL_TEXTURE_CUBE_MAP; + if (m_spec.samples != 1) + { + LIGHT_CORE_WARN("multisampling not supported for cubemaps"); + } + m_colorAttachmentIds.resize(m_colorAttachmentSpecs.size()); + glGenTextures((GLsizei)m_colorAttachmentSpecs.size(), m_colorAttachmentIds.data()); + + // Attach all color buffers + for(int i = 0; i < (int)m_colorAttachmentSpecs.size(); i++) + { + glBindTexture(textureTarget, m_colorAttachmentIds[i]); + + for (unsigned int j = 0; j < 6; j++) + glTexImage2D( + GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, + 0, + TexFormat2OpenGLInternalFormat(m_colorAttachmentSpecs[i].textureFormat), + m_spec.width, + m_spec.height, + 0, + TexFormat2OpenGLFormat(m_colorAttachmentSpecs[i].textureFormat), + TexFormat2OpenGLType(m_colorAttachmentSpecs[i].textureFormat), + nullptr + ); + + if(m_colorAttachmentSpecs[i].textureFormat == FramebufferTextureFormat::RED_INTEGER) + { + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else + { + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + glTexParameterfv(textureTarget, GL_TEXTURE_BORDER_COLOR, &(glm::vec4(0,0,0,0)[0])); + + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_R, + TexWrap2OpenGLType(m_colorAttachmentSpecs[i].wrapFormat)); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, + TexWrap2OpenGLType(m_colorAttachmentSpecs[i].wrapFormat)); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, + TexWrap2OpenGLType(m_colorAttachmentSpecs[i].wrapFormat)); + + glFramebufferTexture(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0 + i, + m_colorAttachmentIds[i], + 0 + ); + } + + } + + // Attach depth buffer + if(m_depthAttachmentSpec.textureFormat != FramebufferTextureFormat::None) + { + GLenum textureTarget = GL_TEXTURE_CUBE_MAP; + if (m_spec.samples != 1) + { + LIGHT_CORE_WARN("multisampling not supported for cubemaps"); + } + glGenTextures(1, &m_depthAttachmentId); + glBindTexture(textureTarget, m_depthAttachmentId); + + for (unsigned int j = 0; j < 6; j++) + glTexImage2D( + GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, + 0, + TexFormat2OpenGLInternalFormat(m_depthAttachmentSpec.textureFormat), + m_spec.width, + m_spec.height, + 0, + TexFormat2OpenGLFormat(m_depthAttachmentSpec.textureFormat), + TexFormat2OpenGLType(m_depthAttachmentSpec.textureFormat), + nullptr + ); glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(textureTarget, GL_TEXTURE_WRAP_R, @@ -236,10 +376,11 @@ namespace Light TexWrap2OpenGLType(m_depthAttachmentSpec.wrapFormat)); glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, TexWrap2OpenGLType(m_depthAttachmentSpec.wrapFormat)); + - glFramebufferTexture2D(GL_FRAMEBUFFER, + + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - textureTarget, m_depthAttachmentId, 0 ); @@ -255,9 +396,9 @@ namespace Light else if(m_colorAttachmentSpecs.empty()) { glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); } - LIGHT_CORE_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -342,16 +483,25 @@ namespace Light LIGHT_CORE_ASSERT(attachmentIndex < m_colorAttachmentIds.size(), "Index exceeds number of color attachments"); glActiveTexture(GL_TEXTURE0 + slot); - - if(m_spec.samples > 1) + if (m_spec.type == FramebufferTextureType::TWO_D) { - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_colorAttachmentIds[attachmentIndex]); + if (m_spec.samples > 1) + { + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_colorAttachmentIds[attachmentIndex]); + } + else + { + glBindTexture(GL_TEXTURE_2D, m_colorAttachmentIds[attachmentIndex]); + } + } + else if (m_spec.type == FramebufferTextureType::CUBEMAP) + { + glBindTexture(GL_TEXTURE_CUBE_MAP, m_colorAttachmentIds[attachmentIndex]); } else { - glBindTexture(GL_TEXTURE_2D, m_colorAttachmentIds[attachmentIndex]); + LIGHT_CORE_ERROR("Unrecognized texture type"); } - } void OpenGLFramebuffer::bindDepthAttachmentTexture(uint32_t slot) @@ -360,13 +510,24 @@ namespace Light glActiveTexture(GL_TEXTURE0 + slot); - if(m_spec.samples > 1) + if (m_spec.type == FramebufferTextureType::TWO_D) + { + if (m_spec.samples > 1) + { + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_depthAttachmentId); + } + else + { + glBindTexture(GL_TEXTURE_2D, m_depthAttachmentId); + } + } + else if (m_spec.type == FramebufferTextureType::CUBEMAP) { - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_depthAttachmentId); + glBindTexture(GL_TEXTURE_CUBE_MAP, m_depthAttachmentId); } else { - glBindTexture(GL_TEXTURE_2D, m_depthAttachmentId); + LIGHT_CORE_ERROR("Unrecognized texture type"); } } } diff --git a/Light/src/platform/opengl/openglrendererapi.cpp b/Light/src/platform/opengl/openglrendererapi.cpp index 60e677ee..c79ad7c8 100644 --- a/Light/src/platform/opengl/openglrendererapi.cpp +++ b/Light/src/platform/opengl/openglrendererapi.cpp @@ -42,6 +42,11 @@ namespace Light { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } + + void OpenGLRendererAPI::clearDepthBit() + { + glClear(GL_DEPTH_BUFFER_BIT); + } static GLenum BlendFactor2OpenGLType(BlendFactor factor) { diff --git a/Light/src/platform/opengl/openglshader.cpp b/Light/src/platform/opengl/openglshader.cpp index 6e77b9f4..310d26f2 100644 --- a/Light/src/platform/opengl/openglshader.cpp +++ b/Light/src/platform/opengl/openglshader.cpp @@ -9,14 +9,18 @@ namespace Light { static GLenum findShaderType(std::string typeStr) { - if(typeStr == " fragment") + if (typeStr == " fragment") { return GL_FRAGMENT_SHADER; } - else if(typeStr == " vertex") + else if (typeStr == " vertex") { return GL_VERTEX_SHADER; } + else if (typeStr == " geometry") + { + return GL_GEOMETRY_SHADER; + } LIGHT_CORE_ERROR("Shader type not supported!"); return 0; @@ -27,6 +31,16 @@ namespace Light return std::make_shared(shaderPath); } + std::shared_ptr Shader::create(const char* vertexShaderPath, const char* fragmentShaderPath) + { + return std::make_shared(vertexShaderPath, fragmentShaderPath); + } + + std::shared_ptr Shader::create(const char* vertexShaderPath, const char* fragmentShaderPath, const char* geometryShaderPath) + { + return std::make_shared(vertexShaderPath, fragmentShaderPath, geometryShaderPath); + } + OpenGLShader::OpenGLShader(const char* shaderPath) { std::string pathStr(shaderPath); @@ -34,7 +48,7 @@ namespace Light lastSlash = lastSlash == std::string::npos ? 0 : lastSlash + 1; auto lastDot = pathStr.find_last_of("."); lastDot = lastDot == std::string::npos ? pathStr.length() - 1 : lastDot; - m_name = pathStr.substr(lastSlash, lastDot - lastSlash); + m_name = pathStr.substr(lastSlash, lastDot - lastSlash); std::string code; std::ifstream shaderFile; @@ -64,12 +78,12 @@ namespace Light { LIGHT_CORE_ERROR("Cannot find any shaders"); } - while(true) + while (true) { size_t eol = code.find_first_of(eolToken, i); GLenum shaderType = findShaderType(code.substr(i + typeToken.length(), eol - i - typeToken.length())); auto j = code.find(typeToken, eol); - std::string shaderCode = code.substr(eol + 1,j - eol - 1); + std::string shaderCode = code.substr(eol + 1, j - eol - 1); const char* shaderCodeCstr = shaderCode.c_str(); i = j; uint32_t shaderId; @@ -79,14 +93,176 @@ namespace Light glCompileShader(shaderId); checkCompileErrors(shaderId, shaderType); glAttachShader(m_rendererId, shaderId); - if(j == std::string::npos) + if (j == std::string::npos) break; } glLinkProgram(m_rendererId); checkCompileErrors(m_rendererId, GL_NONE); - for(auto id : shaderIds) + for (auto id : shaderIds) + { + glDeleteShader(id); + } + } + + OpenGLShader::OpenGLShader(const char* vertexShaderPath, const char* fragmentShaderPath) + { + std::string vertexPathStr(vertexShaderPath); + auto lastSlash = vertexPathStr.find_last_of("/\\"); + lastSlash = lastSlash == std::string::npos ? 0 : lastSlash + 1; + auto lastDot = vertexPathStr.find_last_of("."); + lastDot = lastDot == std::string::npos ? vertexPathStr.length() - 1 : lastDot; + m_name = vertexPathStr.substr(lastSlash, lastDot - lastSlash); + + std::string vertexCode; + std::string fragmentCode; + std::ifstream shaderFile; + shaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + shaderFile.open(vertexShaderPath); + std::stringstream sstream; + sstream << shaderFile.rdbuf(); + shaderFile.close(); + vertexCode = sstream.str(); + } + catch (std::ifstream::failure& e) + { + (void)e; // Supress warning about unused variable in release mode (logs don't get compiled in release) + LIGHT_CORE_ERROR("Shader file read failure:" + e.what()); + } + try + { + shaderFile.open(fragmentShaderPath); + std::stringstream sstream; + sstream << shaderFile.rdbuf(); + shaderFile.close(); + fragmentCode = sstream.str(); + } + catch (std::ifstream::failure& e) + { + (void)e; // Supress warning about unused variable in release mode (logs don't get compiled in release) + LIGHT_CORE_ERROR("Shader file read failure:" + e.what()); + } + + m_rendererId = glCreateProgram(); + + std::vector shaderIds; + + const char* shaderCodeCstr = vertexCode.c_str(); + uint32_t shaderId; + shaderId = glCreateShader(GL_VERTEX_SHADER); + shaderIds.push_back(shaderId); + glShaderSource(shaderId, 1, &shaderCodeCstr, NULL); + glCompileShader(shaderId); + checkCompileErrors(shaderId, GL_VERTEX_SHADER); + glAttachShader(m_rendererId, shaderId); + + shaderCodeCstr = fragmentCode.c_str(); + shaderId = glCreateShader(GL_FRAGMENT_SHADER); + shaderIds.push_back(shaderId); + glShaderSource(shaderId, 1, &shaderCodeCstr, NULL); + glCompileShader(shaderId); + checkCompileErrors(shaderId, GL_FRAGMENT_SHADER); + glAttachShader(m_rendererId, shaderId); + + glLinkProgram(m_rendererId); + checkCompileErrors(m_rendererId, GL_NONE); + + for (auto id : shaderIds) + { + glDeleteShader(id); + } + } + + OpenGLShader::OpenGLShader(const char* vertexShaderPath, const char* fragmentShaderPath, const char* geometryShaderPath) + { + std::string vertexPathStr(vertexShaderPath); + auto lastSlash = vertexPathStr.find_last_of("/\\"); + lastSlash = lastSlash == std::string::npos ? 0 : lastSlash + 1; + auto lastDot = vertexPathStr.find_last_of("."); + lastDot = lastDot == std::string::npos ? vertexPathStr.length() - 1 : lastDot; + m_name = vertexPathStr.substr(lastSlash, lastDot - lastSlash); + + std::string vertexCode; + std::string fragmentCode; + std::string geometryCode; + std::ifstream shaderFile; + shaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + shaderFile.open(vertexShaderPath); + std::stringstream sstream; + sstream << shaderFile.rdbuf(); + shaderFile.close(); + vertexCode = sstream.str(); + } + catch (std::ifstream::failure& e) + { + (void)e; // Supress warning about unused variable in release mode (logs don't get compiled in release) + LIGHT_CORE_ERROR("Shader file read failure:" + e.what()); + } + try + { + shaderFile.open(fragmentShaderPath); + std::stringstream sstream; + sstream << shaderFile.rdbuf(); + shaderFile.close(); + fragmentCode = sstream.str(); + } + catch (std::ifstream::failure& e) + { + (void)e; // Supress warning about unused variable in release mode (logs don't get compiled in release) + LIGHT_CORE_ERROR("Shader file read failure:" + e.what()); + } + try + { + shaderFile.open(geometryShaderPath); + std::stringstream sstream; + sstream << shaderFile.rdbuf(); + shaderFile.close(); + geometryCode = sstream.str(); + } + catch (std::ifstream::failure& e) + { + (void)e; // Supress warning about unused variable in release mode (logs don't get compiled in release) + LIGHT_CORE_ERROR("Shader file read failure:" + e.what()); + } + + m_rendererId = glCreateProgram(); + + std::vector shaderIds; + + const char* shaderCodeCstr = vertexCode.c_str(); + uint32_t shaderId; + shaderId = glCreateShader(GL_VERTEX_SHADER); + shaderIds.push_back(shaderId); + glShaderSource(shaderId, 1, &shaderCodeCstr, NULL); + glCompileShader(shaderId); + checkCompileErrors(shaderId, GL_VERTEX_SHADER); + glAttachShader(m_rendererId, shaderId); + + shaderCodeCstr = fragmentCode.c_str(); + shaderId = glCreateShader(GL_FRAGMENT_SHADER); + shaderIds.push_back(shaderId); + glShaderSource(shaderId, 1, &shaderCodeCstr, NULL); + glCompileShader(shaderId); + checkCompileErrors(shaderId, GL_FRAGMENT_SHADER); + glAttachShader(m_rendererId, shaderId); + + shaderCodeCstr = geometryCode.c_str(); + shaderId = glCreateShader(GL_GEOMETRY_SHADER); + shaderIds.push_back(shaderId); + glShaderSource(shaderId, 1, &shaderCodeCstr, NULL); + glCompileShader(shaderId); + checkCompileErrors(shaderId, GL_GEOMETRY_SHADER); + glAttachShader(m_rendererId, shaderId); + + glLinkProgram(m_rendererId); + checkCompileErrors(m_rendererId, GL_NONE); + + for (auto id : shaderIds) { glDeleteShader(id); } @@ -114,13 +290,25 @@ namespace Light { int success; char infoLog[1024]; - if (shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER) + if (shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER || shaderType == GL_GEOMETRY_SHADER) { glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shader, 1024, NULL, infoLog); - std::string type = shaderType == GL_VERTEX_SHADER ? "VERTEX" : "FRAGMENT"; + std::string type; + switch(shaderType) + { + case GL_VERTEX_SHADER: + type = "VERTEX"; + break; + case GL_FRAGMENT_SHADER: + type = "FRAGMENT"; + break; + case GL_GEOMETRY_SHADER: + type = "GEOMETRY"; + break; + } LIGHT_CORE_ERROR("Shader compilation error of type {}: \n{}", type, infoLog); return; } diff --git a/Light/src/rendering/mesh.cpp b/Light/src/rendering/mesh.cpp index f663aff4..8ec451e1 100644 --- a/Light/src/rendering/mesh.cpp +++ b/Light/src/rendering/mesh.cpp @@ -9,35 +9,40 @@ namespace Light Mesh::Mesh(const std::vector &vertices, const std::vector &colors, const std::vector &normals, + const std::vector &texcoords, const std::vector &indices) - : m_vertices(vertices), m_colors(colors), m_normals(normals), m_indices(indices), m_vao(Light::VertexArray::create()) + : m_vertices(vertices), m_colors(colors), m_normals(normals), m_texcoords(texcoords), m_indices(indices), m_vao(Light::VertexArray::create()) { - LIGHT_ASSERT(vertices.size() == colors.size() && vertices.size() == normals.size()); + LIGHT_ASSERT(vertices.size() == colors.size() && vertices.size() == normals.size() && vertices.size()==texcoords.size()); - std::vector vertex_data(vertices.size() * (3 + 4 + 3)); + std::vector vertex_data(vertices.size() * (3 + 4 + 3 + 2)); int num_verts = (int)vertices.size(); for (int i = 0; i < num_verts; i++) { - vertex_data[10 * i] = m_vertices[i].x; - vertex_data[10 * i + 1] = m_vertices[i].y; - vertex_data[10 * i + 2] = m_vertices[i].z; - - vertex_data[10 * i + 3] = m_colors[i].r; - vertex_data[10 * i + 4] = m_colors[i].g; - vertex_data[10 * i + 5] = m_colors[i].b; - vertex_data[10 * i + 6] = m_colors[i].a; - - vertex_data[10 * i + 7] = m_normals[i].x; - vertex_data[10 * i + 8] = m_normals[i].y; - vertex_data[10 * i + 9] = m_normals[i].z; + vertex_data[12 * i] = m_vertices[i].x; + vertex_data[12 * i + 1] = m_vertices[i].y; + vertex_data[12 * i + 2] = m_vertices[i].z; + + vertex_data[12 * i + 3] = m_colors[i].r; + vertex_data[12 * i + 4] = m_colors[i].g; + vertex_data[12 * i + 5] = m_colors[i].b; + vertex_data[12 * i + 6] = m_colors[i].a; + + vertex_data[12 * i + 7] = m_normals[i].x; + vertex_data[12 * i + 8] = m_normals[i].y; + vertex_data[12 * i + 9] = m_normals[i].z; + + vertex_data[12 * i + 10] = m_texcoords[i].x; + vertex_data[12 * i + 11] = m_texcoords[i].y; } Light::BufferLayout layout({ { Light::ShaderDataType::Float3, "a_Position" }, { Light::ShaderDataType::Float4, "a_Color" }, - { Light::ShaderDataType::Float3, "a_Normal" } + { Light::ShaderDataType::Float3, "a_Normal" }, + { Light::ShaderDataType::Float2, "a_Texcoord" } }); std::shared_ptr vbo(Light::VertexBuffer::create(vertex_data.data(), (uint32_t)vertex_data.size() * sizeof(vertex_data[0]))); @@ -63,6 +68,7 @@ namespace Light const std::vector& vertices, const std::vector& colors, const std::vector& normals, + const std::vector& texcoords, const std::vector& indices) { if(m_meshes.find(name) != m_meshes.end()) @@ -70,7 +76,7 @@ namespace Light LIGHT_CORE_ERROR("Mesh already exists"); } - m_meshes[name] = std::make_shared(vertices, colors, normals, indices); + m_meshes[name] = std::make_shared(vertices, colors, normals, texcoords, indices); } std::shared_ptr MeshLibrary::get(const std::string& name) diff --git a/Light/src/rendering/renderer.cpp b/Light/src/rendering/renderer.cpp index f5e35296..18dcdc73 100644 --- a/Light/src/rendering/renderer.cpp +++ b/Light/src/rendering/renderer.cpp @@ -22,6 +22,15 @@ namespace Light glm::mat4 view = glm::mat4(glm::mat3(camera_view)); s_sceneData->viewProjectionSkyboxMatrix = camera.getProjectionMatrix() * view; s_sceneData->cameraPosition = -glm::vec3(camera_view[3] * view); + } + + void Renderer::beginScene(glm::mat4 viewProjectionMatrix, glm::vec3 position) + { + s_sceneData->viewProjectionMatrix = viewProjectionMatrix; + + // glm::mat4 view = glm::mat4(glm::mat3(camera_view)); + // s_sceneData->viewProjectionSkyboxMatrix = camera.getProjectionMatrix() * view; + s_sceneData->cameraPosition = position; } @@ -56,63 +65,51 @@ namespace Light shader->bind(); shader->setUniformMat4("u_viewProjectionMatrix", s_sceneData->viewProjectionMatrix); + shader->setUniformMat4("u_transform", transform); - for (size_t i = 0; i < 4; i++) + shader->setUniformInt("u_id", id); + shader->setUniformInt("u_n_dLights", (int)s_sceneData->directionalLights.size()); + shader->setUniformInt("u_n_pLights", (int)s_sceneData->pointLights.size()); + shader->setUniformInt("u_n_sLights", (int)s_sceneData->spotLights.size()); + + shader->setUniformVec3("cameraPos", s_sceneData->cameraPosition); + + + + for (unsigned int i = 0; i < 4; i++) { - if (i < s_sceneData->pointLights.size()) + if (i < s_sceneData->directionalLights.size()) { - shader->setUniformVec4("u_pointLights[" + std::to_string(i) + "].position", glm::vec4(s_sceneData->pointLights[i].position, 1.0)); - shader->setUniformVec4("u_pointLights[" + std::to_string(i) + "].color", glm::vec4(s_sceneData->pointLights[i].color, 1.0)); - shader->setUniformFloat("u_pointLights[" + std::to_string(i) + "].range", s_sceneData->pointLights[i].range); - } else + shader->setUniformInt("u_dirLights[" + std::to_string(i) + "].depthMap", i + 4); + shader->setUniformVec4("u_dirLights[" + std::to_string(i) + "].emission_color", glm::vec4(s_sceneData->directionalLights[i].color, 1.0)); + shader->setUniformVec3("u_dirLights[" + std::to_string(i) + "].direction", s_sceneData->directionalLights[i].direction); + shader->setUniformMat4("u_dirLights[" + std::to_string(i) + "].lightSpaceMatrix", s_sceneData->directionalLights[i].getSpaceMatrix()); + } + else { - shader->setUniformVec4("u_pointLights[" + std::to_string(i) + "].position", glm::vec4(0.0, 0.0, 0.0, 1.0)); - shader->setUniformVec4("u_pointLights[" + std::to_string(i) + "].color", glm::vec4(0.0, 0.0, 0.0, 1.0)); - shader->setUniformFloat("u_pointLights[" + std::to_string(i) + "].range", 0.001f); + shader->setUniformInt("u_dirLights[" + std::to_string(i) + "].depthMap", i + 4); + //Note: Skybox texture(Cubemap) is currently bound to tex unit 0 so Sampler2D depthMap cannot have value 0 + //Possible fix: unbind texture after use } } - - for (size_t i = 0; i < 4; i++) + for (unsigned int i = 0; i < s_sceneData->pointLights.size(); i++) { - if (i < s_sceneData->spotLights.size()) - { - shader->setUniformVec4("u_spotLights[" + std::to_string(i) + "].position", glm::vec4(s_sceneData->spotLights[i].position, 1.0)); - shader->setUniformVec4("u_spotLights[" + std::to_string(i) + "].color", glm::vec4(s_sceneData->spotLights[i].color, 1.0)); - shader->setUniformVec4("u_spotLights[" + std::to_string(i) + "].direction", glm::vec4(s_sceneData->spotLights[i].direction, 1.0)); - shader->setUniformFloat("u_spotLights[" + std::to_string(i) + "].innerCutoff", s_sceneData->spotLights[i].innerCutoff); - shader->setUniformFloat("u_spotLights[" + std::to_string(i) + "].outerCutoff", s_sceneData->spotLights[i].outerCutoff); - shader->setUniformFloat("u_spotLights[" + std::to_string(i) + "].range", s_sceneData->spotLights[i].range); - } else - { - shader->setUniformVec4("u_spotLights[" + std::to_string(i) + "].position", glm::vec4(0.0, 0.0, 0.0, 1.0)); - shader->setUniformVec4("u_spotLights[" + std::to_string(i) + "].color", glm::vec4(0.0, 0.0, 0.0, 1.0)); - shader->setUniformVec4("u_spotLights[" + std::to_string(i) + "].direction", glm::vec4(0.0, 0.0, 0.0, 1.0)); - shader->setUniformFloat("u_spotLights[" + std::to_string(i) + "].innerCutoff", 0.0); - shader->setUniformFloat("u_spotLights[" + std::to_string(i) + "].outerCutoff", 0.0); - shader->setUniformFloat("u_spotLights[" + std::to_string(i) + "].range", 0.001f); - } + shader->setUniformInt("u_pointLights[" + std::to_string(i) + "].depthCubemap", i + 8); + shader->setUniformVec4("u_pointLights[" + std::to_string(i) + "].emission_color", glm::vec4(s_sceneData->pointLights[i].color, 1.0)); + shader->setUniformVec3("u_pointLights[" + std::to_string(i) + "].position", s_sceneData->pointLights[i].position); + shader->setUniformFloat("u_pointLights[" + std::to_string(i) + "].far_plane", s_sceneData->pointLights[i].range); } - - for (size_t i = 0; i < 4; i++) + for (unsigned int i = 0; i < s_sceneData->spotLights.size(); i++) { - if (i < s_sceneData->directionalLights.size()) - { - shader->setUniformVec4("u_directionalLights[" + std::to_string(i) + "].direction", glm::vec4(s_sceneData->directionalLights[i].direction, 0.0)); - shader->setUniformVec4("u_directionalLights[" + std::to_string(i) + "].color", glm::vec4(s_sceneData->directionalLights[i].color, 1.0)); - } else - { - shader->setUniformVec4("u_directionalLights[" + std::to_string(i) + "].direction", glm::vec4(0.0, 0.0, 0.0, 0.0)); - shader->setUniformVec4("u_directionalLights[" + std::to_string(i) + "].color", glm::vec4(0.0, 0.0, 0.0, 1.0)); - } + shader->setUniformInt("u_spotLights[" + std::to_string(i) + "].depthCubemap", i + 12); + shader->setUniformVec4("u_spotLights[" + std::to_string(i) + "].emission_color", glm::vec4(s_sceneData->spotLights[i].color, 1.0)); + shader->setUniformVec3("u_spotLights[" + std::to_string(i) + "].position", s_sceneData->spotLights[i].position); + shader->setUniformVec3("u_spotLights[" + std::to_string(i) + "].direction", s_sceneData->spotLights[i].direction); + shader->setUniformFloat("u_spotLights[" + std::to_string(i) + "].far_plane", s_sceneData->spotLights[i].range); + shader->setUniformFloat("u_spotLights[" + std::to_string(i) + "].innerCutoff", s_sceneData->spotLights[i].innerCutoff); + shader->setUniformFloat("u_spotLights[" + std::to_string(i) + "].outerCutoff", s_sceneData->spotLights[i].outerCutoff); } - shader->setUniformVec3("cameraPosition", s_sceneData->cameraPosition); - shader->setUniformInt("u_numPointLights", (int)s_sceneData->pointLights.size()); - shader->setUniformInt("u_id", id); - - shader->setUniformMat4("u_transform", transform); - shader->setUniformMat3("u_normal", glm::mat3(glm::transpose(glm::inverse(transform)))); - RenderCommand::drawIndexed(vao); shader->unbind(); @@ -140,4 +137,59 @@ namespace Light vao->unbind(); } -} \ No newline at end of file + void Renderer::submitForDirectionalShadow(const std::shared_ptr& shader, const std::shared_ptr& vao, glm::mat4 lightSpaceMatrix, glm::mat4 transform) + { + vao->bind(); + + shader->bind(); + + // (void)lightSpaceMatrix; + shader->setUniformMat4("u_lightSpaceMatrix", lightSpaceMatrix); + + shader->setUniformMat4("u_transform", transform); + + RenderCommand::drawIndexed(vao); + + shader->unbind(); + + vao->unbind(); + } + void Renderer::submitForCubeShadow(const std::shared_ptr& shader, const std::shared_ptr& vao, PointLight light, glm::mat4 transform) + { + vao->bind(); + + shader->bind(); + + for (unsigned int i = 0; i < 6; ++i) + shader->setUniformMat4("shadowMatrices[" + std::to_string(i) + "]", light.getSpaceMatrices()[i]); + + shader->setUniformMat4("u_transform", transform); + shader->setUniformFloat("far_plane", light.range); + shader->setUniformVec3("lightPos", light.position); + + RenderCommand::drawIndexed(vao); + + shader->unbind(); + + vao->unbind(); + } + void Renderer::submitForCubeShadow(const std::shared_ptr& shader, const std::shared_ptr& vao, SpotLight light, glm::mat4 transform) + { + vao->bind(); + + shader->bind(); + + for (unsigned int i = 0; i < 6; ++i) + shader->setUniformMat4("shadowMatrices[" + std::to_string(i) + "]", light.getSpaceMatrices()[i]); + + shader->setUniformMat4("u_transform", transform); + shader->setUniformFloat("far_plane", light.range); + shader->setUniformVec3("lightPos", light.position); + + RenderCommand::drawIndexed(vao); + + shader->unbind(); + + vao->unbind(); + } +} diff --git a/LightFramework/include/ecs/components.hpp b/LightFramework/include/ecs/components.hpp index 7ac2e440..25b66d26 100644 --- a/LightFramework/include/ecs/components.hpp +++ b/LightFramework/include/ecs/components.hpp @@ -43,6 +43,29 @@ namespace Light { return glm::translate(glm::mat4(1.0f), position) * glm::toMat4(glm::quat(rotation)) * glm::scale(glm::mat4(1.0f), glm::abs(scale)); } + inline glm::mat4 getViewMatrix() const + { + return glm::lookAt(position, glm::vec3(0.0f), glm::vec3(0.0,1.0,0.0)); + } + inline glm::mat4 getModel() const + { + glm::mat4 model = glm::mat4(1.0); + model = glm::translate(model, position); + model = glm::scale(model, scale); + return model; + } + inline glm::mat4 getProjectionMatrix() const + { + return glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 1.0f, 7.5f); + } + inline glm::mat4 getSpaceMatrix() const + { + return getProjectionMatrix() * getViewMatrix(); + } + inline glm::mat4 getOrientationMatrix() const + { + return glm::toMat4(glm::quat(rotation)); + } glm::vec3 position; glm::vec3 rotation; @@ -52,6 +75,9 @@ namespace Light struct MeshRendererComponent : public Component { MeshRendererComponent(const char* path); + MeshRendererComponent(const char* vertexPath, const char* fragmentPath); + MeshRendererComponent(const char* vertexPath, const char* fragmentPath, const char* geometryPath); + inline void bind() { shader->bind(); diff --git a/LightFramework/include/rendering/scenerenderer.hpp b/LightFramework/include/rendering/scenerenderer.hpp index efdf3ce3..1db102f8 100644 --- a/LightFramework/include/rendering/scenerenderer.hpp +++ b/LightFramework/include/rendering/scenerenderer.hpp @@ -27,7 +27,12 @@ namespace Light { SceneRenderer(); ~SceneRenderer() {}; - void renderEditor(std::shared_ptr scene, EditorCamera &camera); + void renderEditor(std::shared_ptr scene, EditorCamera& camera); + + void renderShadows(std::shared_ptr scene, DirectionalLight light, int index); + void renderShadows(std::shared_ptr scene, PointLight light, int index); + void renderShadows(std::shared_ptr scene, SpotLight light, int index); + void renderOutline(std::shared_ptr scene, Entity entity); void onViewportResize(int width, int height); @@ -43,12 +48,18 @@ namespace Light { std::shared_ptr m_skybox_shader; std::shared_ptr m_outline_shader; std::shared_ptr m_outline_temp_shader; + std::shared_ptr m_depth_shader; + std::shared_ptr m_depth_cube_shader; std::shared_ptr m_skybox_mesh; std::shared_ptr m_outline_mesh; std::shared_ptr m_framebuffer; + std::shared_ptr m_depthFramebuffer[4]; + std::shared_ptr m_pointDepthCubeFramebuffer[4]; + std::shared_ptr m_spotDepthCubeFramebuffer[4]; std::shared_ptr m_outlineFramebuffer; std::shared_ptr m_tempFramebuffer; + //TODO: #63 Directly use texture instead of a dummy framebuffer }; } diff --git a/LightFramework/src/ecs/components.cpp b/LightFramework/src/ecs/components.cpp index 2a46a501..7256dcb7 100644 --- a/LightFramework/src/ecs/components.cpp +++ b/LightFramework/src/ecs/components.cpp @@ -6,10 +6,15 @@ namespace Light { - MeshRendererComponent::MeshRendererComponent(const char *path) : shader(Light::Shader::create(path)) {} + MeshRendererComponent::MeshRendererComponent(const char *path): + shader(Light::Shader::create(path)) {} + MeshRendererComponent::MeshRendererComponent(const char* vertexPath, const char* fragmentPath): + shader(Light::Shader::create(vertexPath, fragmentPath)) {} + MeshRendererComponent::MeshRendererComponent(const char* vertexPath, const char* fragmentPath, const char* geometryPath): + shader(Light::Shader::create(vertexPath, fragmentPath, geometryPath)) {} MeshComponent::MeshComponent(std::shared_ptr mesh) : mesh(mesh) { } -} \ No newline at end of file +} diff --git a/LightFramework/src/rendering/scenerenderer.cpp b/LightFramework/src/rendering/scenerenderer.cpp index 53d9bc85..f84bdb6c 100644 --- a/LightFramework/src/rendering/scenerenderer.cpp +++ b/LightFramework/src/rendering/scenerenderer.cpp @@ -6,8 +6,33 @@ namespace Light { + #define TEXTURE_UNIT_START 4; + SceneRenderer::SceneRenderer() { + // Initialize the depth framebuffer + Light::FramebufferSpec fbspecDepth; + fbspecDepth.attachments = { + { Light::FramebufferTextureFormat::Depth, Light::TextureWrap::CLAMP_TO_BORDER } + }; + fbspecDepth.width = 1280; + fbspecDepth.height = 1280; + for(int i=0;i<4;i++) + m_depthFramebuffer[i] = Light::Framebuffer::create(fbspecDepth); + + Light::FramebufferSpec fbspecDepthCube; + fbspecDepthCube.attachments = { + { Light::FramebufferTextureFormat::Depth, Light::TextureWrap::CLAMP_TO_BORDER } + }; + fbspecDepthCube.width = 1280; + fbspecDepthCube.height = 1280; + fbspecDepthCube.type = Light::FramebufferTextureType::CUBEMAP; + for (int i = 0; i < 4; i++) + { + m_pointDepthCubeFramebuffer[i] = Light::Framebuffer::create(fbspecDepthCube); + m_spotDepthCubeFramebuffer[i] = Light::Framebuffer::create(fbspecDepthCube); + } + // Initialize the outline framebuffer Light::FramebufferSpec fbspecOutline; fbspecOutline.attachments = { @@ -27,6 +52,9 @@ namespace Light { fbspecTemp.height = 720; m_tempFramebuffer = Light::Framebuffer::create(fbspecTemp); + m_depth_shader = Light::Shader::create("assets/shaders/depth.glsl"); + m_depth_cube_shader = Light::Shader::create("assets/shaders/depthCube.glsl"); + // Skybox Mesh (Cube) m_skybox_mesh.reset(VertexArray::create()); @@ -126,16 +154,65 @@ namespace Light { m_tempFramebuffer->resize(width, height); } - void SceneRenderer::renderEditor(std::shared_ptr scene, EditorCamera &camera) + void SceneRenderer::renderShadows(std::shared_ptr scene, DirectionalLight light, int index) { - m_framebuffer->bind(); - Light::RenderCommand::setClearColor({0.5f, 0.1f, 0.1f, 1.0f}); - Light::RenderCommand::clear(); + m_depthFramebuffer[index]->bind(); + Light::RenderCommand::clearDepthBit(); + - m_framebuffer->clearAttachment(1, 0); + // Render depth of entities + { + auto view = scene->m_registry.view(); + for (auto& entity : view) + { + auto [shader, mesh, transform] = view.get(entity); + Renderer::submitForDirectionalShadow(m_depth_shader, mesh.mesh->getVao(), light.getSpaceMatrix(), transform.getTransform()); + } + } + Light::Renderer::endScene(); + m_depthFramebuffer[index]->unbind(); + } - Light::Renderer::beginScene(camera, camera.getViewMatrix()); + void SceneRenderer::renderShadows(std::shared_ptr scene, PointLight light, int index) + { + m_pointDepthCubeFramebuffer[index]->bind(); + Light::RenderCommand::clearDepthBit(); + + // Render depth of entities + { + auto view = scene->m_registry.view(); + for (auto& entity : view) + { + auto [shader, mesh, transform] = view.get(entity); + Renderer::submitForCubeShadow(m_depth_cube_shader, mesh.mesh->getVao(), light, transform.getTransform()); + } + } + Light::Renderer::endScene(); + m_pointDepthCubeFramebuffer[index]->unbind(); + } + + void SceneRenderer::renderShadows(std::shared_ptr scene, SpotLight light, int index) + { + m_spotDepthCubeFramebuffer[index]->bind(); + Light::RenderCommand::clearDepthBit(); + + + // Render depth of entities + { + auto view = scene->m_registry.view(); + for (auto& entity : view) + { + auto [shader, mesh, transform] = view.get(entity); + Renderer::submitForCubeShadow(m_depth_cube_shader, mesh.mesh->getVao(), light, transform.getTransform()); + } + } + Light::Renderer::endScene(); + m_spotDepthCubeFramebuffer[index]->unbind(); + } + + void SceneRenderer::renderEditor(std::shared_ptr scene, EditorCamera &camera) + { std::vector pointLights; std::vector spotLights; std::vector directionalLights; @@ -149,19 +226,48 @@ namespace Light { switch (light.m_lightType) { case LightType::Directional: - directionalLights.push_back({glm::normalize(transform.getTransform() * glm::vec4(0.0, 0.0, 1.0, 0.0)), light.m_lightColor}); + directionalLights.push_back({ transform.position, + glm::normalize(transform.getTransform() * glm::vec4(0.0, 0.0, 1.0, 0.0)), + light.m_lightColor}); break; case LightType::Point: - pointLights.push_back({transform.position, light.m_lightColor, light.m_range}); + pointLights.push_back({ transform.position, light.m_lightColor, light.m_range }); break; case LightType::Spot: - spotLights.push_back({transform.position, light.m_lightColor, glm::normalize(transform.getTransform() * glm::vec4(0.0, 0.0, 1.0, 0.0)), (float)glm::cos(glm::radians(light.m_inner)), (float)glm::cos(glm::radians(light.m_outer)), light.m_range}); + spotLights.push_back({ transform.position, + light.m_lightColor, + glm::normalize(transform.getTransform() * glm::vec4(0.0, 0.0, 1.0, 0.0)), + (float)glm::cos(glm::radians(light.m_inner)), + (float)glm::cos(glm::radians(light.m_outer)), + light.m_range }); break; default: break; } } } + LIGHT_CORE_ASSERT(directionalLights.size() <= 4, "Only 4 lights of each type supported now"); + LIGHT_CORE_ASSERT(pointLights.size() <= 4, "Only 4 lights of each type supported now"); + LIGHT_CORE_ASSERT(spotLights.size() <= 4, "Only 4 lights of each type supported now"); + + for (unsigned int i = 0; i < directionalLights.size(); i++) + renderShadows(scene, directionalLights[i], i); + for (unsigned int i = 0; i < pointLights.size(); i++) + renderShadows(scene, pointLights[i], i); + for (unsigned int i = 0; i < spotLights.size(); i++) + renderShadows(scene, spotLights[i], i); + + // Render scene + m_framebuffer->bind(); + + Light::RenderCommand::setClearColor({0.5f, 0.1f, 0.1f, 1.0f}); + Light::RenderCommand::clear(); + + m_framebuffer->clearAttachment(1, 0); + + Light::Renderer::beginScene(camera, camera.getViewMatrix()); + + Renderer::submitLight(directionalLights); Renderer::submitLight(pointLights); Renderer::submitLight(spotLights); @@ -170,6 +276,14 @@ namespace Light { scene->m_skybox->bind(); Renderer::submitSkybox(m_skybox_shader, m_skybox_mesh); + // binding to texture units + + for (int i = 0; i < 4; i++) + { + m_depthFramebuffer[i]->bindDepthAttachmentTexture(i + 4); + m_pointDepthCubeFramebuffer[i]->bindDepthAttachmentTexture(i + 8); + m_spotDepthCubeFramebuffer[i]->bindDepthAttachmentTexture(i + 12); + } // Render entities { auto view = scene->m_registry.view(); @@ -177,7 +291,6 @@ namespace Light { { auto [shader, mesh, transform] = view.get(entity); Renderer::submitID(shader.shader, mesh.mesh->getVao(), transform.getTransform(), (uint32_t)entity); - } }