View more

View more

View more

### Image of the Day Submit

IOTD | Top Screenshots

### The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.

# Need help with microfacet brdf

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

5 replies to this topic

### #1lipsryme  Members

Posted 22 October 2012 - 12:16 PM

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

Edited by lipsryme, 03 November 2012 - 01:05 PM.

### #2Tombstone  Members

Posted 30 October 2012 - 01:40 PM

Hi

I see at least your half vector is wrong.

"float3 H = normalize(-L - V);" should be: float3 H = normalize(-L + V);

### #3lipsryme  Members

Posted 03 November 2012 - 12:16 PM

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...

Edited by lipsryme, 03 November 2012 - 01:06 PM.

### #4Bacterius  Members

Posted 03 November 2012 - 08:27 PM

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

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

Edited by Bacterius, 03 November 2012 - 08:39 PM.

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

### #5CryZe  Members

Posted 04 November 2012 - 05:01 PM

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

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

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:
float G = min(1, 2 * NdH / VdH * min(NdV, NdL));

### #6lipsryme  Members

Posted 05 November 2012 - 07:31 AM

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 ?

Edited by lipsryme, 05 November 2012 - 09:02 AM.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.