diff --git a/GlitchyEditor/content/Models/plane.glb b/GlitchyEditor/content/Models/plane.glb index 33643af..c345a08 100644 Binary files a/GlitchyEditor/content/Models/plane.glb and b/GlitchyEditor/content/Models/plane.glb differ diff --git a/GlitchyEditor/content/Models/sphere.glb b/GlitchyEditor/content/Models/sphere.glb new file mode 100644 index 0000000..1e81373 Binary files /dev/null and b/GlitchyEditor/content/Models/sphere.glb differ diff --git a/GlitchyEditor/content/Shaders/LightingFunctions.hlsl b/GlitchyEditor/content/Shaders/LightingFunctions.hlsl new file mode 100644 index 0000000..fcd5b5b --- /dev/null +++ b/GlitchyEditor/content/Shaders/LightingFunctions.hlsl @@ -0,0 +1,28 @@ +#define PI 3.14159265358979323846f + +/** + * Calculates the diffuse lighting of a lambertian surface + * @param diffuseColor (rho/ pi) * C_diffuse + * @param illuminanceColor The product of the "brightness" and the light color. + * @param n_dot_l The dot product of the surface normal and the light direction. + */ +float3 CalculateDiffuseReflection(float3 diffuseColor, float3 illuminanceColor, float3 n_dot_l) +{ + float3 directColor = illuminanceColor * saturate(n_dot_l); + + return (directColor * diffuseColor); +} + +/** + * Calculates the blinn-phong-specular reflection + * @param n The normalized surface normal + * @param h The normalized half way vector (nrm(l + v)) + * @param alpha The reflections alpha-value + * @param illuminanceColor The product of the "brightness" and the light color. + * @param n_dot_l The dot product of the surface normal and the light direction. + */ +float3 CalculateSpecularReflection(float3 n, float3 h, float alpha, float3 illuminanceColor, float n_dot_l) +{ + float highlight = pow(saturate(dot(n, h)), alpha) * float(n_dot_l > 0.0); + return (illuminanceColor * highlight); // Todo: * SpecularColor +} \ No newline at end of file diff --git a/GlitchyEditor/content/Shaders/ShaderFunctions.hlsl b/GlitchyEditor/content/Shaders/ShaderFunctions.hlsl new file mode 100644 index 0000000..eb47da9 --- /dev/null +++ b/GlitchyEditor/content/Shaders/ShaderFunctions.hlsl @@ -0,0 +1,84 @@ + +/* +* Calculates the weighted sum of two normal vectors. +* nrm1: The first normal vector +* nrm2: The second normal vector +* a: The weight factor for nrm1 +* b: The weight factor for nrm2 +*/ +float3 BlendNormals(float3 nrm1, float3 nrm2, float a, float b) +{ + return normalize(float3(a * nrm1.x / nrm1.z + b * nrm2.x / nrm2.z, + a * nrm1.y / nrm1.z + b * nrm2.y / nrm2.z, + 1.0f)); +} + +/* +* Scales a normal vector by a factor where 0 results in the vector (0, 0, 1) +* nrm: The normal vector +* a: The scaling factor +*/ +float3 ScaleNormal(float3 nrm1, float a) +{ + return normalize(float3(a * nrm1.x / nrm1.z, + a * nrm1.y / nrm1.z, + 1.0f)); +} + +/* +* Scales a normal vector by a factor where 0 results in the vector (0, 0, 1) +* nrm: The normal vector +* a: The scaling factor +*/ +float3 ScaleNormal(float3 nrm1, float2 a) +{ + return normalize(float3(a.x * nrm1.x / nrm1.z, + a.y * nrm1.y / nrm1.z, + 1.0f)); +} + +/* +* Reconstructs the z-component of a normalized normal vector from a two-component value +* cnrm: The x- and y-components of a normalized normal vector +*/ +float3 DecompressNormal(float2 cnrm) +{ + return float3(cnrm, sqrt(1.0 - cnrm.x * cnrm.x - cnrm.y * cnrm.y)); +} + +/* +* Reconstructs the tangent space from a normal and a tangent +* normal: The surface normal +* tangent: The surface tangent +* sigma: Defines the handedness of the tangent space matrix. 1.0 if it is right handend. -1.0 if it is left handed +*/ +float3x3 ConstructTangentSpace(float3 normal, float3 tangent, float3 sigma) +{ + float3 n = normalize(normal); + float3 t = normalize(tangent - n * dot(tangent, n)); + float3 b = cross(n, t) * sigma; + + return float3x3(t, b, n); +} + +/** + * Calculates the luminance of an rgb-value. + * @param rgb The rgb color. + * @return The luminance of the given rgb color. + */ +float ColorToLuminance(float3 rgb) +{ + return rgb.r * 0.212639 + rgb.g * 0.715169 + rgb.b * 0.072192; +} + +/** + * Extrancts the handedness of the bitangent that is encoded in the z-component of the tangent. + * @param tangentz The z-component of the tangent with the handedness encoded. + * @return The handedness of the bitangent (bitangent = handedness * tangent x normal) + */ +float GetBitangentHandedness(float tangentz) +{ + // handedness is in least significant bit of tangent.z + uint z = asuint(tangentz); + return (z & 1) > 0 ? 1.0 : -1.0; +} \ No newline at end of file diff --git a/GlitchyEditor/content/Shaders/myEffect.hlsl b/GlitchyEditor/content/Shaders/myEffect.hlsl index 81829ca..5b0b28f 100644 --- a/GlitchyEditor/content/Shaders/myEffect.hlsl +++ b/GlitchyEditor/content/Shaders/myEffect.hlsl @@ -1,9 +1,21 @@ +Texture2D AlbedoTexture : register(t0); +SamplerState AlbedoSampler : register(s0); + +Texture2D NormalTexture : register(t1); +SamplerState NormalSampler : register(s1); + +Texture2D MetallicTexture : register(t2); +SamplerState MetallicSampler : register(s2); + +Texture2D RoughnessTexture : register(t3); +SamplerState RoughnessSampler : register(s3); + +// Texture2D AmbientTexture : register(t4); +// SamplerState AmbientSampler : register(s4); + cbuffer SceneConstants { - float4x4 ViewProjection = float4x4(1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); + float4x4 ViewProjection; } cbuffer ObjectConstants @@ -13,7 +25,7 @@ cbuffer ObjectConstants cbuffer Constants { - float4 BaseColor = float4(1, 0, 1, 1); + //float4 BaseColor = float4(1, 0, 1, 1); //float3 LightDir = float3(0, 1, 0); } @@ -21,13 +33,19 @@ struct VS_IN { float3 Position : POSITION; float3 Normal : NORMAL; + // Todo: Tangent.w... handedness + float3 Tangent : TANGENT; + float2 TexCoord : TEXCOORD; }; struct PS_IN { - float4 Position : SV_POSITION; - float3 WorldPosition : TEXCOORD0; - float3 Normal : NORMAL; + float4 Position : SV_POSITION; + float3 WorldPosition : WORLDPOSITION; + float3 Normal : NORMAL; + float3 Tangent : TANGENT; + float2 TexCoord : TEXCOORD; + //nointerpolation float Handedness : HANDEDNESS; }; PS_IN VS(VS_IN input) @@ -36,36 +54,67 @@ PS_IN VS(VS_IN input) float4 worldPosition = mul(Transform, float4(input.Position, 1)); - output.Position = mul(ViewProjection, worldPosition); + output.Position = mul(ViewProjection, worldPosition); output.WorldPosition = worldPosition.xyz / worldPosition.w; - output.Normal = mul((float3x3)Transform, input.Normal); + + output.Normal = mul(input.Normal, (float3x3)Transform); + output.Tangent = mul((float3x3)Transform, input.Tangent); + // TODO: output.Handedness = input.Tangent.w + + output.TexCoord = input.TexCoord; return output; } struct PS_OUT { - float4 Color : SV_TARGET0; - float4 Normal : SV_TARGET1; - float4 Position : SV_TARGET2; + float4 Albedo : SV_TARGET0; + // RG: TextureNormal.XY BA: GeoNrm.XY + float4 Normal : SV_TARGET1; + // R: GeoNrm.Z GBA: GeoTan.XYZ + float4 Tangent : SV_TARGET2; + float4 Position : SV_TARGET3; + // R: Metallicity G: Roughness B: Ambient + float4 Material : SV_TARGET4; }; PS_OUT PS(PS_IN input) { - input.Normal = normalize(input.Normal); + // Build tangent space + float3 normal = normalize(input.Normal); + float3 tangent = normalize(input.Tangent - dot(input.Tangent, normal) * input.Normal); + // TODO: float3 bitangent = input.Handedness * cross(normal, tangent); + float3 bitangent = -cross(normal, tangent); - float f = distance(input.Normal, input.Normal); + float3x3 tangentTransform = float3x3(tangent, bitangent, normal); + //tangentTransform = transpose(tangentTransform); - //float shading = dot(LightDir, input.Normal); - //float shading = dot(LightDir, LightDir) + 1; - //shading = clamp(shading, 0.0f, 1.0f); + float4 texAlbedo = AlbedoTexture.Sample(AlbedoSampler, input.TexCoord); + float3 texNormal = NormalTexture.Sample(NormalSampler, input.TexCoord); + texNormal.xy = texNormal.xy * 2.0 - 1.0; + float texMetallic = MetallicTexture.Sample(MetallicSampler, input.TexCoord); + float texRoughness = RoughnessTexture.Sample(RoughnessSampler, input.TexCoord); - //return float4(BaseColor.rgb * shading, 1.0f); + //float3 objectNormal = mul(tangentTransform, texNormal); + //float3 worldNormal = mul(objectNormal, (float3x3)Transform); - PS_OUT output = (PS_OUT)0; - output.Color = BaseColor; - output.Normal = float4(input.Normal, 1); - output.Position = float4(input.WorldPosition, 1); + +/////////////TODO: REMOVEME + + //worldNormal = max(worldNormal - 10000000, normal); + //texAlbedo = max(texAlbedo - 10000000, 1.0); + //texMetallic = max(texMetallic - 10000000, 0.0); + //texRoughness = max(texRoughness - 10000000, 0.1); + +/////////////TODO: END_REMOVEME + + PS_OUT output; + output.Albedo = texAlbedo; + //output.Normal = float4(objectNormal, 1.0); + output.Normal = float4(texNormal.xy, normal.xy); + output.Tangent = float4(normal.z, tangent.xyz); + output.Position = float4(input.WorldPosition, 1.0); + output.Material = float4(texMetallic, texRoughness, 1.0, 0); return output; } diff --git a/GlitchyEditor/content/Shaders/simpleLight.hlsl b/GlitchyEditor/content/Shaders/simpleLight.hlsl index 0f7fef5..83287f1 100644 --- a/GlitchyEditor/content/Shaders/simpleLight.hlsl +++ b/GlitchyEditor/content/Shaders/simpleLight.hlsl @@ -1,12 +1,22 @@ -Texture2D Colors : register(t0); -Texture2D Normals : register(t1); -Texture2D Positions : register(t2); +#define PI 3.14159265358979323846f SamplerState Sampler : register(s0); +Texture2D GBuffer_Albedo : register(t0); +Texture2D GBuffer_Normal : register(t1); +Texture2D GBuffer_Tangent : register(t2); +Texture2D GBuffer_Position : register(t3); +Texture2D GBuffer_Material : register(t4); + cbuffer Constants { - float3 LightDir = float3(0, 1, 0); + float3 LightColor; + float Illuminance; + float3 LightDir; + + float3 CameraPos; + + float2 Scaling; } struct VS_IN @@ -26,21 +36,170 @@ PS_IN VS(VS_IN input) PS_IN output; output.Position = float4(input.Position, 0, 1); - output.TexCoord = input.TexCoord; + output.TexCoord = input.TexCoord * Scaling; return output; } +/** + * Normal Distribution Function. (Trowbridge-Reits GGX) + * Calculates the relative surface area of microfacets exactly aligned to the halfway vector. + * @param normal The surface normal. + * @param halfway The halfway vector between the surface normal and the view direction. + * @param roughness Roughness value. + * @returns The relative surface area of microfacets exactly aligned to the halfway vector. + */ +float NormalDistributionGGX(float3 normal, float3 halfway, float roughness) +{ + // Square roughness because it looks better + float a = roughness * roughness; + float aa = a * a; + + float n_dot_h = max(dot(normal, halfway), 0.0f); + + float denom = (n_dot_h * n_dot_h) * (aa - 1.0f) + 1.0f; + denom = PI * denom * denom; + + return aa / denom; +} + +/** + * Geometry Function calculating the overshadowing of microfacets based on roughness. (Schlick-Beckmann GGX). + * @param dot-product of normal vector and vector from surface to camera. + * @param k Roughness value. + */ +float GeometrySchlickGGX(float n_dot_v, float k) +{ + return n_dot_v / (n_dot_v * (1 - k) + k); +} + +/** + * Geometry Function calculating the overshadowing of microfacets based on roughness. (Smith) + * @param normal The surface normal. + * @param viewDir Vector from surface to viewer. + * @param lightDir Vector from surface to light source. + * @param roughness Roughness value. + */ +float GeometrySmith(float3 normal, float3 viewDir, float3 lightDir, float roughness) +{ + // Direct lighting + float k = (roughness + 1.0f); + k = (k * k) / 8; + + // IBL + // float k = alpha * alpha / 2 + + float n_dot_v = max(dot(normal, viewDir), 0.0f); + float n_dot_l = max(dot(normal, lightDir), 0.0f); + + return GeometrySchlickGGX(n_dot_v, k) * GeometrySchlickGGX(n_dot_l, k); +} + +/** + * Calculates the fresnel value. + * @param h_dot_v Dot product of the normal and view direction + * @param F0 base reflectivity + */ +float3 FresnelSchlick(float cosTheta, float3 F0) +{ + return F0 + (1.0f - F0) * pow(clamp(1.0f - cosTheta, 0.0f, 1.0f), 5.0f); +} + +/* +* Reconstructs the z-component of a normalized normal vector from a two-component value +* cnrm: The x- and y-components of a normalized normal vector +*/ +float3 DecompressNormal(float2 cnrm) +{ + return float3(cnrm, sqrt(1.0 - cnrm.x * cnrm.x - cnrm.y * cnrm.y)); +} + float4 PS(PS_IN input) : SV_TARGET { - float4 color = Colors.Sample(Sampler, input.TexCoord); - float3 normal = Normals.Sample(Sampler, input.TexCoord); + // Load Data from GBuffer + float4 rawAlbedo = GBuffer_Albedo.Sample(Sampler, input.TexCoord); + + float4 rawNormal = GBuffer_Normal.Sample(Sampler, input.TexCoord); + float4 rawTangent = GBuffer_Tangent.Sample(Sampler, input.TexCoord); + float4 rawPosition = GBuffer_Position.Sample(Sampler, input.TexCoord); + float4 rawMaterial = GBuffer_Material.Sample(Sampler, input.TexCoord); - //float shading = dot(LightDir, normal) + 100; - float shading = dot(float3(0, 1, 0), normal); - shading = clamp(shading, 0.0f, 1.0f); + // Extract data from GBuffer + float3 albedo = rawAlbedo.rgb; + //float3 surfaceNormal = normalize(rawNormal.xyz); + float3 worldPosition = rawPosition.xyz; - return float4(color.rgb * shading, 1); + float metallic = rawMaterial.r; + float roughness = rawMaterial.g; + + float3 textureNormal = DecompressNormal(rawNormal.rg); + float3 rawGeoNrm = float3(rawNormal.ba, rawTangent.r); + float3 rawGeoTan = rawTangent.gba; + + // Reconstruct normal space + float3 normal = normalize(rawGeoNrm); + float3 tangent = normalize(rawGeoTan - dot(rawGeoTan, normal) * normal); + float3 bitangent = -cross(normal, tangent); + + float3x3 tangentTransform = float3x3(tangent, bitangent, normal); + + float3 surfaceNormal = mul(textureNormal, tangentTransform); + + float3 lightDir = normalize(LightDir); + float3 viewDir = normalize(CameraPos - worldPosition.xyz); + float3 halfway = normalize(lightDir + viewDir); + + float n_dot_v = max(dot(surfaceNormal, viewDir), 0.0f); + float n_dot_l = max(dot(surfaceNormal, lightDir), 0.0f); + + float nrmDist = NormalDistributionGGX(surfaceNormal, halfway, roughness); + float geo = GeometrySmith(surfaceNormal, viewDir, lightDir, roughness); + + float3 F0 = 0.04f; + F0 = lerp(F0, albedo, metallic); + float3 fresnel = FresnelSchlick(n_dot_v, F0); + + // if (InspectNrmDist) + // return float4(nrmDist.xxx, 1); + // else if (InspectGeo) + // return float4(geo.xxx, 1); + // else if (InspectFresnel) + // return float4(fresnel, 1); + // else if (CookTorrance) + // { + float3 ks = fresnel; + float3 kd = 1.0f - ks; + + // Metals have no diffuse light + kd *= 1.0f - metallic; + + float3 diffuse = albedo / PI; + float3 specular = (nrmDist * fresnel * geo) / max(4 * n_dot_v * n_dot_l, 0.0001f); + + float3 luminanceColor = LightColor * Illuminance; + + float3 cook = (kd * diffuse + specular) * luminanceColor * n_dot_l; + + float3 final = cook; + + // Tone mapping // TODO: do in postprocessing + final = final / (final + 1.0f); + + // Gamma correction // TODO: do in postprocessing/hardware + final = pow(final, 1.0f / 2.2f); + +/////////////TODO: REMOVEME + + //final = max(final - 10000000, nrmDist.xxx); + //final = max(final - 10000000, geo.xxx); + //final = max(final - 10000000, fresnel); + //final = max(final - 10000000, surfaceNormal / 2 + 0.5f); + //final = max(final - 10000000, abs(normal - surfaceNormal) / 2 + 0.5f); + +/////////////TODO: END_REMOVEME + + return float4(final, 1); + //} } #effect[VS=VS,PS=PS] diff --git a/GlitchyEditor/content/Textures/TestMat/nrm.png b/GlitchyEditor/content/Textures/TestMat/nrm.png new file mode 100644 index 0000000..e65ca29 Binary files /dev/null and b/GlitchyEditor/content/Textures/TestMat/nrm.png differ diff --git a/GlitchyEditor/content/Textures/TestMat/rustediron2_albedo.png b/GlitchyEditor/content/Textures/TestMat/rustediron2_albedo.png new file mode 100644 index 0000000..91896ad Binary files /dev/null and b/GlitchyEditor/content/Textures/TestMat/rustediron2_albedo.png differ diff --git a/GlitchyEditor/content/Textures/TestMat/rustediron2_metallic.png b/GlitchyEditor/content/Textures/TestMat/rustediron2_metallic.png new file mode 100644 index 0000000..76ca751 Binary files /dev/null and b/GlitchyEditor/content/Textures/TestMat/rustediron2_metallic.png differ diff --git a/GlitchyEditor/content/Textures/TestMat/rustediron2_normal.png b/GlitchyEditor/content/Textures/TestMat/rustediron2_normal.png new file mode 100644 index 0000000..cc191ec Binary files /dev/null and b/GlitchyEditor/content/Textures/TestMat/rustediron2_normal.png differ diff --git a/GlitchyEditor/content/Textures/TestMat/rustediron2_roughness.png b/GlitchyEditor/content/Textures/TestMat/rustediron2_roughness.png new file mode 100644 index 0000000..c5cecf7 Binary files /dev/null and b/GlitchyEditor/content/Textures/TestMat/rustediron2_roughness.png differ diff --git a/GlitchyEditor/src/EditorLayer.bf b/GlitchyEditor/src/EditorLayer.bf index 2092ed2..0f6bdf6 100644 --- a/GlitchyEditor/src/EditorLayer.bf +++ b/GlitchyEditor/src/EditorLayer.bf @@ -88,7 +88,8 @@ namespace GlitchyEditor camera.FixedAspectRatio = false; camera.RenderTarget = _viewportTarget; let transform = _cameraEntity.GetComponent(); - transform.Position = .(0, 0, -5); + transform.Position = .(-1.5f, 1.5f, -2.5f); + transform.RotationEuler = .(MathHelper.ToRadians(25), MathHelper.ToRadians(35), 0); _cameraEntity.AddComponent().Bind(); _cameraEntity.AddComponent(); @@ -117,23 +118,42 @@ namespace GlitchyEditor { Effect myEffect = new Effect("content/Shaders/myEffect.hlsl")..ReleaseRefNoDelete(); - Material mat = new Material(myEffect)..ReleaseRefNoDelete(); - mat.SetVariable("BaseColor", Vector4(1, 0, 1, 1)); - //mat.SetVariable("LightDir", Vector3(1, 1, 0).Normalized()); + using (Texture2D albedo = new Texture2D("Textures/TestMat/rustediron2_albedo.png", true)) + using (Texture2D normal = new Texture2D("Textures/TestMat/rustediron2_normal.png")) + using (Texture2D rough = new Texture2D("Textures/TestMat/rustediron2_roughness.png")) + using (Texture2D metal = new Texture2D("Textures/TestMat/rustediron2_metallic.png")) + { + albedo.SamplerState = SamplerStateManager.AnisotropicClamp; + normal.SamplerState = SamplerStateManager.AnisotropicClamp; + rough.SamplerState = SamplerStateManager.AnisotropicClamp; + metal.SamplerState = SamplerStateManager.AnisotropicClamp; - List clips = scope .(); - - ModelLoader.LoadModel("content/Models/plane.glb", myEffect, mat, _scene.[Friend]_ecsWorld, clips); - - mat = new Material(myEffect)..ReleaseRefNoDelete(); - mat.SetVariable("BaseColor", Vector4(1, 1, 0, 1)); - //mat.SetVariable("LightDir", Vector3(0, 1, 0).Normalized()); - - clips = scope .(); - - ModelLoader.LoadModel("content/Models/plane.glb", myEffect, mat, _scene.[Friend]_ecsWorld, clips); - - ClearAndReleaseItems!(clips); + Material mat = new Material(myEffect)..ReleaseRefNoDelete(); + mat.SetTexture("AlbedoTexture", albedo); + mat.SetTexture("NormalTexture", normal); + mat.SetTexture("MetallicTexture", metal); + mat.SetTexture("RoughnessTexture", rough); + //mat.SetVariable("BaseColor", Vector4(1, 0, 1, 1)); + //mat.SetVariable("LightDir", Vector3(1, 1, 0).Normalized()); + + List clips = scope .(); + + ModelLoader.LoadModel("content/Models/sphere.glb", myEffect, mat, _scene.[Friend]_ecsWorld, clips); + + mat = new Material(myEffect)..ReleaseRefNoDelete(); + mat.SetTexture("AlbedoTexture", albedo); + mat.SetTexture("NormalTexture", normal); + mat.SetTexture("MetallicTexture", metal); + mat.SetTexture("RoughnessTexture", rough); + //mat.SetVariable("BaseColor", Vector4(1, 1, 0, 1)); + //mat.SetVariable("LightDir", Vector3(0, 1, 0).Normalized()); + + clips = scope .(); + + ModelLoader.LoadModel("content/Models/sphere.glb", myEffect, mat, _scene.[Friend]_ecsWorld, clips); + + ClearAndReleaseItems!(clips); + } } private void InitGraphics() diff --git a/GlitchyEngine/src/Content/ModelLoader.bf b/GlitchyEngine/src/Content/ModelLoader.bf index 7ced41d..a0e02a7 100644 --- a/GlitchyEngine/src/Content/ModelLoader.bf +++ b/GlitchyEngine/src/Content/ModelLoader.bf @@ -265,7 +265,7 @@ namespace GlitchyEngine.Content StringView strView = .(attribute.Name); // Remove number from end of name - while((*(strView.EndPtr - 1)).IsDigit) + while((*(strView.EndPtr - 1)).IsDigit || (*(strView.EndPtr - 1)) == '_') { strView.Length--; } diff --git a/GlitchyEngine/src/Renderer/Effect.bf b/GlitchyEngine/src/Renderer/Effect.bf index 5800180..98d3de6 100644 --- a/GlitchyEngine/src/Renderer/Effect.bf +++ b/GlitchyEngine/src/Renderer/Effect.bf @@ -2,6 +2,7 @@ using System; using System.IO; using System.Collections; using GlitchyEngine.Core; +using GlitchyEngine.Math; namespace GlitchyEngine.Renderer { diff --git a/GlitchyEngine/src/Renderer/Renderer.bf b/GlitchyEngine/src/Renderer/Renderer.bf index 23e3e67..475bb81 100644 --- a/GlitchyEngine/src/Renderer/Renderer.bf +++ b/GlitchyEngine/src/Renderer/Renderer.bf @@ -25,9 +25,17 @@ namespace GlitchyEngine.Renderer private uint32 _height; public DepthStencilTarget DepthStencil; - public RenderTarget2D Color ~ _?.ReleaseRef(); + + // RGB: Albedo.rgb A: ? + public RenderTarget2D Albedo ~ _?.ReleaseRef(); + // RGB: Normal.xyz(Worldspace) A: Ambient public RenderTarget2D Normal ~ _?.ReleaseRef(); + // ???? + public RenderTarget2D Tangent ~ _?.ReleaseRef(); + // RGB: Worldspace Position A: ? public RenderTarget2D Position ~ _?.ReleaseRef(); + // R: Metallicity G: Roughness B: Ambient A: ? + public RenderTarget2D Material ~ _?.ReleaseRef(); public void EnsureSize(uint32 width, uint32 height) { @@ -37,24 +45,32 @@ namespace GlitchyEngine.Renderer if (_width == 0 || _height == 0) { // Note: Depth-Buffer in Color-Target for convenience - RenderTarget2DDescription colorDesc = .(.R8G8B8A8_UNorm, width, height, 1, 1, .D24_UNorm_S8_UInt); - Color = new RenderTarget2D(colorDesc); + RenderTarget2DDescription albedoDesc = .(.R8G8B8A8_UNorm, width, height, 1, 1, .D24_UNorm_S8_UInt); + Albedo = new RenderTarget2D(albedoDesc); - RenderTarget2DDescription normalDesc = .(.R32G32B32A32_Float, width, height); + RenderTarget2DDescription normalDesc = .(.R8G8B8A8_SNorm, width, height); Normal = new RenderTarget2D(normalDesc); + + RenderTarget2DDescription tangentDesc = .(.R8G8B8A8_SNorm, width, height); + Tangent = new RenderTarget2D(tangentDesc); RenderTarget2DDescription positionDesc = .(.R32G32B32A32_Float, width, height); Position = new RenderTarget2D(positionDesc); + + RenderTarget2DDescription materialDesc = .(.R8G8B8A8_UNorm, width, height); + Material = new RenderTarget2D(materialDesc); } _width = width; _height = height; - Color.Resize(_width, _height); + Albedo.Resize(_width, _height); Normal.Resize(_width, _height); + Tangent.Resize(_width, _height); Position.Resize(_width, _height); + Material.Resize(_width, _height); - DepthStencil = Color.DepthStencilTarget; + DepthStencil = Albedo.DepthStencilTarget; } public void Bind() @@ -62,12 +78,23 @@ namespace GlitchyEngine.Renderer RenderCommand.SetDepthStencilTarget(DepthStencil); RenderCommand.UnbindRenderTargets(); - RenderCommand.SetRenderTarget(Color, 0); + RenderCommand.SetRenderTarget(Albedo, 0); RenderCommand.SetRenderTarget(Normal, 1); - RenderCommand.SetRenderTarget(Position, 2); + RenderCommand.SetRenderTarget(Tangent, 2); + RenderCommand.SetRenderTarget(Position, 3); + RenderCommand.SetRenderTarget(Material, 4); RenderCommand.BindRenderTargets(); } + + public void Clear() + { + RenderCommand.Clear(_gBuffer.Albedo, .Color | .Depth, .HotPink, 1, 0); + RenderCommand.Clear(_gBuffer.Normal, .HotPink); + RenderCommand.Clear(_gBuffer.Tangent, .HotPink); + RenderCommand.Clear(_gBuffer.Position, .HotPink); + RenderCommand.Clear(_gBuffer.Material, .HotPink); + } } static internal GraphicsContext _context ~ _?.ReleaseRef(); @@ -85,6 +112,8 @@ namespace GlitchyEngine.Renderer static GBuffer _gBuffer ~ delete _; static Effect TestFullscreenEffect ~ _?.ReleaseRef(); + static BlendState _gBufferBlend ~ _?.ReleaseRef(); + public static void Init(GraphicsContext context, EffectLibrary effectLibrary) { Debug.Profiler.ProfileFunction!(); @@ -105,6 +134,8 @@ namespace GlitchyEngine.Renderer InitDeferredRenderer(effectLibrary); _gBuffer = new GBuffer(); + BlendStateDescription gBufferBlendDesc = .Default; + _gBufferBlend = new BlendState(gBufferBlendDesc); } public static void Deinit() @@ -152,10 +183,10 @@ namespace GlitchyEngine.Renderer using(var quadVertices = new VertexBuffer(typeof(Vector4), 4, .Immutable)) { Vector4[4] vertices = .( - .(-0.5f,-0.5f, 0, 1), - .(-0.5f, 0.5f, 0, 0), - .( 0.5f, 0.5f, 1, 0), - .( 0.5f,-0.5f, 1, 1) + .(-1,-1, 0, 1), + .(-1, 1, 0, 0), + .( 1, 1, 1, 0), + .( 1,-1, 1, 1) ); quadVertices.SetData(vertices); @@ -257,14 +288,16 @@ namespace GlitchyEngine.Renderer // foreach camera: // { _gBuffer.EnsureSize(_sceneConstants.CameraTarget.Width, _sceneConstants.CameraTarget.Height); + _gBuffer.Clear(); _gBuffer.Bind(); - RenderCommand.Clear(_gBuffer.Color, .Color | .Depth, .Blue, 1, 0); - RenderCommand.Clear(_gBuffer.Normal, Color.Beige); - RenderCommand.Clear(_gBuffer.Position, Color.Black); + + RenderCommand.SetViewport(0, 0, _sceneConstants.CameraTarget.Width, _sceneConstants.CameraTarget.Height); + + RenderCommand.SetBlendState(_gBufferBlend); - /*RenderCommand.UnbindRenderTargets(); - RenderCommand.SetRenderTarget(_sceneConstants.CameraTarget, 0, true); - RenderCommand.BindRenderTargets();*/ + //RenderCommand.UnbindRenderTargets(); + //RenderCommand.SetRenderTarget(_sceneConstants.CameraTarget, 0, true); + //RenderCommand.BindRenderTargets(); // TODO: Draw into GBuffer for (SubmittedMesh entry in _queue) @@ -281,14 +314,20 @@ namespace GlitchyEngine.Renderer RenderCommand.UnbindRenderTargets(); RenderCommand.SetRenderTarget(_sceneConstants.CameraTarget, 0, true); RenderCommand.BindRenderTargets(); + + _gBuffer.Albedo.SamplerState = SamplerStateManager.PointClamp; - _gBuffer.Color.SamplerState = SamplerStateManager.PointClamp; + TestFullscreenEffect.SetTexture("GBuffer_Albedo", _gBuffer.Albedo); + TestFullscreenEffect.SetTexture("GBuffer_Normal", _gBuffer.Normal); + TestFullscreenEffect.SetTexture("GBuffer_Tangent", _gBuffer.Tangent); + TestFullscreenEffect.SetTexture("GBuffer_Position", _gBuffer.Position); + TestFullscreenEffect.SetTexture("GBuffer_Material", _gBuffer.Material); - TestFullscreenEffect.SetTexture("Colors", _gBuffer.Color); - TestFullscreenEffect.SetTexture("Normals", _gBuffer.Normal); - //TestFullscreenEffect.SetTexture("Positions", _gBuffer.Position); - - //TestFullscreenEffect.SetVariable("LightDir"); + TestFullscreenEffect.Variables["LightColor"].SetData(Vector3(1, 1, 1)); + TestFullscreenEffect.Variables["Illuminance"].SetData(5.0f); + TestFullscreenEffect.Variables["LightDir"].SetData(Vector3(0, 1, 0)); + TestFullscreenEffect.Variables["CameraPos"].SetData(_sceneConstants.CameraPosition); + TestFullscreenEffect.Variables["Scaling"].SetData(Vector2(_sceneConstants.CameraTarget.Width, _sceneConstants.CameraTarget.Height) / Vector2(_gBuffer.Albedo.Width, _gBuffer.Albedo.Height)); TestFullscreenEffect.Bind(_context); diff --git a/GlitchyEngine/src/Renderer/Texture.bf b/GlitchyEngine/src/Renderer/Texture.bf index 51a1129..5c11638 100644 --- a/GlitchyEngine/src/Renderer/Texture.bf +++ b/GlitchyEngine/src/Renderer/Texture.bf @@ -63,16 +63,16 @@ namespace GlitchyEngine.Renderer //public override extern uint32 ArraySize {get;} //public override extern uint32 MipLevels {get;} - public this(StringView path) + public this(StringView path, bool pngSrgb = false) { _path = new String(path); - LoadTexture(); + LoadTexture(pngSrgb); } const String PngMagicWord = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"; const String DdsMagicWord = "DDS "; - private void LoadTexture() + private void LoadTexture(bool pngSrgb) { Debug.Profiler.ProfileResourceFunction!(); @@ -91,7 +91,7 @@ namespace GlitchyEngine.Renderer if (strView.StartsWith(PngMagicWord)) { - LoadPng(data); + LoadPng(data, pngSrgb); } else if (strView.StartsWith(DdsMagicWord)) { @@ -104,7 +104,7 @@ namespace GlitchyEngine.Renderer } } - protected void LoadPng(Stream stream) + protected void LoadPng(Stream stream, bool srgb) { Debug.Profiler.ProfileResourceFunction!(); @@ -126,7 +126,7 @@ namespace GlitchyEngine.Renderer // TODO: load as SRGB because PNGs are usually not stored as linear //Texture2DDesc desc = .(width, height, .R8G8B8A8_UNorm_SRGB, 1, 1, .Immutable); - Texture2DDesc desc = .(width, height, .R8G8B8A8_UNorm, 1, 1, .Immutable); + Texture2DDesc desc = .(width, height, srgb? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable); PrepareTexturePlatform(desc, false);