|
@@ -8,6 +8,7 @@ import { SubSurfaceScatteringPostProcess } from "../PostProcesses/subSurfaceScat
|
|
|
import { Effect } from "../Materials/effect";
|
|
|
import { Logger } from "../Misc/logger";
|
|
|
import { _DevTools } from '../Misc/devTools';
|
|
|
+import { Color3 } from "../Maths/math.color";
|
|
|
|
|
|
export class PrePassRenderer {
|
|
|
/** @hidden */
|
|
@@ -31,6 +32,10 @@ export class PrePassRenderer {
|
|
|
private _defaultAttachments: number[];
|
|
|
private _clearAttachments: number[];
|
|
|
|
|
|
+ public ssDiffusionS: number[] = [];
|
|
|
+ public ssFilterRadii: number[] = [];
|
|
|
+ public ssDiffusionD: number[] = [];
|
|
|
+
|
|
|
public sceneCompositorPostProcess: SceneCompositorPostProcess;
|
|
|
public subSurfaceScatteringPostProcess: SubSurfaceScatteringPostProcess;
|
|
|
private _enabled: boolean = false;
|
|
@@ -39,23 +44,47 @@ export class PrePassRenderer {
|
|
|
return this._enabled;
|
|
|
}
|
|
|
|
|
|
+ public get samples() {
|
|
|
+ return this.prePassRT.samples;
|
|
|
+ }
|
|
|
+
|
|
|
+ public set samples(n: number) {
|
|
|
+ this.prePassRT.samples = n;
|
|
|
+ }
|
|
|
+
|
|
|
constructor(scene: Scene) {
|
|
|
this._scene = scene;
|
|
|
this._engine = scene.getEngine();
|
|
|
+ PrePassRenderer._SceneComponentInitialization(this._scene);
|
|
|
|
|
|
this.prePassRT = new MultiRenderTarget("sceneprePassRT", { width: this._engine.getRenderWidth(), height: this._engine.getRenderHeight() }, this.mrtCount, this._scene,
|
|
|
{ generateMipMaps: false, generateDepthTexture: true, defaultType: Constants.TEXTURETYPE_UNSIGNED_INT, types: this._mrtTypes });
|
|
|
this.prePassRT.samples = 1;
|
|
|
|
|
|
- let gl = this._engine._gl;
|
|
|
- this._clearAttachments = [gl.NONE, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3];
|
|
|
- this._multiRenderAttachments = [gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3];
|
|
|
- this._defaultAttachments = [gl.COLOR_ATTACHMENT0, gl.NONE, gl.NONE, gl.NONE];
|
|
|
+ this._initializeAttachments();
|
|
|
+
|
|
|
+ // Adding default diffusion profile
|
|
|
+ this.addDiffusionProfile(new Color3(1, 1, 1));
|
|
|
this.sceneCompositorPostProcess = new SceneCompositorPostProcess("sceneCompositor", 1, null, undefined, this._engine);
|
|
|
this.sceneCompositorPostProcess.inputTexture = this.prePassRT.getInternalTexture()!;
|
|
|
this.subSurfaceScatteringPostProcess = new SubSurfaceScatteringPostProcess("subSurfaceScattering", this._scene, 1, null, undefined, this._engine);
|
|
|
+ }
|
|
|
|
|
|
- PrePassRenderer._SceneComponentInitialization(this._scene);
|
|
|
+ private _initializeAttachments() {
|
|
|
+ let gl = this._engine._gl;
|
|
|
+
|
|
|
+ this._multiRenderAttachments = [];
|
|
|
+ this._clearAttachments = [gl.NONE];
|
|
|
+ this._defaultAttachments = [gl.COLOR_ATTACHMENT0];
|
|
|
+
|
|
|
+ for (let i = 0; i < this.mrtCount; i++) {
|
|
|
+ this._multiRenderAttachments.push((<any>gl)["COLOR_ATTACHMENT" + i]);
|
|
|
+
|
|
|
+ if (i > 0) {
|
|
|
+ this._clearAttachments.push((<any>gl)["COLOR_ATTACHMENT" + i])
|
|
|
+ this._defaultAttachments.push(gl.NONE)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public get isSupported() {
|
|
@@ -166,6 +195,70 @@ export class PrePassRenderer {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ public addDiffusionProfile(color: Color3) : number {
|
|
|
+ if (this.ssDiffusionD.length >= 5) {
|
|
|
+ // We only suppport 5 diffusion profiles
|
|
|
+ Logger.Error("You already reached the maximum number of diffusion profiles.");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Do not add doubles
|
|
|
+ for (let i = 0; i < this.ssDiffusionS.length / 3; i++) {
|
|
|
+ if (this.ssDiffusionS[i * 3] === color.r &&
|
|
|
+ this.ssDiffusionS[i * 3 + 1] === color.g &&
|
|
|
+ this.ssDiffusionS[i * 3 + 2] === color.b) {
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.ssDiffusionS.push(color.r, color.b, color.g);
|
|
|
+ this.ssDiffusionD.push(Math.max(Math.max(color.r, color.b), color.g));
|
|
|
+ this.ssFilterRadii.push(this.getDiffusionProfileParameters(color));
|
|
|
+ this._scene.ssDiffusionProfileColors.push(color);
|
|
|
+
|
|
|
+ return this.ssDiffusionD.length - 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ public clearAllDiffusionProfiles() {
|
|
|
+ this.ssDiffusionD = [];
|
|
|
+ this.ssDiffusionS = [];
|
|
|
+ this.ssFilterRadii = [];
|
|
|
+ this._scene.ssDiffusionProfileColors = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ public getDiffusionProfileParameters(color: Color3)
|
|
|
+ {
|
|
|
+ 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(color.r, color.g, color.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;
|
|
|
+ }
|
|
|
+
|
|
|
public dispose() {
|
|
|
this.sceneCompositorPostProcess.dispose();
|
|
|
this.subSurfaceScatteringPostProcess.dispose();
|