123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- import { Scene } from "../../scene.js";
- import { SceneComponentConstants } from "../../sceneComponent.js";
- import { FluidRenderingObjectParticleSystem } from "./fluidRenderingObjectParticleSystem.js";
- import { FluidRenderingTargetRenderer } from "./fluidRenderingTargetRenderer.js";
- import { FluidRenderingObjectCustomParticles } from "./fluidRenderingObjectCustomParticles.js";
- import { FluidRenderingDepthTextureCopy } from "./fluidRenderingDepthTextureCopy.js";
- import "../../Shaders/fluidRenderingParticleDepth.vertex.js";
- import "../../Shaders/fluidRenderingParticleDepth.fragment.js";
- import "../../Shaders/fluidRenderingParticleThickness.vertex.js";
- import "../../Shaders/fluidRenderingParticleThickness.fragment.js";
- import "../../Shaders/fluidRenderingParticleDiffuse.vertex.js";
- import "../../Shaders/fluidRenderingParticleDiffuse.fragment.js";
- import "../../Shaders/fluidRenderingBilateralBlur.fragment.js";
- import "../../Shaders/fluidRenderingStandardBlur.fragment.js";
- import "../../Shaders/fluidRenderingRender.fragment.js";
- Object.defineProperty(Scene.prototype, "fluidRenderer", {
- get: function () {
- return this._fluidRenderer;
- },
- set: function (value) {
- this._fluidRenderer = value;
- },
- enumerable: true,
- configurable: true,
- });
- Scene.prototype.enableFluidRenderer = function () {
- if (this._fluidRenderer) {
- return this._fluidRenderer;
- }
- this._fluidRenderer = new FluidRenderer(this);
- return this._fluidRenderer;
- };
- Scene.prototype.disableFluidRenderer = function () {
- this._fluidRenderer?.dispose();
- this._fluidRenderer = null;
- };
- function IsParticleSystemObject(obj) {
- return !!obj.particleSystem;
- }
- function IsCustomParticlesObject(obj) {
- return !!obj.addBuffers;
- }
- /**
- * Defines the fluid renderer scene component responsible to render objects as fluids
- */
- export class FluidRendererSceneComponent {
- /**
- * Creates a new instance of the component for the given scene
- * @param scene Defines the scene to register the component in
- */
- constructor(scene) {
- /**
- * The component name helpful to identify the component in the list of scene components.
- */
- this.name = SceneComponentConstants.NAME_FLUIDRENDERER;
- this.scene = scene;
- }
- /**
- * Registers the component in a given scene
- */
- register() {
- this.scene._gatherActiveCameraRenderTargetsStage.registerStep(SceneComponentConstants.STEP_GATHERACTIVECAMERARENDERTARGETS_FLUIDRENDERER, this, this._gatherActiveCameraRenderTargets);
- this.scene._afterCameraDrawStage.registerStep(SceneComponentConstants.STEP_AFTERCAMERADRAW_FLUIDRENDERER, this, this._afterCameraDraw);
- }
- _gatherActiveCameraRenderTargets(_renderTargets) {
- this.scene.fluidRenderer?._prepareRendering();
- }
- _afterCameraDraw(camera) {
- this.scene.fluidRenderer?._render(camera);
- }
- /**
- * Rebuilds the elements related to this component in case of
- * context lost for instance.
- */
- rebuild() {
- const fluidRenderer = this.scene.fluidRenderer;
- if (!fluidRenderer) {
- return;
- }
- const buffers = new Set();
- for (let i = 0; i < fluidRenderer.renderObjects.length; ++i) {
- const obj = fluidRenderer.renderObjects[i].object;
- if (IsCustomParticlesObject(obj)) {
- const vbuffers = obj.vertexBuffers;
- for (const name in vbuffers) {
- buffers.add(vbuffers[name].getWrapperBuffer());
- }
- }
- }
- buffers.forEach((buffer) => {
- buffer._rebuild();
- });
- }
- /**
- * Disposes the component and the associated resources
- */
- dispose() {
- this.scene.disableFluidRenderer();
- }
- }
- /**
- * Class responsible for fluid rendering.
- * It is implementing the method described in https://developer.download.nvidia.com/presentations/2010/gdc/Direct3D_Effects.pdf
- */
- export class FluidRenderer {
- /** @internal */
- static _SceneComponentInitialization(scene) {
- let component = scene._getComponent(SceneComponentConstants.NAME_FLUIDRENDERER);
- if (!component) {
- component = new FluidRendererSceneComponent(scene);
- scene._addComponent(component);
- }
- }
- /**
- * Initializes the class
- * @param scene Scene in which the objects are part of
- */
- constructor(scene) {
- this._scene = scene;
- this._engine = scene.getEngine();
- this._onEngineResizeObserver = null;
- this.renderObjects = [];
- this.targetRenderers = [];
- this._cameras = new Map();
- FluidRenderer._SceneComponentInitialization(this._scene);
- this._onEngineResizeObserver = this._engine.onResizeObservable.add(() => {
- this._initialize();
- });
- }
- /**
- * Reinitializes the class
- * Can be used if you change the object priority (FluidRenderingObject.priority), to make sure the objects are rendered in the right order
- */
- recreate() {
- this._sortRenderingObjects();
- this._initialize();
- }
- /**
- * Gets the render object corresponding to a particle system (null if the particle system is not rendered as a fluid)
- * @param ps The particle system
- * @returns the render object corresponding to this particle system if any, otherwise null
- */
- getRenderObjectFromParticleSystem(ps) {
- const index = this._getParticleSystemIndex(ps);
- return index !== -1 ? this.renderObjects[index] : null;
- }
- /**
- * Adds a particle system to the fluid renderer.
- * @param ps particle system
- * @param generateDiffuseTexture True if you want to generate a diffuse texture from the particle system and use it as part of the fluid rendering (default: false)
- * @param targetRenderer The target renderer used to display the particle system as a fluid. If not provided, the method will create a new one
- * @param camera The camera used by the target renderer (if the target renderer is created by the method)
- * @returns the render object corresponding to the particle system
- */
- addParticleSystem(ps, generateDiffuseTexture, targetRenderer, camera) {
- const object = new FluidRenderingObjectParticleSystem(this._scene, ps);
- object.onParticleSizeChanged.add(() => this._setParticleSizeForRenderTargets());
- if (!targetRenderer) {
- targetRenderer = new FluidRenderingTargetRenderer(this._scene, camera);
- this.targetRenderers.push(targetRenderer);
- }
- if (!targetRenderer._onUseVelocityChanged.hasObservers()) {
- targetRenderer._onUseVelocityChanged.add(() => this._setUseVelocityForRenderObject());
- }
- if (generateDiffuseTexture !== undefined) {
- targetRenderer.generateDiffuseTexture = generateDiffuseTexture;
- }
- const renderObject = { object, targetRenderer };
- this.renderObjects.push(renderObject);
- this._sortRenderingObjects();
- this._setParticleSizeForRenderTargets();
- return renderObject;
- }
- /**
- * Adds a custom particle set to the fluid renderer.
- * @param buffers The list of buffers (should contain at least a "position" buffer!)
- * @param numParticles Number of particles in each buffer
- * @param generateDiffuseTexture True if you want to generate a diffuse texture from buffers and use it as part of the fluid rendering (default: false). For the texture to be generated correctly, you need a "color" buffer in the set!
- * @param targetRenderer The target renderer used to display the particle system as a fluid. If not provided, the method will create a new one
- * @param camera The camera used by the target renderer (if the target renderer is created by the method)
- * @returns the render object corresponding to the custom particle set
- */
- addCustomParticles(buffers, numParticles, generateDiffuseTexture, targetRenderer, camera) {
- const object = new FluidRenderingObjectCustomParticles(this._scene, buffers, numParticles);
- object.onParticleSizeChanged.add(() => this._setParticleSizeForRenderTargets());
- if (!targetRenderer) {
- targetRenderer = new FluidRenderingTargetRenderer(this._scene, camera);
- this.targetRenderers.push(targetRenderer);
- }
- if (!targetRenderer._onUseVelocityChanged.hasObservers()) {
- targetRenderer._onUseVelocityChanged.add(() => this._setUseVelocityForRenderObject());
- }
- if (generateDiffuseTexture !== undefined) {
- targetRenderer.generateDiffuseTexture = generateDiffuseTexture;
- }
- const renderObject = { object, targetRenderer };
- this.renderObjects.push(renderObject);
- this._sortRenderingObjects();
- this._setParticleSizeForRenderTargets();
- return renderObject;
- }
- /**
- * Removes a render object from the fluid renderer
- * @param renderObject the render object to remove
- * @param removeUnusedTargetRenderer True to remove/dispose of the target renderer if it's not used anymore (default: true)
- * @returns True if the render object has been found and released, else false
- */
- removeRenderObject(renderObject, removeUnusedTargetRenderer = true) {
- const index = this.renderObjects.indexOf(renderObject);
- if (index === -1) {
- return false;
- }
- renderObject.object.dispose();
- this.renderObjects.splice(index, 1);
- if (removeUnusedTargetRenderer && this._removeUnusedTargetRenderers()) {
- this._initialize();
- }
- else {
- this._setParticleSizeForRenderTargets();
- }
- return true;
- }
- _sortRenderingObjects() {
- this.renderObjects.sort((a, b) => {
- return a.object.priority < b.object.priority ? -1 : a.object.priority > b.object.priority ? 1 : 0;
- });
- }
- _removeUnusedTargetRenderers() {
- const indexes = {};
- for (let i = 0; i < this.renderObjects.length; ++i) {
- const targetRenderer = this.renderObjects[i].targetRenderer;
- indexes[this.targetRenderers.indexOf(targetRenderer)] = true;
- }
- let removed = false;
- const newList = [];
- for (let i = 0; i < this.targetRenderers.length; ++i) {
- if (!indexes[i]) {
- this.targetRenderers[i].dispose();
- removed = true;
- }
- else {
- newList.push(this.targetRenderers[i]);
- }
- }
- if (removed) {
- this.targetRenderers.length = 0;
- this.targetRenderers.push(...newList);
- }
- return removed;
- }
- _getParticleSystemIndex(ps) {
- for (let i = 0; i < this.renderObjects.length; ++i) {
- const obj = this.renderObjects[i].object;
- if (IsParticleSystemObject(obj) && obj.particleSystem === ps) {
- return i;
- }
- }
- return -1;
- }
- _initialize() {
- for (let i = 0; i < this.targetRenderers.length; ++i) {
- this.targetRenderers[i].dispose();
- }
- const cameras = new Map();
- for (let i = 0; i < this.targetRenderers.length; ++i) {
- const targetRenderer = this.targetRenderers[i];
- targetRenderer._initialize();
- if (targetRenderer.camera && targetRenderer._renderPostProcess) {
- let list = cameras.get(targetRenderer.camera);
- if (!list) {
- list = [[], {}];
- cameras.set(targetRenderer.camera, list);
- }
- list[0].push(targetRenderer);
- targetRenderer.camera.attachPostProcess(targetRenderer._renderPostProcess, i);
- }
- }
- let iterator = cameras.keys();
- for (let key = iterator.next(); key.done !== true; key = iterator.next()) {
- const camera = key.value;
- const list = cameras.get(camera);
- const firstPostProcess = camera._getFirstPostProcess();
- if (!firstPostProcess) {
- continue;
- }
- const [targetRenderers, copyDepthTextures] = list;
- firstPostProcess.onSizeChangedObservable.add(() => {
- if (!firstPostProcess.inputTexture.depthStencilTexture) {
- firstPostProcess.inputTexture.createDepthStencilTexture(0, true, this._engine.isStencilEnable, targetRenderers[0].samples, this._engine.isStencilEnable ? 13 : 14, `PostProcessRTTDepthStencil-${firstPostProcess.name}`);
- }
- for (const targetRenderer of targetRenderers) {
- const thicknessRT = targetRenderer._thicknessRenderTarget?.renderTarget;
- const thicknessTexture = thicknessRT?.texture;
- if (thicknessRT && thicknessTexture) {
- const key = thicknessTexture.width + "_" + thicknessTexture.height;
- let copyDepthTexture = copyDepthTextures[key];
- if (!copyDepthTexture) {
- copyDepthTexture = copyDepthTextures[key] = new FluidRenderingDepthTextureCopy(this._engine, thicknessTexture.width, thicknessTexture.height);
- }
- copyDepthTexture.depthRTWrapper.shareDepth(thicknessRT);
- }
- }
- });
- }
- // Dispose the CopyDepthTexture instances that we don't need anymore
- iterator = this._cameras.keys();
- for (let key = iterator.next(); key.done !== true; key = iterator.next()) {
- const camera = key.value;
- const list = this._cameras.get(camera);
- const copyDepthTextures = list[1];
- const list2 = cameras.get(camera);
- if (!list2) {
- for (const key in copyDepthTextures) {
- copyDepthTextures[key].dispose();
- }
- }
- else {
- for (const key in copyDepthTextures) {
- if (!list2[1][key]) {
- copyDepthTextures[key].dispose();
- }
- }
- }
- }
- this._cameras.clear();
- this._cameras = cameras;
- this._setParticleSizeForRenderTargets();
- }
- _setParticleSizeForRenderTargets() {
- const particleSizes = new Map();
- for (let i = 0; i < this.renderObjects.length; ++i) {
- const renderingObject = this.renderObjects[i];
- let curSize = particleSizes.get(renderingObject.targetRenderer);
- if (curSize === undefined) {
- curSize = 0;
- }
- particleSizes.set(renderingObject.targetRenderer, Math.max(curSize, renderingObject.object.particleSize));
- }
- particleSizes.forEach((particleSize, targetRenderer) => {
- if (targetRenderer._depthRenderTarget) {
- targetRenderer._depthRenderTarget.particleSize = particleSize;
- }
- });
- }
- _setUseVelocityForRenderObject() {
- for (const renderingObject of this.renderObjects) {
- renderingObject.object.useVelocity = renderingObject.targetRenderer.useVelocity;
- }
- }
- /** @internal */
- _prepareRendering() {
- for (const renderer of this.targetRenderers) {
- if (renderer.needInitialization) {
- this._initialize();
- return;
- }
- }
- }
- /** @internal */
- _render(forCamera) {
- for (let i = 0; i < this.targetRenderers.length; ++i) {
- if (!forCamera || this.targetRenderers[i].camera === forCamera) {
- this.targetRenderers[i]._clearTargets();
- }
- }
- const iterator = this._cameras.keys();
- for (let key = iterator.next(); key.done !== true; key = iterator.next()) {
- const camera = key.value;
- const list = this._cameras.get(camera);
- if (forCamera && camera !== forCamera) {
- continue;
- }
- const firstPostProcess = camera._getFirstPostProcess();
- if (!firstPostProcess) {
- continue;
- }
- const sourceCopyDepth = firstPostProcess.inputTexture?.depthStencilTexture;
- if (sourceCopyDepth) {
- const [targetRenderers, copyDepthTextures] = list;
- for (const targetRenderer of targetRenderers) {
- targetRenderer._bgDepthTexture = sourceCopyDepth;
- }
- for (const key in copyDepthTextures) {
- copyDepthTextures[key].copy(sourceCopyDepth);
- }
- }
- }
- for (let i = 0; i < this.renderObjects.length; ++i) {
- const renderingObject = this.renderObjects[i];
- if (!forCamera || renderingObject.targetRenderer.camera === forCamera) {
- renderingObject.targetRenderer._render(renderingObject.object);
- }
- }
- }
- /**
- * Disposes of all the ressources used by the class
- */
- dispose() {
- this._engine.onResizeObservable.remove(this._onEngineResizeObserver);
- this._onEngineResizeObserver = null;
- for (let i = 0; i < this.renderObjects.length; ++i) {
- this.renderObjects[i].object.dispose();
- }
- for (let i = 0; i < this.targetRenderers.length; ++i) {
- this.targetRenderers[i].dispose();
- }
- this._cameras.forEach((list) => {
- const copyDepthTextures = list[1];
- for (const key in copyDepthTextures) {
- copyDepthTextures[key].dispose();
- }
- });
- this.renderObjects = [];
- this.targetRenderers = [];
- this._cameras.clear();
- }
- }
- //# sourceMappingURL=fluidRenderer.js.map
|