diff --git a/include/Engine/Rendering/Renderer.h b/include/Engine/Rendering/Renderer.h index b1b76468..b227f110 100644 --- a/include/Engine/Rendering/Renderer.h +++ b/include/Engine/Rendering/Renderer.h @@ -11,18 +11,30 @@ #include "FrameBuffer.h" #include "../Core/World.h" +#define TILE_SIZE 16 +#define NUM_LIGHTS 3 + + +enum lightType +{ + Point, + Spot, + Directional, + Area +}; + class Renderer : public IRenderer { public: - virtual void Initialize() override; - virtual void Update(double dt) override; - virtual void Draw(RenderQueueCollection& rq) override; + virtual void Initialize() override; + virtual void Update(double dt) override; + virtual void Draw(RenderQueueCollection& rq) override; private: - //----------------------Variables----------------------// - Texture* m_ErrorTexture; - Texture* m_WhiteTexture; - float m_CameraMoveSpeed; + //----------------------Variables----------------------// + Texture* m_ErrorTexture; + Texture* m_WhiteTexture; + float m_CameraMoveSpeed; FrameBuffer m_PickingBuffer; GLuint m_PickingTexture; GLuint m_DepthBuffer; @@ -32,26 +44,76 @@ private: Model* m_UnitSphere; - + std::unordered_map m_PickingColorsToEntity; - //----------------------Functions----------------------// - void InitializeWindow(); - void InitializeShaders(); + //----------------------Functions----------------------// + void InitializeWindow(); + void InitializeShaders(); void InitializeTextures(); void InitializeFrameBuffers(); + void InitializeSSBOs(); //TODO: Renderer: Get InputUpdate out of renderer - void InputUpdate(double dt); + void InputUpdate(double dt); void PickingPass(RenderQueueCollection& rq); void DrawScreenQuad(GLuint textureToDraw); void DrawScene(RenderQueueCollection& rq); + //----------------------Forward+-----------------------// + void CalculateFrustum(); + void CullLights(); + //Frustum + struct Plane + { + glm::vec3 Normal; + float d; + }; + + struct Frustum + { + Plane plane[4]; + }; + Frustum m_Frustums[80*45]; //TODO: Renderer: Make this change with resolution + + //Lights + void TEMPCreateLights(); + //TODO: Renderer: Add Directionllights, spotlights and area lights to this as type. + struct PointLight { + glm::vec4 Position = glm::vec4(0.f); + glm::vec4 Color = glm::vec4(1.f); + float Radius = 5.f; + float Intensity = 0.8f; + float Falloff = 0.3f; + float Padding = 1337; + }; + PointLight m_PointLights[NUM_LIGHTS]; + + struct LightGrid { + int Amount; + int Start; + glm::vec2 Padding; + }; + LightGrid m_LightGrid[80*45]; + + int m_LightOffset = 0; + + int m_LightIndex[80*45*200]; + + //-------------------------SSBO------------------------// + GLuint m_FrustumSSBO; + GLuint m_LightSSBO; + GLuint m_LightGridSSBO; + GLuint m_LightOffsetSSBO; + GLuint m_LightIndexSSBO; void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type); //--------------------ShaderPrograms-------------------// ShaderProgram m_BasicForwardProgram; ShaderProgram m_PickingProgram; ShaderProgram m_DrawScreenQuadProgram; + ShaderProgram m_CalculateFrustumProgram; + ShaderProgram m_LightCullProgram; + }; #endif \ No newline at end of file diff --git a/resources/Shaders/GridFrustum.comp.glsl b/resources/Shaders/GridFrustum.comp.glsl new file mode 100644 index 00000000..64f4d467 --- /dev/null +++ b/resources/Shaders/GridFrustum.comp.glsl @@ -0,0 +1,118 @@ +#version 430 + +#define TILE_SIZE 16 +#define NUM_TILES 3600 + +uniform mat4 P; +uniform vec2 ScreenDimensions; + +struct Plane { + vec3 Normal; + float d; +}; +struct Frustum { + Plane Planes[4]; +}; + +layout (std430, binding = 1) buffer FrustumBuffer +{ + Frustum Data[80*45]; +} Frustums; + + +struct PlaneNormals { + vec3 Normal1; + float pad1; + vec3 Normal2; + float Pad2; +}; + +struct FrustumNormals { + PlaneNormals Planes[4]; +}; + +layout (std430, binding = 2) buffer PlaneNormalBuffer +{ + FrustumNormals Data[80*45]; +} FrustumNorm; + + +vec4 ConvertToView(vec4 ScreenCoords) +{ + vec2 normalizedScreenCoords = ScreenCoords.xy / ScreenDimensions; + vec4 clipSpace = vec4( vec2(normalizedScreenCoords.x, normalizedScreenCoords.y) * 2.0 - 1.0, ScreenCoords.z, ScreenCoords.w); + vec4 view = inverse(P) * clipSpace; + view = view / view.w; + return view; +} + +Plane ComputePlane( vec3 p0, vec3 p1, vec3 p2 ) +{ + Plane plane; + + vec3 v0 = p1 - p0; + vec3 v2 = p2 - p0; + + plane.Normal = normalize( cross( v0, v2 ) ); + plane.d = dot( vec3(plane.Normal), p0 ); // Always 0 probably + return plane; +} + +layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; +void main () +{ + if(gl_GlobalInvocationID.x * TILE_SIZE < ScreenDimensions.x && gl_GlobalInvocationID.y * TILE_SIZE < ScreenDimensions.y) { + //Top-Left = 0 | Top-Right = 1 + //Bottom-Left = 2 | Bottom-Right = 3 + vec4 ScreenCoords[4]; + ScreenCoords[0] = vec4(gl_GlobalInvocationID.x * TILE_SIZE, (gl_GlobalInvocationID.y + 1 ) * TILE_SIZE, -1.0, 1.0); // Z-axis might need to be 1 + ScreenCoords[1] = vec4((gl_GlobalInvocationID.x + 1) * TILE_SIZE, (gl_GlobalInvocationID.y + 1) * TILE_SIZE, -1.0, 1.0); + ScreenCoords[2] = vec4(gl_GlobalInvocationID.x * TILE_SIZE, (gl_GlobalInvocationID.y) * TILE_SIZE, -1.0, 1.0); + ScreenCoords[3] = vec4((gl_GlobalInvocationID.x + 1) * TILE_SIZE, (gl_GlobalInvocationID.y) * TILE_SIZE, -1.0, 1.0); + + vec3 ViewVectors[4]; + for(int i = 0; i < 4; i++) { + ViewVectors[i] = vec3(ConvertToView(ScreenCoords[i])); + } + + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[0].Normal1 = (ViewVectors[2]); + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[0].Normal2 = (ViewVectors[0]); + + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[1].Normal1 = (ViewVectors[1]); + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[1].Normal2 = (ViewVectors[3]); + + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[2].Normal1 = (ViewVectors[0]); + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[2].Normal2 = (ViewVectors[1]); + + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[3].Normal1 = (ViewVectors[3]); + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[3].Normal2 = (ViewVectors[2]); + /* + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[0].Normal1 = vec3(ScreenCoords[2]); + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[0].Normal2 = vec3(ScreenCoords[0]); + + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[1].Normal1 = vec3(ScreenCoords[1]); + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[1].Normal2 = vec3(ScreenCoords[3]); + + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[2].Normal1 = vec3(ScreenCoords[0]); + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[2].Normal2 = vec3(ScreenCoords[1]); + + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[3].Normal1 = vec3(ScreenCoords[3]); + FrustumNorm.Data[gl_GlobalInvocationID.x + (80 * gl_GlobalInvocationID.y)].Planes[3].Normal2 = vec3(ScreenCoords[2]); + +*/ + + + vec3 EyePos = vec3(0,0,0); + + Frustum f; + f.Planes[0] = ComputePlane(EyePos, ViewVectors[2], ViewVectors[0]); + f.Planes[1] = ComputePlane(EyePos, ViewVectors[1], ViewVectors[3]); + f.Planes[2] = ComputePlane(EyePos, ViewVectors[0], ViewVectors[1]); + f.Planes[3] = ComputePlane(EyePos, ViewVectors[3], ViewVectors[2]); + + + + + Frustums.Data[gl_GlobalInvocationID.x + gl_GlobalInvocationID.y*80] = f; + } +} \ No newline at end of file diff --git a/resources/Shaders/cullLights.comp.glsl b/resources/Shaders/cullLights.comp.glsl new file mode 100644 index 00000000..72d36ec1 --- /dev/null +++ b/resources/Shaders/cullLights.comp.glsl @@ -0,0 +1,71 @@ +#version 430 + +//in uvec3 gl_NumWorkGroups; +//in uvec3 gl_WorkGroupID; +//in uvec3 gl_LocalInvocationID; +//in uvec3 gl_GlobalInvocationID; +//in uint gl_LocalInvocationIndex; + +#define NUM_LIGHTS 3 +#define MAX_LIGHTS_PER_TILE 200 +#define NUM_TILES 3600 + +struct PointLight { + vec4 Position; + vec4 Color; + float Radius; + float Intensity; + vec2 Pad; +}; + +layout (std430, binding = 0) buffer PointLightBuffer +{ + PointLight PointLights[NUM_LIGHTS]; +}; + +struct Plane { + vec3 Normal; + float d; +}; + +struct Frustum { + Plane Planes[4]; +}; + +layout (std430, binding = 1) buffer FrustumBuffer +{ + Frustum Frustums[80*45]; +}; + +layout (std430, binding = 3) buffer LightIndexBuffer +{ + float LightIndexList[MAX_LIGHTS_PER_TILE*NUM_TILES]; +}; + +struct LightGrid +{ + int Amount; + int Start; + vec2 padding; +}; + +layout (std430, binding = 4) buffer LightGridBuffer +{ + LightGrid LightGrids[NUM_TILES]; +}; + +layout (std430, binding = 5) buffer LightOffsetCounter +{ + int GlobalLightOffsetCounter; +}; + + +layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; +void main () +{ + if(gl_LocalInvocationIndex == 0) { + LightIndexList[int(gl_WorkGroupID.x) + int(gl_WorkGroupID.y)*80] = int(gl_WorkGroupID.x); + } + + +} \ No newline at end of file diff --git a/src/Engine/Rendering/Renderer.cpp b/src/Engine/Rendering/Renderer.cpp index aba512fd..36f260c5 100644 --- a/src/Engine/Rendering/Renderer.cpp +++ b/src/Engine/Rendering/Renderer.cpp @@ -10,11 +10,17 @@ void Renderer::Initialize() if (m_Camera == nullptr) { m_Camera = m_DefaultCamera; } + TEMPCreateLights(); glfwSwapInterval(m_VSYNC); InitializeShaders(); InitializeTextures(); InitializeFrameBuffers(); + InitializeSSBOs(); + CalculateFrustum(); + + + m_ScreenQuad = ResourceManager::Load("Models/Core/ScreenQuad.obj"); @@ -80,6 +86,13 @@ void Renderer::InitializeShaders() m_DrawScreenQuadProgram.Compile(); m_DrawScreenQuadProgram.Link(); + m_CalculateFrustumProgram.AddShader(std::shared_ptr(new ComputeShader("Shaders/GridFrustum.comp.glsl"))); + m_CalculateFrustumProgram.Compile(); + m_CalculateFrustumProgram.Link(); + + m_CalculateFrustumProgram.AddShader(std::shared_ptr(new ComputeShader("Shaders/cullLights.comp.glsl"))); + m_CalculateFrustumProgram.Compile(); + m_CalculateFrustumProgram.Link(); } void Renderer::InputUpdate(double dt) @@ -169,7 +182,8 @@ void Renderer::Draw(RenderQueueCollection& rq) { //TODO: Renderer: Kanske borde vara längst upp i update. PickingPass(rq); - DrawScreenQuad(m_PickingTexture); + //DrawScreenQuad(m_PickingTexture); + //CullLights(); DrawScene(rq); glfwSwapBuffers(m_Window); @@ -278,7 +292,6 @@ void Renderer::PickingPass(RenderQueueCollection& rq) } - void Renderer::DrawScreenQuad(GLuint textureToDraw) { glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -300,7 +313,6 @@ void Renderer::DrawScreenQuad(GLuint textureToDraw) , GL_UNSIGNED_INT, 0, m_ScreenQuad->TextureGroups[0].StartIndex); } - void Renderer::InitializeTextures() { m_ErrorTexture=ResourceManager::Load("Textures/Core/ErrorTexture.png"); @@ -332,8 +344,6 @@ void Renderer::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filterin GLERROR("Texture initialization failed"); } - - void Renderer::InitializeFrameBuffers()//TODO: Renderer: Get this to a better location, as its really big { glGenRenderbuffers(1, &m_DepthBuffer); @@ -343,4 +353,79 @@ void Renderer::InitializeFrameBuffers()//TODO: Renderer: Get this to a better lo m_PickingBuffer.AddResource(std::shared_ptr(new RenderBuffer(&m_DepthBuffer, GL_DEPTH_ATTACHMENT))); m_PickingBuffer.AddResource(std::shared_ptr(new Texture2D(&m_PickingTexture, GL_COLOR_ATTACHMENT0))); m_PickingBuffer.Generate(); -} \ No newline at end of file +} + +void Renderer::InitializeSSBOs() +{ + glGenBuffers(1, &m_FrustumSSBO); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_FrustumSSBO); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_Frustums), &m_Frustums, GL_DYNAMIC_COPY); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + + GLERROR("m_FrustumSSBO"); + + glGenBuffers(1, &m_LightSSBO); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightSSBO); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_PointLights), &m_PointLights, GL_DYNAMIC_COPY); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + + GLERROR("m_LightSSBO"); + + + glGenBuffers(1, &m_LightGridSSBO); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightGridSSBO); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_LightGrid), &m_LightGrid, GL_DYNAMIC_COPY); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + + GLERROR("m_LightGridSSBO"); + + + glGenBuffers(1, &m_LightOffsetSSBO); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightOffsetSSBO); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_LightOffset), &m_LightOffset, GL_DYNAMIC_COPY); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + + GLERROR("m_LightOffsetSSBO"); + + + glGenBuffers(1, &m_LightIndexSSBO); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightIndexSSBO); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_LightIndex), &m_LightIndex, GL_DYNAMIC_COPY); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + + GLERROR("m_LightIndexSSBO"); + +} + +void Renderer::CalculateFrustum() +{ + m_CalculateFrustumProgram.Bind(); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_FrustumSSBO); + glUniformMatrix4fv(glGetUniformLocation(m_CalculateFrustumProgram.GetHandle(), "P"), 1, false, glm::value_ptr(m_Camera->ProjectionMatrix())); + glUniform2f(glGetUniformLocation(m_CalculateFrustumProgram.GetHandle(), "ScreenDimensions"), m_Resolution.Width, m_Resolution.Height); + glDispatchCompute(m_Resolution.Width / TILE_SIZE, m_Resolution.Height / TILE_SIZE, 1); + GLERROR("CalculateFrustum Error"); + +} + +void Renderer::TEMPCreateLights() +{ + for (int i = 0; i < NUM_LIGHTS; i++) { + m_PointLights[i].Position = glm::vec4(i, 0.f, 0.f, 0.f); + m_PointLights[i].Color = glm::vec4(1.f, 0.5f, 0.f + i*0.1f, 1.f); + } +} + +void Renderer::CullLights() +{ + m_LightCullProgram.Bind(); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_FrustumSSBO); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_LightSSBO); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightGridSSBO); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_LightOffsetSSBO); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_LightIndexSSBO); + glDispatchCompute(m_Resolution.Width / TILE_SIZE, m_Resolution.Height / TILE_SIZE, 1); + GLERROR("CullLights Error"); + +} +