Fixed shading in deferred.

Added sky in deferred.
Started render buffer abstraction
This commit is contained in:
antopilo
2021-09-01 22:31:45 -04:00
parent 54a138c044
commit c3d3e20ab4
12 changed files with 268 additions and 81 deletions

View File

@@ -4,7 +4,6 @@ layout(location = 0) in vec3 VertexPosition;
layout(location = 1) in vec2 UVPosition;
out flat vec2 UV;
out vec3 FragPos;
out mat4 InvProjection;
out mat4 InvView;
@@ -14,9 +13,9 @@ uniform mat4 u_View;
void main()
{
UV = UVPosition;
FragPos = VertexPosition;
InvProjection = inverse(u_Projection);
InvView = inverse(u_View);
gl_Position = vec4(VertexPosition, 1.0f);
}
@@ -25,7 +24,6 @@ void main()
out vec4 FragColor;
in vec3 FragPos;
in vec2 UV;
in mat4 InvProjection;
in mat4 InvView;
@@ -33,18 +31,24 @@ in mat4 InvView;
// Camera
uniform float u_Exposure;
uniform vec3 u_EyePosition;
// IBL
// Environmnent
uniform float u_FogAmount;
uniform float u_FogStepCount;
uniform samplerCube u_IrradianceMap;
uniform samplerCube u_PrefilterMap;
uniform sampler2D u_BrdfLUT;
// Material
// GBuffer
uniform sampler2D m_Depth;
uniform sampler2D m_Albedo;
uniform sampler2D m_Material;
uniform sampler2D m_Normal;
// Lights
const int MaxLight = 20;
uniform int LightCount = 0;
struct Light {
int Type; // 0 = directional, 1 = point
vec3 Direction;
@@ -55,15 +59,19 @@ struct Light {
float LinearAttenuation;
float QuadraticAttenuation;
mat4 LightTransform;
sampler2D ShadowMaps[4];
float CascadeDepth[4];
mat4 LightTransforms[4];
sampler2D ShadowMap;
sampler2D RSMFlux;
sampler2D RSMNormal;
sampler2D RSMPos;
int Volumetric;
};
const int MaxLight = 20;
uniform int LightCount = 0;
uniform Light Lights[MaxLight];
// Converts depth to World space coords.
vec3 WorldPosFromDepth(float depth) {
float z = depth * 2.0 - 1.0;
@@ -78,7 +86,7 @@ vec3 WorldPosFromDepth(float depth) {
return worldSpacePosition.xyz;
}
const float PI = 3.141592653589793f; // mark this as static const wait idk if you can do that in glsl
const float PI = 3.141592653589793f;
float height_scale = 0.02f;
float DistributionGGX(vec3 N, vec3 H, float a)
@@ -123,53 +131,123 @@ vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
}
float ShadowCalculation(vec4 fragPosLightSpace, sampler2D shadowMap, vec3 normal, vec3 lightDir)
float ShadowCalculation(Light light, vec3 FragPos, vec3 normal)
{
// Get Depth
float depth = length(FragPos - u_EyePosition);
int shadowmap = 0;
// Get CSM depth
for (int i = 0; i < 4; i++)
{
float CSMDepth = light.CascadeDepth[i];
if (depth < CSMDepth + 0.0001)
{
shadowmap = i;
break;
}
}
if (shadowmap == -1)
return 1.0;
vec4 fragPosLightSpace = light.LightTransforms[0] * vec4(FragPos, 1.0f);
// perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
// get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
float closestDepth = texture(shadowMap, projCoords.xy).r;
float closestDepth = texture(light.ShadowMaps[0], projCoords.xy).r;
// get depth of current fragment from light's perspective
float currentDepth = projCoords.z;
// check whether current frag pos is in shadow
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
float bias = max(0.005 * (1.0 - dot(normal, light.Direction)), 0.0005);
float shadow = 0.0;
vec2 texelSize = 1.0 / textureSize(shadowMap, 0);
for (int x = -1; x <= 1; ++x)
{
for (int y = -1; y <= 1; ++y)
{
float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
}
}
shadow /= 9.0;
return shadow;
float pcfDepth = texture(light.ShadowMaps[0], projCoords.xy).r;
return currentDepth - bias > pcfDepth ? 1.0 : 0.0;
}
// Mie scaterring approximated with Henyey-Greenstein phase function.
float ComputeScattering(float lightDotView)
{
float result = 1.0f - u_FogAmount * u_FogAmount;
result /= (4.0f * PI * pow(1.0f + u_FogAmount * u_FogAmount - (2.0f * u_FogAmount) * lightDotView, 1.5f));
return result;
}
vec3 ComputeVolumetric(vec3 FragPos, Light light)
{
// world space frag position.
vec3 startPosition = u_EyePosition; // Camera Position
vec3 rayVector = FragPos - startPosition; // Ray Direction
float rayLength = length(rayVector); // Length of the raymarched
float stepLength = rayLength / u_FogStepCount; // Step length
vec3 rayDirection = rayVector / rayLength;
vec3 step = rayDirection * stepLength; // Normalized to step length direction
vec3 currentPosition = startPosition; // First step position
vec3 accumFog = vec3(0.0f, 0.0f, 0.0f); // accumulative color
// Raymarching
for (int i = 0; i < u_FogStepCount; i++)
{
vec4 fragPosLightSpace = light.LightTransforms[0] * vec4(currentPosition, 1.0f);
// perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
float currentDepth = projCoords.z;
// get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
vec2 texelSize = 1.0 / textureSize(light.ShadowMaps[0], 0);
float closestDepth = texture(light.ShadowMaps[0], projCoords.xy).r;
if (closestDepth > currentDepth)
accumFog += (ComputeScattering(dot(rayDirection, light.Direction)).xxx * light.Color);
currentPosition += step;
}
accumFog /= u_FogStepCount;
return accumFog;
}
void main()
{
vec3 worldPos = WorldPosFromDepth(texture(m_Depth, UV).r);
if (texture(m_Depth, UV).r == 1) {
FragColor = vec4(0, 0, 0, 0);
return;
}
// Convert from [0, 1] to [-1, 1].
vec3 albedo = texture(m_Albedo, UV).rgb;
vec3 normal = (texture(m_Normal, UV).rgb - 0.5) * 2.0;
vec3 normal = texture(m_Normal, UV).rgb * 2.0 - 1.0;
float metallic = texture(m_Material, UV).r;
float roughness = texture(m_Material, UV).g;
float ao = texture(m_Material, UV).b;
float roughness = texture(m_Material, UV).b;
float ao = texture(m_Material, UV).g;
vec3 N = normalize(normal);
vec3 N = normal;
vec3 V = normalize(u_EyePosition - worldPos);
vec3 R = reflect(-V, N);
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, vec3(metallic));
F0 = mix(F0, albedo, metallic);
// reflectance equation
vec3 Lo = vec3(0.0);
vec3 fog = vec3(0.0);
float shadow = 0.0f;
vec3 eyeDirection = normalize(u_EyePosition - worldPos);
for (int i = 0; i < LightCount; i++)
@@ -180,11 +258,14 @@ void main()
float attenuation = 1.0 / (distance * distance);
if (Lights[i].Type == 0) {
L = Lights[i].Direction;
L = normalize(Lights[i].Direction);
attenuation = 1.0f;
}
float shadow = ShadowCalculation(Lights[i].LightTransform * vec4(worldPos, 1.0f), Lights[i].ShadowMap, N, Lights[i].Direction);
if (Lights[i].Volumetric == 1)
fog += ComputeVolumetric(worldPos, Lights[i]);
shadow = ShadowCalculation(Lights[i], worldPos, N);
}
vec3 H = normalize(V + L);
vec3 radiance = Lights[i].Color * attenuation * (1.0f - shadow);
@@ -200,22 +281,13 @@ void main()
// kS is equal to Fresnel
vec3 kS = F;
// for energy conservation, the diffuse and specular light can't
// be above 1.0 (unless the surface emits light); to preserve this
// relationship the diffuse component (kD) should equal 1.0 - kS.
vec3 kD = vec3(1.0) - kS;
// multiply kD by the inverse metalness such that only non-metals
// have diffuse lighting, or a linear blend if partly metal (pure metals
// have no diffuse light).
kD *= 1.0 - metallic;
// scale light by NdotL
float NdotL = max(dot(N, L), 0.0);
// add to outgoing radiance Lo
Lo += (kD * albedo / PI + specular) * radiance * NdotL;// note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again
}
/// ambient lighting (we now use IBL as the ambient term)
vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness);
@@ -224,7 +296,7 @@ void main()
vec3 kD = 1.0 - kS;
kD *= 1.0 - metallic;
vec3 irradiance = texture(u_IrradianceMap, N).rgb;
vec3 irradiance = mix(texture(u_IrradianceMap, N).rgb, vec3(0.1f), 0.9f);
vec3 diffuse = irradiance * albedo;
// sample both the pre-filter map and the BRDF lut and combine them together as per the Split-Sum approximation to get the IBL specular part.
@@ -235,11 +307,13 @@ void main()
vec3 ambient = (kD * diffuse + specular) * ao;
vec3 color = ambient + Lo;
// HDR tonemapping
color += fog;
color = color / (color + vec3(1.0));
const float gamma = 2.2;
// HDR tonemapping
color = vec3(1.0) - exp(-color * u_Exposure);
// gamma correct
color = pow(color, vec3(1.0 / u_Exposure));
color = pow(color, vec3(1.0 / gamma));
FragColor = vec4(color, 1.0);
FragColor = mix(vec4(color, 1.0), vec4(albedo, 1.0), 0);
}

