123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- import { __decorate } from "../tslib.es6.js";
- /**
- * Reflective Shadow Maps were first described in http://www.klayge.org/material/3_12/GI/rsm.pdf by Carsten Dachsbacher and Marc Stamminger
- * The ReflectiveShadowMap class only implements the position / normal / flux texture generation part.
- * For the global illumination effect, see the GIRSMManager class.
- */
- import { MultiRenderTarget } from "../Materials/Textures/multiRenderTarget.js";
- import { Color3, Color4 } from "../Maths/math.color.js";
- import { Matrix, TmpVectors } from "../Maths/math.vector.js";
- import { MaterialPluginBase } from "../Materials/materialPluginBase.js";
- import { MaterialDefines } from "../Materials/materialDefines.js";
- import { PBRBaseMaterial } from "../Materials/PBR/pbrBaseMaterial.js";
- import { expandToProperty, serialize } from "../Misc/decorators.js";
- import { RegisterClass } from "../Misc/typeStore.js";
- import { Light } from "../Lights/light.js";
- /**
- * Class used to generate the RSM (Reflective Shadow Map) textures for a given light.
- * The textures are: position (in world space), normal (in world space) and flux (light intensity)
- */
- export class ReflectiveShadowMap {
- /**
- * Enables or disables the RSM generation.
- */
- get enable() {
- return this._enable;
- }
- set enable(value) {
- if (this._enable === value) {
- return;
- }
- this._enable = value;
- this._customRenderTarget(value);
- }
- /**
- * Gets the position texture generated by the RSM process.
- */
- get positionWorldTexture() {
- return this._mrt.textures[0];
- }
- /**
- * Gets the normal texture generated by the RSM process.
- */
- get normalWorldTexture() {
- return this._mrt.textures[1];
- }
- /**
- * Gets the flux texture generated by the RSM process.
- */
- get fluxTexture() {
- return this._mrt.textures[2];
- }
- /**
- * Gets the render list used to generate the RSM textures.
- */
- get renderList() {
- return this._mrt.renderList;
- }
- /**
- * Gets the light used to generate the RSM textures.
- */
- get light() {
- return this._light;
- }
- /**
- * Creates a new RSM for the given light.
- * @param scene The scene
- * @param light The light to use to generate the RSM textures
- * @param textureDimensions The dimensions of the textures to generate. Default: \{ width: 512, height: 512 \}
- */
- constructor(scene, light, textureDimensions = { width: 512, height: 512 }) {
- this._lightTransformMatrix = Matrix.Identity();
- this._enable = false;
- /**
- * Gets or sets a boolean indicating if the light parameters should be recomputed even if the light parameters (position, direction) did not change.
- * You should not set this value to true, except for debugging purpose (if you want to see changes from the inspector, for eg).
- * Instead, you should call updateLightParameters() explicitely at the right time (once the light parameters changed).
- */
- this.forceUpdateLightParameters = false;
- this._scene = scene;
- this._light = light;
- this._textureDimensions = textureDimensions;
- this._regularMatToMatWithPlugin = new Map();
- this._counters = [{ name: "RSM Generation " + light.name, value: 0 }];
- this._createMultiRenderTarget();
- this._recomputeLightTransformationMatrix();
- this.enable = true;
- }
- /**
- * Sets the dimensions of the textures to generate.
- * @param dimensions The dimensions of the textures to generate.
- */
- setTextureDimensions(dimensions) {
- const renderList = this._mrt.renderList;
- this._textureDimensions = dimensions;
- this._disposeMultiRenderTarget();
- this._createMultiRenderTarget();
- renderList?.forEach((mesh) => {
- this._addMeshToMRT(mesh);
- });
- }
- /**
- * Adds the given mesh to the render list used to generate the RSM textures.
- * @param mesh The mesh to add to the render list used to generate the RSM textures. If not provided, all scene meshes will be added to the render list.
- */
- addMesh(mesh) {
- if (mesh) {
- this._addMeshToMRT(mesh);
- }
- else {
- this._scene.meshes.forEach((mesh) => {
- this._addMeshToMRT(mesh);
- });
- }
- this._recomputeLightTransformationMatrix();
- }
- /**
- * Recomputes the light transformation matrix. Call this method if you manually changed the light position / direction / etc. and you want to update the RSM textures accordingly.
- * You should also call this method if you add/remove meshes to/from the render list.
- */
- updateLightParameters() {
- this._recomputeLightTransformationMatrix();
- }
- /**
- * Gets the light transformation matrix used to generate the RSM textures.
- */
- get lightTransformationMatrix() {
- if (this.forceUpdateLightParameters) {
- this.updateLightParameters();
- }
- return this._lightTransformMatrix;
- }
- /**
- * Gets the GPU time spent to generate the RSM textures.
- */
- get countersGPU() {
- return this._counters;
- }
- /**
- * Disposes the RSM.
- */
- dispose() {
- this._disposeMultiRenderTarget();
- }
- _createMultiRenderTarget() {
- const name = this._light.name;
- const caps = this._scene.getEngine().getCaps();
- const fluxTextureType = caps.rg11b10ufColorRenderable ? 13 : 2;
- const fluxTextureFormat = caps.rg11b10ufColorRenderable ? 4 : 5;
- this._mrt = new MultiRenderTarget("RSMmrt_" + name, this._textureDimensions, 3, // number of RTT - position / normal / flux
- this._scene, {
- types: [2, 11, fluxTextureType],
- samplingModes: [2, 2, 2],
- generateMipMaps: false,
- targetTypes: [3553, 3553, 3553],
- formats: [5, 5, fluxTextureFormat],
- }, ["RSMPosition_" + name, "RSMNormal_" + name, "RSMFlux_" + name]);
- this._mrt.renderList = [];
- this._mrt.clearColor = new Color4(0, 0, 0, 1);
- this._mrt.noPrePassRenderer = true;
- let sceneUBO;
- let currentSceneUBO;
- const useUBO = this._scene.getEngine().supportsUniformBuffers;
- if (useUBO) {
- sceneUBO = this._scene.createSceneUniformBuffer(`Scene for RSM (light "${name}")`);
- }
- let shadowEnabled;
- this._mrt.onBeforeBindObservable.add(() => {
- currentSceneUBO = this._scene.getSceneUniformBuffer();
- shadowEnabled = this._light.shadowEnabled;
- this._light.shadowEnabled = false; // we render from the light point of view, so we won't have any shadow anyway!
- });
- this._mrt.onBeforeRenderObservable.add((faceIndex) => {
- if (sceneUBO) {
- this._scene.setSceneUniformBuffer(sceneUBO);
- }
- const viewMatrix = this._light.getViewMatrix(faceIndex);
- const projectionMatrix = this._light.getProjectionMatrix(viewMatrix || undefined, this._mrt.renderList || undefined);
- if (viewMatrix && projectionMatrix) {
- this._scene.setTransformMatrix(viewMatrix, projectionMatrix);
- }
- if (useUBO) {
- this._scene.getSceneUniformBuffer().unbindEffect();
- this._scene.finalizeSceneUbo();
- }
- });
- this._mrt.onAfterUnbindObservable.add(() => {
- if (sceneUBO) {
- this._scene.setSceneUniformBuffer(currentSceneUBO);
- }
- this._scene.updateTransformMatrix(); // restore the view/projection matrices of the active camera
- this._light.shadowEnabled = shadowEnabled;
- this._counters[0].value = this._mrt.renderTarget.gpuTimeInFrame?.counter.lastSecAverage ?? 0;
- });
- this._customRenderTarget(true);
- }
- _customRenderTarget(add) {
- const idx = this._scene.customRenderTargets.indexOf(this._mrt);
- if (add) {
- if (idx === -1) {
- this._scene.customRenderTargets.push(this._mrt);
- }
- }
- else if (idx !== -1) {
- this._scene.customRenderTargets.splice(idx, 1);
- }
- }
- _recomputeLightTransformationMatrix() {
- const viewMatrix = this._light.getViewMatrix();
- const projectionMatrix = this._light.getProjectionMatrix(viewMatrix || undefined, this._mrt.renderList || undefined);
- if (viewMatrix && projectionMatrix) {
- viewMatrix.multiplyToRef(projectionMatrix, this._lightTransformMatrix);
- }
- }
- _addMeshToMRT(mesh) {
- this._mrt.renderList?.push(mesh);
- const material = mesh.material;
- if (mesh.getTotalVertices() === 0 || !material) {
- return;
- }
- let rsmMaterial = this._regularMatToMatWithPlugin.get(material);
- if (!rsmMaterial) {
- rsmMaterial = material.clone("RSMCreate_" + material.name) || undefined;
- if (rsmMaterial) {
- // Disable the prepass renderer for this material
- Object.defineProperty(rsmMaterial, "canRenderToMRT", {
- get: function () {
- return false;
- },
- enumerable: true,
- configurable: true,
- });
- rsmMaterial.disableLighting = true;
- const rsmCreatePlugin = new RSMCreatePluginMaterial(rsmMaterial);
- rsmCreatePlugin.isEnabled = true;
- rsmCreatePlugin.light = this._light;
- this._regularMatToMatWithPlugin.set(material, rsmMaterial);
- }
- }
- this._mrt.setMaterialForRendering(mesh, rsmMaterial);
- }
- _disposeMultiRenderTarget() {
- this._customRenderTarget(false);
- this._mrt.dispose();
- }
- }
- /**
- * @internal
- */
- class MaterialRSMCreateDefines extends MaterialDefines {
- constructor() {
- super(...arguments);
- this.RSMCREATE = false;
- this.RSMCREATE_PROJTEXTURE = false;
- this.RSMCREATE_LIGHT_IS_SPOT = false;
- }
- }
- /**
- * Plugin that implements the creation of the RSM textures
- */
- export class RSMCreatePluginMaterial extends MaterialPluginBase {
- _markAllSubMeshesAsTexturesDirty() {
- this._enable(this._isEnabled);
- this._internalMarkAllSubMeshesAsTexturesDirty();
- }
- /**
- * Create a new RSMCreatePluginMaterial
- * @param material Parent material of the plugin
- */
- constructor(material) {
- super(material, RSMCreatePluginMaterial.Name, 300, new MaterialRSMCreateDefines());
- this._lightColor = new Color3();
- this._hasProjectionTexture = false;
- this._isEnabled = false;
- /**
- * Defines if the plugin is enabled in the material.
- */
- this.isEnabled = false;
- this._internalMarkAllSubMeshesAsTexturesDirty = material._dirtyCallbacks[1];
- this._varAlbedoName = material instanceof PBRBaseMaterial ? "surfaceAlbedo" : "baseColor.rgb";
- }
- prepareDefines(defines) {
- defines.RSMCREATE = this._isEnabled;
- this._hasProjectionTexture = false;
- const isSpot = this.light.getTypeID() === Light.LIGHTTYPEID_SPOTLIGHT;
- if (isSpot) {
- const spot = this.light;
- this._hasProjectionTexture = spot.projectionTexture ? spot.projectionTexture.isReady() : false;
- }
- defines.RSMCREATE_PROJTEXTURE = this._hasProjectionTexture;
- defines.RSMCREATE_LIGHT_IS_SPOT = isSpot;
- }
- getClassName() {
- return "RSMCreatePluginMaterial";
- }
- getUniforms() {
- return {
- ubo: [
- { name: "rsmTextureProjectionMatrix", size: 16, type: "mat4" },
- { name: "rsmSpotInfo", size: 4, type: "vec4" },
- { name: "rsmLightColor", size: 3, type: "vec3" },
- { name: "rsmLightPosition", size: 3, type: "vec3" },
- ],
- fragment: `#ifdef RSMCREATE
- uniform mat4 rsmTextureProjectionMatrix;
- uniform vec4 rsmSpotInfo;
- uniform vec3 rsmLightColor;
- uniform vec3 rsmLightPosition;
- #endif`,
- };
- }
- getSamplers(samplers) {
- samplers.push("rsmTextureProjectionSampler");
- }
- bindForSubMesh(uniformBuffer) {
- if (!this._isEnabled) {
- return;
- }
- this.light.diffuse.scaleToRef(this.light.getScaledIntensity(), this._lightColor);
- uniformBuffer.updateColor3("rsmLightColor", this._lightColor);
- if (this.light.getTypeID() === Light.LIGHTTYPEID_SPOTLIGHT) {
- const spot = this.light;
- if (this._hasProjectionTexture) {
- uniformBuffer.updateMatrix("rsmTextureProjectionMatrix", spot.projectionTextureMatrix);
- uniformBuffer.setTexture("rsmTextureProjectionSampler", spot.projectionTexture);
- }
- const normalizeDirection = TmpVectors.Vector3[0];
- if (spot.computeTransformedInformation()) {
- uniformBuffer.updateFloat3("rsmLightPosition", this.light.transformedPosition.x, this.light.transformedPosition.y, this.light.transformedPosition.z);
- spot.transformedDirection.normalizeToRef(normalizeDirection);
- }
- else {
- uniformBuffer.updateFloat3("rsmLightPosition", this.light.position.x, this.light.position.y, this.light.position.z);
- spot.direction.normalizeToRef(normalizeDirection);
- }
- uniformBuffer.updateFloat4("rsmSpotInfo", normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, Math.cos(spot.angle * 0.5));
- }
- }
- getCustomCode(shaderType) {
- return shaderType === "vertex"
- ? null
- : {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- CUSTOM_FRAGMENT_BEGIN: `
- #ifdef RSMCREATE
- #extension GL_EXT_draw_buffers : require
- #endif
- `,
- // eslint-disable-next-line @typescript-eslint/naming-convention
- CUSTOM_FRAGMENT_DEFINITIONS: `
- #ifdef RSMCREATE
- #ifdef RSMCREATE_PROJTEXTURE
- uniform highp sampler2D rsmTextureProjectionSampler;
- #endif
- layout(location = 0) out highp vec4 glFragData[3];
- vec4 glFragColor;
- #endif
- `,
- // eslint-disable-next-line @typescript-eslint/naming-convention
- CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR: `
- #ifdef RSMCREATE
- vec3 rsmColor = ${this._varAlbedoName} * rsmLightColor;
- #ifdef RSMCREATE_PROJTEXTURE
- {
- vec4 strq = rsmTextureProjectionMatrix * vec4(vPositionW, 1.0);
- strq /= strq.w;
- rsmColor *= texture2D(rsmTextureProjectionSampler, strq.xy).rgb;
- }
- #endif
- #ifdef RSMCREATE_LIGHT_IS_SPOT
- {
- float cosAngle = max(0., dot(rsmSpotInfo.xyz, normalize(vPositionW - rsmLightPosition)));
- rsmColor = sign(cosAngle - rsmSpotInfo.w) * rsmColor;
- }
- #endif
- glFragData[0] = vec4(vPositionW, 1.);
- glFragData[1] = vec4(normalize(normalW) * 0.5 + 0.5, 1.);
- glFragData[2] = vec4(rsmColor, 1.);
- #endif
- `,
- };
- }
- }
- /**
- * Defines the name of the plugin.
- */
- RSMCreatePluginMaterial.Name = "RSMCreate";
- __decorate([
- serialize()
- ], RSMCreatePluginMaterial.prototype, "light", void 0);
- __decorate([
- serialize(),
- expandToProperty("_markAllSubMeshesAsTexturesDirty")
- ], RSMCreatePluginMaterial.prototype, "isEnabled", void 0);
- RegisterClass(`BABYLON.RSMCreatePluginMaterial`, RSMCreatePluginMaterial);
- //# sourceMappingURL=reflectiveShadowMap.js.map
|