Need help with microfacet brdf

Started by
4 comments, last by lipsryme 11 years, 6 months ago
I'm trying to implement a microfacet brdf but my results are wrong somehow.
That's why I was hoping someone can point out what I'm doing wrong or what I'm missing.

-> see below
Advertisement
Hi

I see at least your half vector is wrong.

"float3 H = normalize(-L - V);" should be: float3 H = normalize(-L + V);
Actually doing it like that makes it not work at all.
My View direction is being calculated like this:

// Calculate Position from linear view space depth
float3 ViewRay = input.PositionVS.xyz;
float depth = DepthTarget.Sample(PointSampler, input.UV).r;
float3 ViewDir = ViewRay * depth; // subtraction by the cam position not needed since we're already in view space


Have to say I got it working now with a phong distribution but anything else (the commented out part) gives me wrong results.

// Compute Fresnel Term (F) using Schlick's approximation
float LdotH = max(0, dot(-L, H));
float base = 1 - LdotH;
float exponent = pow(base, 5.0f);
float3 F = saturate(SpecularAlbedo + (1 - SpecularAlbedo) * exponent);

// Lambert
float3 kd = NdotL;
Lr.rgb += (kd / PI) * Ei;


// Normalized Blinn-Phong distribution (D)
float D = 0.0f;
float NdotH = max(0, dot(N, H));
D = ((SpecularPower + 2) / 2 * PI) * pow(NdotH, SpecularPower);

// Beckmann distribution (D)
//float NdotH = max(0, dot(N, H));
//float NdotH2 = NdotH * NdotH;
//float NdotH4 = NdotH * NdotH * NdotH * NdotH;
//float SpecularPower2 = SpecularPower * SpecularPower;
//float Beckmann_exponent = -((1 - NdotH2) / (SpecularPower2 * NdotH2));
//float D = 1 * exp(Beckmann_exponent) / PI * SpecularPower2 * NdotH4;

// Trowbridge-Reitz (GGX) distribution
//float NdotH = max(0, dot(N, H));
//float SpecPow2 = SpecularPower * SpecularPower;
//float D = SpecPow2 / PI * pow(((NdotH*NdotH) * (SpecPow2 - 1) + 1), 2);

// Cook-Torrance approximation (G)
float NdotV = max(0, dot(N, V));
float G = 1.0f;

float3 nominator = F * G * D;
float denominator = 4 * ((LdotH+0.000001f) * (LdotH+0.000001f));
Ls.rgb += nominator / denominator;


Beckmann or Trowbridge-Reitz doesn't...
Pretty sure the Beckmann distribution is actually this (and same comment for GGX, I would guess):

float D = 1 * exp(Beckmann_exponent) / (PI * SpecularPower2 * NdotH4);

This is my path tracer code for Beckmann, it uses a raw BRDF so you'll have to modify the inputs (the incident vector goes towards the surface, the exitant vector goes away from it). The vector * vector operation is the dot product. Also I'm not using the tangent formula trick yet whereas you seem to be.. sorry:

http://pastebin.com/pHqCH1dc

Might have gone overboard with the absolute values but I was dealing with refraction at the same time and didn't want to take risks smile.png

EDIT: dammit, why are the code tags munching my newlines?
EDIT: pastebin it is!

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Your GGX distribution is missing a parenthesis. Everything should be in the denominator except the alpha^2. So the correct implementation would be:

[font=courier new,courier,monospace]float NdotH = max(0, dot(N, H));
float SpecPow2 = SpecularPower * SpecularPower;
float D = SpecPow2 / (PI * pow(((NdotH*NdotH) * (SpecPow2 - 1) + 1), 2));[/font]


float G = min(1, min(2 * NdH * NdV / VdH, 2 * NdH * NdL / VdH));


Don't do it this way, you are wasting instructions this way. Do it like that:
[font=courier new,courier,monospace]float G = min(1, 2 * NdH / VdH * min(NdV, NdL));[/font]
I'm still getting crazy high values (basically the entire mesh white). Does the input alpha have to be ridiculously high ?
edit: hmm no higher values don't seem to fix this.
edit2: ok so when only outputting D or D*F it looks more like it should (still very bright). Is there something wrong with my Geometry term ?

This topic is closed to new replies.

Advertisement