three.tdl.particle.system
Version:
GPU based particle system for three.js. Heavily based on tdl library (https://github.com/greggman/tdl)
511 lines (435 loc) • 24.1 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('three')) :
typeof define === 'function' && define.amd ? define(['exports', 'three'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.THREE_TDL_ParticleSystem = {}, global.THREE));
}(this, (function (exports, three) { 'use strict';
// source: https://github.com/greggman/tdl/blob/master/tdl/particles.js
// ported to three.js by fazeaction
var CORNERS_ = [[-0.5, -0.5], [+0.5, -0.5], [+0.5, +0.5], [-0.5, +0.5]];
function createDefaultClock_(particleSystem) {
return function () {
var now = particleSystem.now_;
var base = particleSystem.timeBase_;
return (now.getTime() - base.getTime()) / 1000.0;
};
}
var POSITION_START_TIME_IDX = 0;
var UV_LIFE_TIME_FRAME_START_IDX = 4;
var VELOCITY_START_SIZE_IDX = 8;
var ACCELERATION_END_SIZE_IDX = 12;
var SPIN_START_SPIN_SPEED_IDX = 16;
var ORIENTATION_IDX = 20;
var COLOR_MULT_IDX = 24;
var LAST_IDX = 28;
var singleParticleArray_ = new Float32Array(4 * LAST_IDX);
// source: https://github.com/greggman/tdl/blob/master/tdl/particles.js
// ported to three.js by fazeaction
function ParticleSpec() {
this.numParticles = 1;
this.numFrames = 1;
this.frameDuration = 1;
this.frameStart = 0;
this.frameStartRange = 0;
this.timeRange = 99999999;
this.startTime = null;
this.lifeTime = 1;
this.lifeTimeRange = 0;
this.startSize = 1;
this.startSizeRange = 0;
this.endSize = 1;
this.endSizeRange = 0;
this.position = [0, 0, 0];
this.positionRange = [0, 0, 0];
this.velocity = [0, 0, 0];
this.velocityRange = [0, 0, 0];
this.acceleration = [0, 0, 0];
this.accelerationRange = [0, 0, 0];
this.spinStart = 0;
this.spinStartRange = 0;
this.spinSpeed = 0;
this.spinSpeedRange = 0;
this.colorMult = [1, 1, 1, 1];
this.colorMultRange = [0, 0, 0, 0];
this.worldVelocity = [0, 0, 0];
this.worldAcceleration = [0, 0, 0];
this.billboard = true;
this.orientation = [0, 0, 0, 1];
}
// source: https://github.com/greggman/tdl/blob/master/tdl/particles.js
class OneShot extends three.Mesh {
constructor(emitter, scene) {
super();
this.emitter_ = emitter.clone();
this.scene = scene;
this.world_ = new three.Matrix4();
this.tempWorld_ = new three.Matrix4();
this.timeOffset_ = 0;
this.visible_ = false; // Remove the parent emitter from the particle system's drawable
// list (if it's still there) and add ourselves instead.
var particleSystem = emitter.particleSystem;
var idx = particleSystem.drawables_.indexOf(this.emitter_);
if (idx >= 0) {
particleSystem.drawables_.splice(idx, 1);
}
particleSystem.drawables_.push(this);
}
trigger(opt_world) {
if (!this.visible_) {
this.scene.add(this.emitter_);
}
if (opt_world) {
this.emitter_.position.copy(new three.Vector3().fromArray(opt_world));
}
this.visible_ = true;
this.timeOffset_ = this.emitter_.timeSource_();
}
draw(world, viewProjection, timeOffset) {
if (this.visible_) {
//this.tempWorld_.multiplyMatrices(this.world_, world);
this.emitter_.draw(this.world_, viewProjection, this.timeOffset_);
}
}
}
var billboardParticleInstancedVertexShader = "\nuniform mat4 viewInverse;\nuniform vec3 worldVelocity;\nuniform vec3 worldAcceleration;\nuniform float timeRange;\nuniform float time;\nuniform float timeOffset;\nuniform float frameDuration;\nuniform float numFrames;\nattribute vec4 uvLifeTimeFrameStart;\nattribute float startTime;\nattribute vec4 velocityStartSize;\nattribute vec4 accelerationEndSize;\nattribute vec4 spinStartSpinSpeed;\nattribute vec4 colorMult;\nvarying vec2 outputTexcoord;\nvarying float outputPercentLife;\nvarying vec4 outputColorMult;\nvoid main() {\n float lifeTime = uvLifeTimeFrameStart.z;\n float frameStart = uvLifeTimeFrameStart.w;\n vec3 velocity = (modelMatrix * vec4(velocityStartSize.xyz,\n 0.)).xyz + worldVelocity;\n float startSize = velocityStartSize.w;\n vec3 acceleration = (modelMatrix * vec4(accelerationEndSize.xyz,\n 0)).xyz + worldAcceleration;\n float endSize = accelerationEndSize.w;\n float spinStart = spinStartSpinSpeed.x;\n float spinSpeed = spinStartSpinSpeed.y;\n float localTime = mod((time - timeOffset - startTime), timeRange);\n float percentLife = localTime / lifeTime;\n float frame = mod(floor(localTime / frameDuration + frameStart),\n numFrames);\n float uOffset = frame / numFrames;\n float u = uOffset + (uv.x + 0.5) * (1. / numFrames);\n outputTexcoord = vec2(u, uv.y + 0.5);\n outputColorMult = colorMult;\n vec3 basisX = viewInverse[0].xyz;\n vec3 basisZ = viewInverse[1].xyz;\n vec4 vertexWorld = modelMatrix * vec4(position, 1.0);\n float size = mix(startSize, endSize, percentLife);\n size = (percentLife < 0. || percentLife > 1.) ? 0. : size;\n float s = sin(spinStart + spinSpeed * localTime);\n float c = cos(spinStart + spinSpeed * localTime);\n vec2 rotatedPoint = vec2(uv.x * c + uv.y * s, -uv.x * s + uv.y * c);\n vec3 localPosition = vec3(basisX * rotatedPoint.x + basisZ * rotatedPoint.y) * size +\n velocity * localTime +\n acceleration * localTime * localTime +\n vertexWorld.xyz;\n outputPercentLife = percentLife;\n gl_Position = projectionMatrix * viewMatrix * vec4(localPosition, 1.);\n}";
var orientedParticleInstancedVertexShader = "\nuniform mat4 worldViewProjection;\nuniform mat4 world;\nuniform vec3 worldVelocity;\nuniform vec3 worldAcceleration;\nuniform float timeRange;\nuniform float time;\nuniform float timeOffset;\nuniform float frameDuration;\nuniform float numFrames;\nattribute vec3 offset;\nattribute vec4 uvLifeTimeFrameStart;attribute float startTime;attribute vec4 velocityStartSize;attribute vec4 accelerationEndSize;attribute vec4 spinStartSpinSpeed;attribute vec4 orientation;attribute vec4 colorMult;\nvarying vec2 outputTexcoord;\nvarying float outputPercentLife;\nvarying vec4 outputColorMult;\nvoid main() {\nfloat lifeTime = uvLifeTimeFrameStart.z;\nfloat frameStart = uvLifeTimeFrameStart.w;\nvec3 velocity = (world * vec4(velocityStartSize.xyz,\n 0.)).xyz + worldVelocity;\nfloat startSize = velocityStartSize.w;\nvec3 acceleration = (world * vec4(accelerationEndSize.xyz,\n 0)).xyz + worldAcceleration;\nfloat endSize = accelerationEndSize.w;\nfloat spinStart = spinStartSpinSpeed.x;\nfloat spinSpeed = spinStartSpinSpeed.y;\nfloat localTime = mod((time - timeOffset - startTime), timeRange);\nfloat percentLife = localTime / lifeTime;\nfloat frame = mod(floor(localTime / frameDuration + frameStart),\n numFrames);\nfloat uOffset = frame / numFrames;\nfloat u = uOffset + (uv.x + 0.5) * (1. / numFrames);\noutputTexcoord = vec2(u, uv.y + 0.5);\noutputColorMult = colorMult;\nfloat size = mix(startSize, endSize, percentLife);\nsize = (percentLife < 0. || percentLife > 1.) ? 0. : size;\nfloat s = sin(spinStart + spinSpeed * localTime);\nfloat c = cos(spinStart + spinSpeed * localTime);\nvec4 rotatedPoint = vec4((uv.x * c + uv.y * s) * size, 0.,\n (uv.x * s - uv.y * c) * size, 1.);\nvec3 center = velocity * localTime +\n acceleration * localTime * localTime +\n position +offset;\nvec4 q2 = orientation + orientation;\nvec4 qx = orientation.xxxw * q2.xyzx;\nvec4 qy = orientation.xyyw * q2.xyzy;\nvec4 qz = orientation.xxzw * q2.xxzz;\nmat4 localMatrix = mat4(\n (1.0 - qy.y) - qz.z,\n qx.y + qz.w,\n qx.z - qy.w,\n 0,\n qx.y - qz.w,\n (1.0 - qx.x) - qz.z,\n qy.z + qx.w,\n 0,\n qx.z + qy.w,\n qy.z - qx.w,\n (1.0 - qx.x) - qy.y,\n 0,\n center.x, center.y, center.z, 1);\nrotatedPoint = localMatrix * rotatedPoint;\noutputPercentLife = percentLife;\ngl_Position = projectionMatrix * modelViewMatrix * rotatedPoint;\n}";
var particleFragmentShader = "\n#ifdef GL_ES\nprecision mediump float;\n#endif\nuniform sampler2D rampSampler;\nuniform sampler2D colorSampler;\nvarying vec2 outputTexcoord;\nvarying float outputPercentLife;\nvarying vec4 outputColorMult;\nvoid main() {\n vec4 colorMult = texture2D(rampSampler, vec2(outputPercentLife, 0.5)) * outputColorMult;\n gl_FragColor = texture2D(colorSampler, outputTexcoord) * colorMult;\n}";
// source: https://github.com/greggman/tdl/blob/master/tdl/particles.js
class ParticleEmitter extends three.Mesh {
constructor(particleSystem, opt_texture, opt_clock) {
super();
opt_clock = opt_clock || particleSystem.timeSource_; //TODO make alternative to instanced buffer
//this.particleBuffer_ = new THREE.BufferGeometry();
//this.indexBuffer_ = [];
this.particleBuffer_ = new three.InstancedBufferGeometry();
this.interleavedBuffer = new three.InterleavedBuffer();
this.numParticles_ = 0;
this.rampTexture_ = particleSystem.defaultRampTexture;
this.colorTexture_ = opt_texture || particleSystem.defaultColorTexture;
this.particleSystem = particleSystem;
this.timeSource_ = opt_clock;
this.setState(three.NormalBlending);
}
setTranslation(x, y, z) {
this.position.x = x;
this.position.y = y;
this.position.z = z;
}
setState(stateId) {
this.blendFunc_ = stateId;
}
setColorRamp(colorRamp) {
var width = colorRamp.length / 4;
if (width % 1 != 0) {
throw 'colorRamp must have multiple of 4 entries';
}
if (this.rampTexture_ == this.particleSystem.defaultRampTexture) {
this.rampTexture_ = null;
}
this.rampTexture_ = this.particleSystem.createTextureFromFloats(width, 1, colorRamp, this.rampTexture_);
}
validateParameters(parameters) {
var defaults = new ParticleSpec();
for (var key in parameters) {
if (typeof defaults[key] === 'undefined') {
throw 'unknown particle parameter "' + key + '"';
}
}
for (var key in defaults) {
if (typeof parameters[key] === 'undefined') {
parameters[key] = defaults[key];
}
}
}
createParticles_(firstParticleIndex, numParticles, parameters, opt_perParticleParamSetter) {
var interleaveBufferData = this.interleavedBuffer.array;
this.billboard_ = parameters.billboard;
var random = this.particleSystem.randomFunction_;
var plusMinus = function (range) {
return (random() - 0.5) * range * 2;
}; // TODO: change to not allocate.
var plusMinusVector = function (range) {
var v = [];
for (var ii = 0; ii < range.length; ++ii) {
v.push(plusMinus(range[ii]));
}
return v;
};
for (var ii = 0; ii < numParticles; ++ii) {
if (opt_perParticleParamSetter) {
opt_perParticleParamSetter(ii, parameters);
}
var pLifeTime = parameters.lifeTime;
var pStartTime = parameters.startTime === null ? ii * parameters.lifeTime / numParticles : parameters.startTime;
var pFrameStart = parameters.frameStart + plusMinus(parameters.frameStartRange);
var pPosition = new three.Vector3().addVectors(new three.Vector3().fromArray(parameters.position), new three.Vector3().fromArray(plusMinusVector(parameters.positionRange)));
var pVelocity = new three.Vector3().addVectors(new three.Vector3().fromArray(parameters.velocity), new three.Vector3().fromArray(plusMinusVector(parameters.velocityRange)));
var pAcceleration = new three.Vector3().addVectors(new three.Vector3().fromArray(parameters.acceleration), new three.Vector3().fromArray(plusMinusVector(parameters.accelerationRange)));
var pColorMult = new three.Vector4().addVectors(new three.Vector4().fromArray(parameters.colorMult), new three.Vector4().fromArray(plusMinusVector(parameters.colorMultRange)));
var pSpinStart = parameters.spinStart + plusMinus(parameters.spinStartRange);
var pSpinSpeed = parameters.spinSpeed + plusMinus(parameters.spinSpeedRange);
var pStartSize = parameters.startSize + plusMinus(parameters.startSizeRange);
var pEndSize = parameters.endSize + plusMinus(parameters.endSizeRange);
var pOrientation = new three.Vector4().fromArray(parameters.orientation);
for (var jj = 0; jj < 1; ++jj) {
var offset0 = LAST_IDX * jj + ii * LAST_IDX * 4 + firstParticleIndex * LAST_IDX * 4;
var offset1 = offset0 + 1;
var offset2 = offset0 + 2;
var offset3 = offset0 + 3;
interleaveBufferData[POSITION_START_TIME_IDX + offset0] = pPosition.x;
interleaveBufferData[POSITION_START_TIME_IDX + offset1] = pPosition.y;
interleaveBufferData[POSITION_START_TIME_IDX + offset2] = pPosition.z;
interleaveBufferData[POSITION_START_TIME_IDX + offset3] = pStartTime;
interleaveBufferData[UV_LIFE_TIME_FRAME_START_IDX + offset0] = CORNERS_[jj][0];
interleaveBufferData[UV_LIFE_TIME_FRAME_START_IDX + offset1] = CORNERS_[jj][1];
interleaveBufferData[UV_LIFE_TIME_FRAME_START_IDX + offset2] = pLifeTime;
interleaveBufferData[UV_LIFE_TIME_FRAME_START_IDX + offset3] = pFrameStart;
interleaveBufferData[VELOCITY_START_SIZE_IDX + offset0] = pVelocity.x;
interleaveBufferData[VELOCITY_START_SIZE_IDX + offset1] = pVelocity.y;
interleaveBufferData[VELOCITY_START_SIZE_IDX + offset2] = pVelocity.z;
interleaveBufferData[VELOCITY_START_SIZE_IDX + offset3] = pStartSize;
interleaveBufferData[ACCELERATION_END_SIZE_IDX + offset0] = pAcceleration.x;
interleaveBufferData[ACCELERATION_END_SIZE_IDX + offset1] = pAcceleration.y;
interleaveBufferData[ACCELERATION_END_SIZE_IDX + offset2] = pAcceleration.z;
interleaveBufferData[ACCELERATION_END_SIZE_IDX + offset3] = pEndSize;
interleaveBufferData[SPIN_START_SPIN_SPEED_IDX + offset0] = pSpinStart;
interleaveBufferData[SPIN_START_SPIN_SPEED_IDX + offset1] = pSpinSpeed;
interleaveBufferData[SPIN_START_SPIN_SPEED_IDX + offset2] = 0;
interleaveBufferData[SPIN_START_SPIN_SPEED_IDX + offset3] = 0;
interleaveBufferData[ORIENTATION_IDX + offset0] = pOrientation.x;
interleaveBufferData[ORIENTATION_IDX + offset1] = pOrientation.y;
interleaveBufferData[ORIENTATION_IDX + offset2] = pOrientation.z;
interleaveBufferData[ORIENTATION_IDX + offset3] = pOrientation.w;
interleaveBufferData[COLOR_MULT_IDX + offset0] = pColorMult.x;
interleaveBufferData[COLOR_MULT_IDX + offset1] = pColorMult.y;
interleaveBufferData[COLOR_MULT_IDX + offset2] = pColorMult.z;
interleaveBufferData[COLOR_MULT_IDX + offset3] = pColorMult.w;
}
}
this.interleavedBuffer.needsUpdate = true;
this.material.uniforms.worldVelocity.value = new three.Vector3(parameters.worldVelocity[0], parameters.worldVelocity[1], parameters.worldVelocity[2]);
this.material.uniforms.worldAcceleration.value = new three.Vector3(parameters.worldAcceleration[0], parameters.worldAcceleration[1], parameters.worldAcceleration[2]);
this.material.uniforms.timeRange.value = parameters.timeRange;
this.material.uniforms.frameDuration.value = parameters.frameDuration;
this.material.uniforms.numFrames.value = parameters.numFrames;
this.material.uniforms.rampSampler.value = this.rampTexture_;
this.material.uniforms.colorSampler.value = this.colorTexture_;
this.material.blending = this.blendFunc_;
}
allocateParticles_(numParticles, parameters) {
if (this.numParticles_ != numParticles) {
var numIndices = 6 * numParticles;
if (numIndices > 65536 && three.BufferGeometry.MaxIndex < 65536) {
throw "can't have more than 10922 particles per emitter";
}
var vertexBuffer = new three.InterleavedBuffer(new Float32Array([// Front
0, 0, 0, 0, -0.5, -0.5, 0, 0, 0, 0, 0, 0, 0.5, -0.5, 0, 0, 0, 0, 0, 0, 0.5, 0.5, 0, 0, 0, 0, 0, 0, -0.5, 0.5, 0, 0]), 8); // Use vertexBuffer, starting at offset 0, 3 items in position attribute
var positions = new three.InterleavedBufferAttribute(vertexBuffer, 3, 0);
this.particleBuffer_.setAttribute('position', positions); // Use vertexBuffer, starting at offset 4, 2 items in uv attribute
var uvs = new three.InterleavedBufferAttribute(vertexBuffer, 2, 4);
this.particleBuffer_.setAttribute('uv', uvs);
var indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
this.particleBuffer_.setIndex(new three.BufferAttribute(indices, 1));
this.numParticles_ = numParticles;
this.interleavedBuffer = new three.InstancedInterleavedBuffer(new Float32Array(numParticles * singleParticleArray_.byteLength), LAST_IDX, 1).setUsage(three.DynamicDrawUsage);
this.particleBuffer_.setAttribute('position', new three.InterleavedBufferAttribute(this.interleavedBuffer, 3, POSITION_START_TIME_IDX));
this.particleBuffer_.setAttribute('startTime', new three.InterleavedBufferAttribute(this.interleavedBuffer, 1, 3));
this.particleBuffer_.setAttribute('uvLifeTimeFrameStart', new three.InterleavedBufferAttribute(this.interleavedBuffer, 4, UV_LIFE_TIME_FRAME_START_IDX));
this.particleBuffer_.setAttribute('velocityStartSize', new three.InterleavedBufferAttribute(this.interleavedBuffer, 4, VELOCITY_START_SIZE_IDX));
this.particleBuffer_.setAttribute('accelerationEndSize', new three.InterleavedBufferAttribute(this.interleavedBuffer, 4, ACCELERATION_END_SIZE_IDX));
this.particleBuffer_.setAttribute('spinStartSpinSpeed', new three.InterleavedBufferAttribute(this.interleavedBuffer, 4, SPIN_START_SPIN_SPEED_IDX));
this.particleBuffer_.setAttribute('orientation', new three.InterleavedBufferAttribute(this.interleavedBuffer, 4, ORIENTATION_IDX));
this.particleBuffer_.setAttribute('colorMult', new three.InterleavedBufferAttribute(this.interleavedBuffer, 4, COLOR_MULT_IDX));
this.particleBuffer_.computeBoundingSphere();
var uniforms = {
//world: { type: 'm4', value: this.matrixWorld },
viewInverse: {
type: 'm4',
value: this.particleSystem.camera.matrixWorld
},
worldVelocity: {
type: 'v3',
value: null
},
worldAcceleration: {
type: 'v3',
value: null
},
timeRange: {
type: 'f',
value: null
},
time: {
type: 'f',
value: null
},
timeOffset: {
type: 'f',
value: null
},
frameDuration: {
type: 'f',
value: null
},
numFrames: {
type: 'f',
value: null
},
rampSampler: {
type: "t",
value: this.rampTexture_
},
colorSampler: {
type: "t",
value: this.colorTexture_
}
};
var material = new three.ShaderMaterial({
uniforms: uniforms,
vertexShader: parameters.billboard ? billboardParticleInstancedVertexShader : orientedParticleInstancedVertexShader,
fragmentShader: particleFragmentShader,
side: this.billboard_ ? three.DoubleSide : three.FrontSide,
blending: this.blendFunc_,
depthTest: true,
depthWrite: false,
transparent: true
});
this.geometry = this.particleBuffer_;
this.material = material;
}
}
setParameters(parameters, opt_perParticleParamSetter) {
this.validateParameters(parameters);
var numParticles = parameters.numParticles;
this.allocateParticles_(numParticles, parameters);
this.createParticles_(0, numParticles, parameters, opt_perParticleParamSetter);
}
draw(world, viewProjection, timeOffset) {
var uniforms = this.material.uniforms;
uniforms.time.value = this.timeSource_();
uniforms.timeOffset.value = timeOffset;
}
createOneShot() {
return new OneShot(this, this.particleSystem.scene);
}
clone(object) {
if (object === undefined) object = this.particleSystem.createParticleEmitter(this.colorTexture_, this.timeSource_);
object.geometry = this.geometry;
object.material = this.material.clone();
object.material.uniforms.viewInverse.value = this.particleSystem.camera.matrixWorld;
object.material.uniforms.rampSampler.value = this.rampTexture_;
object.material.uniforms.colorSampler.value = this.colorTexture_;
super.copy(object);
return object;
}
}
// source: https://github.com/greggman/tdl/blob/master/tdl/particles.js
class Trail extends ParticleEmitter {
constructor(particleSystem, maxParticles, parameters, opt_texture, opt_perParticleParamSetter, opt_clock) {
super(particleSystem, opt_texture, opt_clock);
this.allocateParticles_(maxParticles, parameters);
this.validateParameters(parameters);
this.parameters = parameters;
this.perParticleParamSetter = opt_perParticleParamSetter;
this.birthIndex_ = 0;
this.maxParticles_ = maxParticles;
}
birthParticles(position) {
var numParticles = this.parameters.numParticles;
this.parameters.startTime = this.timeSource_();
this.parameters.position = position;
while (this.birthIndex_ + numParticles >= this.maxParticles_) {
var numParticlesToEnd = this.maxParticles_ - this.birthIndex_;
this.createParticles_(this.birthIndex_, numParticlesToEnd, this.parameters, this.perParticleParamSetter);
numParticles -= numParticlesToEnd;
this.birthIndex_ = 0;
}
this.createParticles_(this.birthIndex_, numParticles, this.parameters, this.perParticleParamSetter);
if (this.birthIndex_ === 0) {
this.particleSystem.scene.add(this);
}
this.birthIndex_ += numParticles;
}
}
// source: https://github.com/greggman/tdl/blob/master/tdl/particles.js
class ParticleSystem {
constructor(scene, camera, opt_clock, opt_randomFunction) {
this.scene = scene;
this.camera = camera;
this.drawables_ = [];
var pixelBase = [0, 0.20, 0.70, 1, 0.70, 0.20, 0, 0];
var pixels = [];
for (var yy = 0; yy < 8; ++yy) {
for (var xx = 0; xx < 8; ++xx) {
var pixel = pixelBase[xx] * pixelBase[yy];
pixels.push(pixel, pixel, pixel, pixel);
}
}
var colorTexture = this.createTextureFromFloats(8, 8, pixels);
var rampTexture = this.createTextureFromFloats(2, 1, [1, 1, 1, 1, 1, 1, 1, 0]);
this.now_ = new Date();
this.timeBase_ = new Date();
if (opt_clock) {
this.timeSource_ = opt_clock;
} else {
this.timeSource_ = createDefaultClock_(this);
}
this.randomFunction_ = opt_randomFunction || function () {
return Math.random();
};
this.defaultColorTexture = colorTexture;
this.defaultRampTexture = rampTexture;
}
createTextureFromFloats(width, height, pixels, opt_texture) {
var texture = null;
if (opt_texture != null) {
texture = opt_texture;
} else {
var data = new Uint8Array(pixels.length);
var t;
for (var i = 0; i < pixels.length; i++) {
t = pixels[i] * 255.;
data[i] = t;
}
texture = new three.DataTexture(data, width, height, three.RGBAFormat);
texture.minFilter = three.LinearFilter;
texture.magFilter = three.LinearFilter;
texture.needsUpdate = true;
return texture;
}
return texture;
}
createParticleEmitter(opt_texture, opt_clock) {
var emitter = new ParticleEmitter(this, opt_texture, opt_clock);
this.drawables_.push(emitter);
return emitter;
}
createTrail(maxParticles, parameters, opt_texture, opt_perParticleParamSetter, opt_clock) {
var trail = new Trail(this, maxParticles, parameters, opt_texture, opt_perParticleParamSetter, opt_clock);
this.drawables_.push(trail);
return trail;
}
draw(viewProjection, world, viewInverse) {
this.now_ = new Date();
for (var ii = 0; ii < this.drawables_.length; ++ii) {
this.drawables_[ii].draw(world, viewProjection, 0);
}
}
}
exports.ACCELERATION_END_SIZE_IDX = ACCELERATION_END_SIZE_IDX;
exports.COLOR_MULT_IDX = COLOR_MULT_IDX;
exports.CORNERS_ = CORNERS_;
exports.LAST_IDX = LAST_IDX;
exports.ORIENTATION_IDX = ORIENTATION_IDX;
exports.OneShot = OneShot;
exports.POSITION_START_TIME_IDX = POSITION_START_TIME_IDX;
exports.ParticleEmitter = ParticleEmitter;
exports.ParticleSpec = ParticleSpec;
exports.ParticleSystem = ParticleSystem;
exports.SPIN_START_SPIN_SPEED_IDX = SPIN_START_SPIN_SPEED_IDX;
exports.Trail = Trail;
exports.UV_LIFE_TIME_FRAME_START_IDX = UV_LIFE_TIME_FRAME_START_IDX;
exports.VELOCITY_START_SIZE_IDX = VELOCITY_START_SIZE_IDX;
exports.createDefaultClock_ = createDefaultClock_;
exports.singleParticleArray_ = singleParticleArray_;
Object.defineProperty(exports, '__esModule', { value: true });
})));