Browse Source

Merge pull request #8265 from Popov72/edgerenderer-instances

Edge Renderer: support regular and thin instances
mergify[bot] 5 years ago
parent
commit
da794fc73f

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

@@ -24,7 +24,6 @@
 - Added support for `material.disableColorWrite` ([Deltakosh](https://github.com/deltakosh))
 - The Mesh Asset Task also accepts File as sceneInput ([RaananW](https://github.com/RaananW))
 - Added support preserving vert colors for CSG objects ([PirateJC](https://github.com/PirateJC))
-- Added support in `ShadowGenerator` for fast fake soft transparent shadows ([Popov72](https://github.com/Popov72))
 - Added `boundingBoxRenderer.onBeforeBoxRenderingObservable` and `boundingBoxRenderer.onAfterBoxRenderingObservable` ([Deltakosh](https://github.com/deltakosh))
 - Added initial code for user facing DeviceSourceManager ([PolygonalSun](https://github.com/PolygonalSun))
 - Added a Simple and advanced timer, based on observables ([RaananW](https://github.com/RaananW))

+ 13 - 1
src/Meshes/instancedMesh.ts

@@ -340,7 +340,12 @@ export class InstancedMesh extends AbstractMesh {
 
     /** @hidden */
     public _postActivate(): void {
-        if (this._edgesRenderer && this._edgesRenderer.isEnabled && this._sourceMesh._renderingGroup) {
+        if (this._sourceMesh.edgesShareWithInstances && this._sourceMesh._edgesRenderer && this._sourceMesh._edgesRenderer.isEnabled && this._sourceMesh._renderingGroup) {
+            // we are using the edge renderer of the source mesh
+            this._sourceMesh._renderingGroup._edgesRenderers.pushNoDuplicate(this._sourceMesh._edgesRenderer);
+            this._sourceMesh._edgesRenderer.customInstances.push(this.getWorldMatrix());
+        } else if (this._edgesRenderer && this._edgesRenderer.isEnabled && this._sourceMesh._renderingGroup) {
+            // we are using the edge renderer defined for this instance
             this._sourceMesh._renderingGroup._edgesRenderers.push(this._edgesRenderer);
         }
     }
@@ -470,6 +475,11 @@ declare module "./mesh" {
          */
         registerInstancedBuffer(kind: string, stride: number): void;
 
+        /**
+         * true to use the edge renderer for all instances of this mesh
+         */
+        edgesShareWithInstances: boolean;
+
         /** @hidden */
         _userInstancedBuffersStorage: {
             data: {[key: string]: Float32Array},
@@ -490,6 +500,8 @@ declare module "./abstractMesh" {
     }
 }
 
+Mesh.prototype.edgesShareWithInstances = false;
+
 Mesh.prototype.registerInstancedBuffer = function(kind: string, stride: number): void {
     // Remove existing one
     this.removeVerticesData(kind);

+ 8 - 0
src/Meshes/mesh.ts

@@ -1108,6 +1108,14 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         }
     }
 
+    /** @hidden */
+    public _postActivate(): void {
+        if (this.edgesShareWithInstances && this.edgesRenderer && this.edgesRenderer.isEnabled && this._renderingGroup) {
+            this._renderingGroup._edgesRenderers.pushNoDuplicate(this.edgesRenderer);
+            this.edgesRenderer.customInstances.push(this.getWorldMatrix());
+        }
+    }
+
     /**
      * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
      * This means the mesh underlying bounding box and sphere are recomputed.

+ 79 - 13
src/Rendering/edgesRenderer.ts

@@ -1,9 +1,10 @@
 import { Nullable } from "../types";
 import { VertexBuffer } from "../Meshes/buffer";
 import { AbstractMesh } from "../Meshes/abstractMesh";
+import { Mesh } from "../Meshes/mesh";
 import { LinesMesh, InstancedLinesMesh } from "../Meshes/linesMesh";
-import { Vector3, TmpVectors } from "../Maths/math.vector";
-import { IDisposable } from "../scene";
+import { Vector3, TmpVectors, Matrix } from "../Maths/math.vector";
+import { IDisposable, Scene } from "../scene";
 import { Observer } from "../Misc/observable";
 import { Effect } from "../Materials/effect";
 import { Material } from "../Materials/material";
@@ -15,6 +16,14 @@ import { Node } from "../node";
 import "../Shaders/line.fragment";
 import "../Shaders/line.vertex";
 import { DataBuffer } from '../Meshes/dataBuffer';
+import { SmartArray } from '../Misc/smartArray';
+
+declare module "../scene" {
+    export interface Scene {
+        /** @hidden */
+        _edgeRenderLineShader: Nullable<ShaderMaterial>;
+    }
+}
 
 declare module "../Meshes/abstractMesh" {
     export interface AbstractMesh {
@@ -114,6 +123,11 @@ export interface IEdgesRenderer extends IDisposable {
      * @return true if ready, otherwise false.
      */
     isReady(): boolean;
+
+    /**
+     * List of instances to render in case the source mesh has instances
+     */
+    customInstances: SmartArray<Matrix>;
 }
 
 /**
@@ -141,6 +155,7 @@ export class EdgesRenderer implements IEdgesRenderer {
     protected _lineShader: ShaderMaterial;
     protected _ib: DataBuffer;
     protected _buffers: { [key: string]: Nullable<VertexBuffer> } = {};
+    protected _buffersForInstances: { [key: string]: Nullable<VertexBuffer> } = {};
     protected _checkVerticesInsteadOfIndices = false;
 
     private _meshRebuildObserver: Nullable<Observer<AbstractMesh>>;
@@ -150,6 +165,28 @@ export class EdgesRenderer implements IEdgesRenderer {
     public isEnabled = true;
 
     /**
+     * List of instances to render in case the source mesh has instances
+     */
+    public customInstances = new SmartArray<Matrix>(32);
+
+    private static GetShader(scene: Scene): ShaderMaterial {
+        if (!scene._edgeRenderLineShader) {
+            const shader = new ShaderMaterial("lineShader", scene, "line",
+                {
+                    attributes: ["position", "normal"],
+                    uniforms: ["world", "viewProjection", "color", "width", "aspectRatio"]
+                });
+
+            shader.disableDepthWrite = true;
+            shader.backFaceCulling = false;
+
+            scene._edgeRenderLineShader = shader;
+        }
+
+        return scene._edgeRenderLineShader;
+    }
+
+    /**
      * Creates an instance of the EdgesRenderer. It is primarily use to display edges of a mesh.
      * Beware when you use this class with complex objects as the adjacencies computation can be really long
      * @param  source Mesh used to create edges
@@ -182,14 +219,7 @@ export class EdgesRenderer implements IEdgesRenderer {
             return;
         }
 
-        this._lineShader = new ShaderMaterial("lineShader", this._source.getScene(), "line",
-            {
-                attributes: ["position", "normal"],
-                uniforms: ["worldViewProjection", "color", "width", "aspectRatio"]
-            });
-
-        this._lineShader.disableDepthWrite = true;
-        this._lineShader.backFaceCulling = false;
+        this._lineShader = EdgesRenderer.GetShader(this._source.getScene());
     }
 
     /** @hidden */
@@ -437,6 +467,9 @@ export class EdgesRenderer implements IEdgesRenderer {
         this._buffers[VertexBuffer.PositionKind] = new VertexBuffer(engine, this._linesPositions, VertexBuffer.PositionKind, false);
         this._buffers[VertexBuffer.NormalKind] = new VertexBuffer(engine, this._linesNormals, VertexBuffer.NormalKind, false, false, 4);
 
+        this._buffersForInstances[VertexBuffer.PositionKind] = this._buffers[VertexBuffer.PositionKind];
+        this._buffersForInstances[VertexBuffer.NormalKind] = this._buffers[VertexBuffer.NormalKind];
+
         this._ib = engine.createIndexBuffer(this._linesIndices);
 
         this._indicesCount = this._linesIndices.length;
@@ -447,7 +480,7 @@ export class EdgesRenderer implements IEdgesRenderer {
      * @return true if ready, otherwise false.
      */
     public isReady(): boolean {
-        return this._lineShader.isReady();
+        return this._lineShader.isReady(this._source, (this._source.hasInstances && this.customInstances.length > 0) || this._source.hasThinInstances);
     }
 
     /**
@@ -469,8 +502,39 @@ export class EdgesRenderer implements IEdgesRenderer {
             engine.setAlphaMode(Constants.ALPHA_DISABLE);
         }
 
+        const hasInstances = this._source.hasInstances && this.customInstances.length > 0;
+        const useBuffersWithInstances = hasInstances || this._source.hasThinInstances;
+
+        let instanceCount = 0;
+
+        if (useBuffersWithInstances) {
+            this._buffersForInstances["world0"] = (this._source as Mesh).getVertexBuffer("world0");
+            this._buffersForInstances["world1"] = (this._source as Mesh).getVertexBuffer("world1");
+            this._buffersForInstances["world2"] = (this._source as Mesh).getVertexBuffer("world2");
+            this._buffersForInstances["world3"] = (this._source as Mesh).getVertexBuffer("world3");
+
+            if (hasInstances) {
+                let instanceStorage = (this._source as Mesh)._instanceDataStorage;
+
+                instanceCount = this.customInstances.length;
+
+                if (!instanceStorage.isFrozen) {
+                    let offset = 0;
+
+                    for (let i = 0; i < instanceCount; ++i) {
+                        this.customInstances.data[i].copyToArray(instanceStorage.instancesData, offset);
+                        offset += 16;
+                    }
+
+                    instanceStorage.instancesBuffer!.updateDirectly(instanceStorage.instancesData, 0, instanceCount);
+                }
+            } else {
+                instanceCount = (this._source as Mesh).thinInstanceCount;
+            }
+        }
+
         // VBOs
-        engine.bindBuffers(this._buffers, this._ib, <Effect>this._lineShader.getEffect());
+        engine.bindBuffers(useBuffersWithInstances ? this._buffersForInstances : this._buffers, this._ib, <Effect>this._lineShader.getEffect());
 
         scene.resetCachedMaterial();
         this._lineShader.setColor4("color", this._source.edgesColor);
@@ -485,8 +549,10 @@ export class EdgesRenderer implements IEdgesRenderer {
         this._lineShader.bind(this._source.getWorldMatrix());
 
         // Draw order
-        engine.drawElementsType(Material.TriangleFillMode, 0, this._indicesCount);
+        engine.drawElementsType(Material.TriangleFillMode, 0, this._indicesCount, instanceCount);
         this._lineShader.unbind();
+
+        this.customInstances.reset();
     }
 }
 

+ 8 - 2
src/Shaders/line.vertex.fx

@@ -1,14 +1,20 @@
-// Attributes
+#include<instancesDeclaration>
+
+// Attributes
 attribute vec3 position;
 attribute vec4 normal;
 
 // Uniforms
-uniform mat4 worldViewProjection;
+uniform mat4 viewProjection;
 
 uniform float width;
 uniform float aspectRatio;
 
 void main(void) {
+    #include<instancesVertex>
+
+    mat4 worldViewProjection = viewProjection * finalWorld;
+
 	vec4 viewPosition = worldViewProjection * vec4(position, 1.0);
 	vec4 viewPositionNext = worldViewProjection * vec4(normal.xyz, 1.0);