View File

@@ -67,17 +67,18 @@ void main()
vec3 normal = vec3(0.5, 0.5, 1.0);
if (u_HasNormal == 1)
normal = texture(m_Normal, UV).rgb;
normal = normal * 2.0 - 1.0;
normal = TBN * normalize(normal);
gNormal = vec4(normal, 1.0);
normal = TBN * normalize(normal);
gNormal = vec4(normal, 1.0) / 2.0 + 0.5;
// Albedo
gAlbedo = vec4(m_AlbedoColor, 1.0);
if (u_HasAlbedo == 1)
gAlbedo = texture(m_Albedo, UV).rgba;
gAlbedo.rgb = texture(m_Albedo, UV).rgb;
gAlbedo.rgba = texture(m_Albedo, UV).rgba;
gAlbedo.rgb = texture(m_Albedo, UV).rgb;
// Material
float finalMetalness = u_MetalnessValue;

View File

@@ -373,7 +373,6 @@ void main()
shadow += ShadowCalculation(Lights[i], v_FragPos, N);
}
vec3 H = normalize(V + L);
vec3 radiance = Lights[i].Color * attenuation * (1.0f - shadow);

View File

@@ -131,6 +131,16 @@ namespace Nuake {
if (m_IsEntitySelected)
{
if (ImGui::Begin("DEFERRED"))
{
ImVec2 regionAvail = ImGui::GetContentRegionAvail();
glm::vec2 viewportPanelSize = glm::vec2(regionAvail.x, regionAvail.y);
Ref<Texture> texture = Engine::GetCurrentWindow()->GetDeferredBuffer()->GetTexture(GL_COLOR_ATTACHMENT0);
ImGui::Image((void*)texture->GetID(), regionAvail, ImVec2(0, 1), ImVec2(1, 0));
}
ImGui::End();
if (ImGui::Begin("GBUFFER"))
{
ImVec2 regionAvail = ImGui::GetContentRegionAvail();

View File

@@ -0,0 +1,19 @@
#pragma once
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
namespace Nuake {
class RenderBuffer
{
public:
RenderBuffer(Vector2 size);
~RenderBuffer();
void Bind();
void Unbind();
unsigned int GetRenderID() const { return m_RenderBuffer; }
private:
unsigned int m_RenderBuffer;
};
}

View File

@@ -51,12 +51,12 @@ namespace Nuake
};
float QuadVertices[] = {
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.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, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f
};
@@ -159,25 +159,41 @@ namespace Nuake
m_Shader->SetUniform1i("Lights[" + std::to_string(idx - 1) + "].Volumetric", light.IsVolumetric);
}
void Renderer::RegisterDeferredLight(TransformComponent transform, LightComponent light, Camera* cam)
void Renderer::RegisterDeferredLight(TransformComponent transform, LightComponent light)
{
if (m_Lights.size() == 20)
return;
Ref<Shader> deferredShader = ShaderManager::GetShader("resources/Shaders/deferred.shader");
deferredShader->Bind();
m_Lights.push_back({ transform , light });
int idx = m_Lights.size();
Vector3 direction = light.GetDirection();
Vector3 pos = transform.Translation;
Matrix4 lightView = glm::lookAt(pos, pos - direction, Vector3(0.0f, 1.0f, 0.0f));
Vector3 pos = transform.GlobalTranslation;
Matrix4 lightView = glm::lookAt(pos, pos - direction, glm::vec3(0.0f, 1.0f, 0.0f));
light.m_Framebuffer->GetTexture()->Bind(11);
//light.m_Framebuffer->GetTexture(GL_DEPTH_ATTACHMENT)->Bind(17);
m_DeferredShader->SetUniform1i("LightCount", idx);
m_DeferredShader->SetUniform1i("Lights[" + std::to_string(idx - 1) + "].Type", light.Type);
m_DeferredShader->SetUniform1i("Lights[" + std::to_string(idx - 1) + "].ShadowMap", 11);
m_DeferredShader->SetUniformMat4f("Lights[" + std::to_string(idx - 1) + "].LightTransform", light.GetProjection() * lightView);
m_DeferredShader->SetUniform3f("Lights[" + std::to_string(idx - 1) + "].Position", transform.Translation.x, transform.Translation.y, transform.Translation.z);
m_DeferredShader->SetUniform3f("Lights[" + std::to_string(idx - 1) + "].Direction", direction.x, direction.y, direction.z);
m_DeferredShader->SetUniform3f("Lights[" + std::to_string(idx - 1) + "].Color", light.Color.r * light.Strength, light.Color.g * light.Strength, light.Color.b * light.Strength);
if (light.CastShadows)
{
for (unsigned int i = 0; i < CSM_AMOUNT; i++)
{
light.m_Framebuffers[i]->GetTexture(GL_DEPTH_ATTACHMENT)->Bind(17 + i);
deferredShader->SetUniform1i("Lights[" + std::to_string(idx - 1) + "].ShadowMaps[" + std::to_string(i) + "]", 17 + i);
deferredShader->SetUniform1f("Lights[" + std::to_string(idx - 1) + "].CascadeDepth[" + std::to_string(i) + "]", light.mCascadeSplitDepth[i]);
deferredShader->SetUniformMat4f("Lights[" + std::to_string(idx - 1) + "].LightTransforms[" + std::to_string(i) + "]", light.mViewProjections[i]);
}
}
deferredShader->SetUniform1i("LightCount", idx);
deferredShader->SetUniform1i("Lights[" + std::to_string(idx - 1) + "].Type", light.Type);
deferredShader->SetUniformMat4f("Lights[" + std::to_string(idx - 1) + "].LightTransform", light.GetProjection() * lightView);
deferredShader->SetUniform3f("Lights[" + std::to_string(idx - 1) + "].Position", transform.GlobalTranslation.x, transform.GlobalTranslation.y, transform.GlobalTranslation.z);
deferredShader->SetUniform3f("Lights[" + std::to_string(idx - 1) + "].Direction", direction.x, direction.y, direction.z);
deferredShader->SetUniform3f("Lights[" + std::to_string(idx - 1) + "].Color", light.Color.r * light.Strength, light.Color.g * light.Strength, light.Color.b * light.Strength);
deferredShader->SetUniform1i("Lights[" + std::to_string(idx - 1) + "].Volumetric", light.IsVolumetric);
}
void Renderer::DrawDebugLine(glm::vec3 start, glm::vec3 end, glm::vec4 color)

View File

@@ -46,7 +46,7 @@ namespace Nuake
// Lights
static std::vector<Light> m_Lights;
static void RegisterLight(TransformComponent transform, LightComponent light);
static void RegisterDeferredLight(TransformComponent transform, LightComponent light, Camera* cam);
static void RegisterDeferredLight(TransformComponent transform, LightComponent light);

View File

@@ -93,11 +93,6 @@ namespace Nuake {
Renderer::m_ShadowmapShader->Bind();
}
void LightComponent::DrawDeferred(TransformComponent transformComponent, Camera* cam)
{
Renderer::RegisterDeferredLight(transformComponent, *this, cam);
}
void LightComponent::DrawEditor() {
ImGui::TextColored(ImGui::GetStyleColorVec4(1), "Light properties");
ImGui::ColorEdit3("Light Color", &Color.r);

View File

@@ -363,7 +363,6 @@ namespace Nuake {
}
glCullFace(GL_BACK);
Renderer::Flush(pbrShader);
glCullFace(GL_FRONT);
auto quakeView = m_Registry.view<TransformComponent, BSPBrushComponent, ParentComponent>();
for (auto e : quakeView)
@@ -430,12 +429,20 @@ namespace Nuake {
void Scene::EditorDrawDeferred()
{
glEnable(GL_DEPTH_TEST);
Ref<Shader> gBufferShader = ShaderManager::GetShader("resources/Shaders/gbuffer.shader");
gBufferShader->Bind();
gBufferShader->SetUniformMat4f("u_Projection", m_EditorCamera->GetPerspective());
gBufferShader->SetUniformMat4f("u_View", m_EditorCamera->GetTransform());
auto view = m_Registry.view<TransformComponent, MeshComponent, ParentComponent>();
for (auto e : view)
{
auto [transform, mesh, parent] = view.get<TransformComponent, MeshComponent, ParentComponent>(e);
for (auto& m : mesh.meshes)
Renderer::SubmitMesh(m, transform.GetTransform());
}
auto quakeView = m_Registry.view<TransformComponent, BSPBrushComponent, ParentComponent>();
for (auto e : quakeView)
{
@@ -447,10 +454,41 @@ namespace Nuake {
for (auto& b : model.Meshes)
Renderer::SubmitMesh(b, transform.GetTransform());
}
glCullFace(GL_FRONT);
Renderer::Flush(gBufferShader, false);
}
void Scene::EditorDrawDeferredShading()
{
glDisable(GL_DEPTH_TEST);
Ref<Shader> deferredShader = ShaderManager::GetShader("resources/Shaders/deferred.shader");
deferredShader->Bind();
deferredShader->SetUniformMat4f("u_Projection", m_EditorCamera->GetPerspective());
deferredShader->SetUniformMat4f("u_View", m_EditorCamera->GetTransform());
deferredShader->SetUniform1f("u_Exposure", 1.0);
Vector3 camPosition = m_EditorCamera->GetTranslation();
deferredShader->SetUniform3f("u_EyePosition", camPosition.x, camPosition.y, camPosition.z);
Ref<Environment> env = GetEnvironment();
deferredShader->SetUniform1f("u_FogAmount", env->VolumetricFog);
deferredShader->SetUniform1f("u_FogStepCount", env->VolumetricStepCount);
// Register the lights
auto view = m_Registry.view<TransformComponent, LightComponent, ParentComponent>();
for (auto l : view)
{
auto [transform, light, parent] = view.get<TransformComponent, LightComponent, ParentComponent>(l);
if (light.SyncDirectionWithSky)
light.Direction = GetEnvironment()->ProceduralSkybox->GetSunDirection();
Renderer::RegisterDeferredLight(transform, light);
}
}
std::vector<Entity> Scene::GetAllEntities()
{
std::vector<Entity> allEntities;

View File

@@ -58,6 +58,7 @@ namespace Nuake {
void DrawInterface(Vector2 screensize);
void Draw();
void EditorDrawDeferred();
void EditorDrawDeferredShading();
void EditorDraw();
std::vector<Entity> GetAllEntities();

View File

@@ -83,6 +83,11 @@ namespace Nuake {
return m_GBuffer;
}
Ref<FrameBuffer> Window::GetDeferredBuffer() const
{
return m_DeferredBuffer;
}
Vector2 Window::GetSize()
{
int w, h = 0;
@@ -146,6 +151,9 @@ namespace Nuake {
m_GBuffer->SetTexture(CreateRef<Texture>(Vector2(1920, 1080), GL_RGB), GL_COLOR_ATTACHMENT1);
m_GBuffer->SetTexture(CreateRef<Texture>(Vector2(1920, 1080), GL_RGB), GL_COLOR_ATTACHMENT2);
m_DeferredBuffer = CreateRef<FrameBuffer>(true, Vector2(1920, 1080));
m_DeferredBuffer->SetTexture(CreateRef<Texture>(Vector2(1920, 1080), GL_RGB));
// Temporary quad vbo for deferred.
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
@@ -262,8 +270,8 @@ namespace Nuake {
{
if (Engine::IsPlayMode)
m_Scene->Draw();
else
m_Scene->EditorDraw();
//else
// m_Scene->EditorDraw();
m_Scene->DrawInterface(m_Framebuffer->GetSize());
}
@@ -277,6 +285,31 @@ namespace Nuake {
m_GBuffer->Unbind();
m_DeferredBuffer->Bind();
m_DeferredBuffer->Clear();
{
glDisable(GL_CULL_FACE);
if (m_Scene->GetEnvironment()->ProceduralSkybox)
m_Scene->GetEnvironment()->ProceduralSkybox->Draw(m_Scene->m_EditorCamera);
m_Scene->EditorDrawDeferredShading();
m_GBuffer->GetTexture(GL_DEPTH_ATTACHMENT)->Bind(5);
m_GBuffer->GetTexture(GL_COLOR_ATTACHMENT0)->Bind(6);
m_GBuffer->GetTexture(GL_COLOR_ATTACHMENT1)->Bind(7);
m_GBuffer->GetTexture(GL_COLOR_ATTACHMENT2)->Bind(8);
Ref<Shader> deferredShader = ShaderManager::GetShader("resources/Shaders/deferred.shader");
deferredShader->SetUniform1i("m_Depth", 5);
deferredShader->SetUniform1i("m_Albedo", 6);
deferredShader->SetUniform1i("m_Normal", 7);
deferredShader->SetUniform1i("m_Material", 8);
Renderer::DrawQuad(Matrix4());
}
m_DeferredBuffer->Unbind();
Renderer::EndDraw();
}

View File

@@ -20,6 +20,7 @@ namespace Nuake
Ref<FrameBuffer> m_Framebuffer;
Ref<FrameBuffer> m_GBuffer;
Ref<FrameBuffer> m_DeferredBuffer;
Ref<Scene> m_Scene;
Vector2 m_FramebufferOffset;
@@ -41,7 +42,7 @@ namespace Nuake
Ref<FrameBuffer> GetFrameBuffer() const;
Ref<FrameBuffer> GetGBuffer() const;
Ref<FrameBuffer> GetDeferredBuffer() const;
Vector2 GetSize();
Ref<Scene> GetScene();