At the moment I am implementing Specular Lighting for my engine in DirectX on top of Diffuse Lighting. I am using a physically based technique and as you can see from the image below something is clearly wrong. Can somebody please help me?

One thing I think that may be causing the issue is a buffer packing error (I only started learning to do this yesterday) so some values may not be sent across to HLSL properly. Here's my cbuffer struct.
struct cbPerFrame { Light light; XMVECTOR cameraPosition; float pad; float pad2; float pad3; float Roughness; float Metalness; };
Or is it how I'm sending my Camera Position over to HLSL?
constbuffPerFrame.light = light; constbuffPerFrame.Roughness = 10.0f; constbuffPerFrame.Metalness = 10.0f; constbuffPerFrame.cameraPosition = camPosition; //camPosition is a XMVector
If that's fine then there must be something dead stupid & simple I've done in my shader:
Effects.fx
#include "common.hlsli" struct Light { float3 dir; float4 ambient; float4 diffuse; }; cbuffer cbPerFrame { Light light; float3 cameraPosition; 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; }; 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 specularAlbedo = float3(Metalness, Metalness, Metalness); float3 lighting = 0.0f; float3 lightPos = float3(100.0f, 100.0f, 0.0f); float3 pixelToLight = lightPos - input.Pos; float lightDist = length(pixelToLight); float3 lightDir = pixelToLight / lightDist; float nDotL = saturate(dot(input.normal, light.dir)); float3 diffuseLighting = textureColor * light.ambient * light.diffuse; diffuseLighting += saturate(DirectDiffuseBRDF(textureColor, nDotL)); float3 specularLighting = textureColor * light.ambient * light.diffuse; specularLighting += DirectSpecularBRDF(specularAlbedo, input.Pos, input.normal, lightDir, cameraPosition, Roughness); lighting = diffuseLighting + specularLighting; return float4(lighting, textureColor.a); }
common.hlsli
//================================================================================================= // 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; } //The Direct Diffuse BRDF float3 DirectDiffuseBRDF(float3 diffuseAlbedo, float nDotL) { return (diffuseAlbedo * nDotL); } //The Direct Specular BRDF float3 DirectSpecularBRDF(float3 specularAlbedo, float3 positionWS, float3 normalWS, float3 lightDir, float3 CameraPos, float Roughness) { float3 viewDir = normalize(CameraPos - 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; }