UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

324 lines (323 loc) 11.9 kB
"use strict"; import { Vector2, Vector3, Vector4, FloatType, HalfFloatType } from "three"; import { GlConstant } from "../geometry/GlConstant"; import { GPUComputationRenderer } from "./gpuCompute/GPUComputationRenderer"; import { GlParamConfig } from "../../engine/nodes/gl/code/utils/GLParamConfig"; import { CoreUserAgent } from "../UserAgent"; import { CoreParticlesAttribute } from "./CoreParticlesAttribute"; import { coreParticlesInitParticlesUVs } from "./CoreParticlesInit"; import { textureFromAttributePointsCount, textureSizeFromPointsCount } from "../geometry/operation/TextureFromAttribute"; import { corePointClassFactory } from "../geometry/CoreObjectFactory"; export var ParticlesDataType = /* @__PURE__ */ ((ParticlesDataType2) => { ParticlesDataType2["AUTO"] = "Auto"; ParticlesDataType2["FLOAT"] = "Float"; ParticlesDataType2["HALF_FLOAT"] = "HalfFloat"; return ParticlesDataType2; })(ParticlesDataType || {}); export const PARTICLE_DATA_TYPES = [ "Auto" /* AUTO */, "Float" /* FLOAT */, "HalfFloat" /* HALF_FLOAT */ ]; const DATA_TYPE_BY_ENUM = { ["Auto" /* AUTO */]: CoreUserAgent.isiOS() ? HalfFloatType : FloatType, ["Float" /* FLOAT */]: FloatType, ["HalfFloat" /* HALF_FLOAT */]: HalfFloatType }; function dataType(object) { const dataType2 = CoreParticlesAttribute.getDataType(object); const dataTypeName = PARTICLE_DATA_TYPES[dataType2]; return DATA_TYPE_BY_ENUM[dataTypeName]; } const tmpV2 = new Vector2(); const tmpV3 = new Vector3(); const tmpV4 = new Vector4(); export class CoreParticlesGpuComputeController { constructor(mainController) { this.mainController = mainController; this._variablesByName = /* @__PURE__ */ new Map(); this._allVariables = []; this._createdTexturesByName = /* @__PURE__ */ new Map(); this._texturesSize = new Vector2(); } dispose() { if (this._gpuCompute) { this._gpuCompute.dispose(); this._gpuCompute = void 0; } this._variablesByName.clear(); this._allVariables.splice(0, this._allVariables.length); this._createdTexturesByName.clear(); if (this._persistedTextureAllocationsController) { this._persistedTextureAllocationsController.dispose(); this._persistedTextureAllocationsController = void 0; } } setPersistedTextureAllocationController(controller) { this._persistedTextureAllocationsController = controller; } allVariables() { return this._allVariables; } init() { this._initPoints(); return this.createGPUCompute(); } _initPoints() { this.resetGpuCompute(); } _initParticlesUVs(object) { coreParticlesInitParticlesUVs(object, this._texturesSize); } createGPUCompute() { var _a; const object = this.mainController.object(); const renderer = this.mainController.renderer(); if (!(object && renderer)) { return; } const geometry = object.geometry; if (!geometry) { return; } textureSizeFromPointsCount(geometry, this._texturesSize); this._initParticlesUVs(object); this.mainController.renderController.reset(); if (this._gpuCompute) { this._gpuCompute.dispose(); } this._gpuCompute = new GPUComputationRenderer(this._texturesSize.x, this._texturesSize.y, renderer); this._gpuCompute.setDataType(dataType(object)); this._lastSimulatedFrame = void 0; this._variablesByName.forEach((variable, shader_name) => { variable.renderTargets[0].dispose(); variable.renderTargets[1].dispose(); this._variablesByName.delete(shader_name); }); this._allVariables = []; this.mainController.shadersByName().forEach((shader, shader_name) => { if (this._gpuCompute) { const gpuVariable = this._gpuCompute.addVariable( this._textureNameForShaderName(shader_name), shader, this._createdTexturesByName.get(shader_name) ); this._variablesByName.set(shader_name, gpuVariable); this._allVariables.push(gpuVariable); } }); (_a = this._variablesByName) == null ? void 0 : _a.forEach((variable, shader_name) => { if (this._gpuCompute) { this._gpuCompute.setVariableDependencies( variable, this._allVariables // currently all depend on all ); } }); this._createTextureRenderTargets(); this._fillTextures(object); this._createSimulationMaterialUniforms(); const configRef = this._gpuCompute.init(); if (!configRef) { this.mainController.setError(`failed to generate the simulation shader`); } return configRef; } computeSimulation(delta, configRef) { if (!this._gpuCompute) { return; } this._gpuCompute.compute(configRef); this.mainController.renderController.updateRenderMaterialUniforms(); this._updateSimulationMaterialUniforms(delta); } getCurrentRenderTarget(shader_name) { var _a; const variable = this._variablesByName.get(shader_name); if (variable) { return (_a = this._gpuCompute) == null ? void 0 : _a.getCurrentRenderTarget(variable); } } _textureNameForShaderName(shaderName) { return `texture_${shaderName}`; } materials() { const materials = []; this._variablesByName.forEach((variable, shader_name) => { materials.push(variable.material); }); return materials; } _createSimulationMaterialUniforms() { const node = this.mainController.node(); const assemblerController = node.assemblerController(); const assembler = assemblerController == null ? void 0 : assemblerController.assembler; if (!assembler && !this._persistedTextureAllocationsController) { return; } const all_materials = []; this._variablesByName.forEach((variable, shader_name) => { all_materials.push(variable.material); }); const readonlyAllocations = this._readonlyAllocations(); for (const material of all_materials) { material.uniforms[GlConstant.TIME] = this.mainController.scene.timeController.timeUniform(); material.uniforms[GlConstant.DELTA_TIME] = this.mainController.scene.timeController.timeDeltaUniform(); if (readonlyAllocations) { this._assignReadonlyTextures(material, readonlyAllocations); } } if (assembler) { for (const material of all_materials) { for (const param_config of assembler.param_configs()) { material.uniforms[param_config.uniformName()] = param_config.uniform(); } } } else { const persisted_data = node.persisted_config.loaded_data(); if (persisted_data) { const persisted_uniforms = node.persisted_config.uniforms(); if (persisted_uniforms) { const param_uniform_pairs = persisted_data.param_uniform_pairs; for (const pair of param_uniform_pairs) { const param_name = pair[0]; const uniform_name = pair[1]; const param = node.params.get(param_name); const uniform = persisted_uniforms[uniform_name]; for (const material of all_materials) { material.uniforms[uniform_name] = uniform; if (readonlyAllocations) { this._assignReadonlyTextures(material, readonlyAllocations); } } if (param && uniform) { const callback = () => { for (const material of all_materials) { GlParamConfig.callback(param, material.uniforms[uniform_name]); } }; param.options.setOption("callback", callback); callback(); } } } } } } _assignReadonlyTextures(material, readonlyAllocations) { for (const allocation of readonlyAllocations) { const shaderName = allocation.shaderName(); const texture = this._createdTexturesByName.get(shaderName); if (texture) { const uniformName = this._textureNameForShaderName(shaderName); material.uniforms[uniformName] = { value: texture }; } } } _updateSimulationMaterialUniforms(delta) { for (const variable of this._allVariables) { variable.material.uniforms[GlConstant.TIME].value += delta; variable.material.uniforms[GlConstant.DELTA_TIME].value = delta; } } createdTexturesByName() { return this._createdTexturesByName; } _fillTextures(object) { const geometry = object.geometry; if (!geometry) { return; } const corePointClass = corePointClassFactory(object); const pointsCount = textureFromAttributePointsCount(geometry); const texture_allocations_controller = this._textureAllocationsController(); if (!texture_allocations_controller) { return; } this._createdTexturesByName.forEach((texture, shader_name) => { const texture_allocation = texture_allocations_controller.allocationForShaderName(shader_name); if (!texture_allocation) { console.warn(`no allocation found for shader ${shader_name}`); return; } const texture_variables = texture_allocation.variables(); if (!texture_variables) { console.warn(`allocation has no variables`); return; } const array = texture.image.data; for (const texture_variable of texture_variables) { const texture_position = texture_variable.position(); let variable_name = texture_variable.name(); const has_attrib = corePointClass.hasAttribute(object, variable_name); if (has_attrib) { const attrib_size = corePointClass.attribSize(object, variable_name); let cmptr = texture_position; for (let i = 0; i < pointsCount; i++) { switch (attrib_size) { case 1: { const val = corePointClass.attribValue(object, i, variable_name); array[cmptr] = val; break; } case 2: { corePointClass.attribValue(object, i, variable_name, tmpV2); tmpV2.toArray(array, cmptr); break; } case 3: { corePointClass.attribValue(object, i, variable_name, tmpV3); tmpV3.toArray(array, cmptr); break; } case 4: { corePointClass.attribValue(object, i, variable_name, tmpV4); tmpV4.toArray(array, cmptr); break; } } cmptr += 4; } } } texture.needsUpdate = true; }); } reset() { this.resetGpuCompute(); } resetGpuCompute() { var _a; (_a = this._gpuCompute) == null ? void 0 : _a.dispose(); this._gpuCompute = void 0; } _createTextureRenderTargets() { this._createdTexturesByName.forEach((texture, shader_name) => { texture.dispose(); }); this._createdTexturesByName.clear(); this._variablesByName.forEach((texture_variable, shader_name) => { if (this._gpuCompute) { this._createdTexturesByName.set(shader_name, this._gpuCompute.createTexture()); } }); const readonlyAllocations = this._readonlyAllocations(); if (readonlyAllocations && this._gpuCompute) { for (const readonlyAllocation of readonlyAllocations) { this._createdTexturesByName.set(readonlyAllocation.shaderName(), this._gpuCompute.createTexture()); } } } _textureAllocationsController() { var _a; const node = this.mainController.node(); return ((_a = node.assemblerController()) == null ? void 0 : _a.assembler.textureAllocationsController()) || this._persistedTextureAllocationsController; } _readonlyAllocations() { var _a; return (_a = this._textureAllocationsController()) == null ? void 0 : _a.readonlyAllocations(); } }