Kaynağa Gözat

Extend EffectRenderer (set texture width/height, use internal textures only)

Popov72 5 yıl önce
ebeveyn
işleme
86f4db39a0

+ 1 - 0
dist/preview release/what's new.md

@@ -14,6 +14,7 @@
 
 - Simplified code contributions by fully automating the dev setup with gitpod ([nisarhassan12](https://github.com/nisarhassan12))
 - Add a `CascadedShadowMap.IsSupported` method and log an error instead of throwing an exception when CSM is not supported ([Popov72](https://github.com/Popov72))
+- Extend `EffectRenderer` (set texture width/height, use internal textures only) ([Popov72](https://github.com/Popov72))
 
 ### Engine
 

+ 65 - 14
src/Materials/effectRenderer.ts

@@ -25,16 +25,31 @@ export interface IEffectRendererOptions {
      * Defines the indices.
      */
     indices?: number[];
+    /**
+     * width of the textures created by the effect renderer. By default, textures are created the same size than the canvas
+     */
+    textureWidth?: number;
+    /**
+     * height of the textures created by the effect renderer. By default, textures are created the same size than the canvas
+     */
+    textureHeight?: number;
+     /**
+     * Flip between the two internal textures for input/output and does not use the outputTexture parameter of the render function
+     * To get the texture used for the latest rendering, read the outputTexture property
+     */
+    useInternalTexturesOnly?: boolean;
 }
 
 /**
- * Helper class to render one or more effects
+ * Helper class to render one or more effects.
+ * You can access the previous rendering in your shader by declaring a sampler named textureSampler
  */
 export class EffectRenderer {
     // Fullscreen quad buffers by default.
     private static _DefaultOptions: IEffectRendererOptions = {
         positions: [1, 1, -1, 1, -1, -1, 1, -1],
-        indices: [0, 1, 2, 0, 2, 3]
+        indices: [0, 1, 2, 0, 2, 3],
+        useInternalTexturesOnly: false,
     };
 
     private _vertexBuffers: {[key: string]: VertexBuffer};
@@ -44,14 +59,39 @@ export class EffectRenderer {
     private _ringScreenBuffer: Nullable<Array<Texture>> = null;
     private _fullscreenViewport = new Viewport(0, 0, 1, 1);
 
+    private _outputTexture: Nullable<Texture>;
+    /**
+     * Get the texture used for the latest rendering. If useInternalTexturesOnly is false and you passed null
+     * to the render function, you will get null here
+     */
+    public get outputTexture(): Nullable<Texture> {
+        return this._outputTexture;
+    }
+
+    /**
+     * width of the textures created by the effect renderer. By default, textures are created the same size than the canvas
+     */
+    public textureWidth: number | undefined;
+    /**
+     * height of the textures created by the effect renderer. By default, textures are created the same size than the canvas
+     */
+    public textureHeight: number | undefined;
+
+    /**
+     * Flip between the two internal textures for input/output and does not use the outputTexture parameter of the render function
+     * To get the texture used for the latest rendering, use outputTexture. In this mode, you can use the previous rendering texture
+     * with a sampler name textureSampler in your shader
+     */
+    public useInternalTexturesOnly: boolean = false;
+
     private _getNextFrameBuffer(incrementIndex = true) {
         if (!this._ringScreenBuffer) {
             this._ringScreenBuffer = [];
             for (var i = 0; i < 2; i++) {
                 var internalTexture = this.engine.createRenderTargetTexture(
                     {
-                        width: this.engine.getRenderWidth(true),
-                        height: this.engine.getRenderHeight(true),
+                        width: this.textureWidth ?? this.engine.getRenderWidth(true),
+                        height: this.textureHeight ?? this.engine.getRenderHeight(true),
                     },
                     {
                         generateDepthBuffer: false,
@@ -83,14 +123,14 @@ export class EffectRenderer {
             ...options,
         };
 
+        this.textureWidth = options.textureWidth;
+        this.textureHeight = options.textureHeight;
+        this.useInternalTexturesOnly = options.useInternalTexturesOnly ?? false;
+
         this._vertexBuffers = {
             [VertexBuffer.PositionKind]: new VertexBuffer(engine, options.positions!, VertexBuffer.PositionKind, false, false, 2),
         };
         this._indexBuffer = engine.createIndexBuffer(options.indices!);
-
-        // No need here for full screen render.
-        engine.depthCullingState.depthTest = false;
-        engine.stencilState.stencilTest = false;
     }
 
     /**
@@ -131,9 +171,10 @@ export class EffectRenderer {
     /**
      * renders one or more effects to a specified texture
      * @param effectWrappers list of effects to renderer
-     * @param outputTexture texture to draw to, if null it will render to the screen
+     * @param outputTexture texture to draw to, if null it will render to the screen. Note that this parameter is not used if useInternalTexturesOnly is true
+     * @returns returns the texture used for the latest rendering
      */
-    public render(effectWrappers: Array<EffectWrapper> | EffectWrapper, outputTexture: Nullable<Texture> = null) {
+    public render(effectWrappers: Array<EffectWrapper> | EffectWrapper, outputTexture: Nullable<Texture> = null): Nullable<Texture> {
         if (!Array.isArray(effectWrappers)) {
             effectWrappers = [effectWrappers];
         }
@@ -141,22 +182,28 @@ export class EffectRenderer {
         // Ensure all effects are ready
         for (var wrapper of effectWrappers) {
             if (!wrapper.effect.isReady()) {
-                return;
+                return null;
             }
         }
 
+        // No need here for full screen render.
+        this.engine.depthCullingState.depthTest = false;
+        this.engine.stencilState.stencilTest = false;
+
+        var renderTo = outputTexture;
+
         effectWrappers.forEach((effectWrapper, i) => {
-            var renderTo = outputTexture;
+            renderTo = outputTexture;
 
             // for any next effect make it's input the output of the previous effect
-            if (i !== 0) {
+            if (this.useInternalTexturesOnly || i !== 0) {
                 effectWrapper.effect.onBindObservable.addOnce(() => {
                     effectWrapper.effect.setTexture("textureSampler", this._getNextFrameBuffer(false));
                 });
             }
 
             // Set the output to the next screenbuffer
-            if ((effectWrappers as Array<EffectWrapper>).length > 1 && i != (effectWrappers as Array<EffectWrapper>).length - 1) {
+            if (this.useInternalTexturesOnly || (effectWrappers as Array<EffectWrapper>).length > 1 && i != (effectWrappers as Array<EffectWrapper>).length - 1) {
                 renderTo = this._getNextFrameBuffer();
             } else {
                 renderTo = outputTexture;
@@ -177,6 +224,10 @@ export class EffectRenderer {
                 this.engine.unBindFramebuffer(renderTo.getInternalTexture()!);
             }
         });
+
+        this._outputTexture = renderTo;
+
+        return renderTo;
     }
 
     /**