Chromium Code Reviews| Index: samples/o3djs/particles.js |
| =================================================================== |
| --- samples/o3djs/particles.js (revision 18491) |
| +++ samples/o3djs/particles.js (working copy) |
| @@ -127,6 +127,7 @@ |
| ' output.colorMult = input.colorMult;\n' + |
| '\n' + |
| ' float size = lerp(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' + |
| '\n' + |
| @@ -239,6 +240,7 @@ |
| ' float3 basisZ = viewInverse[1].xyz;\n' + |
| '\n' + |
| ' float size = lerp(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' + |
| '\n' + |
| @@ -269,6 +271,18 @@ |
| '// #o3d MatrixLoadOrder RowMajor\n'}]; |
| /** |
| + * Corner values. |
| + * @private |
| + * @type {!Array.<!Array.<number>>} |
| + */ |
| +o3djs.particles.CORNERS_ = [ |
| + [-0.5, -0.5], |
| + [+0.5, -0.5], |
| + [+0.5, +0.5], |
| + [-0.5, +0.5]]; |
| + |
| + |
| +/** |
| * Creates a particle system. |
| * You only need one of these to run multiple emitters of different types |
| * of particles. |
| @@ -676,6 +690,29 @@ |
| }; |
| /** |
| + * Creates a Trail particle emitter. |
| + * You can use this for jet exhaust, etc... |
| + * @param {!o3d.Transform} opt_parent The parent for the oneshot. |
|
apatrick
2009/06/16 18:12:57
Missing @param comments.
|
| + * @return {!o3djs.particles.Trail} A Trail object. |
| + */ |
| +o3djs.particles.ParticleSystem.prototype.createTrail = function( |
| + parent, |
|
apatrick
2009/06/16 18:12:57
it's called opt_parent in the @param comment
|
| + maxParticles, |
| + parameters, |
| + opt_texture, |
| + opt_perParticleParamSetter, |
| + opt_clockParam) { |
| + return new o3djs.particles.Trail( |
| + this, |
| + parent, |
| + maxParticles, |
| + parameters, |
| + opt_texture, |
| + opt_perParticleParamSetter, |
| + opt_clockParam); |
| +}; |
| + |
| +/** |
| * A ParticleEmitter |
| * @constructor |
| * @param {!o3djs.particles.ParticleSystem} particleSystem The particle system |
| @@ -688,7 +725,6 @@ |
| o3djs.particles.ParticleEmitter = function(particleSystem, |
| opt_texture, |
| opt_clockParam) { |
| - |
| opt_clockParam = opt_clockParam || particleSystem.clockParam; |
| var o3d = o3djs.base.o3d; |
| @@ -842,23 +878,29 @@ |
| }; |
| /** |
| - * Sets the parameters of the particle emitter. |
| - * |
| - * Each of these parameters are in pairs. The used to create a table |
| - * of particle parameters. For each particle a specfic value is |
| - * set like this |
| - * |
| - * particle.field = value + Math.random() - 0.5 * valueRange * 2; |
| - * |
| - * or in English |
| - * |
| - * particle.field = value plus or minus valueRange. |
| - * |
| - * So for example, if you wanted a value from 10 to 20 you'd pass 15 for value |
| - * and 5 for valueRange because |
| - * |
| - * 15 + or - 5 = (10 to 20) |
| - * |
| + * Validates and adds missing particle parameters. |
| + * @param {!o3djs.particles.ParticleSpec} parameters The parameters to validate. |
| + */ |
| +o3djs.particles.ParticleEmitter.prototype.validateParameters = function( |
| + parameters) { |
| + var defaults = new o3djs.particles.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]; |
| + } |
| + } |
| +}; |
| + |
| +/** |
| + * Creates particles. |
| + * @private |
| + * @param {number} firstParticleIndex Index of first particle to create. |
| + * @param {number} numParticles The number of particles to create. |
| * @param {!o3djs.particles.ParticleSpec} parameters The parameters for the |
| * emitters. |
| * @param {!function(number, !o3djs.particles.ParticleSpec): void} |
| @@ -868,49 +910,36 @@ |
| * 20 this value will be 0 to 19. The ParticleSpec is a spec for this |
| * particular particle. You can set any per particle value before returning. |
| */ |
| -o3djs.particles.ParticleEmitter.prototype.setParameters = function( |
| +o3djs.particles.ParticleEmitter.prototype.createParticles_ = function( |
| + firstParticleIndex, |
| + numParticles, |
| parameters, |
| opt_perParticleParamSetter) { |
| - var defaults = new o3djs.particles.ParticleSpec(); |
| - for (var key in parameters) { |
| - if (typeof defaults[key] === 'undefined') { |
| - throw 'unknown particle parameter "' + key + '"'; |
| - } |
| - defaults[key] = parameters[key]; |
| - } |
| + var uvLifeTimeFrameStart = this.uvLifeTimeFrameStart_; |
| + var positionStartTime = this.positionStartTime_; |
| + var velocityStartSize = this.velocityStartSize_; |
| + var accelerationEndSize = this.accelerationEndSize_; |
| + var spinStartSpinSpeed = this.spinStartSpinSpeed_; |
| + var orientation = this.orientation_; |
| + var colorMults = this.colorMults_; |
| - var numParticles = defaults.numParticles; |
| - |
| - var uvLifeTimeFrameStart = []; |
| - var positionStartTime = []; |
| - var velocityStartSize = []; |
| - var accelerationEndSize = []; |
| - var spinStartSpinSpeed = []; |
| - var orientation = []; |
| - var colorMults = []; |
| - |
| // Set the globals. |
| this.material.effect = |
| - this.particleSystem.effects[defaults.billboard ? 1 : 0]; |
| - this.material.getParam('timeRange').value = defaults.timeRange; |
| - this.material.getParam('numFrames').value = defaults.numFrames; |
| - this.material.getParam('frameDuration').value = defaults.frameDuration; |
| - this.material.getParam('worldVelocity').value = defaults.worldVelocity; |
| + this.particleSystem.effects[parameters.billboard ? 1 : 0]; |
| + this.material.getParam('timeRange').value = parameters.timeRange; |
| + this.material.getParam('numFrames').value = parameters.numFrames; |
| + this.material.getParam('frameDuration').value = parameters.frameDuration; |
| + this.material.getParam('worldVelocity').value = parameters.worldVelocity; |
| this.material.getParam('worldAcceleration').value = |
| - defaults.worldAcceleration; |
| + parameters.worldAcceleration; |
| - var corners = [ |
| - [-0.5, -0.5], |
| - [+0.5, -0.5], |
| - [+0.5, +0.5], |
| - [-0.5, +0.5]]; |
| - |
| 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) { |
| @@ -921,44 +950,105 @@ |
| for (var ii = 0; ii < numParticles; ++ii) { |
| if (opt_perParticleParamSetter) { |
| - opt_perParticleParamSetter(ii, defaults); |
| + opt_perParticleParamSetter(ii, parameters); |
| } |
| - var pLifeTime = defaults.lifeTime; |
| - var pStartTime = (defaults.startTime === null) ? |
| - (ii * defaults.lifeTime / numParticles) : defaults.startTime; |
| - var pFrameStart = defaults.frameStart + plusMinus(defaults.frameStartRange); |
| + var pLifeTime = parameters.lifeTime; |
| + var pStartTime = (parameters.startTime === null) ? |
| + (ii * parameters.lifeTime / numParticles) : parameters.startTime; |
| + var pFrameStart = |
| + parameters.frameStart + plusMinus(parameters.frameStartRange); |
| var pPosition = o3djs.math.addVector( |
| - defaults.position, plusMinusVector(defaults.positionRange)); |
| + parameters.position, plusMinusVector(parameters.positionRange)); |
| var pVelocity = o3djs.math.addVector( |
| - defaults.velocity, plusMinusVector(defaults.velocityRange)); |
| + parameters.velocity, plusMinusVector(parameters.velocityRange)); |
| var pAcceleration = o3djs.math.addVector( |
| - defaults.acceleration, plusMinusVector(defaults.accelerationRange)); |
| + parameters.acceleration, |
| + plusMinusVector(parameters.accelerationRange)); |
| var pColorMult = o3djs.math.addVector( |
| - defaults.colorMult, plusMinusVector(defaults.colorMultRange)); |
| - var pSpinStart = defaults.spinStart + plusMinus(defaults.spinStartRange); |
| - var pSpinSpeed = defaults.spinSpeed + plusMinus(defaults.spinSpeedRange); |
| - var pStartSize = defaults.startSize + plusMinus(defaults.startSizeRange); |
| - var pEndSize = defaults.endSize + plusMinus(defaults.endSizeRange); |
| - var pOrientation = defaults.orientation; |
| + parameters.colorMult, 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 = parameters.orientation; |
| // make each corner of the particle. |
| for (var jj = 0; jj < 4; ++jj) { |
| - uvLifeTimeFrameStart.push(corners[jj][0], corners[jj][1], pLifeTime, |
| - pFrameStart); |
| - positionStartTime.push( |
| - pPosition[0], pPosition[1], pPosition[2], pStartTime); |
| - velocityStartSize.push( |
| - pVelocity[0], pVelocity[1], pVelocity[2], pStartSize); |
| - accelerationEndSize.push( |
| - pAcceleration[0], pAcceleration[1], pAcceleration[2], pEndSize); |
| - spinStartSpinSpeed.push(pSpinStart, pSpinSpeed, 0, 0); |
| - orientation.push( |
| - pOrientation[0], pOrientation[1], pOrientation[2], pOrientation[3]); |
| - colorMults.push( |
| - pColorMult[0], pColorMult[1], pColorMult[2], pColorMult[3]); |
| + var offset0 = (ii * 4 + jj) * 4; |
| + var offset1 = offset0 + 1; |
| + var offset2 = offset0 + 2; |
| + var offset3 = offset0 + 3; |
| + |
| + uvLifeTimeFrameStart[offset0] = o3djs.particles.CORNERS_[jj][0]; |
| + uvLifeTimeFrameStart[offset1] = o3djs.particles.CORNERS_[jj][1]; |
| + uvLifeTimeFrameStart[offset2] = pLifeTime; |
| + uvLifeTimeFrameStart[offset3] = pFrameStart; |
| + |
| + positionStartTime[offset0] = pPosition[0]; |
| + positionStartTime[offset1] = pPosition[1]; |
| + positionStartTime[offset2] = pPosition[2]; |
| + positionStartTime[offset3] = pStartTime; |
| + |
| + velocityStartSize[offset0] = pVelocity[0]; |
| + velocityStartSize[offset1] = pVelocity[1]; |
| + velocityStartSize[offset2] = pVelocity[2]; |
| + velocityStartSize[offset3] = pStartSize; |
| + |
| + accelerationEndSize[offset0] = pAcceleration[0]; |
| + accelerationEndSize[offset1] = pAcceleration[1]; |
| + accelerationEndSize[offset2] = pAcceleration[2]; |
| + accelerationEndSize[offset3] = pEndSize; |
| + |
| + spinStartSpinSpeed[offset0] = pSpinStart; |
| + spinStartSpinSpeed[offset1] = pSpinSpeed; |
| + spinStartSpinSpeed[offset2] = 0; |
| + spinStartSpinSpeed[offset3] = 0; |
| + |
| + orientation[offset0] = pOrientation[0]; |
| + orientation[offset1] = pOrientation[1]; |
| + orientation[offset2] = pOrientation[2]; |
| + orientation[offset3] = pOrientation[3]; |
| + |
| + colorMults[offset0] = pColorMult[0]; |
| + colorMults[offset1] = pColorMult[1]; |
| + colorMults[offset2] = pColorMult[2]; |
| + colorMults[offset3] = pColorMult[3]; |
| } |
| } |
| + firstParticleIndex *= 4; |
| + this.uvLifeTimeFrameStartField_.setAt( |
| + firstParticleIndex, |
| + uvLifeTimeFrameStart); |
| + this.positionStartTimeField_.setAt( |
| + firstParticleIndex, |
| + positionStartTime); |
| + this.velocityStartSizeField_.setAt( |
| + firstParticleIndex, |
| + velocityStartSize); |
| + this.accelerationEndSizeField_.setAt( |
| + firstParticleIndex, |
| + accelerationEndSize); |
| + this.spinStartSpinSpeedField_.setAt( |
| + firstParticleIndex, |
| + spinStartSpinSpeed); |
| + this.orientationField_.setAt( |
| + firstParticleIndex, |
| + orientation); |
| + this.colorMultField_.setAt( |
| + firstParticleIndex, |
| + colorMults); |
| +}; |
| + |
| +/** |
| + * Allocates particles. |
| + * @param {number} numParticles Number of particles to allocate. |
|
apatrick
2009/06/16 18:12:57
@private
|
| + */ |
| +o3djs.particles.ParticleEmitter.prototype.allocateParticles_ = function( |
| + numParticles) { |
| if (this.vertexBuffer_.numElements != numParticles * 4) { |
| this.vertexBuffer_.allocateElements(numParticles * 4); |
| @@ -970,21 +1060,65 @@ |
| indices.push(startIndex + 0, startIndex + 2, startIndex + 3); |
| } |
| this.indexBuffer_.set(indices); |
| + |
| + // We keep these around to avoid memory allocations for trails. |
| + this.uvLifeTimeFrameStart_ = []; |
| + this.positionStartTime_ = []; |
| + this.velocityStartSize_ = []; |
| + this.accelerationEndSize_ = []; |
| + this.spinStartSpinSpeed_ = []; |
| + this.orientation_ = []; |
| + this.colorMults_ = []; |
| } |
| - this.uvLifeTimeFrameStartField_.setAt(0, uvLifeTimeFrameStart); |
| - this.positionStartTimeField_.setAt(0, positionStartTime); |
| - this.velocityStartSizeField_.setAt(0, velocityStartSize); |
| - this.accelerationEndSizeField_.setAt(0, accelerationEndSize); |
| - this.spinStartSpinSpeedField_.setAt(0, spinStartSpinSpeed); |
| - this.orientationField_.setAt(0, orientation); |
| - this.colorMultField_.setAt(0, colorMults); |
| - |
| this.primitive_.numberPrimitives = numParticles * 2; |
| this.primitive_.numberVertices = numParticles * 4; |
| }; |
| /** |
| + * Sets the parameters of the particle emitter. |
| + * |
| + * Each of these parameters are in pairs. The used to create a table |
| + * of particle parameters. For each particle a specfic value is |
| + * set like this |
| + * |
| + * particle.field = value + Math.random() - 0.5 * valueRange * 2; |
| + * |
| + * or in English |
| + * |
| + * particle.field = value plus or minus valueRange. |
| + * |
| + * So for example, if you wanted a value from 10 to 20 you'd pass 15 for value |
| + * and 5 for valueRange because |
| + * |
| + * 15 + or - 5 = (10 to 20) |
| + * |
| + * @param {!o3djs.particles.ParticleSpec} parameters The parameters for the |
| + * emitters. |
| + * @param {!function(number, !o3djs.particles.ParticleSpec): void} |
| + * opt_perParticleParamSetter A function that is called for each particle to |
| + * allow it's parameters to be adjusted per particle. The number is the |
| + * index of the particle being created, in other words, if numParticles is |
| + * 20 this value will be 0 to 19. The ParticleSpec is a spec for this |
| + * particular particle. You can set any per particle value before returning. |
| + */ |
| +o3djs.particles.ParticleEmitter.prototype.setParameters = function( |
| + parameters, |
| + opt_perParticleParamSetter) { |
| + this.validateParameters(parameters); |
| + |
| + var numParticles = parameters.numParticles; |
| + |
| + this.allocateParticles_(numParticles); |
| + |
| + this.createParticles_( |
| + 0, |
| + numParticles, |
| + parameters, |
| + opt_perParticleParamSetter); |
| +}; |
| + |
| +/** |
| * Creates a OneShot particle emitter instance. |
| * You can use this for dust puffs, explosions, fireworks, etc... |
| * @param {!o3d.Transform} opt_parent The parent for the oneshot. |
| @@ -1049,3 +1183,81 @@ |
| this.transform.visible = true; |
| this.timeOffsetParam_.value = this.emitter_.clockParam.value; |
| }; |
| + |
| +/** |
| + * A type of emitter to use for particle effects that leave trails like exhaust. |
| + * @constructor |
| + * @param {!o3djs.particles.ParticleSystem} particleSystem The particle system |
| + * to manage this emitter. |
| + * @param {!o3d.Transform} parent Transform to put emitter on. |
| + * @param {number} maxParticles Maximum number of particles to appear at once. |
| + * @param {!o3djs.particles.ParticleSpec} parameters The parameters used to |
| + * generate particles. |
| + * @param {!o3d.Texture} opt_texture The texture to use for the particles. |
| + * If you don't supply a texture a default is provided. |
| + * @param {!o3d.ParamFloat} opt_clockParam A ParamFloat to be the clock for |
|
apatrick
2009/06/16 18:12:57
you could swap this @param comment with the one fo
|
| + * the emitter. |
| + * @param {!function(number, !o3djs.particles.ParticleSpec): void} |
| + * opt_perParticleParamSetter A function that is called for each particle to |
| + * allow it's parameters to be adjusted per particle. The number is the |
| + * index of the particle being created, in other words, if numParticles is |
| + * 20 this value will be 0 to 19. The ParticleSpec is a spec for this |
| + * particular particle. You can set any per particle value before returning. |
| + */ |
| +o3djs.particles.Trail = function( |
| + particleSystem, |
| + parent, |
| + maxParticles, |
| + parameters, |
| + opt_texture, |
| + opt_perParticleParamSetter, |
| + opt_clockParam) { |
| + o3djs.particles.ParticleEmitter.call( |
| + this, particleSystem, opt_texture, opt_clockParam); |
| + |
| + var pack = particleSystem.pack; |
| + |
| + this.allocateParticles_(maxParticles); |
| + this.validateParameters(parameters); |
| + |
| + this.parameters = parameters; |
| + this.perParticleParamSetter = opt_perParticleParamSetter; |
| + this.birthIndex_ = 0; |
| + this.maxParticles_ = maxParticles; |
| + |
| + /** |
| + * Transform for OneShot. |
| + * @type {!o3d.Transform} |
| + */ |
| + this.transform = pack.createObject('Transform'); |
| + this.transform.addShape(this.shape); |
| + |
| + this.transform.parent = parent; |
| +}; |
| + |
| +o3djs.base.inherit(o3djs.particles.Trail, o3djs.particles.ParticleEmitter); |
| + |
| +/** |
| + * Births particles from this Trail. |
| + * @param {!o3djs.math.Vector3} position Position to birth particles at. |
| + */ |
| +o3djs.particles.Trail.prototype.birthParticles = function(position) { |
| + var numParticles = this.parameters.numParticles; |
| + this.parameters.startTime = this.clockParam.value; |
| + 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); |
| + this.birthIndex_ += numParticles; |
| +}; |
| + |