UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

148 lines (107 loc) 3.55 kB
import { AbstractRenderAdapter } from "./AbstractRenderAdapter.js"; import { HashMap } from "../../../../../../core/collection/map/HashMap.js"; import { InstancedMeshGroup } from "../../../../geometry/instancing/InstancedMeshGroup.js"; import { ShadedGeometryFlags } from "../../ShadedGeometryFlags.js"; import { StreamDrawUsage } from "three"; import { SGCacheKey } from "./SGCacheKey.js"; const INSTANCED_EQUALITY_FLAGS = ShadedGeometryFlags.CastShadow | ShadedGeometryFlags.ReceiveShadow ; /** * @readonly * @type {SGCacheKey} */ const scratch_key = new SGCacheKey(); export class InstancedRendererAdapter extends AbstractRenderAdapter { /** * * @type {HashMap<SGCacheKey, InstancedMeshGroup>} * @private */ __instanced_meshes = new HashMap(); /** * * @type {Set<InstancedMeshGroup>} * @private */ __active_meshes = new Set(); score(geometry, material, instance_count) { if (instance_count > 16) { return 1; } else if (instance_count < 4) { return -1; } else { return 0; } } /** * * @param {ShadedGeometry} sg * @returns {InstancedMeshGroup} * @private */ __get_instanced_mesh(sg) { scratch_key.fromSG(sg); // mask out some flags scratch_key.flags &= INSTANCED_EQUALITY_FLAGS let im = this.__instanced_meshes.get(scratch_key); if (im !== undefined) { return im; } else { im = new InstancedMeshGroup(); im.instance_usage = StreamDrawUsage; im.shrinkFactor = 0; // prevent shrinking as we're essentially rebuilding this geometry frame im.draw_mode = sg.mode; im.setMaterial(sg.material); im.setGeometry(sg.geometry); im.mesh.castShadow = sg.getFlag(ShadedGeometryFlags.CastShadow); im.mesh.receiveShadow = sg.getFlag(ShadedGeometryFlags.ReceiveShadow); this.__instanced_meshes.set(scratch_key.clone(), im); return im; } } add(sg) { const mesh = this.__get_instanced_mesh(sg); const index = mesh.count; const new_size = index + 1; if (new_size > mesh.capacity) { mesh.ensureCapacity(new_size); } mesh.setTransformAt(index, sg.transform); mesh.count = new_size; this.__active_meshes.add(mesh); } /** * * @param {THREE.WebGLRenderer} renderer * @param {CameraView} view */ build_start(renderer, view) { this.clear(); } build_end() { const objects = this.__objects; for (const activeMesh of this.__active_meshes) { // force underlying geometry to update activeMesh.setCount(activeMesh.getCount()); activeMesh.requestAttributeUpdate(); objects[this.__object_count++] = activeMesh.mesh; } } clear() { super.clear(); const meshes = this.__active_meshes; for (const mesh of meshes) { mesh.setCount(0); } meshes.clear(); } dispose() { this.clear(); // release GPU memory this.__instanced_meshes.forEach((value, key) => { value.dispose(); }); this.__instanced_meshes.clear(); } }