📄 particlesystem.java
字号:
/*
* Copyright (c) 2003-2009 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jmex.effects.particles;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.logging.Logger;
import com.jme.math.FastMath;
import com.jme.math.Line;
import com.jme.math.Matrix3f;
import com.jme.math.Rectangle;
import com.jme.math.Ring;
import com.jme.math.TransformMatrix;
import com.jme.math.Triangle;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Controller;
import com.jme.scene.Geometry;
import com.jme.scene.Node;
import com.jme.scene.TriMesh;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.OutputCapsule;
/**
* ParticleGeometry is an abstract class representing a particle system. A
* ParticleController must be attached for the effect to be complete.
*
* @author Joshua Slack
* @version $Id: ParticleGeometry.java,v 1.11 2007/09/21 15:45:32 nca Exp $
*/
public abstract class ParticleSystem extends Node {
private static final Logger logger = Logger.getLogger(ParticleSystem.class
.getName());
protected static final long serialVersionUID = 2L;
public enum EmitType {
Point, Line, Rectangle, Ring, Geometry;
}
public enum ParticleType {
Quad, Triangle, Point, Line, GeomMesh;
}
protected static final float DEFAULT_END_SIZE = 4f;
protected static final float DEFAULT_START_SIZE = 20f;
protected static final float DEFAULT_MAX_ANGLE = 0.7853982f;
protected static final float DEFAULT_MAX_LIFE = 3000f;
protected static final float DEFAULT_MIN_LIFE = 2000f;
protected static final ColorRGBA DEFAULT_START_COLOR = new ColorRGBA(1.0f,
0.0f, 0.0f, 1.0f);
protected static final ColorRGBA DEFAULT_END_COLOR = new ColorRGBA(1.0f,
1.0f, 0.0f, 0.0f);
protected ParticleType particleType;
protected EmitType emitType = EmitType.Point;
protected Line psLine;
protected Rectangle psRect;
protected Geometry psGeom;
protected Ring psRing;
protected boolean cameraFacing = true;
protected boolean velocityAligned = false;
protected boolean particlesInWorldCoords = true;
protected float startSize, endSize;
protected ColorRGBA startColor;
protected ColorRGBA endColor;
protected ParticleAppearanceRamp ramp = new ParticleAppearanceRamp();
protected TexAnimation texAnimation = new TexAnimation();
protected float initialVelocity;
protected float minimumLifeTime, maximumLifeTime;
protected float minimumAngle, maximumAngle;
protected float startSpin, endSpin;
protected float startMass, endMass;
protected int startTexIndex, texQuantity;
protected Vector3f emissionDirection;
protected TransformMatrix emitterTransform = new TransformMatrix();
protected Vector3f worldEmit = new Vector3f();
protected int numParticles;
protected boolean rotateWithScene = false;
protected Matrix3f rotMatrix;
protected float particleOrientation;
protected FloatBuffer geometryCoordinates;
protected FloatBuffer appearanceColors;
// vectors to prevent repeated object creation:
protected Vector3f upXemit, absUpVector, abUpMinUp;
protected Vector3f upVector;
protected Vector3f leftVector;
protected Vector3f invScale;
protected Particle particles[];
// protected Vector3f particleSpeed;
protected int releaseRate; // particles per second
protected Vector3f originOffset;
protected Vector3f originCenter;
protected static Vector2f workVect2 = new Vector2f();
protected static Vector3f workVect3 = new Vector3f();
protected Geometry particleGeom;
protected ParticleController controller;
public ParticleSystem() {
}
public ParticleSystem(String name, int numParticles) {
this(name, numParticles, ParticleType.Quad);
}
public ParticleSystem(String name, int numParticles,
ParticleType particleType) {
super(name);
this.numParticles = numParticles;
this.particleType = particleType;
emissionDirection = new Vector3f(0.0f, 1.0f, 0.0f);
minimumLifeTime = DEFAULT_MIN_LIFE;
maximumLifeTime = DEFAULT_MAX_LIFE;
maximumAngle = DEFAULT_MAX_ANGLE;
startSize = DEFAULT_START_SIZE;
endSize = DEFAULT_END_SIZE;
startColor = DEFAULT_START_COLOR.clone();
endColor = DEFAULT_END_COLOR.clone();
upVector = Vector3f.UNIT_Y.clone();
leftVector = new Vector3f(-1, 0, 0);
originCenter = new Vector3f();
originOffset = new Vector3f();
startSpin = 0;
endSpin = 0;
startMass = 1;
endMass = 1;
startTexIndex = 0;
texQuantity = 1;
releaseRate = numParticles;
// init working vectors.. used to prevent additional object creation.
upXemit = new Vector3f();
absUpVector = new Vector3f();
abUpMinUp = new Vector3f();
initialVelocity = 1.0f;
rotMatrix = new Matrix3f();
initializeParticles(numParticles);
}
protected abstract void initializeParticles(int numParticles);
public static int getVertsForParticleType(ParticleType type) {
switch (type) {
case Triangle:
case GeomMesh:
return 3;
case Point:
return 1;
case Line:
return 2;
case Quad:
return 4;
}
if (type == null)
throw new NullPointerException("type is null");
throw new IllegalArgumentException("Invalid ParticleType: " + type);
}
public void forceRespawn() {
for (int i = particles.length; --i >= 0;) {
particles[i].recreateParticle(0);
particles[i].setStatus(Particle.Status.Alive);
particles[i].updateAndCheck(1);
particles[i].setStatus(Particle.Status.Available);
}
if (controller != null) {
controller.setActive(true);
}
}
/**
* Setup the rotation matrix used to determine initial particle velocity
* based on emission angle and emission direction. called automatically by
* the set* methods for those parameters.
*/
protected Vector3f oldEmit = new Vector3f(Float.NaN, Float.NaN, Float.NaN);
protected float matData[][] = new float[3][3];
public void updateRotationMatrix() {
if (oldEmit.equals(worldEmit))
return;
float upDotEmit = upVector.dot(worldEmit);
if (FastMath.abs(upDotEmit) > 1.0d - FastMath.DBL_EPSILON) {
absUpVector.x = upVector.x <= 0.0f ? -upVector.x : upVector.x;
absUpVector.y = upVector.y <= 0.0f ? -upVector.y : upVector.y;
absUpVector.z = upVector.z <= 0.0f ? -upVector.z : upVector.z;
if (absUpVector.x < absUpVector.y) {
if (absUpVector.x < absUpVector.z) {
absUpVector.x = 1.0f;
absUpVector.y = absUpVector.z = 0.0f;
} else {
absUpVector.z = 1.0f;
absUpVector.x = absUpVector.y = 0.0f;
}
} else if (absUpVector.y < absUpVector.z) {
absUpVector.y = 1.0f;
absUpVector.x = absUpVector.z = 0.0f;
} else {
absUpVector.z = 1.0f;
absUpVector.x = absUpVector.y = 0.0f;
}
absUpVector.subtract(upVector, abUpMinUp);
absUpVector.subtract(worldEmit, upXemit);
float f4 = 2.0f / abUpMinUp.dot(abUpMinUp);
float f6 = 2.0f / upXemit.dot(upXemit);
float f8 = f4 * f6 * abUpMinUp.dot(upXemit);
float af1[] = { abUpMinUp.x, abUpMinUp.y, abUpMinUp.z };
float af2[] = { upXemit.x, upXemit.y, upXemit.z };
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
matData[i][j] = (-f4 * af1[i] * af1[j] - f6 * af2[i]
* af2[j])
+ f8 * af2[i] * af1[j];
}
matData[i][i]++;
}
} else {
upVector.cross(worldEmit, upXemit);
float f2 = 1.0f / (1.0f + upDotEmit);
float f5 = f2 * upXemit.x;
float f7 = f2 * upXemit.z;
float f9 = f5 * upXemit.y;
float f10 = f5 * upXemit.z;
float f11 = f7 * upXemit.y;
matData[0][0] = upDotEmit + f5 * upXemit.x;
matData[0][1] = f9 - upXemit.z;
matData[0][2] = f10 + upXemit.y;
matData[1][0] = f9 + upXemit.z;
matData[1][1] = upDotEmit + f2 * upXemit.y * upXemit.y;
matData[1][2] = f11 - upXemit.x;
matData[2][0] = f10 - upXemit.y;
matData[2][1] = f11 + upXemit.x;
matData[2][2] = upDotEmit + f7 * upXemit.z;
}
rotMatrix.set(matData);
oldEmit.set(worldEmit);
}
public abstract Geometry getParticleGeometry();
public ParticleController getParticleController() {
return controller;
}
public void addController(Controller c) {
super.addController(c);
if (c instanceof ParticleController) {
this.controller = (ParticleController) c;
}
}
public Vector3f getEmissionDirection() {
return emissionDirection;
}
public void setEmissionDirection(Vector3f emissionDirection) {
this.emissionDirection = emissionDirection;
this.worldEmit.set(emissionDirection);
}
public float getEndSize() {
return endSize;
}
public void setEndSize(float size) {
endSize = size >= 0.0f ? size : 0.0f;
}
public float getStartSize() {
return startSize;
}
public void setStartSize(float size) {
startSize = size >= 0.0f ? size : 0.0f;
}
/**
* Set the start color for particles. This is the base color of the quad.
*
* @param color
* The start color.
*/
public void setStartColor(ColorRGBA color) {
this.startColor = color;
}
/**
* <code>getStartColor</code> returns the starting color.
*
* @return ColorRGBA The begining color.
*/
public ColorRGBA getStartColor() {
return startColor;
}
/**
* Set the end color for particles. The base color of the quad will linearly
* approach this color from the start color over the lifetime of the
* particle.
*
* @param color
* ColorRGBA The ending color.
*/
public void setEndColor(ColorRGBA color) {
this.endColor = color;
}
/**
* getEndColor returns the ending color.
*
* @return The ending color
*/
public ColorRGBA getEndColor() {
return endColor;
}
/**
* Set the start and end spinSpeed of particles managed by this manager.
* Setting it to 0 means no spin.
*
* @param speed
* float
*/
public void setParticleSpinSpeed(float speed) {
startSpin = speed;
endSpin = speed;
}
public Vector3f getInvScale() {
return invScale;
}
public void setInvScale(Vector3f invScale) {
this.invScale = invScale;
}
public void updateInvScale() {
invScale.set(worldScale);
invScale.set(1f / invScale.x, 1f / invScale.y, 1f / invScale.z);
}
/**
* Add an external influence to the particle controller for this mesh.
*
* @param influence
* ParticleInfluence
*/
public void addInfluence(ParticleInfluence influence) {
controller.addInfluence(influence);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -