Explorar o código

ported but untested

Benjamin Guignabert %!s(int64=5) %!d(string=hai) anos
pai
achega
860b06f7b0

+ 43 - 1
src/PostProcesses/SubSurfaceScatteringPostProcess.ts

@@ -5,6 +5,7 @@ import { Texture } from "../Materials/Textures/texture";
 import { PostProcess, PostProcessOptions } from "./postProcess";
 import { PostProcess, PostProcessOptions } from "./postProcess";
 import { Engine } from "../Engines/engine";
 import { Engine } from "../Engines/engine";
 import { Scene } from "../scene";
 import { Scene } from "../scene";
+import { Color3 } from "../Maths/math.color";
 import { Constants } from "../Engines/constants";
 import { Constants } from "../Engines/constants";
 
 
 import "../Shaders/sceneCompositor.fragment";
 import "../Shaders/sceneCompositor.fragment";
@@ -19,8 +20,11 @@ export class SubSurfaceScatteringPostProcess extends PostProcess {
     /** @hidden */
     /** @hidden */
     public texelHeight: number;
     public texelHeight: number;
 
 
+    private _diffusionColor: Color3 = new Color3(0.7568628, 0.32156864, 0.20000002);
+    private _filterRadius: number;
+
     constructor(name: string, scene: Scene, options: number | PostProcessOptions, camera: Nullable<Camera> = null, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT) {
     constructor(name: string, scene: Scene, options: number | PostProcessOptions, camera: Nullable<Camera> = null, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT) {
-        super(name, "subSurfaceScattering", ["texelSize"], ["irradianceSampler"], options, camera, samplingMode || Texture.BILINEAR_SAMPLINGMODE, engine, reusable, null, textureType, "postprocess", undefined, true);
+        super(name, "subSurfaceScattering", ["texelSize", "filterRadius", "viewportSize"], ["irradianceSampler"], options, camera, samplingMode || Texture.BILINEAR_SAMPLINGMODE, engine, reusable, null, textureType, "postprocess", undefined, true);
 
 
         const defines = this._getDefines();
         const defines = this._getDefines();
         this.updateEffect(defines);
         this.updateEffect(defines);
@@ -29,7 +33,13 @@ export class SubSurfaceScatteringPostProcess extends PostProcess {
             var texelSize = this.texelSize;
             var texelSize = this.texelSize;
             effect.setFloat2("texelSize", texelSize.x, texelSize.y);
             effect.setFloat2("texelSize", texelSize.x, texelSize.y);
             effect.setTexture("irradianceSampler", scene.highDefinitionMRT.textures[2]);
             effect.setTexture("irradianceSampler", scene.highDefinitionMRT.textures[2]);
+            effect.setFloat("filterRadius", this._filterRadius);
+            effect.setFloat2("viewportSize", 
+                Math.tan(scene.activeCamera!.fov / 2) * scene.getEngine().getAspectRatio(scene.activeCamera!, true),
+                Math.tan(scene.activeCamera!.fov / 2));
         });
         });
+
+        this._filterRadius = this._getDiffusionProfileParameters();
     }
     }
 
 
     private _getDefines(): Nullable<string> {
     private _getDefines(): Nullable<string> {
@@ -40,4 +50,36 @@ export class SubSurfaceScatteringPostProcess extends PostProcess {
 
 
         return "";
         return "";
     }
     }
+
+    private _getDiffusionProfileParameters()
+    {
+        const cdf = 0.997;
+        // Importance sample the normalized diffuse reflectance profile for the computed value of 's'.
+        // ------------------------------------------------------------------------------------
+        // R[r, phi, s]   = s * (Exp[-r * s] + Exp[-r * s / 3]) / (8 * Pi * r)
+        // PDF[r, phi, s] = r * R[r, phi, s]
+        // CDF[r, s]      = 1 - 1/4 * Exp[-r * s] - 3/4 * Exp[-r * s / 3]
+        // ------------------------------------------------------------------------------------
+        // We importance sample the color channel with the widest scattering distance.
+        const maxScatteringDistance = Math.max(this._diffusionColor.r, this._diffusionColor.g, this._diffusionColor.b);
+
+        return this._sampleBurleyDiffusionProfile(cdf, maxScatteringDistance);
+    }
+    // https://zero-radiance.github.io/post/sampling-diffusion/
+    // Performs sampling of a Normalized Burley diffusion profile in polar coordinates.
+    // 'u' is the random number (the value of the CDF): [0, 1).
+    // rcp(s) = 1 / ShapeParam = ScatteringDistance.
+    // Returns the sampled radial distance, s.t. (u = 0 -> r = 0) and (u = 1 -> r = Inf).
+    private _sampleBurleyDiffusionProfile(u: number, rcpS: number)
+    {
+        u = 1 - u; // Convert CDF to CCDF
+
+        let g = 1 + (4 * u) * (2 * u + Math.sqrt(1 + (4 * u) * u));
+        let n = Math.pow(g, -1.0/3.0);                      // g^(-1/3)
+        let p = (g * n) * n;                                   // g^(+1/3)
+        let c = 1 + p + n;                                     // 1 + g^(+1/3) + g^(-1/3)
+        let x = 3 * Math.log(c / (4 * u));
+
+        return x * rcpS;
+    }
 }
 }

