diff --git a/packages/core/src/material/PBRMaterial.ts b/packages/core/src/material/PBRMaterial.ts index 888b1b8f14..a59d4955b2 100644 --- a/packages/core/src/material/PBRMaterial.ts +++ b/packages/core/src/material/PBRMaterial.ts @@ -32,7 +32,6 @@ export class PBRMaterial extends PBRBaseMaterial { private static _transmissionMacro: ShaderMacro = ShaderMacro.getByName("MATERIAL_ENABLE_TRANSMISSION"); private static _thicknessMacro: ShaderMacro = ShaderMacro.getByName("MATERIAL_HAS_THICKNESS"); - private static _absorptionMacro: ShaderMacro = ShaderMacro.getByName("MATERIAL_HAS_ABSORPTION"); private static _thicknessTextureMacro: ShaderMacro = ShaderMacro.getByName("MATERIAL_HAS_THICKNESS_TEXTURE"); private static _transmissionTextureMacro: ShaderMacro = ShaderMacro.getByName("MATERIAL_HAS_TRANSMISSION_TEXTURE"); private static _transmissionProp = ShaderProperty.getByName("material_Transmission"); @@ -46,7 +45,6 @@ export class PBRMaterial extends PBRBaseMaterial { private _anisotropyRotation: number = 0; private _iridescenceRange = new Vector2(100, 400); private _sheenEnabled = false; - private _absorptionEnabled = true; /** * Index Of Refraction. @@ -317,7 +315,7 @@ export class PBRMaterial extends PBRBaseMaterial { set refractionMode(value: RefractionMode) { if (value !== this._refractionMode) { this._refractionMode = value; - this._setRefractionMode(value); + this.shaderData.enableMacro("REFRACTION_MODE", value.toString()); } } @@ -468,20 +466,17 @@ export class PBRMaterial extends PBRBaseMaterial { shaderData.setVector4(PBRMaterial._iridescenceInfoProp, new Vector4(0, 1.3, 100, 400)); const sheenColor = new Color(0, 0, 0); shaderData.setColor(PBRMaterial._sheenColorProp, sheenColor); - this.refractionMode = RefractionMode.Plane; + this.refractionMode = RefractionMode.Planar; shaderData.setFloat(PBRMaterial._transmissionProp, 0); shaderData.setFloat(PBRMaterial._thicknessProp, 0); shaderData.setFloat(PBRMaterial._attenuationDistanceProp, Infinity); const attenuationColor = new Color(1, 1, 1); shaderData.setColor(PBRMaterial._attenuationColorProp, attenuationColor); - shaderData.enableMacro(PBRMaterial._absorptionMacro); // @ts-ignore this._iridescenceRange._onValueChanged = this._onIridescenceRangeChanged.bind(this); // @ts-ignore sheenColor._onValueChanged = this._onSheenColorChanged.bind(this); - // @ts-ignore - attenuationColor._onValueChanged = this._attenuationColorChanged.bind(this); } /** @@ -511,31 +506,4 @@ export class PBRMaterial extends PBRBaseMaterial { } } } - - private _attenuationColorChanged(): void { - const attenuationColor = this.attenuationColor; - const enableAbsorption = attenuationColor.r + attenuationColor.g + attenuationColor.b > 0; - if (enableAbsorption !== this._absorptionEnabled) { - this._absorptionEnabled = enableAbsorption; - if (enableAbsorption) { - this.shaderData.enableMacro(PBRMaterial._absorptionMacro); - } else { - this.shaderData.disableMacro(PBRMaterial._absorptionMacro); - } - } - } - - private _setRefractionMode(refractionMode: RefractionMode): void { - switch (refractionMode) { - case RefractionMode.Sphere: - this.shaderData.enableMacro("REFRACTION_MODE", "SPHERE"); - break; - case RefractionMode.Plane: - this.shaderData.enableMacro("REFRACTION_MODE", "PLANE"); - break; - case RefractionMode.Thin: - this.shaderData.enableMacro("REFRACTION_MODE", "THIN"); - break; - } - } } diff --git a/packages/core/src/material/enums/Refraction.ts b/packages/core/src/material/enums/Refraction.ts index e043ad6f49..0db3d5891f 100644 --- a/packages/core/src/material/enums/Refraction.ts +++ b/packages/core/src/material/enums/Refraction.ts @@ -2,10 +2,8 @@ * Refraction mode. */ export enum RefractionMode { - /** Refraction shape is sphere. */ - Sphere, - /** Refraction shape is plane. */ - Plane, - /** Refraction shape is thin. */ - Thin + /** Use the sphere refraction model when light passes through the surface. */ + Sphere = 0, + /** Use the planar refraction model when light passes through the surface. */ + Planar = 1 } diff --git a/packages/shader-shaderlab/src/shaders/Common.glsl b/packages/shader-shaderlab/src/shaders/Common.glsl index b245a1ca6c..ed43818846 100644 --- a/packages/shader-shaderlab/src/shaders/Common.glsl +++ b/packages/shader-shaderlab/src/shaders/Common.glsl @@ -6,7 +6,7 @@ #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 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 ) @@ -99,10 +99,10 @@ 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); -// } +vec3 safeNormalize(vec3 inVec) +{ + float dp3 = max(float(HALF_MIN), dot(inVec, inVec)); + return inVec * inversesqrt(dp3); +} #endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/PBR.gs b/packages/shader-shaderlab/src/shaders/PBR.gs index ad6d98fc04..ad3881cec9 100644 --- a/packages/shader-shaderlab/src/shaders/PBR.gs +++ b/packages/shader-shaderlab/src/shaders/PBR.gs @@ -58,6 +58,10 @@ Shader "PBR.gs" { Header("Transmission"){ material_Transmission("Transmission", Range(0, 1, 0.01)) = 0; material_TransmissionTexture("TransmissionTexture", Texture2D); + material_AttenuationColor("AttenuationColor", Color ) = (1, 1, 1, 1); + material_AttenuationDistance("AttenuationDistance", Range(0, 1, 0.01)) = 0; + material_Thickness("Thickness", Range(0, 5, 0.01)) = 0; + material_ThicknessTexture("ThicknessTexture", Texture2D); } Header("Common") { diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/BTDF.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/BTDF.glsl index bbc5fabde1..0a6ae4919d 100644 --- a/packages/shader-shaderlab/src/shaders/shadingPBR/BTDF.glsl +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/BTDF.glsl @@ -5,12 +5,16 @@ #ifdef MATERIAL_ENABLE_TRANSMISSION sampler2D camera_OpaqueTexture; - vec3 evaluateRefraction(SurfaceData surfaceData, BRDFData brdfData) { + vec3 evaluateTransmission(SurfaceData surfaceData, BRDFData brdfData) { RefractionModelResult ray; - #ifdef REFRACTION_MODE - refractionModelBox(-surfaceData.viewDir, surfaceData.position, surfaceData.normal, surfaceData.IOR, 0.005, ray); + #if REFRACTION_MODE == 0 + // RefractionMode.Sphere + refractionModelSphere(-surfaceData.viewDir, surfaceData.position, surfaceData.normal, surfaceData.IOR, surfaceData.thickness, ray); + #elif REFRACTION_MODE == 1 + // RefractionMode.Planar + refractionModelPlanar(-surfaceData.viewDir, surfaceData.position, surfaceData.normal, surfaceData.IOR, surfaceData.thickness, ray); #endif - //TODO: support cubemap refraction. + vec3 refractedRayExit = ray.positionExit; // We calculate the screen space position of the refracted point @@ -18,15 +22,18 @@ vec2 refractionCoords = (samplingPositionNDC.xy / samplingPositionNDC.w) * 0.5 + 0.5; // Sample the opaque texture to get the transmitted light - vec4 getTransmission = texture2D(camera_OpaqueTexture, refractionCoords); - vec3 refractionTransmitted = getTransmission.rgb; + vec3 refractionTransmitted = texture2D(camera_OpaqueTexture, refractionCoords).rgb; refractionTransmitted *= brdfData.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 - vec3 specularDFG = brdfData.envSpecularDFG; + refractionTransmitted *= (1.0 - brdfData.envSpecularDFG); - refractionTransmitted *= (1.0 - specularDFG); + #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(-surfaceData.absorptionCoefficient * ray.transmissionLength)); + refractionTransmitted *= transmittance; + #endif return refractionTransmitted; } diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/ForwardPassPBR.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/ForwardPassPBR.glsl index 2550aaf08b..78b9e926c1 100644 --- a/packages/shader-shaderlab/src/shaders/shadingPBR/ForwardPassPBR.glsl +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/ForwardPassPBR.glsl @@ -95,7 +95,7 @@ void PBRFragment(Varyings varyings) { evaluateIBL(varyings, surfaceData, brdfData, totalDiffuseColor, totalSpecularColor); #ifdef MATERIAL_ENABLE_TRANSMISSION - vec3 refractionTransmitted = evaluateRefraction(surfaceData, brdfData); + vec3 refractionTransmitted = evaluateTransmission(surfaceData, brdfData); totalDiffuseColor = mix(totalDiffuseColor, refractionTransmitted, surfaceData.transmission); #endif diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/FragmentPBR.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/FragmentPBR.glsl index 3fbd0b619e..db2bad2a07 100644 --- a/packages/shader-shaderlab/src/shaders/shadingPBR/FragmentPBR.glsl +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/FragmentPBR.glsl @@ -62,11 +62,20 @@ float material_OcclusionTextureCoord; #endif #endif -#ifdef MATERIAL_ENABLE_TRANSMISSION - float material_Transmission; - #ifdef MATERIAL_HAS_TRANSMISSION_TEXTURE - sampler2D material_TransmissionTexture; +#ifdef MATERIAL_ENABLE_TRANSMISSION + float material_Transmission; + #ifdef MATERIAL_HAS_TRANSMISSION_TEXTURE + sampler2D material_TransmissionTexture; + #endif + + #ifdef MATERIAL_HAS_THICKNESS + vec3 material_AttenuationColor; + float material_AttenuationDistance; + float material_Thickness; + #ifdef MATERIAL_HAS_THICKNESS_TEXTURE + sampler2D material_ThicknessTexture; #endif + #endif #endif // Texture @@ -302,10 +311,18 @@ SurfaceData getSurfaceData(Varyings v, vec2 aoUV, bool isFrontFacing){ #endif #ifdef MATERIAL_ENABLE_TRANSMISSION - surfaceData.transmission = material_Transmission; - #ifdef MATERIAL_HAS_TRANSMISSION_TEXTURE - surfaceData.transmission *= texture2D(material_TransmissionTexture, uv).r; - #endif + surfaceData.transmission = material_Transmission; + #ifdef MATERIAL_HAS_TRANSMISSION_TEXTURE + surfaceData.transmission *= texture2D(material_TransmissionTexture, uv).r; + #endif + + #ifdef MATERIAL_HAS_THICKNESS + surfaceData.absorptionCoefficient = -log(material_AttenuationColor + HALF_EPS) / max(HALF_EPS, material_AttenuationDistance); + surfaceData.thickness = max(material_Thickness, 0.0001); + #ifdef MATERIAL_HAS_THICKNESS_TEXTURE + surfaceData.thickness *= texture2D( material_ThicknessTexture, uv).g; + #endif + #endif #endif // AO diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/Refraction.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/Refraction.glsl index 91e3f1ebaf..cfb0d86ecb 100644 --- a/packages/shader-shaderlab/src/shaders/shadingPBR/Refraction.glsl +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/Refraction.glsl @@ -9,7 +9,28 @@ struct RefractionModelResult{ // vec3 directionExit; // out ray direction }; -void refractionModelBox(vec3 V, vec3 positionWS, vec3 normalWS, float ior, float thickness, out RefractionModelResult ray){ +//https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@15.0/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