WEB开发网
开发学院WEB开发Jsp 3D编程指南第三部分:粒子系统和立即模式渲染(2) 阅读

3D编程指南第三部分:粒子系统和立即模式渲染(2)

 2008-01-05 08:52:07 来源:WEB开发网   
核心提示:TutorialMidletimport javax.microedition.lcdui.Command;import javax.microedition.lcdui.CommandListener;import javax.microedition.lcdui.Display;import javax.micro

TutorialMidlet
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
public class TutorialMidlet extends MIDlet implements CommandListener
{
   // A variable that holds the unique display
 PRivate Display display = null;
 
 // The canvas
 private M3GCanvas canvas = null;
 
 // The MIDlet itself
 private static MIDlet self = null;
 /** Called when the application starts, and when it is resumed.
  * We ignore the resume here and allocate data for our canvas
  * in the startApp method. This is generally very bad practice.
  */
 protected void startApp() throws MIDletStateChangeException
 {
   // Allocate
  display = Display.getDisplay(this);
  canvas = new M3GCanvas(30);
 
  // Add a quit command to the canvas
  // This command won't be seen, as we
  // are running in fullScreen mode
  // but it's always nice to have a quit command
  canvas.addCommand(new Command("Quit", Command.EXIT, 1));
 
  // Set the listener to be the MIDlet
  canvas.setCommandListener(this);
 
  // Start canvas
  canvas.start();
  display.setCurrent(canvas);
 
  // Set the self
  self = this;
 }
 /** Called when the game should pause, sUCh as during a call */
 protected void pauseApp()
 {
 
 }
 /** Called when the application should shut down */
 protected void destroyApp(boolean unconditional) throws MIDletStateChangeException
 {
   // Method that shuts down the entire MIDlet
  notifyDestroyed();
 }
 /** Listens to commands and processes */
   public void commandAction(Command c, Displayable d) {
     // If we get an EXIT command we destroy the application
     if(c.getCommandType() == Command.EXIT)
       notifyDestroyed();
   }
  
   /** Static method that quits our application
   * by using the static field 'self' */
   public static void die()
   {
     self.notifyDestroyed();
   }
}
 