+ 19 - 14
src/Shaders/subSurfaceScattering.fragment.fx

@@ -6,10 +6,14 @@ varying vec2 texelSize;
 uniform sampler2D textureSampler;
 uniform sampler2D textureSampler;
 uniform sampler2D irradianceSampler;
 uniform sampler2D irradianceSampler;
 
 
+uniform float filterRadius;
+uniform vec2 viewportSize;
+
 const float LOG2_E = 1.4426950408889634;
 const float LOG2_E = 1.4426950408889634;
 const float PI = 3.1415926535897932;
 const float PI = 3.1415926535897932;
-const int SSS_PIXELS_PER_SAMPLE = 32;
+const int SSS_PIXELS_PER_SAMPLE = 1;
 const int _SssSampleBudget = 32;
 const int _SssSampleBudget = 32;
+
 #define rcp(x) 1. / x
 #define rcp(x) 1. / x
 #define Sq(x) x * x
 #define Sq(x) x * x
 
 
@@ -27,7 +31,7 @@ vec3 EvalBurleyDiffusionProfile(float r, vec3 S)
 // rcp(s) = 1 / ShapeParam = ScatteringDistance.
 // rcp(s) = 1 / ShapeParam = ScatteringDistance.
 // 'r' is the sampled radial distance, s.t. (u = 0 -> r = 0) and (u = 1 -> r = Inf).
 // 'r' is the sampled radial distance, s.t. (u = 0 -> r = 0) and (u = 1 -> r = Inf).
 // rcp(Pdf) is the reciprocal of the corresponding PDF value.
 // rcp(Pdf) is the reciprocal of the corresponding PDF value.
-vec2 SampleBurleyDiffusionProfile(float u, float rcpS, out float r, out float rcpPdf)
+vec2 SampleBurleyDiffusionProfile(float u, float rcpS)
 {
 {
     u = 1. - u; // Convert CDF to CCDF
     u = 1. - u; // Convert CDF to CCDF
 
 
@@ -79,17 +83,17 @@ void main(void)
     //   ior: 1.4
     //   ior: 1.4
     //   hash: 1075477546
     //   hash: 1075477546
 
 
+    // TODO : uniforms
 	float  distScale     = 1.; //sssData.subsurfaceMask;
 	float  distScale     = 1.; //sssData.subsurfaceMask;
 	vec3 S             = vec3(0.7568628, 0.32156864, 0.20000002); //_ShapeParamsAndMaxScatterDists[profileIndex].rgb; -> diffusion color
 	vec3 S             = vec3(0.7568628, 0.32156864, 0.20000002); //_ShapeParamsAndMaxScatterDists[profileIndex].rgb; -> diffusion color
-	float  d             = 0.5; //_ShapeParamsAndMaxScatterDists[profileIndex].a; -> max scatter dist
-	float  metersPerUnit = 1.; //_WorldScalesAndFilterRadiiAndThicknessRemaps[profileIndex].x;
-	float  filterRadius  = 0.5; //_WorldScalesAndFilterRadiiAndThicknessRemaps[profileIndex].y; // In millimeters
+	float  d             = 0.7568628; //_ShapeParamsAndMaxScatterDists[profileIndex].a; -> max scatter dist
+	float  metersPerUnit = 0.01; //_WorldScalesAndFilterRadiiAndThicknessRemaps[profileIndex].x;
 
 
 	// Reconstruct the view-space position corresponding to the central sample.
 	// Reconstruct the view-space position corresponding to the central sample.
 	vec2 centerPosNDC = vUV;
 	vec2 centerPosNDC = vUV;
 	vec2 cornerPosNDC = vUV + 0.5 * texelSize;
 	vec2 cornerPosNDC = vUV + 0.5 * texelSize;
-	vec3 centerPosVS  = vec3(0.); // TODO -> ComputeViewSpacePosition(centerPosNDC, centerDepth, UNITY_MATRIX_I_P);
-	vec3 cornerPosVS  = vec3(0.); // TODO -> ComputeViewSpacePosition(cornerPosNDC, centerDepth, UNITY_MATRIX_I_P);
+	vec3 centerPosVS  = vec3(centerPosNDC * viewportSize, 1.0) * centerDepth; // ComputeViewSpacePosition(centerPosNDC, centerDepth, UNITY_MATRIX_I_P);
+	vec3 cornerPosVS  = vec3(cornerPosNDC * viewportSize, 1.0) * centerDepth; // ComputeViewSpacePosition(cornerPosNDC, centerDepth, UNITY_MATRIX_I_P);
 
 
 	// Rescaling the filter is equivalent to inversely scaling the world.
 	// Rescaling the filter is equivalent to inversely scaling the world.
 	float mmPerUnit  = 1000. * (metersPerUnit * rcp(distScale));
 	float mmPerUnit  = 1000. * (metersPerUnit * rcp(distScale));
@@ -97,7 +101,7 @@ void main(void)
 
 
 	// Compute the view-space dimensions of the pixel as a quad projected onto geometry.
 	// Compute the view-space dimensions of the pixel as a quad projected onto geometry.
 	// Assuming square pixels, both X and Y are have the same dimensions.
 	// Assuming square pixels, both X and Y are have the same dimensions.
-	float unitsPerPixel = 2 * abs(cornerPosVS.x - centerPosVS.x);
+	float unitsPerPixel = 2. * abs(cornerPosVS.x - centerPosVS.x);
 	float pixelsPerMm   = rcp(unitsPerPixel) * unitsPerMm;
 	float pixelsPerMm   = rcp(unitsPerPixel) * unitsPerMm;
 
 
 	// Area of a disk.
 	// Area of a disk.
@@ -105,8 +109,8 @@ void main(void)
 	int  sampleCount  = (int)(filterArea * rcp(SSS_PIXELS_PER_SAMPLE));
 	int  sampleCount  = (int)(filterArea * rcp(SSS_PIXELS_PER_SAMPLE));
 	int  sampleBudget = _SssSampleBudget;
 	int  sampleBudget = _SssSampleBudget;
 
 
-	int   texturingMode = 0; // GetSubsurfaceScatteringTexturingMode(profileIndex);
-	vec3 albedo  = vec3(1.) // texture2D(albedoSampler, vUV); //ApplySubsurfaceScatteringTexturingMode(texturingMode, sssData.diffuseColor);
+	int texturingMode = 0; // GetSubsurfaceScatteringTexturingMode(profileIndex);
+	vec3 albedo  = vec3(0.5) // texture2D(albedoSampler, vUV); //ApplySubsurfaceScatteringTexturingMode(texturingMode, sssData.diffuseColor);
 
 
 	if (distScale == 0. || sampleCount < 1)
 	if (distScale == 0. || sampleCount < 1)
 	{
 	{
@@ -132,7 +136,7 @@ void main(void)
     {
     {
         // Integrate over the image or tangent plane in the view space.
         // Integrate over the image or tangent plane in the view space.
         EvaluateSample(i, n, S, d, centerPosVS, mmPerUnit, pixelsPerMm,
         EvaluateSample(i, n, S, d, centerPosVS, mmPerUnit, pixelsPerMm,
-                       phase, tangentX, tangentY, projMatrix,
+                       phase, tangentX, tangentY,
                        totalIrradiance, totalWeight);
                        totalIrradiance, totalWeight);
     }
     }
 
 
@@ -144,9 +148,10 @@ void main(void)
 	// gl_FragColor = mix(texture2D(textureSampler, vUV), centerIrradiance, 0.5);
 	// gl_FragColor = mix(texture2D(textureSampler, vUV), centerIrradiance, 0.5);
 }
 }
 
 
+// TODO : inout vec3 totalIrradiance, inout vec3 totalWeight
 void EvaluateSample(uint i, uint n, vec3 S, float d, vec3 centerPosVS, float mmPerUnit, float pixelsPerMm,
 void EvaluateSample(uint i, uint n, vec3 S, float d, vec3 centerPosVS, float mmPerUnit, float pixelsPerMm,
-                    float phase, vec3 tangentX, vec3 tangentY, mat projMatrix,
-                    inout vec3 totalIrradiance, inout vec3 totalWeight)
+                    float phase, vec3 tangentX, vec3 tangentY,
+                    vec3 totalIrradiance, vec3 totalWeight)
 {
 {
     // The sample count is loop-invariant.
     // The sample count is loop-invariant.
     const float scale  = rcp(n);
     const float scale  = rcp(n);
@@ -181,7 +186,7 @@ void EvaluateSample(uint i, uint n, vec3 S, float d, vec3 centerPosVS, float mmP
     // position = vUV + round(vec * pixelsPerMm);
     // position = vUV + round(vec * pixelsPerMm);
     // Note that (int) truncates towards 0, while floor() truncates towards -Inf!
     // Note that (int) truncates towards 0, while floor() truncates towards -Inf!
 
 
-    position = vUV + (int2)round((pixelsPerMm * r) * vec2(cosPsi, sinPsi)) / texelSize;
+    position = vUV + round((pixelsPerMm * r) * vec2(cosPsi, sinPsi)) * texelSize;
     xy2      = r * r;
     xy2      = r * r;
 
 
     vec4 textureSample = sampler2D(irradianceSampler, position);
     vec4 textureSample = sampler2D(irradianceSampler, position);