Skip to content

Commit

Permalink
BRDF explorer app: Some progress on generating shaders
Browse files Browse the repository at this point in the history
  • Loading branch information
Crisspl committed Jun 16, 2019
1 parent 9790747 commit 914b50d
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 36 deletions.
70 changes: 40 additions & 30 deletions examples_tests/13.BRDF_Explorer/BRDFExplorerApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,38 +142,48 @@ class CShaderManager
video::E_MATERIAL_TYPE addShader(const SParams& _params)
{
std::string source =
R"(#version 430 core
R"(#version 430 core
layout (location = 0) out vec4 OutColor;
in vec3 WorldPos;
in vec2 TexCoords;
in vec3 Normal;
layout (location = 0) uniform vec3 uEmissive;
layout (location = 1) uniform vec3 uAlbedo;
layout (location = 2) uniform float uRoughness1;
layout (location = 3) uniform float uRoughness2;
layout (location = 4) uniform float uIoR;
layout (location = 5) uniform float uMetallic;
layout (location = 6) uniform float uHeightFactor;
layout (location = 7) uniform vec3 uLightColor;
layout (location = 8) uniform vec3 uLightPos;
layout (location = 9) uniform sampler2D uAlbedoMap;
layout (location = 10) uniform sampler2D uRoughnessMap;
layout (location = 11) uniform sampler2D uIoRMap;
layout (location = 12) uniform sampler2D uMetallicMap;
layout (location = 13) uniform sampler2D uBumpMap;
layout (location = 14) uniform sampler2D uAOMap;
layout (location = 0) uniform vec3 uEmissive;
layout (location = 1) uniform vec3 uAlbedo;
layout (location = 2) uniform float uRoughness1;
layout (location = 3) uniform float uRoughness2;
layout (location = 4) uniform float uIoR;
layout (location = 5) uniform float uMetallic;
layout (location = 6) uniform float uHeightFactor;
layout (location = 7) uniform vec3 uLightColor;
layout (location = 8) uniform vec3 uLightPos;
layout (binding = 0) uniform sampler2D uAlbedoMap;
layout (binding = 1) uniform sampler2D uRoughnessMap;
layout (binding = 2) uniform sampler2D uIoRMap;
layout (binding = 3) uniform sampler2D uMetallicMap;
layout (binding = 4) uniform sampler2D uBumpMap;
layout (binding = 5) uniform sampler2D uAOMap;
float getRoughness();
float getMetallic();
float getIoR();
float getAO();
vec3 getAlbedo();
float diffuse(...);
float specular(...);
)"
+
IncludeHandler->getIncludeStandard("irr/builtin/glsl/brdf/diffuse/oren_nayar.glsl")
+
IncludeHandler->getIncludeStandard("irr/builtin/glsl/brdf/specular/ndf/ggx_trowbridge_reitz.glsl")
+
IncludeHandler->getIncludeStandard("irr/builtin/glsl/brdf/specular/geom/ggx_smith.glsl")
+
IncludeHandler->getIncludeStandard("irr/builtin/glsl/brdf/specular/fresnel/fresnel_schlick.glsl")
+
R"(
float diffuse(in float a2, in vec3 N, in vec3 L, in vec3 V, in float NdotL, in float NdotV);
float specular(in float a2, in float NdotL, in float NdotV, in float NdotH);
void main() {
const vec3 N = normalize(Normal);

This comment has been minimized.

Copy link
@devshgraphicsprogramming

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 18, 2019

obvs most of those identities you can only do before the clamp with max(x,0.0)

This comment has been minimized.

Copy link
@devshgraphicsprogramming
Expand All @@ -193,36 +203,36 @@ void main() {
const vec3 albedo = getAlbedo();
const float ior = getIoR();
const float ao = getAO();
const float F0 = mix(vec3(ior, ior, ior), albedo, metallic);
const vec3 F0 = mix(vec3(1.0-ior), albedo, metallic);

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

F0 from ior is a different calculation

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 21, 2019

@Crisspl

F0_texture = FresnelEquallyPolarized(1.0/*NdotV==1.0*/)/SCALE_FACTOR/*0.08 usually but double check*/;

now need to get the inverse function ;)

This comment has been minimized.

Copy link
@devshgraphicsprogramming
const vec3 fresnel = FresnelSchlick(F0, NdotV);

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 21, 2019

@Crisspl quick digression on the topic of Earl Hammon and Fresnel diffuse/specular weighing
914b50d#r33961898

What we have right now (and so do Mitsuba, UE4, Cycles, Frostbite, etc.) is actually a bad approximation, because physically:

  • Rough Specular = only microfacets visible (local/micro smith) and oriented ideally so the light vector can reflect towards the observer (half-vector == microfacet normal) so contribution from all other microfacets is ignored (Delta function so integration drops out)
  • Rough Diffuse = all microfacets that are visible (local/micro smith) of any orientation will emit equal amounts of light (that trasmits through the microfacet surface in and out) in all directions, so full integration necessary and no closed solution possible (this why Hammon had to integrate numerically and then fit approximations).

So to reiterate
diffuse = Integral Over All Possible Microfacet Normals { dot(l,m) FresnelIn(l,m) FresnelOut(v,m)/dot(v.m) } dm
(page 45)
Unfortunately Hammon used Schlick on page 106, which probably makes the diffuse he derived too dark for low reflectivity materials (which I don't understand cause he was numerically raytracing heightfields and deriving the approximations off-line).

What all renderer's get wrong:

  • is that the fresnel for all microfacets (with local normal m) is assumed to be the same as the fresnel for the microfacet with the same normal as the half-vector
  • there's no fresnel for the diffuse leaving the microfacet (it needs to get out from the scattering medium with a different light-speed than the outside void [IoR]) which is on page 100 of the PDF I linked

This is obviously not something we can fix for Orren-Nayar, we'd actually have to use GGX Diffuse from Titanfall 2.
And we could not really mix any other Specular model with any other diffuse (the microfacet distributions have to match for both distributions).

If we wanted to simulate any other combination then it would have to be simulated as a "coating" (there are actually two different microfacet surfaces and one is below the other).
This is actually what UE4, etc. (and the current code) are doing in approximation because the assumption is clearly that whatever does not get reflected (1-fresnel), gets passed to the diffuse BRDF. An approximation because we're not taking into account the light lost from all the other microfacets reflecting light into the aether as well as the fresnel (Internal Reflection) as the diffuse exits through the specular coating.

P.S. To fix Hammon's approximation with Schlick can probably be fixed with smooth = 1.05*(1-Fresnel(NdotL,IoR))*(1-Fresnel(NdotV,IoR));, but I'm not really sure (page 183 onwards). We could write him an email XD ;)

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 21, 2019

Page 187-188 would actually outline how to do it with a proper Fresnel Function

Solve for k (with numerical integration package such as Mathematica)
2PIIntegrate[k*(1-Fresnel(theta,IoR))*cos(theta)*sin(theta),,0,PI/2] = 1

Could probably do change of variables from dtheta to dcos(theta)

Then we could get k as a function of just IoR and that would probably come out to something slightly different than 1.05 when IoR==1 (it could likely be 1.05 for IoR>1.01), but at least we'd know to lerp (or interpolate in a different way) between A and 1.05 depending on IoR

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 21, 2019

would be nice to have something that does not fall apart with F0 < 0.02

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 21, 2019

This is interesting (when they start discussing diffuse fresnel)
https://patapom.com/blog/BRDF/BRDF%20Models/

This comment has been minimized.

Copy link
@devshgraphicsprogramming

This comment has been minimized.

Copy link
@devshgraphicsprogramming

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 21, 2019

Seems that the 1.05 nomalization factor could be instead made as k=4/(A+B) (4 because there is a 2PI missing from the chain of equations and k doesn't have PI factored in)

Where A
https://www.wolframalpha.com/input/?i=integrate++((cos(%CE%B8_1)+-+eta+sqrt(1+-+(eta+sin(%CE%B8_1))%5E2))%2F(cos(%CE%B8_1)+%2B+eta+sqrt(1+-+(eta+sin(%CE%B8_1))%5E2)))%5E2*sin(%CE%B8_1)*cos(%CE%B8_1)+from+0+to+pi%2F2

and B
https://www.wolframalpha.com/input/?i=integrate++((eta+cos(%CE%B8_1)+-+sqrt(1+-+(eta+sin(%CE%B8_1))%5E2))%2F(eta+cos(%CE%B8_1)+%2B+sqrt(1+-+(eta+sin(%CE%B8_1))%5E2)))%5E2*sin(%CE%B8_1)*cos(%CE%B8_1)+from+0+to+pi%2F2

You could use Sage to compute these integrals and then fit functions to them (just create a 1D plot of k vs. IoR {eta})

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 22, 2019

@Crisspl This guy fixed Orren Nayar to conserver energy
http://research.tri-ace.com/Data/DesignReflectanceModel_notes.pdf

His correction factor is 1.05 again, but he integrated the bloody Schlick approximation and not the Fresnel function (which would have made correction factor 1.0 for F0 = 0.0 a.k.a. IoR 1.0)

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 22, 2019

P.S. But Gotanda fucked up the reciprocity and the approximation is wrong.

float diffuse = diffuse(...) * (1.0 - metallic);
float spec = specular(...);
float diffuse = diffuse(a2, N, L, V, NdotL, NdotV) * (1.0 - metallic);
float spec = specular(a2, NdotL, NdotV, NdotH);

This comment has been minimized.

Copy link
@Crisspl

Crisspl Jun 17, 2019

Author Owner

diffuse and specular are weighted by Fresnel (1-fresnel and fresnel accordingly ofc). But additionally diffuse is multiplied by (1-metallic) because there's no diffusion in fully metallic materials

This comment has been minimized.

Copy link
@devshgraphicsprogramming
vec3 color = ((diffuse * albedo * (vec3(1.0) - fresnel)) + (spec * fresnel)) * uLightColor / dot(relLightPos, relLightPos);
// color *= NdotL; // ???
OutColor = vec4(color, 1.0);
}
)";
source += genGetters(_params);

source += "float diffuse(...) {\n";
source += "float diffuse(in float a2, in vec3 N, in vec3 L, in vec3 V, in float NdotL, in float NdotV) {\n";
if (_params.constantMetallic && !_params.metallicIsOne)
{
if (_params.constantRoughness && !_params.roughnessIsZero)
source += "\treturn lambert(...);";
if (_params.constantRoughness && _params.roughnessIsZero)
source += "\treturn NdotL;";
else
source += "\treturn orey_nayar(...);";
source += "\treturn oren_nayar(a2, N, L, V, NdotL, NdotV);";
}
else source += "\treturn 0.0;";
source += "\n}\n";
source +=
R"(float specular(...) {
R"(float specular(in float a2, in float NdotL, in float NdotV, in float NdotH) {

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

Because Fresnel can be coloured, this function needs to return vec3 (if metallic is 0 then you can provide an optimized float version)

you should optimize this function to return vec3(0.0) immediately if NdotL<FLT_MIN

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

actually you MUST optimize because normal mapping will produce normals pointing away from the camera, and that brings a shitshow of negative square roots, etc.

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

The same must happen if NdotV<FLT_MIN because GGX would then give you a 0 ;) (and have a division by as well)

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

Finally you NEED a "fast path" for when roughness == 0.0 (actual if-statement in the shader)

roughness == 0.0 , will:

  • Make your Geometry (Shadowing) term == 1.0 always (unless ofcourse NdotV<=0.0 or NdotL<=0.0)
  • Cause a division by 0 in your NDF

So if we get past the NdotV and NdotL checks, then if (roughness<FLT_MIN) return /*NdotH>0.9999999 ? FLT_INF:*/0.0;
(you can actually return 0.0 if roughness equals 0.0 because we'll never get a pixel, view and light pos that align perfectly)

This would ofc naturally change once we decide to render with Area-Lights

This comment has been minimized.

Copy link
@Crisspl

Crisspl Jun 17, 2019

Author Owner

is there any difference between NdotV<FLT_MIN and NdotV==0.0? I mean.. there's nothing between FLT_MIN and 0

This comment has been minimized.

Copy link
@Crisspl

Crisspl Jun 17, 2019

Author Owner

Because Fresnel can be coloured, this function needs to return

fresnel calculation is outside of this function

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

fresnel calculation is outside of this function

specular should return the appropriate BRDF, fresnel is part of the Cook-Torrance Microfacet Theory BRDF and therefore should be inside.

if you need the 1.0-fresnel (transmittance) to weigh the diffuse then pass it out of the function with a out vec3 variable

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

is there any difference between NdotV<FLT_MIN and NdotV==0.0? I mean.. there's nothing between FLT_MIN and 0

FLT_MIN is the minimum normalized floating point number, so technically there could be something between FLT_MIN and 0.
https://stackoverflow.com/questions/28763410/glsl-small-float-value-truncation-starting-from-ipad-air

Also you should probably have a bunch of FLT_MIN defines for different floating point precisions XD.

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 21, 2019

specular should return the appropriate BRDF, fresnel is part of the Cook-Torrance Microfacet Theory BRDF and therefore should be inside.

if you need the 1.0-fresnel (transmittance) to weigh the diffuse then pass it out of the function with a out vec3 variable

Cool thing is that with proper GGX diffuse (like Earl Hammon's) the diffuse weighing factor is not necessarily vec3(1.0)-Fresnel(HdotL) (but that is a good approximation)

This comment has been minimized.

Copy link
@devshgraphicsprogramming
float ndf = GGXTrowbridgeReitz(a2, NdotH);
float geom = GGXSmith(a2, NdotV);
float geom = GGXSmith(a2, NdotL, NdotV);
return ndf*geom / (4.0 * NdotV * NdotL);

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

Other Renderer's have just / (4.0 * NdotL) can you explain why is there an NdotV ?

UPDATE: They have typos XD, its just the NdotL term factored out and the denominator being misnamed.

This comment has been minimized.

Copy link
@Crisspl

Crisspl Jun 17, 2019

Author Owner

I haven't done any actual research on specular terms (yet), all of it is taken from http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

"UE4 bad, DICE good" ... seb Legarde is a better reference ;)

P.S. Just a joke, UE4 devs please don't take offense

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

The denominator should stay as 0.25/(NdotV*NdotL) (then the BRDF will satisfy reciprocity)

But then this needs fixing
914b50d#r33961594

Optimized versions of BRDFs with terms factored out should be provided from a different set of headers and only after the reference BRDFs are finished.

(And obvs the originals should stay somewhere so we can do a Unit-Test at a later date to compare optimized against reference)

This comment has been minimized.

Copy link
@devshgraphicsprogramming

This comment has been minimized.

Copy link
@devshgraphicsprogramming
})";
}
)";