M3GCanvas
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.m3g.Background;
import javax.microedition.m3g.Camera;
import javax.microedition.m3g.Graphics3D;
import javax.microedition.m3g.Light;
import javax.microedition.m3g.Transform;
public class M3GCanvas
extends GameCanvas
implements Runnable {
   // Thread-control
   boolean running = false;
   boolean done = true;
  
   // If the game should end
   public static boolean gameOver = false;
  
   // Rendering hints
   public static final int STRONG_RENDERING_HINTS = Graphics3D.ANTIALIAS Graphics3D.TRUE_COLOR Graphics3D.DITHER;
   public static final int WEAK_RENDERING_HINTS = 0;
   public static int RENDERING_HINTS = STRONG_RENDERING_HINTS;
  
   // Key array
   boolean[] key = new boolean[5];
  
   // Key constants
   public static final int FIRE = 0;
   public static final int UP = FIRE + 1;
   public static final int DOWN = UP + 1;
   public static final int LEFT = DOWN + 1;
   public static final int RIGHT = LEFT + 1;
  
   // Global identity matrix
   Transform identity = new Transform();
  
   // Global Graphics3D object
   Graphics3D g3d = null;
  
   // The background
   Background back = null;
  
   // The global camera object
   Camera cam = null;
  
   // The particle system
   ParticleSystem ps = null;
   FountainEffect fx = null;
  
   /** Constructs the canvas
   */
   public M3GCanvas(int fps)
   {
     // We don't want to capture keys normally
     super(true);
    
     // We want a fullscreen canvas
     setFullScreenMode(true);
    
     // Load our camera
     loadCamera();
    
     // Load our background
     loadBackground();
    
     // Set up graphics 3d
     setUp();
   }
  
   /** Prepares the Graphics3D engine for immediate mode rendering by adding a light */
   private void setUp()
   {
     // Get the instance
     g3d = Graphics3D.getInstance();
    
     // Add a light to our scene, so we can see something
     g3d.addLight(createAmbientLight(), identity);
   }
  
  
   /** Creates a simple ambient light */
   private Light createAmbientLight()
   {
     Light l = new Light();
     l.setMode(Light.AMBIENT);
     l.setIntensity(1.0f);
     return l;
   }
   /** When fullscreen mode is set, some devices will call
   * this method to notify us of the new width/height.
   * However, we don't really care about the width/height
   * in this tutorial so we just let it be
   */
   public void sizeChanged(int newWidth, int newHeight)
   {
    
   }
  
   /** Loads our camera */
   private void loadCamera()
   {
     // Create a new camera
     cam = new Camera();
   }
  
   /** Loads the background */
   private void loadBackground()
   {
     // Create a new background, set bg color to black
     back = new Background();
     back.setColor(0);
   }
   /** Draws to screen
   */  
   private void draw(Graphics g)
   {
     // Envelop all in a try/catch block just in case
     try
     {      
       // Get the Graphics3D context
       g3d = Graphics3D.getInstance();
      
     // First bind the graphics object. We use our pre-defined rendering hints.
     g3d.bindTarget(g, true, RENDERING_HINTS);
    
     // Clear background
     g3d.clear(back);
    
     // Bind camera at fixed position in origo
     g3d.setCamera(cam, identity);
    
     // Init particles
     if(ps == null)
     {
       fx = new FountainEffect(90);
       ps = new ParticleSystem(fx, 20);
     }
    
     // Emit the particles
     ps.emit(g3d);
    
     // Check controls for fountain rotation
     if(key[LEFT])
       fx.setAngle(fx.getAngle() + 5);
     if(key[RIGHT])
       fx.setAngle(fx.getAngle() - 5);
    
     // Quit if user presses fire
     if(key[FIRE])
       TutorialMidlet.die();
     }
     catch(Exception e)
     {
       reportException(e);
     }
     finally
     {
       // Always remember to release!
       g3d.releaseTarget();
     }
   }
   /** Starts the canvas by firing up a thread
   */
   public void start() {
     Thread myThread = new Thread(this);
    
     // Make sure we know we are running
     running = true;
     done = false;
    
     // Start
     myThread.start();
   }
  
   /** Run, runs the whole thread. Also keeps track of FPS
   */
   public void run() {
     while(running) {
       try {        
         // Call the process method (computes keys)
         process();
        
         // Draw everything
         draw(getGraphics());
         flushGraphics();
        
         // Sleep to prevent starvation
         try{ Thread.sleep(30); } catch(Exception e) {}
       }
       catch(Exception e) {
         reportException(e);
       }
     }
    
     // Notify completion
     done = true;
   }
  
   /**
   * @param e
   */
   private void reportException(Exception e) {
     System.out.println(e.getMessage());
     System.out.println(e);
     e.printStackTrace();
   }
   /** Pauses the game
   */
   public void pause() {}
  
   /** Stops the game
   */
   public void stop() { running = false; }
  
   /** Processes keys
   */
   protected void process()
   {
     int keys = getKeyStates();
    
     if((keys & GameCanvas.FIRE_PRESSED) != 0)
       key[FIRE] = true;
     else
       key[FIRE] = false;
    
     if((keys & GameCanvas.UP_PRESSED) != 0)
       key[UP] = true;
     else
       key[UP] = false;
    
     if((keys & GameCanvas.DOWN_PRESSED) != 0)
       key[DOWN] = true;
     else
       key[DOWN] = false;
    
     if((keys & GameCanvas.LEFT_PRESSED) != 0)
       key[LEFT] = true;
     else
       key[LEFT] = false;
    
     if((keys & GameCanvas.RIGHT_PRESSED) != 0)
       key[RIGHT] = true;
     else
       key[RIGHT] = false;
   }
  
   /** Checks if thread is running
   */
   public boolean isRunning() { return running; }
  
   /** checks if thread has finished its execution completely
   */
   public boolean isDone() { return done; }
}
MeshFactory
import javax.microedition.lcdui.Image;
import javax.microedition.m3g.Appearance;
import javax.microedition.m3g.Image2D;
import javax.microedition.m3g.IndexBuffer;
import javax.microedition.m3g.Mesh;
import javax.microedition.m3g.PolygonMode;
import javax.microedition.m3g.Texture2D;
import javax.microedition.m3g.TriangleStripArray;
import javax.microedition.m3g.VertexArray;
import javax.microedition.m3g.VertexBuffer;
/**
 * Static class that handles creation of code-generated Meshes
 */
