@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
324 lines (323 loc) • 11.9 kB
JavaScript
"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();
}
}