return Shaders.insert({flagsToKey(_params), video::EMT_SOLID}).first->second; // TODO
}
Expand Down
86 changes: 80 additions & 6 deletions examples_tests/13.BRDF_Explorer/CBRDFBuiltinIncludeLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,90 @@ class CBRDFBuiltinIncludeLoader : public irr::asset::IBuiltinIncludeLoader
public:
const char* getVirtualDirectoryName() const override { return "glsl/brdf/"; }

private:
static std::string getOrenNayar(const std::string&)
{
return
R"(#ifndef _BRDF_DIFFUSE_OREN_NAYAR_INCLUDED_
#define _BRDF_DIFFUSE_OREN_NAYAR_INCLUDED_
float oren_nayar(in float a2, in vec3 N, in vec3 L, in vec3 V, in float NdotL, in float NdotV)
{
// theta - polar angles
// phi - azimuth angles
vec2 AB = vec2(1.0, 0.0) + vec2(-0.5, 0.45) * vec2(a2, a2)/vec2(a2+0.33, a2+0.09);

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

a2!=sigma2 if you want to convert a2 to Oren-Nayar's sigma2 then

sigma2 = a2*0.5; // its okay for up to roughness 0.5, but then Beckmann-style RMS roughness is not matched well anymore

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

If you want to get into more advanced "roughness matching" then read this bad boy
Hammon_Earl_PBR_Diffuse_Lighting.pdf

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 18, 2019

@Crisspl page 80-onwards is also quite interesting about Height-Correlated Smith Shadowing (even for specular), interesting note that the numerator of the GGXSmith can cancel out the denominator of the Cook Torrance

vec2 cos_theta = vec2(NdotL, NdotV);
vec2 cos_theta2 = cos_theta*cos_theta;
float sin_theta = sqrt((1.0 - cos_theta2.x) * (1.0 - cos_theta2.y)); //this is actually equal to sqrt(sin(theta_i) * sin(theta_r))
float C = sin_theta / max(cos_theta.x, cos_theta.y);
vec3 light_plane = normalize(L - cos_theta.x*N);
vec3 view_plane = normalize(V - cos_theta.y*N);
float cos_phi = max(0.0, dot(light_plane, view_plane));//not sure about this

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

Some call it Cosine of the Phi Difference, you can use Ptolemy's Identities
image

cos(Phi_i-Phi_o) = cos(Phi_i)*sin(Phi_i)+cos(Phi_o)*sin(Phi_o)

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

I think if you kill the normal component (as you do above) and get vectors lying completely in the tangent plane then it would indeed be the dot product!

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

But you must pay attention to numerical issues, if any of light_plane and view_plane are 0 then you will get INF in the equation

if the dot(light_plane,light_plane)*dot(view_plane,view_plane) < FLT_MIN then you need to assume cos_phi=0

This comment has been minimized.

Copy link
@devshgraphicsprogramming

This comment has been minimized.

Copy link
@Crisspl

Crisspl Jun 26, 2019

Author Owner

no, it's not. It still needs fixing but just didnt want to waste time on this when more impoertant todos are/were untouched

return cos_theta.x * (AB.x + AB.y * cos_phi * C) / 3.14159265359;
}
#endif
)";
}
static std::string getGGXTrowbridgeReitz(const std::string&)
{
return
R"(#ifndef _BRDF_SPECULAR_NDF_GGX_TROWBRIDGE_REITZ_INCLUDED_
#define _BRDF_SPECULAR_NDF_GGX_TROWBRIDGE_REITZ_INCLUDED_
float GGXTrowbridgeReitz(in float a2, in float NdotH)
{
float denom = NdotH*NdotH * (a2 - 1.0) + 1.0;

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

if a2==0.0 and NdotH==1.0 then we have a division by zero (ideal mirror-like reflector)

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 21, 2019

or you can //assert(a2>0.0); and assume this function will never get called with a2==0.0

This comment has been minimized.

Copy link
@devshgraphicsprogramming
return a2 / (3.14159265359 * denom*denom);
}
#endif
)";
}
static std::string getGGXSmith(const std::string&)
{
return
R"(#ifndef _BRDF_SPECULAR_GEOM_GGX_SMITH_INCLUDED_
#define _BRDF_SPECULAR_GEOM_GGX_SMITH_INCLUDED_
float _GGXSmith_G1_(in float a2, in float NdotX)
{

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

you should also pass VdotH and return 0.0 if VdotH < FLT_MIN

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

actually its impossible for a BRDF but put a comment to remember to enable it for the BSDF ;)

This comment has been minimized.

Copy link
@devshgraphicsprogramming
return (2.0*NdotX) / (NdotX + sqrt(a2 + (1.0 - a2)*NdotX*NdotX));

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

Are you sure its the right equation?
https://developer.blender.org/diffusion/C/browse/master/src/kernel/closure/bsdf_microfacet.h$436

I think there's supposed to be a tangent here + if NdotX>0.999999 (or some other threshold that would make your tangent 0) then just return 1.0

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

ok, they're all the same equation, but you could optimize to

float _GGXSmith_G1_(in float a2, in float cos2) // OR additionally , in float sin2)
{
   // if (cos2<FLT_MIN) return 0.0; // cos2 is never < FLT_MIN
   return 2.0/(1.0+sqrt(1.0+a2/cos2-a2));
   // OR
   return 2.0/(1.0+sqrt(1.0+a2*sin2/cos2));
}

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 18, 2019

If you make an optimized Cook-Torrance GGX Specular BRDF, then you could take out the (2.0*NdotL)*(2.0*NdotV) from GGXSmith (call it GGXSmith_without_numerator) because its present in the denominator of Cook Torrance, Also Earl Hammon (914b50d#r33984244) has a cool point about how correlated-height smith is more accurate (just please don't approximate the sqrt with a lerp!!! I Dont' want square highlights!).

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 18, 2019

(you could make the lerp approximation an option/extra function with different name, or some from different header)

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 25, 2019

almost resolved.

}
float GGXSmith(in float a2, in float NdotL, in float NdotV)
{
return _GGXSmith_G1_(a2, NdotL) * _GGXSmith_G1_(a2, NdotV);
}
#endif
)";
}
static std::string getFresnelSchlick(const std::string&)
{
return
R"(#ifndef _BRDF_SPECULAR_FRESNEL_FRESNEL_SCHLICK_INCLUDED_
#define _BRDF_SPECULAR_FRESNEL_FRESNEL_SCHLICK_INCLUDED_
vec3 FresnelSchlick(in vec3 F0, in float NdotV)
{
return F0 + (1.0 - F0) * pow(1.0 - NdotV, 5.0);

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

you can kind-of see why it would fall apart with low F0

maybe better approximations exist out there than the full equal mix of polarized light sine equations

This comment has been minimized.

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

https://graphics.stanford.edu/courses/cs148-10-summer/docs/2006--degreve--reflection_refraction.pdf

Its interesting that Schlick is only 30% faster if you use x*x*x*x*x instead of pow(x,5.0) , otherwise is twice as slow XD

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 17, 2019

Maybe you could cook something up that takes metallic into consideration and blends "smoothly" between fresnel for conductor and dielectric?

https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/

This comment has been minimized.

Copy link
@devshgraphicsprogramming

devshgraphicsprogramming Jun 26, 2019

conversation moved somewhere else

}
#endif
)";
}

protected:
irr::core::vector<std::pair<std::regex, HandleFunc_t>> getBuiltinNamesToFunctionMapping() const override
{
/* TODO */
return {
{ std::regex{"diffuse/lambert\\.glsl"}, [this](const std::string&) { return nullptr; }},
{ std::regex{"diffuse/oren_nayar\\.glsl"}, [](const std::string&) { return nullptr; }},
{ std::regex{"specular/ndf/ggx_trowbridge_reitz\\.glsl"}, nullptr },
{ std::regex{"specular/geom/ggx_smith\\.glsl"}, nullptr },
{ std::regex{"specular/fresnel/fresnel_schlick\\.glsl"}, nullptr }
{ std::regex{"diffuse/oren_nayar\\.glsl"}, &getOrenNayar },
{ std::regex{"specular/ndf/ggx_trowbridge_reitz\\.glsl"}, &getGGXTrowbridgeReitz },
{ std::regex{"specular/geom/ggx_smith\\.glsl"}, &getGGXSmith },
{ std::regex{"specular/fresnel/fresnel_schlick\\.glsl"}, &getFresnelSchlick }
};
}
};
Expand Down
7 changes: 7 additions & 0 deletions examples_tests/13.BRDF_Explorer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <irrlicht.h>
#include "BRDFExplorerApp.h"
#include "CBRDFBuiltinIncludeLoader.h"

using namespace irr;

Expand Down Expand Up @@ -36,6 +37,12 @@ int main()
camera->setFarValue(1000.0f);
smgr->setActiveCamera(camera);

{
auto brdfBuiltinLoader = new CBRDFBuiltinIncludeLoader();
device->getIncludeHandler()->addBuiltinIncludeLoader(brdfBuiltinLoader);
brdfBuiltinLoader->drop();
}

auto* brdfExplorerApp = new BRDFExplorerApp(device, camera);

uint64_t lastFPSTime = 0;
Expand Down

0 comments on commit 914b50d

Please sign in to comment.