public class MeshFactory
{
   /** Creates a texture plane that is alpha-blended
   *
   * @param texFilename The name of the texture image file
   * @param cullFlags The flags for culling. See PolygonMode.
   * @param alpha The alpha value of blending. Is a full color in 0xAARRGGBB format
   * @return The finished textured mesh
   */
   public static Mesh createAlphaPlane(String texFilename, int cullFlags, int alpha)
   {
     // Create a normal mesh
     Mesh mesh = createPlane(texFilename, cullFlags);
    
     // Make it blended
     MeshOperator.convertToBlended(mesh, alpha, Texture2D.FUNC_BLEND);
     return mesh;
   }
  
   /**
   * Creates a textured plane.
   * @param texFilename The name of the texture image file
   * @param cullFlags The flags for culling. See PolygonMode.
   * @return The finished textured mesh
   */
   public static Mesh createPlane(String texFilename, int cullFlags)
   {
     // The vertrices of the plane
     short vertrices[] = new short[] {-1, -1, 0,
                    1, -1, 0,
                    1, 1, 0,
                    -1, 1, 0};
     // Texture coords of the plane
     short texCoords[] = new short[] {0, 255,
                     255, 255,
                     255, 0,
                     0, 0};
    
     // The classes
     VertexArray vertexArray, texArray;
     IndexBuffer triangles;
     // Create the model's vertrices
     vertexArray = new VertexArray(vertrices.length/3, 3, 2);
     vertexArray.set(0, vertrices.length/3, vertrices);
    
     // Create the model's texture coords
     texArray = new VertexArray(texCoords.length / 2, 2, 2);
     texArray.set(0, texCoords.length / 2, texCoords);
    
     // Compose a VertexBuffer out of the previous vertrices and texture coordinates
     VertexBuffer vertexBuffer = new VertexBuffer();
     vertexBuffer.setPositions(vertexArray, 1.0f, null);
     vertexBuffer.setTexCoords(0, texArray, 1.0f/255.0f, null);
    
     // Create indices and face lengths
     int indices[] = new int[] {0, 1, 3, 2};
     int[] stripLengths = new int[] {4};
    
     // Create the model's triangles
     triangles = new TriangleStripArray(indices, stripLengths);
     // Create the appearance
     Appearance appearance = new Appearance();
     PolygonMode pm = new PolygonMode();
     pm.setCulling(cullFlags);
     appearance.setPolygonMode(pm);
     // Create and set the texture
     try
     {
       // Open image
       Image texImage = Image.createImage(texFilename);
       Texture2D theTexture = new Texture2D(new Image2D(Image2D.RGBA, texImage));
      
       // Replace the mesh's original colors (no blending)
       theTexture.setBlending(Texture2D.FUNC_REPLACE);
      
       // Set wrapping and filtering
       theTexture.setWrapping(Texture2D.WRAP_CLAMP, Texture2D.WRAP_CLAMP);
       theTexture.setFiltering(Texture2D.FILTER_BASE_LEVEL, Texture2D.FILTER_NEAREST);
       // Add texture to the appearance
       appearance.setTexture(0, theTexture);
     }
     catch(Exception e)
     {
       // Something went wrong
       System.out.println("Failed to create texture");
       System.out.println(e);
     }
    
     // Finally create the Mesh
     Mesh mesh = new Mesh(vertexBuffer, triangles, appearance);
     // All done
     return mesh;
   }
}
MeshOperator
import javax.microedition.m3g.CompositingMode;
import javax.microedition.m3g.Mesh;
/**
 * Performs some basic operations on Mesh objects
 */
public class MeshOperator
{
   /** Sets the alpha blending of a mesh. Only meaningful if the mesh already is alpha blended */
   public static void setMeshAlpha(Mesh m, int alpha)
   {
     m.getVertexBuffer().setDefaultColor(alpha);
   }
  
   /**
   *
   * @param m The mesh to convert to a blended one
   * @param alpha The alpha color to blend with
   * @param textureBlending The texture blending parameter.
   */
   public static void convertToBlended(Mesh m, int alpha, int textureBlending)
   {
     // Set the alpha
     setMeshAlpha(m, alpha);
    
     // Fix the compositing mode
     CompositingMode cm = new CompositingMode();
     cm.setBlending(CompositingMode.ALPHA);
     m.getAppearance(0).setCompositingMode(cm);
     m.getAppearance(0).getTexture(0).setBlending(textureBlending);
   }
}
Particle
/**
 * Holds all the information of a particle.
 * A particle's alpha is controlled directly by its life. Its alpha is always
 * life * 255.
 */
