Right now I am trying to implement Specular lighting in my DirectX Engine. Whenever I create the DirectSpecularBRDF function in my .HLSL file, my program crashes. Can anybody help me? The problem is in DirectSpecularBRDF, I haven't called the function yet but when I comment out the function code everything works fine. However DirectDiffuseBRDF works fine though? Here is my code:
effects.fx
#include "Common.hlsl"
struct Light
{
float3 dir;
float4 ambient;
float4 diffuse;
};
cbuffer cbPerFrame
{
Light light;
float4x4 camPos;
float Roughness;
float Metalness;
};
cbuffer cbPerObject
{
float4x4 WVP;
float4x4 World;
};
Texture2D ObjTexture;
SamplerState ObjSamplerState
{
Filter = ANISOTROPIC;
MaxAnisotropy = 16;
AddressU = Wrap;
AddressV = Wrap;
};
struct VS_OUTPUT
{
float4 Pos : SV_POSITION;
float2 TexCoord : TEXCOORD;
float3 normal : NORMAL;
};
float3 DirectDiffuseBRDF(float3 diffuseAlbedo, float nDotL)
{
return (diffuseAlbedo * nDotL);
}
float3 DirectSpecularBRDF(float3 specularAlbedo, float3 positionWS, float3 normalWS, float3 lightDir)
{
float3 viewDir = normalize(camPos - positionWS);
float3 halfVec = normalize(viewDir + lightDir);
float nDotH = saturate(dot(normalWS, halfVec));
float nDotL = saturate(dot(normalWS, lightDir));
float nDotV = max(dot(normalWS, viewDir), 0.0001f);
float alpha2 = Roughness * Roughness;
// Computes the distribution of the microfacets for the shaded surface.
// Trowbridge-Reitz/GGX normal distribution function.
float D = alpha2 / (Pi * pow(nDotH * nDotH * (alpha2 - 1) + 1, 2.0f));
// Computes the amount of light that reflects from a mirror surface given its index of refraction.
// Schlick's approximation.
float3 F = Schlick_Fresnel(specularAlbedo, halfVec, lightDir);
// Computes the shadowing from the microfacets.
// Smith's approximation.
float G = G_Smith(Roughness, nDotV, nDotL);
return D * F * G;
}
VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float3 normal : NORMAL)
{
VS_OUTPUT output;
output.Pos = mul(inPos, WVP);
output.normal = mul(normal, World);
output.TexCoord = inTexCoord;
return output;
}
float4 PS(VS_OUTPUT input) : SV_TARGET
{
input.normal = normalize(input.normal);
float4 textureColor = ObjTexture.Sample(ObjSamplerState, input.TexCoord);
float3 specularColor = float3(Metalness, Metalness, Metalness);
float nDotL = saturate(dot(input.normal, light.dir));
float3 diffuseLighting = textureColor * light.ambient * light.diffuse;
diffuseLighting += saturate(DirectDiffuseBRDF(textureColor, nDotL));
return float4(diffuseLighting, textureColor.a);
}
common.hlsl
//=================================================================================================
// Constant Variables
//=================================================================================================
static const float Pi = 3.141592654f;
static const float Pi2 = 6.283185307f;
static const float Pi_2 = 1.570796327f;
static const float Pi_4 = 0.7853981635f;
static const float InvPi = 0.318309886f;
static const float InvPi2 = 0.159154943f;
//=================================================================================================
// Sampler States
//=================================================================================================
SamplerState SamplerLinear
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
SamplerState SamplerAnisotropic
{
Filter = ANISOTROPIC;
MaxAnisotropy = 16;
AddressU = Wrap;
AddressV = Wrap;
};
// ===============================================================================================
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
// ===============================================================================================
float2 Hammersley(uint i, uint N)
{
float ri = reversebits(i) * 2.3283064365386963e-10f;
return float2(float(i) / float(N), ri);
}
// ===============================================================================================
// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
// ===============================================================================================
float GGX(float NdotV, float a)
{
float k = a / 2;
return NdotV / (NdotV * (1.0f - k) + k);
}
// ===============================================================================================
// Geometry Term
// -----------------------------------------------------------------------------------------------
// Defines the shadowing from the microfacets.
//
// Smith approximation:
// http://blog.selfshadow.com/publications/s2013-shading-course/rad/s2013_pbs_rad_notes.pdf
// http://graphicrants.blogspot.fr/2013/08/specular-brdf-reference.html
//
// ===============================================================================================
float G_Smith(float a, float nDotV, float nDotL)
{
return GGX(nDotL, a * a) * GGX(nDotV, a * a);
}
// ================================================================================================
// Fresnel
// ------------------------------------------------------------------------------------------------
// The Fresnel function describes the amount of light that reflects from a mirror surface
// given its index of refraction.
//
// Schlick's approximation:
// http://blog.selfshadow.com/publications/s2013-shading-course/rad/s2013_pbs_rad_notes.pdf
// http://graphicrants.blogspot.fr/2013/08/specular-brdf-reference.html
//
// ================================================================================================
float3 Schlick_Fresnel(float3 f0, float3 h, float3 l)
{
return f0 + (1.0f - f0) * pow((1.0f - dot(l, h)), 5.0f);
}
// ===============================================================================================
// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
// ===============================================================================================
float3 ImportanceSampleGGX(float2 Xi, float Roughness, float3 N)
{
float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
float Phi = 2 * Pi * Xi.x;
float CosTheta = sqrt((1 - Xi.y) / (1 + (a * a - 1) * Xi.y));
float SinTheta = sqrt(1 - CosTheta * CosTheta);
float3 H;
H.x = SinTheta * cos(Phi);
H.y = SinTheta * sin(Phi);
H.z = CosTheta;
float3 UpVector = abs(N.z) < 0.999 ? float3(0, 0, 1) : float3(1, 0, 0);
float3 TangentX = normalize(cross(UpVector, N));
float3 TangentY = cross(N, TangentX);
// Tangent to world space
return TangentX * H.x + TangentY * H.y + N * H.z;
}