@three.ez/batched-mesh-extensions
Version:
Utility extension methods for BatchedMesh
83 lines • 3.18 kB
JavaScript
import { SquareDataTexture } from '../SquareDataTexture.js';
import { patchBatchedMeshMaterial } from '../../patch/PatchBatchedMeshMaterial.js';
export function getUniformAt(id, name, target) {
if (!this.uniformsTexture) {
throw new Error('Before get/set uniform, it\'s necessary to use "initUniformsPerInstance".');
}
return this.uniformsTexture.getUniformAt(id, name, target);
}
export function setUniformAt(id, name, value) {
if (!this.uniformsTexture) {
throw new Error('Before get/set uniform, it\'s necessary to use "initUniformsPerInstance".');
}
this.uniformsTexture.setUniformAt(id, name, value);
this.uniformsTexture.enqueueUpdate(id);
}
export function initUniformsPerInstance(schema) {
if (this.uniformsTexture)
throw new Error('"initUniformsPerInstance" must be called only once.');
const { channels, pixelsPerInstance, uniformMap, fetchInFragmentShader } = getUniformSchemaResult(schema);
this.uniformsTexture = new SquareDataTexture(Float32Array, channels, pixelsPerInstance, this.maxInstanceCount, uniformMap, fetchInFragmentShader);
patchBatchedMeshMaterial(this);
}
export function getUniformSchemaResult(schema) {
let totalSize = 0;
const uniformMap = new Map();
const uniforms = [];
const vertexSchema = schema.vertex ?? {};
const fragmentSchema = schema.fragment ?? {};
let fetchInFragmentShader = true;
for (const name in vertexSchema) {
const type = vertexSchema[name];
const size = getUniformSize(type);
totalSize += size;
uniforms.push({ name, type, size });
fetchInFragmentShader = false;
}
for (const name in fragmentSchema) {
if (!vertexSchema[name]) {
const type = fragmentSchema[name];
const size = getUniformSize(type);
totalSize += size;
uniforms.push({ name, type, size });
}
}
uniforms.sort((a, b) => b.size - a.size);
const tempOffset = [];
for (const { name, size, type } of uniforms) {
const offset = getUniformOffset(size, tempOffset);
uniformMap.set(name, { offset, size, type });
}
const pixelsPerInstance = Math.ceil(totalSize / 4);
const channels = Math.min(totalSize, 4);
return { channels, pixelsPerInstance, uniformMap, fetchInFragmentShader };
}
export function getUniformOffset(size, tempOffset) {
if (size < 4) {
for (let i = 0; i < tempOffset.length; i++) {
if (tempOffset[i] + size <= 4) {
const offset = i * 4 + tempOffset[i];
tempOffset[i] += size;
return offset;
}
}
}
const offset = tempOffset.length * 4;
for (; size > 0; size -= 4) {
tempOffset.push(size);
}
return offset;
}
export function getUniformSize(type) {
switch (type) {
case 'float': return 1;
case 'vec2': return 2;
case 'vec3': return 3;
case 'vec4': return 4;
case 'mat3': return 9;
case 'mat4': return 16;
default:
throw new Error(`Invalid uniform type: ${type}`);
}
}
//# sourceMappingURL=Uniforms.js.map