Skip to content

Commit

Permalink
feat: refraction
Browse files Browse the repository at this point in the history
  • Loading branch information
hhhhkrx committed Dec 16, 2024
1 parent c5dbbcc commit d1620dc
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 4 deletions.
52 changes: 52 additions & 0 deletions packages/shaderlab/src/shaders/Common.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,57 @@ float remapDepthBufferLinear01(float z){
#define INVERSE_MAT(mat) inverseMat(mat)
#endif

vec4 sampleTexture(sampler2D tex, vec2 uv){
vec4 color = texture2D(tex, uv);

#ifndef ENGINE_IS_COLORSPACE_GAMMA
color = gammaToLinear(color);
#endif

return color;
}

vec2 bSpline3MiddleLeft(vec2 x){
return 0.16666667 + x * (0.5 + x * (0.5 - x * 0.5));
}

vec2 bSpline3MiddleRight(vec2 x){
return 0.66666667 + x * (-1.0 + 0.5 * x) * x;
}

vec2 bSpline3Rightmost(vec2 x){
return 0.16666667 + x * (-0.5 + x * (0.5 - x * 0.16666667));
}

// Compute weights & offsets for 4x bilinear taps for the bicubic B-Spline filter.
// The fractional coordinate should be in the [0, 1] range (centered on 0.5).
// Inspired by: http://vec3.ca/bicubic-filtering-in-fewer-taps/
void bicubicFilter(vec2 fracCoord, out vec2 weights[2], out vec2 offsets[2]){
vec2 r = bSpline3Rightmost(fracCoord);
vec2 mr = bSpline3MiddleRight(fracCoord);
vec2 ml = bSpline3MiddleLeft(fracCoord);
vec2 l = 1.0 - mr - ml - r;

weights[0] = r + mr;
weights[1] = ml + l;
offsets[0] = -1.0 + mr / weights[0];
offsets[1] = 1.0 + l / weights[1];
}


// texSize: (1/width, 1/height, width, height)
vec4 sampleTexture2DBicubic(sampler2D tex, vec2 coord, vec4 texSize){
vec2 xy = coord * texSize.zw + 0.5;
vec2 ic = floor(xy);
vec2 fc = fract(xy);

vec2 weights[2];
vec2 offsets[2];
bicubicFilter(fc, weights, offsets);

return weights[0].y * (weights[0].x * sampleTexture(tex, (ic + vec2(offsets[0].x, offsets[0].y) - 0.5) * texSize.xy) +
weights[1].x * sampleTexture(tex, (ic + vec2(offsets[1].x, offsets[0].y) - 0.5) * texSize.xy)) +
weights[1].y * (weights[0].x * sampleTexture(tex, (ic + vec2(offsets[0].x, offsets[1].y) - 0.5) * texSize.xy) +
weights[1].x * sampleTexture(tex, (ic + vec2(offsets[1].x, offsets[1].y) - 0.5) * texSize.xy));
}
#endif
9 changes: 8 additions & 1 deletion packages/shaderlab/src/shaders/PBR.gs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,14 @@ Shader "PBR.gs" {
material_SheenTexture("ColorTexture", Texture2D);
material_SheenRoughnessTexture("RoughnessTexture", Texture2D);
}

Header("Refraction"){
material_attenuationColor("AttenuationColor", Color ) = (0, 0, 0, 1);
material_attenuationDistance("AttenuationDistance", Range(0, 1, 0.01)) = 0;
material_transmission("Transmission", Range(0, 1, 0.01)) = 0;
material_Thickness("Thickness", Float) = 0;
material_TransmissionTexture("TransmissionTexture", Texture2D);
material_ThicknessTexture("ThicknessTexture", Texture2D);
}
Header("Common") {
material_AlphaCutoff( "AlphaCutoff", Range(0, 1, 0.01) ) = 0;
material_TilingOffset("TilingOffset", Vector4) = (1, 1, 0, 0);
Expand Down
14 changes: 14 additions & 0 deletions packages/shaderlab/src/shaders/shadingPBR/BRDF.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct SurfaceData{
float specularAO;
float f0;
float opacity;
float IOR;

// geometry
vec3 position;
Expand Down Expand Up @@ -64,6 +65,19 @@ struct SurfaceData{
vec3 sheenColor;
#endif

#ifdef MATERIAL_ENABLE_SS_REFRACTION
vec3 attenuationColor;
float attenuationDistance;

// #ifdef MATERIAL_HAS_TRANSMISSION
float transmission;
// #endif

// #ifdef MATERIAL_ENABLE_THICKNESS
float thickness;
// #endif
#endif

};


Expand Down
53 changes: 53 additions & 0 deletions packages/shaderlab/src/shaders/shadingPBR/BTDF.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef BTDF_INCLUDED
#define BTDF_INCLUDED

#include "Refraction.glsl"

vec4 renderer_texelSize; // x: 1/width, y: 1/height, z: width, w: height
sampler2D camera_OpaqueTexture;

#ifdef MATERIAL_ENABLE_SS_REFRACTION
vec3 evaluateRefraction(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, vec3 speculaColor) {
RefractionModel ray;
#if REFRACTION_SPHERE
RefractionModelSphere(surfaceData.viewDir, varyings.positionWS, varyings.normalWS, surfaceData.IOR, surfaceData.thickness, ray);
#elif REFRACTION_PLANE
RefractionModelBox(surfaceData.viewDir, varyings.positionWS, varyings.normalWS, surfaceData.IOR, surfaceData.thickness, ray);
#elif REFRACTION_THIN
RefractionModelBox(surfaceData.viewDir, varyings.positionWS, varyings.normalWS, surfaceData.IOR, surfaceData.thickness, ray);
#endif

vec3 refractedRayExit = ray.position; //ray.position + ray.direction;

// Project refracted vector on the framebuffer, while mapping to normalized device coordinates.
vec4 ndcPos = camera_ProjMat * camera_ViewMat * vec4( refractedRayExit, 1.0 );
vec2 refractionCoords = ndcPos.xy / ndcPos.w;
refractionCoords *= 0.5;
refractionCoords += 0.5;

// compute transmission
vec3 absorptionCoefficient = max(vec3(0), -log(surfaceData.attenuationColor)/surfaceData.attenuationDistance);
#ifdef MATERIAL_HAS_ABSORPTION
vec3 transmittance = min(vec3(1.0), exp(-absorptionCoefficient * ray.dist));
#else
vec3 transmittance = 1.0 - absorptionCoefficient;
#endif

// vec4 transmittedLight = texture2D(camera_OpaqueTexture, varyings.uv);
vec4 transmittedLight = sampleTexture2DBicubic(camera_OpaqueTexture, refractionCoords, renderer_texelSize);
// vec3 transmittanceColor = brdfData.diffuseColor * transmittance;
vec3 E = envBRDFApprox(speculaColor, brdfData.roughness, surfaceData.dotNV);

vec3 ft = transmittedLight.rgb;
ft *= brdfData.diffuseColor;
ft *= 1.0 - E;

#ifdef MATERIAL_HAS_ABSORPTION
ft *= transmittance;
#endif

return ft;
}
#endif

#endif
58 changes: 57 additions & 1 deletion packages/shaderlab/src/shaders/shadingPBR/FragmentPBR.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@

#include "Normal.glsl"

// #if MATERIAL_ENABLE_SS_REFRACTION
// #define REFRACTION_SPHERE
// #define REFRACTION_PLANE
// #define REFRACTION_THIN
// #endif

float material_AlphaCutoff;
vec4 material_BaseColor;
float material_Metal;
Expand Down Expand Up @@ -62,6 +68,28 @@ float material_OcclusionTextureCoord;
#endif
#endif

#ifdef MATERIAL_ENABLE_SS_REFRACTION
#define REFRACTION_SPHERE
#define REFRACTION_PLANE
#define REFRACTION_THIN

vec3 material_attenuationColor;
float material_attenuationDistance;

// #ifdef MATERIAL_ENABLE_SS_REFRACTION
float material_transmission;
// #ifdef MATERIAL_HAS_TRANSMISSION_TEXTURE
// sampler2D material_TransmissionTexture;
// #endif
// #endif

// #ifdef MATERIAL_ENABLE_THICKNESS
float material_thickness;
// #ifdef MATERIAL_HAS_THICKNESS_TEXTURE
// sampler2D material_ThicknessTexture;
// #endif
// #endif
#endif
// Texture
#ifdef MATERIAL_HAS_BASETEXTURE
sampler2D material_BaseTexture;
Expand Down Expand Up @@ -166,7 +194,7 @@ SurfaceData getSurfaceData(Varyings v, vec2 aoUV, bool isFrontFacing){
surfaceData.emissiveColor = emissiveRadiance;
surfaceData.metallic = metallic;
surfaceData.roughness = roughness;
surfaceData.f0 = f0;
surfaceData.IOR = material_IOR;

#ifdef MATERIAL_IS_TRANSPARENT
surfaceData.opacity = baseColor.a;
Expand Down Expand Up @@ -292,6 +320,34 @@ SurfaceData getSurfaceData(Varyings v, vec2 aoUV, bool isFrontFacing){
#endif
#endif


#ifdef MATERIAL_ENABLE_SS_REFRACTION
surfaceData.attenuationColor = material_attenuationColor;

// #if REFRACTION_THIN
// #define REFRACTION_THIN_DISTANCE 0.005
// surfaceData.attenuationDistance = REFRACTION_THIN_DISTANCE;
// #else
surfaceData.attenuationDistance = material_attenuationDistance;
// #endif

// #ifdef MATERIAL_HAS_TRANSMISSION
surfaceData.transmission = material_transmission;
// #ifdef MATERIAL_HAS_TRANSMISSION_TEXTURE
// surfaceData.transmission *= texture2D( material_TransmissionTexture, uv).r;
// #endif
// #else
// surfaceData.transmission = 1.0;
// #endif

// #ifdef MATERIAL_ENABLE_THICKNESS
surfaceData.thickness = max(0.0, material_thickness);
// #ifdef MATERIAL_HAS_THICKNESS_TEXTURE
// surfaceData.thickness *= texture2D( material_ThicknessTexture, uv).g;
// #endif
// #endif

#endif
// AO
float diffuseAO = 1.0;
float specularAO = 1.0;
Expand Down
5 changes: 5 additions & 0 deletions packages/shaderlab/src/shaders/shadingPBR/LightDirectPBR.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ 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);

// #ifdef MATERIAL_ENABLE_SS_REFRACTION
// diffuseColor *= (1.0 - surfaceData.transmission);
// #endif

// Sheen Lobe
FUNCTION_SHEEN_LOBE(varyings, surfaceData, brdfData, incidentDirection, attenuationIrradiance, diffuseColor, specularColor);

Expand Down
13 changes: 12 additions & 1 deletion packages/shaderlab/src/shaders/shadingPBR/LightIndirectPBR.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define FUNCTION_SHEEN_IBL evaluateSheenIBL
#endif
#include "BRDF.glsl"
#include "BTDF.glsl"
#include "Light.glsl"
#include "LightIndirectFunctions.glsl"

Expand Down Expand Up @@ -92,7 +93,7 @@ void evaluateSheenIBL(Varyings varyings, SurfaceData surfaceData, BRDFData brdfD
void evaluateIBL(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, inout vec3 color){
vec3 diffuseColor = vec3(0);
vec3 specularColor = vec3(0);

vec3 transmissioncolor = vec3(0);
// IBL diffuse
FUNCTION_DIFFUSE_IBL(varyings, surfaceData, brdfData, diffuseColor);

Expand All @@ -105,8 +106,18 @@ void evaluateIBL(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData,
// IBL sheen
FUNCTION_SHEEN_IBL(varyings, surfaceData, brdfData, radianceAttenuation, diffuseColor, specularColor);


// #ifdef MATERIAL_ENABLE_SS_REFRACTION
// vec3 Ft = evaluateRefraction(varyings, surfaceData, brdfData, specularColor);
// Ft *= surfaceData.transmission;
// diffuseColor *= (1.0 - surfaceData.transmission);
// #endif

color += diffuseColor + specularColor;

// #ifdef MATERIAL_ENABLE_SS_REFRACTION
// color.rgb += Ft;
// #endif
}


Expand Down
56 changes: 56 additions & 0 deletions packages/shaderlab/src/shaders/shadingPBR/Refraction.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#ifndef REFRACTION_INCLUDED
#define REFRACTION_INCLUDED

#ifdef MATERIAL_ENABLE_SS_REFRACTION

struct RefractionModel{
float dist; // length of the transmission during refraction through the shape
vec3 position; // out ray position
vec3 direction; // out ray direction
};

void RefractionModelSphere(vec3 V, vec3 positionWS, vec3 normalWS, float ior, float thickness, out RefractionModel ray){
// Sphere shape model:
// We approximate locally the shape of the object as sphere, that is tangent to the shape.
// The sphere has a diameter of {thickness}
// The center of the sphere is at {positionWS} - {normalWS} * {thickness} * 0.5
// So the light is refracted twice: in and out of the tangent sphere

// First refraction (tangent sphere in)
// 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 NoR1 = dot(normalWS, R1);
// Optical depth within the sphere
float dist = -NoR1 * thickness;
// Out hit point in the tangent sphere
vec3 P1 = positionWS + R1 * dist;
// Out normal
vec3 N1 = normalize(C - P1);
// Out refracted ray
vec3 R2 = refract(R1, N1, ior);

ray.dist = dist;
ray.position = P1;
ray.direction = R2;
}

void RefractionModelBox(vec3 V, vec3 positionWS, vec3 normalWS, float ior, float thickness, out RefractionModel ray){
// Plane shape model:
// We approximate locally the shape of the object as a plane with normal {normalWS} at {positionWS}
// with a thickness {thickness}
// Refracted ray
vec3 R = refract(V, normalWS, 1.0 / ior);

// Optical depth within the thin plane
float dist = thickness / max(dot(R, -normalWS), 0.001);

ray.dist = dist;
ray.position = positionWS + R * dist;
ray.direction = V;
}
#endif
#endif
6 changes: 5 additions & 1 deletion packages/shaderlab/src/shaders/shadingPBR/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import LightIndirectPBR from "./LightIndirectPBR.glsl";
import ReflectionLobe from "./ReflectionLobe.glsl";
import VaryingsPBR from "./VaryingsPBR.glsl";
import VertexPBR from "./VertexPBR.glsl";
import Refraction from "./Refraction.glsl";
import BTDF from "./BTDF.glsl";

export default [
{ source: ForwardPassPBR, includeKey: "ForwardPassPBR.glsl" },
Expand All @@ -19,5 +21,7 @@ export default [
{ source: VertexPBR, includeKey: "VertexPBR.glsl" },
{ source: BRDF, includeKey: "BRDF.glsl" },
{ source: LightIndirectFunctions, includeKey: "LightIndirectFunctions.glsl" },
{ source: ReflectionLobe, includeKey: "ReflectionLobe.glsl" }
{ source: ReflectionLobe, includeKey: "ReflectionLobe.glsl" },
{ source: Refraction, includeKey: "Refraction.glsl" },
{ source: BTDF, includeKey: "BTDF.glsl" }
];

0 comments on commit d1620dc

Please sign in to comment.