Start of PBR

This commit is contained in:
Simon Lübeß
2022-05-09 16:45:16 +02:00
parent 2817c5b1a1
commit dc235399c8
16 changed files with 462 additions and 82 deletions
Binary file not shown.
Binary file not shown.
@@ -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
}
@@ -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;
}
+72 -23
View File
@@ -1,9 +1,21 @@
Texture2D AlbedoTexture : register(t0);
SamplerState AlbedoSampler : register(s0);
Texture2D<float3> NormalTexture : register(t1);
SamplerState NormalSampler : register(s1);
Texture2D<float> MetallicTexture : register(t2);
SamplerState MetallicSampler : register(s2);
Texture2D<float> RoughnessTexture : register(t3);
SamplerState RoughnessSampler : register(s3);
// Texture2D<float> 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;
}
+170 -11
View File
@@ -1,12 +1,22 @@
Texture2D Colors : register(t0);
Texture2D<float3> 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]
Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB