Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gltf iridescence #309

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/shaderlab/src/shaders/PBR.gs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ Shader "PBR.gs" {
material_ClearCoatNormalTexture("ClearCoatNormalTexture", Texture2D);
}

Header("Thin Film Iridescence"){
material_IridescenceInfo("Iridescence", Vector4) = (0, 0, 0, 0);
material_IridescenceThicknessTexture("IridescenceThicknessTexture", Texture2D);
material_IridescenceTexture("IridescenceTexture", Texture2D);
}

Header("Common") {
material_AlphaCutoff( "AlphaCutoff", Range(0, 1, 0.01) ) = 0;
material_TilingOffset("TilingOffset", Vector4) = (1, 1, 0, 0);
Expand All @@ -60,6 +66,9 @@ Shader "PBR.gs" {
MATERIAL_HAS_CLEAR_COAT_TEXTURE("HAS_CLEAR_COAT_TEXTURE");
MATERIAL_HAS_CLEAR_COAT_ROUGHNESS_TEXTURE("HAS_CLEAR_COAT_ROUGHNESS_TEXTURE");
MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE("HAS_CLEAR_COAT_NORMAL_TEXTURE");
MATERIAL_ENABLE_IRIDESCENCE("ENABLE_IRIDESCENCE");
MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE("HAS_IRIDESCENCE_THICKNESS_TEXTURE");
MATERIAL_HAS_IRIDESCENCE_TEXTURE("HAS_IRIDESCENCE_TEXTURE");
MATERIAL_IS_TRANSPARENT("IS_TRANSPARENT");
MATERIAL_IS_ALPHA_CUTOFF("IS_ALPHA_CUTOFF");
}
Expand Down
110 changes: 110 additions & 0 deletions packages/shaderlab/src/shaders/shadingPBR/BRDF.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ struct SurfaceData{
vec3 clearCoatNormal;
float clearCoatDotNV;
#endif

#ifdef MATERIAL_ENABLE_IRIDESCENCE
float iridesceceIor;
float iridesceceFactor;
float iridescenceThickness;
#endif
};


Expand All @@ -61,6 +67,10 @@ struct BRDFData{
vec3 clearCoatSpecularColor;
float clearCoatRoughness;
#endif

#ifdef MATERIAL_ENABLE_IRIDESCENCE
vec3 iridescenceSpecularColor;
#endif
};


Expand Down Expand Up @@ -202,6 +212,100 @@ vec3 BRDF_Diffuse_Lambert(vec3 diffuseColor) {
return RECIPROCAL_PI * diffuseColor;
}

#ifdef MATERIAL_ENABLE_IRIDESCENCE
float sqr(float x) {
return x * x;
}

// Conversion f0/ior
vec3 iorToFresnel(vec3 transmittedIor, float incidentIor) {
return pow((transmittedIor - incidentIor) / (transmittedIor + incidentIor),vec3(2.0));
}

float iorToFresnel(float transmittedIor, float incidentIor) {
return pow((transmittedIor - incidentIor) / (transmittedIor + incidentIor),2.0);
}

// Assume air interface for top
// Note: We don't handle the case fresnel0 == 1
vec3 fresnelToIor(vec3 F0){
vec3 sqrtF0 = sqrt(F0);
return (vec3(1.0) + sqrtF0) / (vec3(1.0) - sqrtF0);
}

// Fresnel equations for dielectric/dielectric interfaces.
// Ref: https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html
// Evaluation XYZ sensitivity curves in Fourier space
vec3 evalSensitivity(float opd, vec3 shift){
// Use Gaussian fits, given by 3 parameters: val, pos and var
float phase = 2.0 * PI * opd * 1.0e-9;
const vec3 val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13);
const vec3 pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06);
const vec3 var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09);
vec3 xyz = val * sqrt(2.0 * PI * var) * cos(pos * phase + shift) * exp(-var * sqr(phase));
xyz.x += 9.7470e-14 * sqrt(2.0 * PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift[0]) * exp(-4.5282e+09 * sqr(phase));
xyz /= 1.0685e-7;
// XYZ to RGB color space
const mat3 XYZ_TO_RGB = mat3( 3.2404542, -0.9692660, 0.0556434,
-1.5371385, 1.8760108, -0.2040259,
-0.4985314, 0.0415560, 1.0572252);
vec3 rgb = XYZ_TO_RGB * xyz;
return rgb;
}

vec3 EvalIridescence(float outsideIOR, float cosTheta1, float eta2, vec3 baseF0,float iridescenceThickness){
vec3 iridescence = vec3(1.0);
// Force iridescenceIOR -> outsideIOR when thinFilmThickness -> 0.0
float iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, iridescenceThickness ) );
// Evaluate the cosTheta on the base layer (Snell law)
float sinTheta2Sq = pow( outsideIOR / iridescenceIOR, 2.0) * (1.0 - pow( cosTheta1, 2.0));
float cosTheta2Sq = 1.0 - sinTheta2Sq;
// Handle total internal reflection
if (cosTheta2Sq < 0.0) {
return iridescence;
}
float cosTheta2 = sqrt(cosTheta2Sq);

// First interface
float R0 = iorToFresnel(iridescenceIOR, outsideIOR);
float R12 = F_Schlick(R0, cosTheta1);
float R21 = R12;
float T121 = 1.0 - R12;
float phi12 = 0.0;
if (iridescenceIOR < outsideIOR) {phi12 = PI;}
float phi21 = PI - phi12;

// Second interface
vec3 baseIor = fresnelToIor(clamp(baseF0, 0.0, 0.9999)); // guard against 1.0
vec3 R1 =iorToFresnel(baseIor, iridescenceIOR);
vec3 R23 = F_Schlick(R1, cosTheta2);
vec3 phi23 =vec3(0.0);
if (baseIor[0] < iridescenceIOR) {phi23[0] = PI;}
if (baseIor[1] < iridescenceIOR) {phi23[1] = PI;}
if (baseIor[2] < iridescenceIOR) {phi23[2] = PI;}

// Phase shift
float OPD = 2.0 * iridescenceIOR * iridescenceThickness * cosTheta2;
vec3 phi = vec3(phi21) + phi23;

// Compound terms
vec3 R123 = clamp(R12 * R23, 1e-5, 0.9999);
vec3 r123 = sqrt(R123);
vec3 Rs = sqr(T121) * R23 / (vec3(1.0) - R123);
// Reflectance term for m = 0 (DC term amplitude)
vec3 C0 = R12 + Rs;
iridescence = C0;
// Reflectance term for m > 0 (pairs of diracs)
vec3 Cm = Rs - T121;
for (int m = 1; m <= 2; ++m) {
Cm *= r123;
vec3 Sm = 2.0 * evalSensitivity(float(m) * OPD, float(m) * phi);
iridescence += Cm * Sm;
}
iridescence = max(iridescence, vec3(0.0));
return iridescence;
}
#endif

void initBRDFData(SurfaceData surfaceData, out BRDFData brdfData){
vec3 albedoColor = surfaceData.albedoColor;
Expand All @@ -225,6 +329,12 @@ void initBRDFData(SurfaceData surfaceData, out BRDFData brdfData){
brdfData.clearCoatRoughness = max(MIN_PERCEPTUAL_ROUGHNESS, min(surfaceData.clearCoatRoughness + getAARoughnessFactor(surfaceData.clearCoatNormal), 1.0));
brdfData.clearCoatSpecularColor = vec3(0.04);
#endif

#ifdef MATERIAL_ENABLE_IRIDESCENCE
float topIor = 1.0;
float NdotV = saturate(dot(surfaceData.normal, surfaceData.viewDir ) );
brdfData.iridescenceSpecularColor = EvalIridescence(topIor, NdotV, surfaceData.iridesceceIor, brdfData.specularColor, surfaceData.iridescenceThickness);
#endif
}

#endif
31 changes: 31 additions & 0 deletions packages/shaderlab/src/shaders/shadingPBR/FragmentPBR.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ float material_OcclusionTextureCoord;
#endif
#endif

#ifdef MATERIAL_ENABLE_IRIDESCENCE
vec4 material_IridescenceInfo;
#ifdef MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE
sampler2D material_IridescenceThicknessTexture;
#endif

#ifdef MATERIAL_HAS_IRIDESCENCE_TEXTURE
sampler2D material_IridescenceTexture;
#endif
#endif

// Texture
#ifdef MATERIAL_HAS_BASETEXTURE
sampler2D material_BaseTexture;
Expand Down Expand Up @@ -235,6 +246,26 @@ SurfaceData getSurfaceData(Varyings v, vec2 aoUV, bool isFrontFacing){
surfaceData.anisotropicN = getAnisotropicBentNormal(surfaceData);
#endif

//Iridescence
#ifdef MATERIAL_ENABLE_IRIDESCENCE
surfaceData.iridesceceFactor = material_IridescenceInfo.x;
surfaceData.iridesceceIor = material_IridescenceInfo.y;

float iridesceceThicknessMin = material_IridescenceInfo.z;
float iridesceceThicknessMax = material_IridescenceInfo.w;
#ifdef MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE
vec3 iridescenceThicknessInfo = (texture2D( material_IridescenceThicknessTexture, uv)).rgb;
surfaceData.iridescenceThickness = mix(iridesceceThicknessMin, iridesceceThicknessMax, iridescenceThicknessInfo.g);
#else
surfaceData.iridescenceThickness = iridesceceThicknessMax;
#endif

#ifdef MATERIAL_HAS_IRIDESCENCE_TEXTURE
vec3 iridecenceIntensity = (texture2D( material_IridescenceTexture, uv)).rgb;
surfaceData.iridesceceFactor *= iridecenceIntensity.x;
#endif
#endif

// AO
float diffuseAO = 1.0;
float specularAO = 1.0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#ifndef FUNCTION_CLEAR_COAT_LOBE
#define FUNCTION_CLEAR_COAT_LOBE clearCoatLobe
#endif
#ifndef FUNCTION_IRIDESCENCE_LOBE
#define FUNCTION_IRIDESCENCE_LOBE iridescenceLobe
#endif

#include "BRDF.glsl"
#include "Light.glsl"
Expand All @@ -34,7 +37,9 @@ void surfaceShading(Varyings varyings, SurfaceData surfaceData, BRDFData brdfDat
FUNCTION_DIFFUSE_LOBE(varyings, surfaceData, brdfData, attenuationIrradiance, diffuseColor);
// Specular Lobe
FUNCTION_SPECULAR_LOBE(varyings, surfaceData, brdfData, incidentDirection, attenuationIrradiance, specularColor);

// Iridescence Lobe
FUNCTION_IRIDESCENCE_LOBE(varyings, surfaceData, brdfData, incidentDirection, attenuationIrradiance, specularColor);

color += diffuseColor + specularColor;

}
Expand Down
19 changes: 18 additions & 1 deletion packages/shaderlab/src/shaders/shadingPBR/LightIndirectPBR.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
#ifndef FUNCTION_CLEAR_COAT_IBL
#define FUNCTION_CLEAR_COAT_IBL evaluateClearCoatIBL
#endif

#ifndef FUNCTION_IRIDESCENCE_IBL
#define FUNCTION_IRIDESCENCE_IBL evaluateIridescenceIBL
#endif

#include "BRDF.glsl"
#include "Light.glsl"
Expand Down Expand Up @@ -66,6 +68,18 @@ float evaluateClearCoatIBL(Varyings varyings, SurfaceData surfaceData, BRDFData
return radianceAttenuation;
}

void evaluateIridescenceIBL(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, float radianceAttenuation, inout vec3 specularColor){
vec3 radiance = getLightProbeRadiance(surfaceData, surfaceData.normal, brdfData.roughness);
vec3 envBRDF = envBRDFApprox(brdfData.specularColor, brdfData.roughness, surfaceData.dotNV);

#ifdef MATERIAL_ENABLE_IRIDESCENCE
envBRDF = mix(envBRDF, brdfData.iridescenceSpecularColor, surfaceData.iridesceceFactor);
#endif

specularColor += surfaceData.specularAO * radianceAttenuation * radiance * envBRDF;

}

void evaluateSpecularIBL(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, float radianceAttenuation, inout vec3 specularColor){
vec3 radiance = getLightProbeRadiance(surfaceData, surfaceData.normal, brdfData.roughness);
specularColor += surfaceData.specularAO * radianceAttenuation * radiance * envBRDFApprox(brdfData.specularColor, brdfData.roughness, surfaceData.dotNV );
Expand All @@ -85,6 +99,9 @@ void evaluateIBL(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData,
// IBL specular
FUNCTION_SPECULAR_IBL(varyings, surfaceData, brdfData, radianceAttenuation, specularColor);

// IBL Iridescence
FUNCTION_IRIDESCENCE_IBL(varyings, surfaceData, brdfData, radianceAttenuation, specularColor);

color += diffuseColor + specularColor;
}

Expand Down
8 changes: 8 additions & 0 deletions packages/shaderlab/src/shaders/shadingPBR/ReflectionLobe.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ float clearCoatLobe(Varyings varyings, SurfaceData surfaceData, BRDFData brdfDat
return attenuation;
}

void iridescenceLobe(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, vec3 incidentDirection, vec3 attenuationIrradiance, inout vec3 specularColor){
vec3 BRDF_Specular = BRDF_Specular_GGX( incidentDirection, surfaceData, surfaceData.normal, brdfData.specularColor, brdfData.roughness);

#ifdef MATERIAL_ENABLE_IRIDESCENCE
BRDF_Specular = mix(BRDF_Specular, brdfData.iridescenceSpecularColor, surfaceData.iridesceceFactor);
#endif

specularColor += attenuationIrradiance * BRDF_Specular;
}

#endif
Loading