Skip to content

Commit

Permalink
feat: support transmission and refraction
Browse files Browse the repository at this point in the history
  • Loading branch information
zhuxudong committed Jan 20, 2025
1 parent afd64de commit de7148f
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 10 deletions.
8 changes: 8 additions & 0 deletions packages/core/src/shaderlib/common.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#define RECIPROCAL_PI 0.31830988618
#define EPSILON 1e-6
#define LOG2 1.442695
#define HALF_MIN 6.103515625e-5 // 2^-14, the same value for 10, 11 and 16-bit: https://www.khronos.org/opengl/wiki/Small_Float_Formats
#define HALF_EPS 4.8828125e-4 // 2^-11, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f)

#define saturate( a ) clamp( a, 0.0, 1.0 )

Expand Down Expand Up @@ -93,3 +95,9 @@ float remapDepthBufferLinear01(float z){

#define INVERSE_MAT(mat) inverseMat(mat)
#endif


vec3 safeNormalize(vec3 inVec) {
float dp3 = max(float(HALF_MIN), dot(inVec, inVec));
return inVec * inversesqrt(dp3);
}
1 change: 1 addition & 0 deletions packages/core/src/shaderlib/extra/pbr.fs.glsl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#define IS_METALLIC_WORKFLOW
#include <common>
#include <camera_declare>
#include <transform_declare>

#include <FogFragmentDeclaration>

Expand Down
37 changes: 37 additions & 0 deletions packages/core/src/shaderlib/pbr/btdf.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <refraction>

#ifdef MATERIAL_ENABLE_TRANSMISSION
uniform sampler2D camera_OpaqueTexture;
vec3 evaluateTransmission(Geometry geometry, Material material) {
RefractionModelResult ray;
#if REFRACTION_MODE == 0
// RefractionMode.Sphere
refractionModelSphere(-geometry.viewDir, geometry.position, geometry.normal, material.IOR, material.thickness, ray);
#elif REFRACTION_MODE == 1
// RefractionMode.Planar
refractionModelPlanar(-geometry.viewDir, geometry.position, geometry.normal, material.IOR, material.thickness, ray);
#endif

vec3 refractedRayExit = ray.positionExit;

// We calculate the screen space position of the refracted point
vec4 samplingPositionNDC = camera_ProjMat * camera_ViewMat * vec4( refractedRayExit, 1.0 );
vec2 refractionCoords = (samplingPositionNDC.xy / samplingPositionNDC.w) * 0.5 + 0.5;

// Sample the opaque texture to get the transmitted light
vec3 refractionTransmitted = texture2D(camera_OpaqueTexture, refractionCoords).rgb;
refractionTransmitted *= material.diffuseColor;

// Use specularFGD as an approximation of the fresnel effect
// https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf
refractionTransmitted *= (1.0 - material.envSpecularDFG);

#ifdef MATERIAL_HAS_THICKNESS
// Absorption coefficient from Disney: http://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf
vec3 transmittance = min(vec3(1.0), exp(-material.absorptionCoefficient * ray.transmissionLength));
refractionTransmitted *= transmittance;
#endif

return refractionTransmitted;
}
#endif
8 changes: 7 additions & 1 deletion packages/core/src/shaderlib/pbr/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import ibl_frag_define from "./ibl_frag_define.glsl";

import pbr_frag from "./pbr_frag.glsl";

import btdf from "./btdf.glsl";
import refraction from "./refraction.glsl";

export default {
pbr_frag_define,

Expand All @@ -16,5 +19,8 @@ export default {
direct_irradiance_frag_define,
ibl_frag_define,

pbr_frag
pbr_frag,

btdf,
refraction
};
24 changes: 16 additions & 8 deletions packages/core/src/shaderlib/pbr/pbr_frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ reflectedLight.indirectSpecular += material.specularAO * radianceAttenuation * r
// IBL Sheen
evaluateSheenIBL(geometry, material, radianceAttenuation, reflectedLight.indirectDiffuse, reflectedLight.indirectSpecular);


// Final color
vec3 totalDiffuseColor = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;
vec3 totalSpecularColor = reflectedLight.directSpecular + reflectedLight.indirectSpecular;

#ifdef MATERIAL_ENABLE_TRANSMISSION
vec3 refractionTransmitted = evaluateTransmission(geometry, material);
totalDiffuseColor = mix(totalDiffuseColor, refractionTransmitted, material.transmission);
#endif

vec4 finalColor = vec4(totalDiffuseColor + totalSpecularColor, material.opacity);


// Emissive
vec3 emissiveRadiance = material_EmissiveColor;
#ifdef MATERIAL_HAS_EMISSIVETEXTURE
Expand All @@ -56,12 +69,7 @@ vec3 emissiveRadiance = material_EmissiveColor;
emissiveRadiance *= emissiveColor.rgb;
#endif

// Total
vec3 totalRadiance = reflectedLight.directDiffuse +
reflectedLight.indirectDiffuse +
reflectedLight.directSpecular +
reflectedLight.indirectSpecular +
emissiveRadiance;
finalColor.rgb += emissiveRadiance;


vec4 targetColor =vec4(totalRadiance, material.opacity);
gl_FragColor = targetColor;
gl_FragColor = finalColor;
26 changes: 25 additions & 1 deletion packages/core/src/shaderlib/pbr/pbr_frag_define.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,23 @@ uniform float material_OcclusionTextureCoord;
#endif
#endif

#ifdef MATERIAL_ENABLE_TRANSMISSION
uniform float material_Transmission;
#ifdef MATERIAL_HAS_TRANSMISSION_TEXTURE
uniform sampler2D material_TransmissionTexture;
#endif

#ifdef MATERIAL_HAS_THICKNESS
uniform vec3 material_AttenuationColor;
uniform float material_AttenuationDistance;
uniform float material_Thickness;

#ifdef MATERIAL_HAS_THICKNESS_TEXTURE
uniform sampler2D material_ThicknessTexture;
#endif
#endif
#endif

// Runtime
struct ReflectedLight {
vec3 directDiffuse;
Expand Down Expand Up @@ -123,7 +140,8 @@ struct Material {
float f0;
float diffuseAO;
float specularAO;
vec3 envSpecularDFG;
vec3 envSpecularDFG;
float IOR;

#ifdef MATERIAL_ENABLE_CLEAR_COAT
float clearCoat;
Expand All @@ -143,4 +161,10 @@ struct Material {
float sheenScaling;
float approxIBLSheenDG;
#endif

#ifdef MATERIAL_ENABLE_TRANSMISSION
vec3 absorptionCoefficient;
float transmission;
float thickness;
#endif
};
18 changes: 18 additions & 0 deletions packages/core/src/shaderlib/pbr/pbr_helper.glsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <normal_get>
#include <brdf>
#include <btdf>

// direct + indirect
#include <direct_irradiance_frag_define>
Expand Down Expand Up @@ -90,6 +91,7 @@ void initMaterial(out Material material, inout Geometry geometry){
float f0 = pow2( (material_IOR - 1.0) / (material_IOR + 1.0) );

material.f0 = f0;
material.IOR = material_IOR;

#ifdef MATERIAL_HAS_BASETEXTURE
vec4 baseTextureColor = texture2D(material_BaseTexture, v_uv);
Expand Down Expand Up @@ -228,6 +230,22 @@ void initMaterial(out Material material, inout Geometry geometry){
#endif
#endif

// Transmission
#ifdef MATERIAL_ENABLE_TRANSMISSION
material.transmission = material_Transmission;
#ifdef MATERIAL_HAS_TRANSMISSION_TEXTURE
material.transmission *= texture2D(material_TransmissionTexture, v_uv).r;
#endif

#ifdef MATERIAL_HAS_THICKNESS
material.absorptionCoefficient = -log(material_AttenuationColor + HALF_EPS) / max(HALF_EPS, material_AttenuationDistance);
material.thickness = max(material_Thickness, 0.0001);
#ifdef MATERIAL_HAS_THICKNESS_TEXTURE
material.thickness *= texture2D( material_ThicknessTexture, v_uv).g;
#endif
#endif
#endif

}


40 changes: 40 additions & 0 deletions packages/core/src/shaderlib/pbr/refraction.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifdef MATERIAL_ENABLE_TRANSMISSION
struct RefractionModelResult {
float transmissionLength; // length of the transmission during refraction through the shape
vec3 positionExit; // out ray position
// vec3 directionExit; // out ray direction
};

//https://docs.unity3d.com/Packages/[email protected]/manual/refraction-models.html
void refractionModelSphere(vec3 V, vec3 positionWS, vec3 normalWS, float ior, float thickness, out RefractionModelResult ray) {
// Refracted ray
vec3 R1 = refract(V, normalWS, 1.0 / ior);
// Center of the tangent sphere
// vec3 C = positionWS - normalWS * thickness * 0.5;

// Second refraction (tangent sphere out)
float dist = dot(-normalWS, R1) * thickness;
// Out hit point in the tangent sphere
vec3 P1 = positionWS + R1 * dist;
// Out normal
// vec3 N1 = safeNormalize(C - P1);
// Out refracted ray
// vec3 R2 = refract(R1, N1, ior);

ray.transmissionLength = dist;
ray.positionExit = P1;
// ray.directionExit = R2;
}

void refractionModelPlanar(vec3 V, vec3 positionWS, vec3 normalWS, float ior, float thickness, out RefractionModelResult ray) {
// Refracted ray
vec3 R = refract(V, normalWS, 1.0 / ior);
// Optical depth within the thin plane
float dist = thickness / max(dot(-normalWS, R), 1e-5f);

ray.transmissionLength = dist;
ray.positionExit = vec3(positionWS + R * dist);
// ray.directionExit = V;
}

#endif

0 comments on commit de7148f

Please sign in to comment.