فهرست منبع

Move all instance data from Geometry to Mesh such that it can be shared between many Meshes even if they have instances.

breakin 4 سال پیش
والد
کامیت
ad0e105cdf
5فایلهای تغییر یافته به همراه87 افزوده شده و 38 حذف شده
  1. 3 0
      dist/preview release/what's new.md
  2. 11 6
      src/Engines/thinEngine.ts
  3. 27 9
      src/Meshes/geometry.ts
  4. 28 6
      src/Meshes/instancedMesh.ts
  5. 18 17
      src/Meshes/mesh.ts

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

@@ -14,6 +14,9 @@
 - Moving button to shared uI folder.([msDestiny14](https://github.com/msDestiny14))
 - Moving additional components to shared UI folder.([msDestiny14](https://github.com/msDestiny14))
 
+### Engine
+- Moved all sourceMesh data from Geometry to Mesh such that one Geometry can be used by many source meshes without making the geometry unique. ([AndersLindqvist](https://github.com/breakin)
+
 ### Loaders
 
 - Added support for EXT_meshopt_compression for glTF loader. ([zeux](https://github.com/zeux))

+ 11 - 6
src/Engines/thinEngine.ts

@@ -1766,7 +1766,7 @@ export class ThinEngine {
         }
     }
 
-    private _bindVertexBuffersAttributes(vertexBuffers: { [key: string]: Nullable<VertexBuffer> }, effect: Effect): void {
+    private _bindVertexBuffersAttributes(vertexBuffers: { [key: string]: Nullable<VertexBuffer> }, effect: Effect, extraVertexBuffers?: { [kind: string]: Nullable<VertexBuffer>}): void {
         var attributes = effect.getAttributesNames();
 
         if (!this._vaoRecordInProgress) {
@@ -1779,7 +1779,12 @@ export class ThinEngine {
             var order = effect.getAttributeLocation(index);
 
             if (order >= 0) {
-                var vertexBuffer = vertexBuffers[attributes[index]];
+                var ai = attributes[index];
+                var vertexBuffer = vertexBuffers[ai];
+
+                if (!vertexBuffer && extraVertexBuffers) {
+                    vertexBuffer = extraVertexBuffers[ai];
+                }
 
                 if (!vertexBuffer) {
                     continue;
@@ -1814,7 +1819,7 @@ export class ThinEngine {
      * @param effect defines the effect to store
      * @returns the new vertex array object
      */
-    public recordVertexArrayObject(vertexBuffers: { [key: string]: VertexBuffer; }, indexBuffer: Nullable<DataBuffer>, effect: Effect): WebGLVertexArrayObject {
+    public recordVertexArrayObject(vertexBuffers: { [key: string]: VertexBuffer; }, indexBuffer: Nullable<DataBuffer>, effect: Effect, extraVertexBuffers?: { [kind: string]: Nullable<VertexBuffer>}): WebGLVertexArrayObject {
         var vao = this._gl.createVertexArray();
 
         this._vaoRecordInProgress = true;
@@ -1822,7 +1827,7 @@ export class ThinEngine {
         this._gl.bindVertexArray(vao);
 
         this._mustWipeVertexAttributes = true;
-        this._bindVertexBuffersAttributes(vertexBuffers, effect);
+        this._bindVertexBuffersAttributes(vertexBuffers, effect, extraVertexBuffers);
 
         this.bindIndexBuffer(indexBuffer);
 
@@ -1905,12 +1910,12 @@ export class ThinEngine {
      * @param indexBuffer defines the index buffer to bind
      * @param effect defines the effect associated with the vertex buffers
      */
-    public bindBuffers(vertexBuffers: { [key: string]: Nullable<VertexBuffer> }, indexBuffer: Nullable<DataBuffer>, effect: Effect): void {
+    public bindBuffers(vertexBuffers: { [key: string]: Nullable<VertexBuffer> }, indexBuffer: Nullable<DataBuffer>, effect: Effect, extraVertexBuffers?: {[kind: string]: Nullable<VertexBuffer>}): void {
         if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
             this._cachedVertexBuffers = vertexBuffers;
             this._cachedEffectForVertexBuffers = effect;
 
-            this._bindVertexBuffersAttributes(vertexBuffers, effect);
+            this._bindVertexBuffersAttributes(vertexBuffers, effect, extraVertexBuffers);
         }
 
         this._bindIndexBufferWithCache(indexBuffer);

+ 27 - 9
src/Meshes/geometry.ts

@@ -216,6 +216,13 @@ export class Geometry implements IGetSetVerticesData {
             let vertexBuffer = <VertexBuffer>this._vertexBuffers[key];
             vertexBuffer._rebuild();
         }
+
+        // Invalidate MESH VAO
+        const meshes = this.meshes
+        const numMeshes = meshes.length
+        for (let i = 0; i < numMeshes; i++) {
+            meshes[i].invalidateVAO(true);
+        }
     }
 
     /**
@@ -267,6 +274,8 @@ export class Geometry implements IGetSetVerticesData {
         }
 
         this._vertexBuffers[kind] = buffer;
+        var meshes = this._meshes;
+        var numOfMeshes = meshes.length;
 
         if (kind === VertexBuffer.PositionKind) {
             var data = <FloatArray>buffer.getData();
@@ -281,9 +290,6 @@ export class Geometry implements IGetSetVerticesData {
             this._updateExtend(data);
             this._resetPointsArrayCache();
 
-            var meshes = this._meshes;
-            var numOfMeshes = meshes.length;
-
             for (var index = 0; index < numOfMeshes; index++) {
                 var mesh = meshes[index];
                 mesh._boundingInfo = new BoundingInfo(this._extend.minimum, this._extend.maximum);
@@ -294,6 +300,11 @@ export class Geometry implements IGetSetVerticesData {
 
         this.notifyUpdate(kind);
 
+        var meshes = this._meshes;
+        for (var index = 0; index < numOfMeshes; index++) {
+            meshes[index].invalidateVAO(false);
+        }
+
         if (this._vertexArrayObjects) {
             this._disposeVertexArrayObjects();
             this._vertexArrayObjects = {}; // Will trigger a rebuild of the VAO if supported
@@ -367,7 +378,7 @@ export class Geometry implements IGetSetVerticesData {
     }
 
     /** @hidden */
-    public _bind(effect: Nullable<Effect>, indexToBind?: Nullable<DataBuffer>): void {
+    public _bind(effect: Nullable<Effect>, indexToBind?: Nullable<DataBuffer>, extraVertexBuffers?: { [kind:string]: Nullable<VertexBuffer>}, overrideVAO?: {[key: string]: WebGLVertexArrayObject}): void {
         if (!effect) {
             return;
         }
@@ -381,17 +392,21 @@ export class Geometry implements IGetSetVerticesData {
             return;
         }
 
-        if (indexToBind != this._indexBuffer || !this._vertexArrayObjects) {
-            this._engine.bindBuffers(vbs, indexToBind, effect);
+        // TODO: It could be the case that all vertex bufferas are in extraVertexBuffers but lets ignore that for now
+
+        if (indexToBind != this._indexBuffer || (!this._vertexArrayObjects && !overrideVAO)) {
+            this._engine.bindBuffers(vbs, indexToBind, effect, extraVertexBuffers);
             return;
         }
 
+        var vaos = overrideVAO ? overrideVAO : this._vertexArrayObjects;
+
         // Using VAO
-        if (!this._vertexArrayObjects[effect.key]) {
-            this._vertexArrayObjects[effect.key] = this._engine.recordVertexArrayObject(vbs, indexToBind, effect);
+        if (!vaos[effect.key]) {
+            vaos[effect.key] = this._engine.recordVertexArrayObject(vbs, indexToBind, effect, extraVertexBuffers);
         }
 
-        this._engine.bindVertexArrayObject(this._vertexArrayObjects[effect.key], indexToBind);
+        this._engine.bindVertexArrayObject(vaos[effect.key], indexToBind);
     }
 
     /**
@@ -697,6 +712,7 @@ export class Geometry implements IGetSetVerticesData {
 
         // must be done before setting vertexBuffers because of mesh._createGlobalSubMesh()
         mesh._geometry = this;
+        mesh.invalidateVAO(false);
 
         this._scene.pushGeometry(this);
 
@@ -915,6 +931,8 @@ export class Geometry implements IGetSetVerticesData {
             }
             this._vertexArrayObjects = {};
         }
+
+        // TODO: Do the meshes too?
     }
 
     /**

+ 28 - 6
src/Meshes/instancedMesh.ts

@@ -490,6 +490,8 @@ declare module "./mesh" {
          */
         registerInstancedBuffer(kind: string, stride: number): void;
 
+        invalidateVAO(lostContext: boolean): void;
+
         /**
          * true to use the edge renderer for all instances of this mesh
          */
@@ -500,7 +502,8 @@ declare module "./mesh" {
             data: {[key: string]: Float32Array},
             sizes: {[key: string]: number},
             vertexBuffers: {[key: string]: Nullable<VertexBuffer>},
-            strides: {[key: string]: number}
+            strides: {[key: string]: number},
+            vertexArrayObjects: {[key: string]: WebGLVertexArrayObject}
         };
     }
 }
@@ -518,8 +521,10 @@ declare module "./abstractMesh" {
 Mesh.prototype.edgesShareWithInstances = false;
 
 Mesh.prototype.registerInstancedBuffer = function(kind: string, stride: number): void {
-    // Remove existing one
-    this.removeVerticesData(kind);
+    if (this.geometry?._vertexBuffers[kind] !== undefined) {
+        console.error('Mesh.registerInstancedBuffer; ignored', kind, ' since geometry already specifies it!');
+        return;
+    }
 
     // Creates the instancedBuffer field if not present
     if (!this.instancedBuffers) {
@@ -533,7 +538,8 @@ Mesh.prototype.registerInstancedBuffer = function(kind: string, stride: number):
             data: {},
             vertexBuffers: {},
             strides: {},
-            sizes: {}
+            sizes: {},
+            vertexArrayObjects: {}
         };
     }
 
@@ -544,11 +550,12 @@ Mesh.prototype.registerInstancedBuffer = function(kind: string, stride: number):
     this._userInstancedBuffersStorage.sizes[kind] = stride * 32; // Initial size
     this._userInstancedBuffersStorage.data[kind] = new Float32Array(this._userInstancedBuffersStorage.sizes[kind]);
     this._userInstancedBuffersStorage.vertexBuffers[kind] = new VertexBuffer(this.getEngine(), this._userInstancedBuffersStorage.data[kind], kind, true, false, stride, true);
-    this.setVerticesBuffer(this._userInstancedBuffersStorage.vertexBuffers[kind]!);
 
     for (var instance of this.instances) {
         instance.instancedBuffers[kind] = null;
     }
+
+    this.invalidateVAO(false);
 };
 
 Mesh.prototype._processInstancedBuffers = function(visibleInstances: InstancedMesh[], renderSelf: boolean) {
@@ -607,13 +614,28 @@ Mesh.prototype._processInstancedBuffers = function(visibleInstances: InstancedMe
         // Update vertex buffer
         if (!this._userInstancedBuffersStorage.vertexBuffers[kind]) {
             this._userInstancedBuffersStorage.vertexBuffers[kind] = new VertexBuffer(this.getEngine(), this._userInstancedBuffersStorage.data[kind], kind, true, false, stride, true);
-            this.setVerticesBuffer(this._userInstancedBuffersStorage.vertexBuffers[kind]!);
+            this.invalidateVAO(false);
         } else {
             this._userInstancedBuffersStorage.vertexBuffers[kind]!.updateDirectly(data, 0);
         }
     }
 };
 
+Mesh.prototype.invalidateVAO = function(lostContext: boolean) {
+    if (!this._userInstancedBuffersStorage) {
+        return;
+    }
+
+    if (!lostContext) {
+        for (var kind in this._userInstancedBuffersStorage.vertexArrayObjects) {
+            this.getEngine().releaseVertexArrayObject(this._userInstancedBuffersStorage.vertexArrayObjects[kind]);
+        }
+    }
+
+    this._userInstancedBuffersStorage.vertexArrayObjects = {}
+    console.log('Invalidate mesh VAO')
+}
+
 Mesh.prototype._disposeInstanceSpecificData = function() {
     if (this._instanceDataStorage.instancesBuffer) {
         this._instanceDataStorage.instancesBuffer.dispose();

+ 18 - 17
src/Meshes/mesh.ts

@@ -1521,7 +1521,11 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         }
 
         // VBOs
-        this._geometry._bind(effect, indexToBind);
+        if (!this._userInstancedBuffersStorage) {
+            this._geometry._bind(effect, indexToBind)
+        } else {
+            this._geometry._bind(effect, indexToBind, this._userInstancedBuffersStorage.vertexBuffers, this._userInstancedBuffersStorage.vertexArrayObjects);
+        }
         return this;
     }
 
@@ -1678,11 +1682,20 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
 
             instancesBuffer = new Buffer(engine, instanceStorage.instancesData, true, 16, false, true);
             instanceStorage.instancesBuffer = instancesBuffer;
+            if (!this._userInstancedBuffersStorage) {
+                this._userInstancedBuffersStorage = {
+                    data: {},
+                    vertexBuffers: {},
+                    strides: {},
+                    sizes: {},
+                    vertexArrayObjects: {}
+                };
+            }
 
-            this.setVerticesBuffer(instancesBuffer.createVertexBuffer("world0", 0, 4));
-            this.setVerticesBuffer(instancesBuffer.createVertexBuffer("world1", 4, 4));
-            this.setVerticesBuffer(instancesBuffer.createVertexBuffer("world2", 8, 4));
-            this.setVerticesBuffer(instancesBuffer.createVertexBuffer("world3", 12, 4));
+            this._userInstancedBuffersStorage.vertexBuffers["world0"] = instancesBuffer.createVertexBuffer("world0", 0, 4)
+            this._userInstancedBuffersStorage.vertexBuffers["world1"] = instancesBuffer.createVertexBuffer("world0", 4, 4)
+            this._userInstancedBuffersStorage.vertexBuffers["world2"] = instancesBuffer.createVertexBuffer("world0", 8, 4)
+            this._userInstancedBuffersStorage.vertexBuffers["world3"] = instancesBuffer.createVertexBuffer("world0", 12, 4)
         } else {
             if (!this._instanceDataStorage.isFrozen) {
                 instancesBuffer!.updateDirectly(instanceStorage.instancesData, 0, instancesCount);
@@ -2949,18 +2962,6 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
      * @returns a new InstancedMesh
      */
     public createInstance(name: string): InstancedMesh {
-        let geometry = this.geometry;
-
-        if (geometry && geometry.meshes.length > 1) {
-            let others = geometry.meshes.slice(0);
-            for (var other of others) {
-                if (other === this) {
-                    continue;
-                }
-                other.makeGeometryUnique();
-            }
-        }
-
         return Mesh._instancedMeshFactory(name, this);
     }