public class Particle
{
   // The life of the particle. Goes from 1.0f to 0.0f
   private float life = 1.0f;
  
   // The degradation of the particle
   private float degradation = 0.1f;
  
   // The velocities of the particle
   private float[] vel = {0.0f, 0.0f, 0.0f};
  
   // The position of the particle
   private float[] pos = {0.0f, 0.0f, 0.0f};
  
   // The color of the particle (RGB format 0xRRGGBB)
   private int color = 0xffffff;
  
   /** Empty initialization */
   public Particle()
   {
    
   }
  
   /**
   * Initializes the particle
   * @param velocity Sets the velocity
   * @param position Sets the position
   * @param color Sets the color (no alpha)
   */
   public Particle(float[] velocity, float[] position, int color)
   {
     setVel(velocity);
     setPos(position);
     this.setColor(color);
   }
   /**
   * @param life The life to set.
   */
   void setLife(float life) {
     this.life = life;
   }
   /**
   * @return Returns the life.
   */
   float getLife() {
     return life;
   }
   /**
   * @param vel The vel to set.
   */
   void setVel(float[] tvel) {
     System.arraycopy(tvel, 0, vel, 0, vel.length);
   }
   /**
   * @return Returns the vel.
   */
   float[] getVel() {
     return vel;
   }
   /**
   * @param pos The pos to set.
   */
   void setPos(float[] tpos) {
     System.arraycopy(tpos, 0, pos, 0, pos.length);
   }
   /**
   * @return Returns the pos.
   */
   float[] getPos() {
     return pos;
   }
   /**
   * @param color The color to set.
   */
   void setColor(int color) {
     this.color = color;
   }
   /**
   * @return Returns the color.
   */
   int getColor() {
     return color;
   }
   /**
   * @param degradation The degradation to set.
   */
   public void setDegradation(float degradation) {
     this.degradation = degradation;
   }
   /**
   * @return Returns the degradation.
   */
   public float getDegradation() {
     return degradation;
   }
}
ParticleEffect
import javax.microedition.m3g.Graphics3D;
/**
 * The interface that determines which effect the particle engine will display.
 * The ParticleEffect class also holds information about the bitmap used
 * for displaying particles (if any)
 */
public interface ParticleEffect
{
   // Initializes a particle
   public void init(Particle p);
  
   // Updates a particle
   public void update(Particle p);
  
   // Renders a particle
   public void render(Particle p, Graphics3D g3d);
}
BitmapParticleEffect
import javax.microedition.m3g.Graphics3D;
import javax.microedition.m3g.Mesh;
import javax.microedition.m3g.PolygonMode;
import javax.microedition.m3g.Transform;
/**
 * Represents a particle effect that uses a bitmap.
 */
public abstract class BitmapParticleEffect implements ParticleEffect
{
   // The mesh
   Mesh mesh = null;
  
   // The transformation matrix
   Transform trans = new Transform();
  
   // The scale
   float scale = 1.0f;
  
   /** Initializes the bitmap used to render particles */
   public BitmapParticleEffect(String filename, float scale)
   {
     // Load the plane with the wanted texture
     mesh = MeshFactory.createAlphaPlane(filename, PolygonMode.CULL_BACK, 0xffffffff);
    
     // Make sure we set the scale
     this.scale = scale;
   }
  
   /**
   * @see ParticleEffect#render(Particle, Graphics3D)
   */
   public void render(Particle p, Graphics3D g3d)
   {
     // Calculate the alpha
     int alpha = (int)(255 * p.getLife());
    
     // Create the color
     int color = p.getColor() (alpha << 24);
    
     // Set alpha
     MeshOperator.setMeshAlpha(mesh, color);
    
     // Transform
     trans.setIdentity();
     trans.postScale(scale, scale, scale);
     float[] pos = p.getPos();
     trans.postTranslate(pos[0], pos[1], pos[2]);
    
     // Render
     g3d.render(mesh, trans);
   }
}
FountainEffect
import java.util.Random;
/*
 * Created on 2005-aug-31
 */
/**
 * Creates a nice fountain effect for the particles, that shoots particles
 * in a certain direction, determined by its angle. The angle can be changed in real-time.
 */
public class FountainEffect extends BitmapParticleEffect
{
   // The angle of particle emission
   private int angle = 90;
  
   // The sine and cosine of the current angle
   private float[] trig = {1.0f, 0.0f};
  
   // The emitting origin
   private float[] pos = {0.0f, 0.0f, 0.0f};
  
   // The randomizer
   Random rand = null;
  
   /**
   * @param angle The angle of particle emission
   */
   public FountainEffect(int angle)
   {
     // Init the bitmap
     super("/res/particle.png", 0.05f);
    
     // Set the angle
     setAngle(angle);
    
     // Get randomizer
     rand = new Random();
   }
   /**
   * @see ParticleEffect#init(Particle)
   */
   public void init(Particle p)
   {
     // Set the particle's life
     p.setLife(1.0f);
    
     // Set the particle's position
     p.setPos(pos);
    
     // Create the particle's velocties
     float[] vel = new float[3];
    
     // We want velocities from 0.2f to 1.0f
     float xyvel = rand.nextFloat() * 0.8f + 0.2f;
    
     // We want the particle to die slowly
     p.setDegradation(xyvel / 18);
    
     // Set velocities according to trigonometry with a small deviation
     vel[0] = xyvel * trig[1] + rand.nextFloat() * 0.125f - 0.0625f;
     vel[1] = xyvel * trig[0] + rand.nextFloat() * 0.125f - 0.0625f;
    
     // No movement in depth
     vel[2] = 0.0f;
    
     // Set the velocity
     p.setVel(vel);
    
     // Set the random color
     int r = (int)(120 * rand.nextFloat()) + 135;
     int g = (int)(120 * rand.nextFloat()) + 135;
     int b = (int)(120 * rand.nextFloat()) + 135;
     int col = (r << 16) (g << 8) b;
     p.setColor(col);
   }
   /**
   * @see ParticleEffect#update(Particle)
   */
   public void update(Particle p)
   {
     // Simply update position
     float[] ppos = p.getPos();
     float[] vel = p.getVel();
     ppos[0] += vel[0];
     ppos[1] += vel[1];
     ppos[2] += vel[2];
    
     // Update life
     p.setLife(p.getLife() - p.getDegradation());
    
     // Check life. If it is dead, we just reinit it
     if(p.getLife() < -0.001f)
     {
       init(p);
     }
   }
   /**
   * @param angle The angle to set.
   */
   public void setAngle(int angle) {
     this.angle = angle;
     trig[0] = (float)Math.sin(Math.toRadians(angle));
     trig[1] = (float)Math.cos(Math.toRadians(angle));
   }
   /**
   * @return Returns the angle.
   */
   public int getAngle() {
     return angle;
   }
   /**
   * @param pos The pos to set.
   */
   void setEmittingOrigin(float[] pos) {
     this.pos = pos;
   }
   /**
   * @return Returns the pos.
   */
   float[] getEmittingOrigin() {
     return pos;
   }
}
ParticleSystem
import javax.microedition.m3g.Graphics3D;
/**
 * Manages emission of particles in our 3D world
 */
public class ParticleSystem
{
   // The effect
   private ParticleEffect effect = null;
  
   // The particles
   Particle[] parts = null;
  
   /**
   * Creates a particle system that emits particles according to a defined effect.
   * @param effect The effect that controls the behaviour of the particles
   * @param numParticles The number of particles to emit
   */
   public ParticleSystem(ParticleEffect effect, int numParticles)
   {
     // Copy the effect
     setEffect(effect);
    
     // Init the particles
     parts = new Particle[numParticles];
     for(int i = 0; i < numParticles; i++)
     {
       parts[i] = new Particle();
       effect.init(parts[i]);
     }
   }
  
   /** The method that does it all. Needs to be called every tick of a game loop */
   public void emit(Graphics3D g3d)
   {
     for(int i = 0; i < parts.length; i++)
     {
       getEffect().update(parts[i]);
       getEffect().render(parts[i], g3d);
     }
   }
   /**
   * @param effect The effect to set.
   */
   public void setEffect(ParticleEffect effect) {
     this.effect = effect;
   }
/**
   * @return Returns the effect.
   */
   public ParticleEffect getEffect() {
     return effect;
   }
}

原文地址:http://developer.sonyeriCSSon.com/site/global/techsupport/tipstrickscode/mobilejava3d/p_java3d_tutorial_part3_compliments_redikod.jsp


Tags:编程 指南 第三

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接