Skip to content

Instantly share code, notes, and snippets.

@benanil
Last active March 15, 2022 15:14
Show Gist options
  • Save benanil/a9a57785cecf2da6de9a59ffc03fe078 to your computer and use it in GitHub Desktop.
Save benanil/a9a57785cecf2da6de9a59ffc03fe078 to your computer and use it in GitHub Desktop.
a pbr shader
cbuffer cbPerObject : register(b0)
{
float4x4 MVP;
float4x4 Model;
};
cbuffer cbPerMaterial : register(b1)
{
float shininess;
float roughness;
float metallic;
float padding;
};
cbuffer cbGlobal : register(b2)
{
float sunAngle;
float3 ambientColor; // 16
float3 sunColor;
float time; // 32
float3 viewPos;
float ambientStength; // 48
float4x4 LightSpaceMatrix;
};
struct VS_OUTPUT
{
float4 Pos : SV_POSITION;
float2 TexCoord : TEXCOORD;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 fragPos : TEXCOORD1;
float4 lightSpaceFrag : TEXCOORD2;
};
Texture2D ObjTexture : register(t0);
Texture2D SpecularTexture : register(t1);
Texture2D NormalTexture : register(t2);
Texture2D ShadowTexture : register(t3);
SamplerState ObjSamplerState : register(s0);
SamplerState SpecularSampler : register(s1);
SamplerState NormalSampler : register(s2);
SamplerState ShadowSampler : register(s3);
VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float4 inNormal : NORMAL, float4 inTangent : TANGENT)
{
VS_OUTPUT output;
inPos.w = 1;
inNormal.w = 0; inTangent.w = 0;
output.Pos = mul(inPos, MVP);
output.normal = mul(inNormal, Model).xyz;
output.TexCoord = inTexCoord;
output.tangent = mul(inTangent, Model).xyz;
output.fragPos = mul(inPos, Model).xyz;
output.lightSpaceFrag = mul(inPos, mul(Model, LightSpaceMatrix));
return output;
}
#define DX_DEG_TO_RAD 0.01745f
#define DX_RAD_TO_DEG 57.295f
#define PI 3.1415f
// product could be NdV or VdH depending on used technique
float3 fresnel_factor(in float3 F0, in float cosTheta)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
float G_schlick(in float roughness, in float NdV, in float NdL)
{
float k = roughness * roughness * 0.5;
float V = NdV * (1.0 - k) + k;
float L = NdL * (1.0 - k) + k;
return 0.25 / (V * L);
}
float D_blinn(in float roughness, in float NdH)
{
float m = roughness * roughness;
float m2 = m * m;
float n = 2.0 / m2 - 2.0;
return (n + 2.0) / (2.0 * PI) * pow(NdH, n);
}
float D_beckmann(in float roughness, in float NdH)
{
float m = roughness * roughness;
float m2 = m * m;
float NdH2 = NdH * NdH;
return exp((NdH2 - 1.0) / (m2 * NdH2)) / (PI * m2 * NdH2 * NdH2);
}
float D_GGX(in float roughness, in float cosLh)
{
float alpha = roughness * roughness;
float alphaSq = alpha * alpha;
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
return alphaSq / (PI * denom * denom);
}
// cook-torrance specular calculation
float3 cooktorrance_specular(in float NdL, in float NdV, in float NdH, in float3 specular, in float roughness, in float metallic)
{
// float D = min(D_blinn(roughness, NdH), 1);
// float D = min(D_beckmann(roughness, NdH), 1);
float D = D_GGX(roughness, NdH);
float G = G_schlick(roughness, NdV, NdL);
float rim = lerp(1.0 - roughness * metallic * 0.9, 1.0, NdV);
return (1.0 / rim) * specular * G * D;
}
#define SCALAR3f(x) float3(x, x, x)
float3 CalculatePointLight(in float3 normal, in float3 fragPos, in float3 specTex, in float time)
{
// calculate first light
float3 direction = float3(-950, 300, 0) - fragPos;
float lightDist = length(direction);
float diffuseFactor = dot(normal, normalize(direction));
float lightFactor = diffuseFactor * (max(500 - lightDist, 0) / 500);
float3 firstLight = float3(0.5, 0.3, 0.25) * lightFactor;
float3 viewDirection = normalize(fragPos - viewPos);
// float3 specular = firstLight * pow(max(0, dot(reflect(direction, normal), viewDirection)), 0.2) * specTex * 0.33;
float3 specular = firstLight * pow(saturate(dot(normalize(direction + viewDirection), normal)), 0.2) * specTex * 0.5;
return firstLight + specular * 3; // + secondLight * 10;
}
float3 CalculateNormalMap(in float3 normalMapSample,
in float3 unitNormalW,
in float3 tangentW)
{
// Uncompress each component from [0,1] to [-1,1].
float3 normalT = 2.0f * normalMapSample - 1.0f;
// Build orthonormal basis.
float3 N = unitNormalW;
float3 T = normalize(tangentW - dot(tangentW, N) * N);
float3 B = cross(N, T);
float3x3 TBN = float3x3(T, B, N);
// Transform from tangent space to world space.
float3 bumpedNormalW = mul(normalT, TBN);
return bumpedNormalW;
}
float ShadowCalculation(float4 lpos)
{
//re-homogenize position after interpolation
lpos.xyz /= lpos.w;
//if position is not visible to the light - dont illuminate it
if( lpos.x < -1.0f || lpos.x > 1.0f ||
lpos.y < -1.0f || lpos.y > 1.0f ||
lpos.z < 0.0f || lpos.z > 1.0f ) return 1;
//transform clip space coords to texture space coords (-1:1 to 0:1)
lpos.x = lpos.x * 0.5f + 0.5;
lpos.y = lpos.y * -0.5f + 0.5;
//sample shadow map - point sampler
float shadowMapDepth = ShadowTexture.Sample(ShadowSampler, lpos.xy).r;
//if clip space z value greater than shadow map value then pixel is in shadow
return shadowMapDepth > lpos.z ? 0.3f : 1.0f;
}
float4 PS(VS_OUTPUT input) : SV_TARGET
{
float4 albedo = ObjTexture.Sample(ObjSamplerState, input.TexCoord);
float4 specularTex = SpecularTexture.Sample(SpecularSampler, input.TexCoord) * (shininess);
clip(albedo.a - 0.15f);
float3 L = float3(0, max(sin(sunAngle * DX_DEG_TO_RAD), 0), cos(sunAngle * DX_DEG_TO_RAD));
float3 V = normalize(input.fragPos - viewPos);
float3 H = normalize(V - L);
float3 normal = CalculateNormalMap(NormalTexture.Sample(NormalSampler, input.TexCoord).xyz, input.normal, input.tangent);
float ndl = max(0.1f, dot(normal, L));
float ndv = max(0.0f, dot(normal, V));
float ndh = max(0.0f, dot(normal, H));
float hdv = max(0.0f, dot(H, V));
float3 F0 = float3(0,0,0);
F0 = lerp(F0, albedo.xyz, metallic);
float newRoughness = max(roughness - (shininess / 2), 0.001f);
float3 specFresnel = fresnel_factor(F0, hdv);
float3 specular = cooktorrance_specular(ndl, ndv, ndh, specFresnel, newRoughness, metallic) * ndl * specularTex.xyz;
float3 ambient = ambientColor * ambientStength;
float4 result = float4(0, 0, 0, 1);
result.xyz = albedo.xyz * (ndl * sunColor) + specular + ambient;
result.xyz += CalculatePointLight(normal, input.fragPos, specularTex.xyz, time);
result.xyz *= ShadowCalculation(input.lightSpaceFrag);
return result;
}
// sadfasdf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment