|
@@ -1,4 +1,4 @@
|
|
-import { Vector3, Quaternion } from 'babylonjs/Maths/math.vector';
|
|
|
|
|
|
+import { Vector3, Quaternion, Matrix } from 'babylonjs/Maths/math.vector';
|
|
import { InstancedMesh } from 'babylonjs/Meshes/instancedMesh';
|
|
import { InstancedMesh } from 'babylonjs/Meshes/instancedMesh';
|
|
import { Mesh } from 'babylonjs/Meshes/mesh';
|
|
import { Mesh } from 'babylonjs/Meshes/mesh';
|
|
import { TransformNode } from "babylonjs/Meshes/transformNode";
|
|
import { TransformNode } from "babylonjs/Meshes/transformNode";
|
|
@@ -10,12 +10,18 @@ import { INode } from "../glTFLoaderInterfaces";
|
|
import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
|
|
import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
|
|
|
|
|
|
const NAME = "EXT_mesh_gpu_instancing";
|
|
const NAME = "EXT_mesh_gpu_instancing";
|
|
|
|
+const useThinInstances = true;
|
|
|
|
|
|
interface IEXTMeshGpuInstancing {
|
|
interface IEXTMeshGpuInstancing {
|
|
mesh?: number;
|
|
mesh?: number;
|
|
attributes: { [name: string]: number };
|
|
attributes: { [name: string]: number };
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+const T = new Vector3(0, 0, 0);
|
|
|
|
+const R = new Quaternion(0, 0, 0, 1);
|
|
|
|
+const S = new Vector3(1, 1, 1);
|
|
|
|
+const M = new Matrix();
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1691)
|
|
* [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1691)
|
|
* [Playground Sample](https://playground.babylonjs.com/#QFIGLW#9)
|
|
* [Playground Sample](https://playground.babylonjs.com/#QFIGLW#9)
|
|
@@ -55,8 +61,10 @@ export class EXT_mesh_gpu_instancing implements IGLTFLoaderExtension {
|
|
}
|
|
}
|
|
|
|
|
|
// Hide the source meshes.
|
|
// Hide the source meshes.
|
|
- for (const babylonMesh of node._primitiveBabylonMeshes) {
|
|
|
|
- babylonMesh.isVisible = false;
|
|
|
|
|
|
+ if (!useThinInstances) {
|
|
|
|
+ for (const babylonMesh of node._primitiveBabylonMeshes) {
|
|
|
|
+ babylonMesh.isVisible = false;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
const promises = new Array<Promise<Nullable<Float32Array>>>();
|
|
const promises = new Array<Promise<Nullable<Float32Array>>>();
|
|
@@ -86,25 +94,49 @@ export class EXT_mesh_gpu_instancing implements IGLTFLoaderExtension {
|
|
return promise;
|
|
return promise;
|
|
}
|
|
}
|
|
|
|
|
|
- const digitLength = instanceCount.toString().length;
|
|
|
|
- for (let i = 0; i < instanceCount; ++i) {
|
|
|
|
- for (const babylonMesh of node._primitiveBabylonMeshes!) {
|
|
|
|
- const instanceName = `${babylonMesh.name || babylonMesh.id}_${StringTools.PadNumber(i, digitLength)}`;
|
|
|
|
- const babylonInstancedMesh = (babylonMesh as (InstancedMesh | Mesh)).createInstance(instanceName);
|
|
|
|
- babylonInstancedMesh.setParent(babylonMesh);
|
|
|
|
|
|
+ if (!useThinInstances) {
|
|
|
|
+ const digitLength = instanceCount.toString().length;
|
|
|
|
+ for (let i = 0; i < instanceCount; ++i) {
|
|
|
|
+ for (const babylonMesh of node._primitiveBabylonMeshes!) {
|
|
|
|
+ const instanceName = `${babylonMesh.name || babylonMesh.id}_${StringTools.PadNumber(i, digitLength)}`;
|
|
|
|
+ const babylonInstancedMesh = (babylonMesh as (InstancedMesh | Mesh)).createInstance(instanceName);
|
|
|
|
+ babylonInstancedMesh.setParent(babylonMesh);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return promise.then((babylonTransformNode) => {
|
|
return promise.then((babylonTransformNode) => {
|
|
return Promise.all(promises).then(([translationBuffer, rotationBuffer, scaleBuffer]) => {
|
|
return Promise.all(promises).then(([translationBuffer, rotationBuffer, scaleBuffer]) => {
|
|
- for (const babylonMesh of node._primitiveBabylonMeshes!) {
|
|
|
|
- const babylonInstancedMeshes = babylonMesh.getChildMeshes(true, (node) => (node as AbstractMesh).isAnInstance);
|
|
|
|
|
|
+ if (!useThinInstances) {
|
|
|
|
+ for (const babylonMesh of node._primitiveBabylonMeshes!) {
|
|
|
|
+ const babylonInstancedMeshes = babylonMesh.getChildMeshes(true, (node) => (node as AbstractMesh).isAnInstance);
|
|
|
|
+ for (let i = 0; i < instanceCount; ++i) {
|
|
|
|
+ const babylonInstancedMesh = babylonInstancedMeshes[i];
|
|
|
|
+ translationBuffer && Vector3.FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
|
|
|
|
+ rotationBuffer && Quaternion.FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion!);
|
|
|
|
+ scaleBuffer && Vector3.FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
|
|
|
|
+ babylonInstancedMesh.refreshBoundingInfo();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ const matrices = new Float32Array(instanceCount * 16);
|
|
|
|
+
|
|
|
|
+ T.copyFromFloats(0, 0, 0);
|
|
|
|
+ R.copyFromFloats(0, 0, 0, 1);
|
|
|
|
+ S.copyFromFloats(1, 1, 1);
|
|
|
|
+
|
|
for (let i = 0; i < instanceCount; ++i) {
|
|
for (let i = 0; i < instanceCount; ++i) {
|
|
- const babylonInstancedMesh = babylonInstancedMeshes[i];
|
|
|
|
- translationBuffer && Vector3.FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
|
|
|
|
- rotationBuffer && Quaternion.FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion!);
|
|
|
|
- scaleBuffer && Vector3.FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
|
|
|
|
- babylonInstancedMesh.refreshBoundingInfo();
|
|
|
|
|
|
+ translationBuffer && Vector3.FromArrayToRef(translationBuffer, i * 3, T);
|
|
|
|
+ rotationBuffer && Quaternion.FromArrayToRef(rotationBuffer, i * 4, R);
|
|
|
|
+ scaleBuffer && Vector3.FromArrayToRef(scaleBuffer, i * 3, S);
|
|
|
|
+
|
|
|
|
+ Matrix.ComposeToRef(S, R, T, M);
|
|
|
|
+
|
|
|
|
+ M.copyToArray(matrices, i * 16);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (const babylonMesh of node._primitiveBabylonMeshes!) {
|
|
|
|
+ (babylonMesh as Mesh).setThinInstanceBuffer("matrix", matrices);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|