playcanvas
Version:
PlayCanvas WebGL game engine
154 lines (151 loc) • 5.45 kB
JavaScript
import { Mat4 } from '../../core/math/mat4.js';
import { Vec3 } from '../../core/math/vec3.js';
import { PIXELFORMAT_R32U, TYPE_UINT32, SEMANTIC_ATTR13, BUFFER_STATIC } from '../../platform/graphics/constants.js';
import { DITHER_NONE } from '../constants.js';
import { MeshInstance } from '../mesh-instance.js';
import { Mesh } from '../mesh.js';
import { GSplatSorter } from './gsplat-sorter.js';
import { VertexFormat } from '../../platform/graphics/vertex-format.js';
import { VertexBuffer } from '../../platform/graphics/vertex-buffer.js';
var mat = new Mat4();
var cameraPosition = new Vec3();
var cameraDirection = new Vec3();
var viewport = [
0,
0
];
class GSplatInstance {
destroy() {
var _this_material, _this_meshInstance, _this_sorter;
(_this_material = this.material) == null ? void 0 : _this_material.destroy();
(_this_meshInstance = this.meshInstance) == null ? void 0 : _this_meshInstance.destroy();
(_this_sorter = this.sorter) == null ? void 0 : _this_sorter.destroy();
}
clone() {
return new GSplatInstance(this.splat, this.options);
}
createMaterial(options) {
this.material = this.splat.createMaterial(options);
this.material.setParameter('splatOrder', this.orderTexture);
if (this.meshInstance) {
this.meshInstance.material = this.material;
}
}
updateViewport(cameraNode) {
var _camera_camera;
var camera = cameraNode == null ? void 0 : cameraNode.camera;
var renderTarget = camera == null ? void 0 : camera.renderTarget;
var { width, height } = renderTarget != null ? renderTarget : this.splat.device;
viewport[0] = width;
viewport[1] = height;
var xr = camera == null ? void 0 : (_camera_camera = camera.camera) == null ? void 0 : _camera_camera.xr;
if ((xr == null ? void 0 : xr.active) && xr.views.list.length === 2) {
viewport[0] *= 0.5;
}
this.material.setParameter('viewport', viewport);
}
sort(cameraNode) {
if (this.sorter) {
var cameraMat = cameraNode.getWorldTransform();
cameraMat.getTranslation(cameraPosition);
cameraMat.getZ(cameraDirection);
var modelMat = this.meshInstance.node.getWorldTransform();
var invModelMat = mat.invert(modelMat);
invModelMat.transformPoint(cameraPosition, cameraPosition);
invModelMat.transformVector(cameraDirection, cameraDirection);
if (!cameraPosition.equalsApprox(this.lastCameraPosition) || !cameraDirection.equalsApprox(this.lastCameraDirection)) {
this.lastCameraPosition.copy(cameraPosition);
this.lastCameraDirection.copy(cameraDirection);
this.sorter.setCamera(cameraPosition, cameraDirection);
}
}
this.updateViewport(cameraNode);
}
update() {
if (this.cameras.length > 0) {
var camera = this.cameras[0];
this.sort(camera._node);
this.cameras.length = 0;
}
}
constructor(splat, options){
var _splat_chunks;
this.options = {};
this.sorter = null;
this.lastCameraPosition = new Vec3();
this.lastCameraDirection = new Vec3();
this.cameras = [];
this.splat = splat;
options = Object.assign(this.options, options);
var device = splat.device;
this.orderTexture = this.splat.createTexture('splatOrder', PIXELFORMAT_R32U, this.splat.evalTextureSize(this.splat.numSplats));
this.createMaterial(options);
var splatInstanceSize = 128;
var numSplats = Math.ceil(splat.numSplats / splatInstanceSize) * splatInstanceSize;
var numSplatInstances = numSplats / splatInstanceSize;
var indexData = new Uint32Array(numSplatInstances);
for(var i = 0; i < numSplatInstances; ++i){
indexData[i] = i * splatInstanceSize;
}
var vertexFormat = new VertexFormat(device, [
{
semantic: SEMANTIC_ATTR13,
components: 1,
type: TYPE_UINT32,
asInt: true
}
]);
var indicesVB = new VertexBuffer(device, vertexFormat, numSplatInstances, {
usage: BUFFER_STATIC,
data: indexData.buffer
});
var meshPositions = new Float32Array(12 * splatInstanceSize);
var meshIndices = new Uint32Array(6 * splatInstanceSize);
for(var i1 = 0; i1 < splatInstanceSize; ++i1){
meshPositions.set([
-1,
-1,
i1,
1,
-1,
i1,
1,
1,
i1,
-1,
1,
i1
], i1 * 12);
var b = i1 * 4;
meshIndices.set([
0 + b,
1 + b,
2 + b,
0 + b,
2 + b,
3 + b
], i1 * 6);
}
var mesh = new Mesh(device);
mesh.setPositions(meshPositions, 3);
mesh.setIndices(meshIndices);
mesh.update();
this.mesh = mesh;
this.mesh.aabb.copy(splat.aabb);
this.meshInstance = new MeshInstance(this.mesh, this.material);
this.meshInstance.setInstancing(indicesVB, true);
this.meshInstance.gsplatInstance = this;
this.meshInstance.instancingCount = 0;
var centers = splat.centers.slice();
var chunks = (_splat_chunks = splat.chunks) == null ? void 0 : _splat_chunks.slice();
if (!options.dither || options.dither === DITHER_NONE) {
this.sorter = new GSplatSorter();
this.sorter.init(this.orderTexture, centers, chunks);
this.sorter.on('updated', (count)=>{
this.meshInstance.instancingCount = Math.ceil(count / splatInstanceSize);
this.material.setParameter('numSplats', count);
});
}
}
}
export { GSplatInstance };