particle system updates

beta.r3js.org
-=yb4f310 2017-11-15 11:43:46 +01:00
parent e552963f30
commit 4f48b3cc36
8 changed files with 260 additions and 280 deletions

View File

@ -34,6 +34,8 @@ GameLib.Component = function(
this.cloneNumber = 0;
this.isClone = false;
if (GameLib.Utils.UndefinedOrNull(delayed)) {
delayed = false;
}
@ -574,6 +576,8 @@ GameLib.Component.prototype.clone = function() {
}
}
runtimeObject.isClone = true;
GameLib.Event.Emit(
GameLib.Event.COMPONENT_CLONED,
{

View File

@ -4,7 +4,6 @@
* @param name
* @param position
* @param direction
* @param scale
* @param enabled
* @param templateParticle
* @param particlesPerSecond
@ -19,7 +18,6 @@ GameLib.D3.API.ParticleEngine = function(
name,
position,
direction,
scale,
enabled,
templateParticle,
particlesPerSecond,
@ -49,11 +47,6 @@ GameLib.D3.API.ParticleEngine = function(
}
this.direction = direction;
if (GameLib.Utils.UndefinedOrNull(scale)) {
scale = new GameLib.API.Vector3(1, 1, 1);
}
this.scale = scale;
if (GameLib.Utils.UndefinedOrNull(enabled)) {
enabled = false;
}
@ -120,18 +113,12 @@ GameLib.D3.API.ParticleEngine.FromObject = function(objectParticleEngine) {
apiDirection = GameLib.API.Vector3.FromObject(objectParticleEngine.direction);
}
var apiScale = null;
if (objectParticleEngine.scale) {
apiScale = GameLib.API.Vector3.FromObject(objectParticleEngine.scale);
}
return new GameLib.D3.API.ParticleEngine(
objectParticleEngine.id,
objectParticleEngine.name,
apiPosition,
apiDirection,
apiScale,
objectParticleEngine.enabled,
apiTemplateParticle,
objectParticleEngine.particlesPerSecond,

View File

@ -264,6 +264,7 @@ GameLib.D3.Material.TYPE_VERTEX_COLORS = 2;
* Blending Mode
* @type {number}
*/
GameLib.D3.Material.TYPE_NO_BLENDING = 0;
GameLib.D3.Material.TYPE_NORMAL_BLENDING = 1;
GameLib.D3.Material.TYPE_ADDITIVE_BLENDING = 2;
GameLib.D3.Material.TYPE_SUBTRACTIVE_BLENDING = 3;
@ -632,7 +633,7 @@ GameLib.D3.Material.prototype.updateTextures = function() {
};
GameLib.D3.Material.prototype.updateStandardMaterialInstance = function() {
GameLib.D3.Material.prototype.updateStandardMaterialInstance = function(property) {
this.instance.name = this.name;
this.instance.opacity = this.opacity;
this.instance.transparent = this.transparent;
@ -676,7 +677,7 @@ GameLib.D3.Material.prototype.updateStandardMaterialInstance = function() {
this.instance.morphNormals = this.morphNormals;
};
GameLib.D3.Material.prototype.updatePointsMaterialInstance = function() {
GameLib.D3.Material.prototype.updatePointsMaterialInstance = function(property) {
this.instance.name = this.name;
this.instance.opacity = this.opacity;
this.instance.transparent = this.transparent;
@ -703,7 +704,7 @@ GameLib.D3.Material.prototype.updatePointsMaterialInstance = function() {
//this.instance.fog = this.fog;
};
GameLib.D3.Material.prototype.updateLineBasicMaterialInstance = function() {
GameLib.D3.Material.prototype.updateLineBasicMaterialInstance = function(property) {
var linecap = 'round';
@ -755,7 +756,7 @@ GameLib.D3.Material.prototype.updateLineBasicMaterialInstance = function() {
};
GameLib.D3.Material.prototype.updatePhongMaterialInstance = function() {
GameLib.D3.Material.prototype.updatePhongMaterialInstance = function(property) {
this.instance.name = this.name;
this.instance.opacity = this.opacity;
this.instance.transparent = this.transparent;
@ -800,7 +801,7 @@ GameLib.D3.Material.prototype.updatePhongMaterialInstance = function() {
this.instance.morphNormals = this.morphNormals;
};
GameLib.D3.Material.prototype.updateMeshBasicMaterialInstance = function() {
GameLib.D3.Material.prototype.updateMeshBasicMaterialInstance = function(property) {
this.instance.name = this.name;
this.instance.opacity = this.opacity;
this.instance.transparent = this.transparent;
@ -865,65 +866,56 @@ GameLib.D3.Material.prototype.createInstance = function() {
/**
* Updates the instance with the current state
*/
GameLib.D3.Material.prototype.updateInstance = function() {
// console.log('material update instance');
GameLib.D3.Material.prototype.updateInstance = function(property) {
if (!this.instance) {
//console.warn('Attempt to update a non-existent instance');
console.warn('Attempt to update a non-existent instance');
return;
}
var typeChange = false;
if (property === 'materialType') {
if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_STANDARD) {
if (!(this.instance instanceof THREE.MeshStandardMaterial)) {
this.createInstance();
typeChange = true;
} else {
this.updateStandardMaterialInstance();
}
} else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_POINTS) {
if (!(this.instance instanceof THREE.PointsMaterial)) {
this.createInstance();
typeChange = true;
} else {
this.updatePointsMaterialInstance();
}
} else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_PHONG) {
if (!(this.instance instanceof THREE.MeshPhongMaterial)) {
this.createInstance();
typeChange = true;
} else {
this.updatePhongMaterialInstance();
}
} else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_BASIC) {
if (!(this.instance instanceof THREE.MeshBasicMaterial)) {
this.createInstance();
typeChange = true;
} else {
this.updateMeshBasicMaterialInstance();
}
} else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_LINE_BASIC) {
if (!(this.instance instanceof THREE.LineBasicMaterial)) {
this.createInstance();
typeChange = true;
} else {
this.updateLineBasicMaterialInstance();
}
} else {
console.warn('not yet implemented (material type = ' + this.materialType + ')');
}
this.createInstance();
this.updateTextures();
if (typeChange) {
this.publish(
GameLib.Event.MATERIAL_TYPE_CHANGED,
{
material: this
}
);
return;
}
if (
property === 'alphaMap' ||
property === 'aoMap' ||
property === 'bumpMap' ||
property === 'diffuseMap' ||
property === 'displacementMap' ||
property === 'emissiveMap' ||
property === 'environmentMap' ||
property === 'lightMap' ||
property === 'metalnessMap' ||
property === 'normalMap' ||
property === 'roughnessMap' ||
property === 'specularMap'
) {
this.updateTextures();
}
if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_STANDARD) {
this.updateStandardMaterialInstance(property);
} else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_POINTS) {
this.updatePointsMaterialInstance(property);
} else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_PHONG) {
this.updatePhongMaterialInstance(property);
} else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_BASIC) {
this.updateMeshBasicMaterialInstance(property);
} else if (this.materialType === GameLib.D3.Material.MATERIAL_TYPE_LINE_BASIC) {
this.updateLineBasicMaterialInstance(property);
} else {
console.warn('not yet implemented (material type = ' + this.materialType + ')');
}
this.instance.needsUpdate = true;

View File

@ -26,7 +26,6 @@ GameLib.D3.ParticleEngine = function(
apiParticleEngine.name,
apiParticleEngine.position,
apiParticleEngine.direction,
apiParticleEngine.scale,
apiParticleEngine.enabled,
apiParticleEngine.templateParticle,
apiParticleEngine.particlesPerSecond,
@ -58,19 +57,8 @@ GameLib.D3.ParticleEngine = function(
throw new Error('direction not instance of API.Vector3');
}
if (this.scale instanceof GameLib.API.Vector3) {
this.scale = new GameLib.Vector3(
graphics,
this.scale,
this
);
} else {
console.warn('scale not instance of API.Vector3');
throw new Error('scale not instance of API.Vector3');
}
if (this.camera instanceof GameLib.D3.API.Camera) {
this.templateParticle = new GameLib.D3.Camera(
this.camera = new GameLib.D3.Camera(
graphics,
this.camera
)
@ -109,20 +97,20 @@ GameLib.D3.ParticleEngine.prototype.createInstance = function() {
this.instance = true;
if (this.templateParticle) {
this.templateParticle.mesh.position.x = this.position.x;
this.templateParticle.mesh.position.y = this.position.y;
this.templateParticle.mesh.position.z = this.position.z;
this.templateParticle.direction.x = this.direction.x;
this.templateParticle.direction.y = this.direction.y;
this.templateParticle.direction.z = this.direction.z;
this.templateParticle.scale.x = this.scale.x;
this.templateParticle.scale.y = this.scale.y;
this.templateParticle.scale.z = this.scale.z;
}
// if (this.templateParticle) {
//
// this.templateParticle.mesh.position.x = this.position.x;
// this.templateParticle.mesh.position.y = this.position.y;
// this.templateParticle.mesh.position.z = this.position.z;
//
// this.templateParticle.direction.x = this.direction.x;
// this.templateParticle.direction.y = this.direction.y;
// this.templateParticle.direction.z = this.direction.z;
//
// this.templateParticle.scale.x = this.scale.x;
// this.templateParticle.scale.y = this.scale.y;
// this.templateParticle.scale.z = this.scale.z;
// }
GameLib.Component.prototype.createInstance.call(this);
};
@ -140,42 +128,20 @@ GameLib.D3.ParticleEngine.prototype.updateInstance = function(property) {
this.particlesPerSecond = Math.round(1 / this.frequency);
}
if (property === 'templateParticle') {
this.templateParticle.mesh.position.x = this.position.x;
this.templateParticle.mesh.position.y = this.position.y;
this.templateParticle.mesh.position.z = this.position.z;
this.templateParticle.direction.x = this.direction.x;
this.templateParticle.direction.y = this.direction.y;
this.templateParticle.direction.z = this.direction.z;
}
if (property === 'position') {
this.position.updateInstance('position', true);
this.templateParticle.mesh.position.x = this.position.x;
this.templateParticle.mesh.position.y = this.position.y;
this.templateParticle.mesh.position.z = this.position.z;
this.templateParticle.mesh.updateInstancePosition();
this.position.instance.x = this.position.x;
this.position.instance.y = this.position.y;
this.position.instance.z = this.position.z;
this.templateParticle.mesh.position = this.position.clone();
this.templateParticle.mesh.updateInstance('position', true);
}
if (property === 'direction') {
this.direction.updateInstance('direction', true);
this.templateParticle.direction.x = this.direction.x;
this.templateParticle.direction.y = this.direction.y;
this.templateParticle.direction.z = this.direction.z;
}
if (property === 'scale') {
this.scale.updateInstance('direction', true);
this.templateParticle.scale.x = this.scale.x;
this.templateParticle.scale.y = this.scale.y;
this.templateParticle.scale.z = this.scale.z;
this.direction.instance.x = this.direction.x;
this.direction.instance.y = this.direction.y;
this.direction.instance.z = this.direction.z;
this.templateParticle.direction = this.direction.clone();
this.templateParticle.direction.updateInstance('direction', true);
}
};
@ -185,29 +151,34 @@ GameLib.D3.ParticleEngine.prototype.remove = function() {
GameLib.Event.REMOVE_PARTICLE_ENGINE,
function(data){
if (data.component === this) {
/**
* We only remove the things we cloned, the mesh, particle, and this
*/
GameLib.Event.Emit(
GameLib.Event.REMOVE_COMPONENT,
{
component : this.templateParticle.mesh
}
);
GameLib.Event.Emit(
GameLib.Event.REMOVE_COMPONENT,
{
component : this.templateParticle
}
);
if (this.isClone) {
/**
* We only remove the things we cloned, the mesh, particle, and this
*/
GameLib.Event.Emit(
GameLib.Event.REMOVE_COMPONENT,
{
component: this.templateParticle.mesh
}
);
GameLib.Event.Emit(
GameLib.Event.REMOVE_COMPONENT,
{
component : this
}
)
GameLib.Event.Emit(
GameLib.Event.REMOVE_COMPONENT,
{
component: this.templateParticle
}
);
GameLib.Event.Emit(
GameLib.Event.REMOVE_COMPONENT,
{
component: this
}
)
} else {
GameLib.Component.prototype.remove.call(this);
}
}
}.bind(this)
);
@ -220,6 +191,30 @@ GameLib.D3.ParticleEngine.prototype.remove = function() {
this.disabledForRemoval = true;
};
// GameLib.D3.ParticleEngine.prototype.getChildrenComponents = function() {
//
// var components = [];
//
// if (this.templateParticle) {
// components.push(this.templateParticle);
//
// if (this.templateParticle.mesh) {
// components.push(this.templateParticle.mesh);
//
// if (this.templateParticle.mesh.materials && this.templateParticle.mesh.materials[0]) {
//
// components.push(this.templateParticle.mesh.materials[0]);
//
// if (this.templateParticle.mesh.materials[0].diffuseMap) {
// components.push(this.templateParticle.mesh.materials[0].diffuseMap);
// }
// }
// }
// }
//
// return components;
// };
GameLib.D3.ParticleEngine.prototype.clone = function() {
var mesh = this.templateParticle.mesh.clone();
var templateParticle = this.templateParticle.clone();
@ -270,7 +265,6 @@ GameLib.D3.ParticleEngine.prototype.toApiObject = function() {
this.name,
this.position.toApiObject(),
this.direction.toApiObject(),
this.scale.toApiObject(),
this.enabled,
GameLib.Utils.IdOrNull(this.templateParticle),
this.particlesPerSecond,

View File

@ -153,32 +153,123 @@ GameLib.D3.Particle.prototype.createInstance = function() {
* Updates the instance with the current state
*/
GameLib.D3.Particle.prototype.updateInstance = function(property) {
console.log('Update Particle Property : ' + property);
if (this.scaleType === GameLib.D3.Particle.SCALE_TYPE_RANDOM_X_EQUALS_Y) {
console.log(property);
// this.scale.y = this.scale.x;
if (property === 'positionOffset') {
this.positionOffset.instance.x = this.positionOffset.x;
this.positionOffset.instance.y = this.positionOffset.y;
this.positionOffset.instance.z = this.positionOffset.z;
}
if (property === 'direction') {
this.direction.instance.x = this.direction.x;
this.direction.instance.y = this.direction.y;
this.direction.instance.z = this.direction.z;
}
if (property === 'scale') {
this.scale.instance.x = this.scale.x;
this.scale.instance.y = this.scale.y;
this.scale.instance.z = this.scale.z;
}
if (property === 'rotation') {
this.rotation.instance.x = this.rotation.x;
this.rotation.instance.y = this.rotation.y;
this.rotation.instance.z = this.rotation.z;
}
};
/**
* Clones a particle - this only clones 3rd party instances, so we have less overhead of creating these types of objects
*/
// GameLib.D3.Particle.prototype.clone = function() {
//
// var clone = GameLib.Component.prototype.clone.call(this);
//
// clone.mesh = this.mesh.clone();
//
// return clone;
// //var material = this.mesh.materials[0].clone();
//
// //var texture = material.diffuseMap.clone();
//
// //this.mesh.materials =
//
// };
GameLib.D3.Particle.prototype.cloneInstance = function() {
this.updateInstance('positionOffset');
this.updateInstance('direction');
this.updateInstance('scale');
this.updateInstance('rotation');
var clone = GameLib.Component.prototype.cloneInstance.call(this);
clone.position = this.parentEngine.position.instance.clone();
clone.material = this.mesh.materials[0].instance.clone();
clone.visible = true;
if (this.positionOffsetType === GameLib.D3.Particle.POSITION_OFFSET_TYPE_CONSTANT) {
clone.position.add(this.positionOffset.instance);
}
var add = 1;
if (this.positionOffsetType === GameLib.D3.Particle.POSITION_OFFSET_TYPE_RANDOM) {
add = GameLib.Utils.GetRandomIntInclusive(1,2);
if (add === 1) {
clone.position.x += Math.random() * this.positionOffset.x;
clone.position.y += Math.random() * this.positionOffset.y;
clone.position.z += Math.random() * this.positionOffset.z;
} else {
clone.position.x -= Math.random() * this.positionOffset.x;
clone.position.y -= Math.random() * this.positionOffset.y;
clone.position.z -= Math.random() * this.positionOffset.z;
}
}
if (this.scaleType === GameLib.D3.Particle.SCALE_TYPE_CONSTANT) {
clone.scale.x += this.scale.x;
clone.scale.y += this.scale.y;
clone.scale.z += this.scale.z;
}
if (this.scaleType === GameLib.D3.Particle.SCALE_TYPE_RANDOM) {
add = GameLib.Utils.GetRandomIntInclusive(1,2);
if (add === 1) {
clone.scale.x += Math.random() * this.scale.x;
clone.scale.y += Math.random() * this.scale.y;
clone.scale.z += Math.random() * this.scale.z;
} else {
clone.scale.x -= Math.random() * this.scale.x;
clone.scale.y -= Math.random() * this.scale.y;
clone.scale.z -= Math.random() * this.scale.z;
}
}
if (this.scaleType === GameLib.D3.Particle.SCALE_TYPE_RANDOM_X_EQUALS_Y) {
add = GameLib.Utils.GetRandomIntInclusive(1,2);
var factor = Math.random() * this.scale.x;
if (add === 1) {
clone.scale.x += factor;
clone.scale.y += factor;
clone.scale.z += Math.random() * this.scale.z;
} else {
clone.scale.x -= factor;
clone.scale.y -= factor;
clone.scale.z -= Math.random() * this.scale.z;
}
}
clone.userData.direction = this.direction.clone();
clone.userData.scale = this.scale.clone();
clone.userData.lifeTime = this.lifeTime;
clone.userData.speed = this.speed;
clone.userData.scene = this.mesh.parentScene.instance;
clone.userData.elapsed = 0;
clone.userData.scene.add(clone);
return clone;
};
/**
* Converts a GameLib.D3.Particle to a new GameLib.D3.API.Particle

View File

@ -884,10 +884,12 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate,
object,
property,
{
'none': GameLib.D3.Material.TYPE_NO_BLENDING,
'normal': GameLib.D3.Material.TYPE_NORMAL_BLENDING,
'additive': GameLib.D3.Material.TYPE_ADDITIVE_BLENDING,
'subtractive': GameLib.D3.Material.TYPE_SUBTRACTIVE_BLENDING,
'multiply': GameLib.D3.Material.TYPE_MULTIPLY_BLENDING
'multiply': GameLib.D3.Material.TYPE_MULTIPLY_BLENDING,
'custom': GameLib.D3.Material.TYPE_CUSTOM_BLENDING
}
)
);

View File

@ -629,6 +629,19 @@ GameLib.System.Linking.prototype.instanceCreated = function(data) {
);
}
if (
data.component.parentEngine &&
typeof data.component.parentEngine === 'string'
) {
GameLib.EntityManager.Instance.queryComponents(GameLib.D3.ParticleEngine).map(
function (particleEngine) {
if (data.component.parentEngine === particleEngine.id) {
data.component.parentEngine = particleEngine;
}
}
);
}
/**
* Link all meshes
*/

View File

@ -131,7 +131,17 @@ GameLib.System.Particle.prototype.beforeRender = function(data) {
particle.position.y += particle.userData.direction.y * data.delta * particle.userData.speed;
particle.position.z += particle.userData.direction.z * data.delta * particle.userData.speed;
if (particle.scaleType === GameLib.D3.Particle.SCALE_TYPE_LINEAR) {
if (particleEngine.templateParticle.scaleType === GameLib.D3.Particle.SCALE_TYPE_CONSTANT) {
/**
* Do nothing - scale should already be set
*/
/* particle.scale.x = particle.userData.scale.x;
particle.scale.y = particle.userData.scale.y;
particle.scale.z = particle.userData.scale.z;
*/
}
if (particleEngine.templateParticle.scaleType === GameLib.D3.Particle.SCALE_TYPE_LINEAR) {
particle.scale.x += particle.userData.scale.x * data.delta;
particle.scale.y += particle.userData.scale.x * data.delta;
particle.scale.z += particle.userData.scale.x * data.delta;
@ -177,122 +187,9 @@ GameLib.System.Particle.prototype.beforeRender = function(data) {
particleEngine.elapsed = 0;
var particle = particleEngine.templateParticle;
var particleInstance = particle.cloneInstance();
particleInstance.visible = true;
// var texture = particleEngine.templateParticle.mesh.materials[0].diffuseMap.clone();
//
// texture.offset.x = 0;
// texture.offset.y = 0;
// texture.updateInstance('offset');
//
// var material = particleEngine.templateParticle.mesh.materials[0].instance.clone();
//
// material.map = texture.instance;
//
// particleInstance.material = material;
// var texture = .clone();
//image.instance);
// texture.repeat.x = particleEngine.templateParticle.mesh.materials[0].diffuseMap.repeat.x;
// texture.repeat.y = particleEngine.templateParticle.mesh.materials[0].diffuseMap.repeat.y;
// texture.offset.x = particleEngine.templateParticle.mesh.materials[0].diffuseMap.offset.x;
// texture.offset.y = particleEngine.templateParticle.mesh.materials[0].diffuseMap.offset.y;
/**
* Ok - here we have a problem - we cannot reliably clone textures without a call to texture.needsUpdate,
* which recompiles the shader and slows down the particle system - dramatically
* @type {THREE.MeshBasicMaterial}
*/
particleInstance.material = new THREE.MeshBasicMaterial(
{
map : particle.mesh.materials[0].diffuseMap.instance,
transparent : true,
opacity : 1.0,
depthWrite : false
}
);
if (particle.positionOffsetType === GameLib.D3.Particle.POSITION_OFFSET_TYPE_CONSTANT) {
particleInstance.position.x += particle.positionOffset.x;
particleInstance.position.y += particle.positionOffset.y;
particleInstance.position.z += particle.positionOffset.z;
}
var add = 1;
if (particle.positionOffsetType === GameLib.D3.Particle.POSITION_OFFSET_TYPE_RANDOM) {
add = GameLib.Utils.GetRandomIntInclusive(1,2);
if (add === 1) {
particleInstance.position.x += Math.random() * particle.positionOffset.x;
particleInstance.position.y += Math.random() * particle.positionOffset.y;
particleInstance.position.z += Math.random() * particle.positionOffset.z;
} else {
particleInstance.position.x -= Math.random() * particle.positionOffset.x;
particleInstance.position.y -= Math.random() * particle.positionOffset.y;
particleInstance.position.z -= Math.random() * particle.positionOffset.z;
}
}
if (particle.scaleType === GameLib.D3.Particle.SCALE_TYPE_CONSTANT) {
particleInstance.scale.x = particle.scale.x;
particleInstance.scale.y = particle.scale.y;
particleInstance.scale.z = particle.scale.z;
}
if (particle.scaleType === GameLib.D3.Particle.SCALE_TYPE_RANDOM) {
add = GameLib.Utils.GetRandomIntInclusive(1,2);
if (add === 1) {
particleInstance.scale.x += Math.random() * particle.scale.x;
particleInstance.scale.y += Math.random() * particle.scale.y;
particleInstance.scale.z += Math.random() * particle.scale.z;
} else {
particleInstance.scale.x -= Math.random() * particle.scale.x;
particleInstance.scale.y -= Math.random() * particle.scale.y;
particleInstance.scale.z -= Math.random() * particle.scale.z;
}
}
if (particle.scaleType === GameLib.D3.Particle.SCALE_TYPE_RANDOM_X_EQUALS_Y) {
add = GameLib.Utils.GetRandomIntInclusive(1,2);
var factor = Math.random() * particle.scale.x;
if (add === 1) {
particleInstance.scale.x += factor;
particleInstance.scale.y += factor;
particleInstance.scale.z += Math.random() * particle.scale.z;
} else {
particleInstance.scale.x -= factor;
particleInstance.scale.y -= factor;
particleInstance.scale.z -= Math.random() * particle.scale.z;
}
}
particleInstance.userData.direction = particle.direction.clone();
particleInstance.userData.scale = particle.scale.clone();
particleInstance.userData.lifeTime = particle.lifeTime;
particleInstance.userData.speed = particle.speed;
particleInstance.userData.scene = particle.mesh.parentScene.instance;
particleInstance.userData.elapsed = 0;
particleInstance.userData.scene.add(particleInstance);
particleEngine.particles.push(particleInstance);
var instanceClone = particleEngine.templateParticle.cloneInstance();
particleEngine.particles.push(instanceClone);
}
}