Selaa lähdekoodia

Support for Newtonian Physics in particles importing.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7565 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
Kae..pl 14 vuotta sitten
vanhempi
sitoutus
c6be5633ce

+ 109 - 3
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java

@@ -31,6 +31,7 @@
  */
  */
 package com.jme3.scene.plugins.blender.helpers.v249;
 package com.jme3.scene.plugins.blender.helpers.v249;
 
 
+import java.nio.ByteBuffer;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
@@ -39,12 +40,14 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
 import com.jme3.asset.BlenderKey.FeaturesToLoad;
 import com.jme3.asset.BlenderKey.FeaturesToLoad;
+import com.jme3.asset.TextureKey;
 import com.jme3.material.MatParam;
 import com.jme3.material.MatParam;
 import com.jme3.material.Material;
 import com.jme3.material.Material;
 import com.jme3.material.Material.MatParamTexture;
 import com.jme3.material.Material.MatParamTexture;
 import com.jme3.material.RenderState.BlendMode;
 import com.jme3.material.RenderState.BlendMode;
 import com.jme3.material.RenderState.FaceCullMode;
 import com.jme3.material.RenderState.FaceCullMode;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
 import com.jme3.scene.plugins.blender.data.Structure;
 import com.jme3.scene.plugins.blender.data.Structure;
 import com.jme3.scene.plugins.blender.exception.BlenderFileException;
 import com.jme3.scene.plugins.blender.exception.BlenderFileException;
 import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
@@ -53,8 +56,11 @@ import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType
 import com.jme3.scene.plugins.blender.utils.DynamicArray;
 import com.jme3.scene.plugins.blender.utils.DynamicArray;
 import com.jme3.scene.plugins.blender.utils.Pointer;
 import com.jme3.scene.plugins.blender.utils.Pointer;
 import com.jme3.shader.VarType;
 import com.jme3.shader.VarType;
+import com.jme3.texture.Image;
+import com.jme3.texture.Image.Format;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture.WrapMode;
 import com.jme3.texture.Texture.WrapMode;
+import com.jme3.util.BufferUtils;
 
 
 public class MaterialHelper extends AbstractBlenderHelper {
 public class MaterialHelper extends AbstractBlenderHelper {
 	private static final Logger		LOGGER					= Logger.getLogger(MaterialHelper.class.getName());
 	private static final Logger		LOGGER					= Logger.getLogger(MaterialHelper.class.getName());
@@ -67,6 +73,12 @@ public class MaterialHelper extends AbstractBlenderHelper {
 	public static final String		TEXTURE_TYPE_GLOW		= "GlowMap";
 	public static final String		TEXTURE_TYPE_GLOW		= "GlowMap";
 	public static final String		TEXTURE_TYPE_ALPHA		= "AlphaMap";
 	public static final String		TEXTURE_TYPE_ALPHA		= "AlphaMap";
 
 
+	public static final Integer		ALPHA_MASK_NONE			= Integer.valueOf(0);
+	public static final Integer		ALPHA_MASK_CIRCLE		= Integer.valueOf(1);
+	public static final Integer		ALPHA_MASK_CONE			= Integer.valueOf(2);
+	public static final Integer		ALPHA_MASK_HYPERBOLE	= Integer.valueOf(3);
+	protected final Map<Integer, IAlphaMask> alphaMasks = new HashMap<Integer, IAlphaMask>();
+	
 	/**
 	/**
 	 * The type of the material's diffuse shader.
 	 * The type of the material's diffuse shader.
 	 */
 	 */
@@ -93,6 +105,64 @@ public class MaterialHelper extends AbstractBlenderHelper {
 	 */
 	 */
 	public MaterialHelper(String blenderVersion) {
 	public MaterialHelper(String blenderVersion) {
 		super(blenderVersion);
 		super(blenderVersion);
+		//setting alpha masks
+		alphaMasks.put(ALPHA_MASK_NONE, new IAlphaMask() {
+			@Override
+			public void setImageSize(int width, int height) {}
+			
+			@Override
+			public byte getAlpha(float x, float y) {
+				return (byte)255;
+			}
+		});
+		alphaMasks.put(ALPHA_MASK_CIRCLE, new IAlphaMask() {
+			private float r;
+			private float[] center;
+			
+			@Override
+			public void setImageSize(int width, int height) {
+				r = Math.min(width, height) * 0.5f;
+				center = new float[] {width*0.5f, height * 0.5f};
+			}
+			
+			@Override
+			public byte getAlpha(float x, float y) {
+				float d = FastMath.abs(FastMath.sqrt((x-center[0])*(x-center[0]) + (y-center[1])*(y-center[1])));
+				return (byte)(d>=r ? 0 : 255);
+			}
+		});
+		alphaMasks.put(ALPHA_MASK_CONE, new IAlphaMask() {
+			private float r;
+			private float[] center;
+			
+			@Override
+			public void setImageSize(int width, int height) {
+				r = Math.min(width, height) * 0.5f;
+				center = new float[] {width*0.5f, height * 0.5f};
+			}
+			
+			@Override
+			public byte getAlpha(float x, float y) {
+				float d = FastMath.abs(FastMath.sqrt((x-center[0])*(x-center[0]) + (y-center[1])*(y-center[1])));
+				return (byte)(d>=r ? 0 : -255.0f*d/r+255.0f);
+			}
+		});
+		alphaMasks.put(ALPHA_MASK_HYPERBOLE, new IAlphaMask() {
+			private float r;
+			private float[] center;
+			
+			@Override
+			public void setImageSize(int width, int height) {
+				r = Math.min(width, height) * 0.5f;
+				center = new float[] {width*0.5f, height * 0.5f};
+			}
+			
+			@Override
+			public byte getAlpha(float x, float y) {
+				float d = FastMath.abs(FastMath.sqrt((x-center[0])*(x-center[0]) + (y-center[1])*(y-center[1]))) / r;
+				return d>=1.0f ? 0 : (byte)((-FastMath.sqrt((2.0f-d)*d)+1.0f)*255.0f);
+			}
+		});
 	}
 	}
 
 
 	/**
 	/**
@@ -287,13 +357,36 @@ public class MaterialHelper extends AbstractBlenderHelper {
 	 * @param dataRepository the data repository
 	 * @param dataRepository the data repository
 	 * @return material converted into particles-usable material
 	 * @return material converted into particles-usable material
 	 */
 	 */
-	public Material getParticlesMaterial(Material material, DataRepository dataRepository) {
+	public Material getParticlesMaterial(Material material, Integer alphaMaskIndex, DataRepository dataRepository) {
 		Material result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
 		Material result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
 		
 		
 		//copying texture
 		//copying texture
 		MatParam diffuseMap = material.getParam("DiffuseMap");
 		MatParam diffuseMap = material.getParam("DiffuseMap");
 		if(diffuseMap!=null) {
 		if(diffuseMap!=null) {
-			Texture texture = (Texture) diffuseMap.getValue();
+			Texture texture = ((Texture) diffuseMap.getValue()).clone();
+			
+			//applying alpha mask to the texture
+			Image image = texture.getImage();
+			ByteBuffer sourceBB = image.getData(0);
+			sourceBB.rewind();
+			int w = image.getWidth();
+			int h = image.getHeight();
+			ByteBuffer bb = BufferUtils.createByteBuffer(w * h * 4);
+			IAlphaMask iAlphaMask = alphaMasks.get(alphaMaskIndex);
+			iAlphaMask.setImageSize(w, h);
+			
+			for(int x=0;x<w;++x) {
+				for(int y=0;y<h;++y) {
+					bb.put(sourceBB.get());
+					bb.put(sourceBB.get());
+					bb.put(sourceBB.get());
+					bb.put(iAlphaMask.getAlpha(x, y));
+				}
+			}
+
+			image = new Image(Format.RGBA8, w, h, bb);
+			texture.setImage(image);
+			
 			result.setTextureParam("Texture", VarType.Texture2D, texture);
 			result.setTextureParam("Texture", VarType.Texture2D, texture);
 		}
 		}
 		
 		
@@ -303,9 +396,17 @@ public class MaterialHelper extends AbstractBlenderHelper {
 			ColorRGBA color = (ColorRGBA) glowColor.getValue();
 			ColorRGBA color = (ColorRGBA) glowColor.getValue();
 			result.setParam("GlowColor", VarType.Vector3, color);
 			result.setParam("GlowColor", VarType.Vector3, color);
 		}
 		}
-		//material.setTexture("Texture", dataRepository.getAssetManager().loadTexture("Effects/Explosion/flame.png"));
 		return result;
 		return result;
 	}
 	}
+	
+	protected byte calculateAlpha(float x, float y) {
+		return (byte)255;
+	}
+	
+	protected Texture loadParticleAlphaMapTexture(DataRepository dataRepository) {
+		TextureKey textureKey = new TextureKey(this.getClass().getPackage().getName().replace('.', '/') + "/particle_alpha_map.png");
+		return dataRepository.getAssetManager().loadTexture(textureKey);
+	}
 
 
 	/**
 	/**
 	 * This method indicates if the material has a texture of a specified type.
 	 * This method indicates if the material has a texture of a specified type.
@@ -586,4 +687,9 @@ public class MaterialHelper extends AbstractBlenderHelper {
 			}
 			}
 		}
 		}
 	}
 	}
+	
+	protected static interface IAlphaMask {
+		void setImageSize(int width, int height);
+		byte getAlpha(float x, float y);
+	}
 }
 }

+ 4 - 4
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MeshHelper.java

@@ -301,13 +301,13 @@ public class MeshHelper extends AbstractBlenderHelper {
 
 
 			// creating vertices indices for this mesh
 			// creating vertices indices for this mesh
 			List<Integer> indexList = meshEntry.getValue();
 			List<Integer> indexList = meshEntry.getValue();
-			int[] indices = new int[indexList.size()];
-			for (int i = 0; i < indexList.size(); ++i) {
-				indices[i] = indexList.get(i).intValue();
+			short[] indices = new short[indexList.size()];//TODO: check if the model doesn't have more than 32767 vertices
+			for (int i = 0; i < indexList.size(); ++i) {//if yes then mesh.getVertices method must be changed to accept other than ShortBuffer
+				indices[i] = indexList.get(i).shortValue();
 			}
 			}
 
 
 			// setting vertices
 			// setting vertices
-			mesh.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(indices));
+			mesh.setBuffer(Type.Index, 1, BufferUtils.createShortBuffer(indices));
 			mesh.setBuffer(verticesBuffer);
 			mesh.setBuffer(verticesBuffer);
 			mesh.setBuffer(verticesBind);
 			mesh.setBuffer(verticesBind);
 
 

+ 27 - 13
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java

@@ -235,28 +235,42 @@ public class ModifierHelper extends AbstractBlenderHelper {
 		}
 		}
 	}
 	}
 	
 	
+	/**
+	 * This method applies particles emitter to the given node.
+	 * @param node the particles emitter node
+	 * @param modifier the modifier containing the emitter data
+	 * @param dataRepository the data repository
+	 * @return node with particles' emitter applied
+	 */
 	protected Node applyParticleSystemModifierData(Node node, Modifier modifier, DataRepository dataRepository) {
 	protected Node applyParticleSystemModifierData(Node node, Modifier modifier, DataRepository dataRepository) {
 		MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
 		MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
 		ParticleEmitter emitter = (ParticleEmitter) modifier.getJmeModifierRepresentation();
 		ParticleEmitter emitter = (ParticleEmitter) modifier.getJmeModifierRepresentation();
 		emitter = emitter.clone();
 		emitter = emitter.clone();
 
 
+		//veryfying the alpha function for particles' texture
+		Integer alphaFunction = MaterialHelper.ALPHA_MASK_HYPERBOLE;
+		char nameSuffix = emitter.getName().charAt(emitter.getName().length()-1);
+		if(nameSuffix=='B' || nameSuffix=='N') {
+			alphaFunction = MaterialHelper.ALPHA_MASK_NONE;
+		}
+		//removing the type suffix from the name
+		emitter.setName(emitter.getName().substring(0, emitter.getName().length()-1));
+		
 		//applying emitter shape
 		//applying emitter shape
 		EmitterShape emitterShape = emitter.getShape();
 		EmitterShape emitterShape = emitter.getShape();
-		if(emitterShape instanceof EmitterMeshVertexShape) {
-			List<Mesh> meshes = new ArrayList<Mesh>();
-			for(Spatial spatial : node.getChildren()) {
-				if(spatial instanceof Geometry) {
-					Mesh mesh = ((Geometry) spatial).getMesh();
-					if(mesh != null) {
-						meshes.add(mesh);
-						Material material = materialHelper.getParticlesMaterial(((Geometry) spatial).getMaterial(), dataRepository);
-						emitter.setMaterial(material);//TODO: rozbić na kilka części
-					}
+		List<Mesh> meshes = new ArrayList<Mesh>();
+		for(Spatial spatial : node.getChildren()) {
+			if(spatial instanceof Geometry) {
+				Mesh mesh = ((Geometry) spatial).getMesh();
+				if(mesh != null) {
+					meshes.add(mesh);
+					Material material = materialHelper.getParticlesMaterial(((Geometry) spatial).getMaterial(), alphaFunction, dataRepository);
+					emitter.setMaterial(material);//TODO: divide into several pieces
 				}
 				}
 			}
 			}
-			if(meshes.size()>0) {
-				((EmitterMeshVertexShape) emitterShape).setMeshes(meshes);
-			}
+		}
+		if(meshes.size()>0 && emitterShape instanceof EmitterMeshVertexShape) {
+			((EmitterMeshVertexShape) emitterShape).setMeshes(meshes);
 		}
 		}
 		
 		
 		node.attachChild(emitter);
 		node.attachChild(emitter);

+ 87 - 15
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ParticlesHelper.java

@@ -7,8 +7,10 @@ import com.jme3.effect.EmitterMeshFaceShape;
 import com.jme3.effect.EmitterMeshVertexShape;
 import com.jme3.effect.EmitterMeshVertexShape;
 import com.jme3.effect.ParticleEmitter;
 import com.jme3.effect.ParticleEmitter;
 import com.jme3.effect.ParticleMesh.Type;
 import com.jme3.effect.ParticleMesh.Type;
+import com.jme3.effect.influencers.EmptyParticleInfluencer;
+import com.jme3.effect.influencers.ParticleInfluencer;
+import com.jme3.effect.influencers.NewtonianParticleInfluencer;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.ColorRGBA;
-import com.jme3.math.Vector3f;
 import com.jme3.scene.plugins.blender.data.Structure;
 import com.jme3.scene.plugins.blender.data.Structure;
 import com.jme3.scene.plugins.blender.exception.BlenderFileException;
 import com.jme3.scene.plugins.blender.exception.BlenderFileException;
 import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
@@ -62,6 +64,24 @@ public class ParticlesHelper extends AbstractBlenderHelper {
 	public static final int PART_FROM_PARTICLE	=3;
 	public static final int PART_FROM_PARTICLE	=3;
 	public static final int PART_FROM_CHILD		=4;
 	public static final int PART_FROM_CHILD		=4;
 	
 	
+	// part->phystype
+	public static final int PART_PHYS_NO	=	0;
+	public static final int PART_PHYS_NEWTON=	1;
+	public static final int PART_PHYS_KEYED	=	2;
+	public static final int PART_PHYS_BOIDS	=	3;
+	
+	// part->draw_as
+	public static final int PART_DRAW_NOT	=	0;
+	public static final int PART_DRAW_DOT	=	1;
+	public static final int PART_DRAW_CIRC	=	2;
+	public static final int PART_DRAW_CROSS	=	3;
+	public static final int PART_DRAW_AXIS	=	4;
+	public static final int PART_DRAW_LINE	=	5;
+	public static final int PART_DRAW_PATH	=	6;
+	public static final int PART_DRAW_OB	=	7;
+	public static final int PART_DRAW_GR	=	8;
+	public static final int PART_DRAW_BB	=	9;
+	
 	/**
 	/**
 	 * This constructor parses the given blender version and stores the result. Some functionalities may differ in
 	 * This constructor parses the given blender version and stores the result. Some functionalities may differ in
 	 * different blender versions.
 	 * different blender versions.
@@ -78,8 +98,35 @@ public class ParticlesHelper extends AbstractBlenderHelper {
 		Pointer pParticleSettings = (Pointer) particleSystem.getFieldValue("part");
 		Pointer pParticleSettings = (Pointer) particleSystem.getFieldValue("part");
 		if(!pParticleSettings.isNull()) {
 		if(!pParticleSettings.isNull()) {
 			Structure particleSettings = pParticleSettings.fetchData(dataRepository.getInputStream()).get(0);
 			Structure particleSettings = pParticleSettings.fetchData(dataRepository.getInputStream()).get(0);
+			
 			int totPart = ((Number) particleSettings.getFieldValue("totpart")).intValue();
 			int totPart = ((Number) particleSettings.getFieldValue("totpart")).intValue();
-			result = new ParticleEmitter(particleSettings.getName(), Type.Triangle, totPart);
+			
+			//draw type will be stored temporarily in the name (it is used during modifier applying operation)
+			int drawAs = ((Number)particleSettings.getFieldValue("draw_as")).intValue();
+			char nameSuffix;//P - point, L - line, N - None, B - Bilboard
+			switch(drawAs) {
+				case PART_DRAW_NOT:
+					nameSuffix = 'N';
+					totPart = 0;//no need to generate particles in this case
+					break;
+				case PART_DRAW_BB:
+					nameSuffix = 'B';
+					break;
+				case PART_DRAW_OB:
+				case PART_DRAW_GR:
+					nameSuffix = 'P';
+					LOGGER.warning("Neither object nor group particles supported yet! Using point representation instead!");//TODO: support groups and aobjects
+					break;
+				case PART_DRAW_LINE:
+					nameSuffix = 'L';
+					LOGGER.warning("Lines not yet supported! Using point representation instead!");//TODO: support lines
+				default://all others are rendered as points in blender
+					nameSuffix = 'P';
+			}
+			result = new ParticleEmitter(particleSettings.getName()+nameSuffix, Type.Triangle, totPart);
+			if(nameSuffix=='N') {
+				return result;//no need to set anything else
+			}
 			
 			
 			//setting the emitters shape (the shapes meshes will be set later during modifier applying operation)
 			//setting the emitters shape (the shapes meshes will be set later during modifier applying operation)
 			int from = ((Number)particleSettings.getFieldValue("from")).intValue();
 			int from = ((Number)particleSettings.getFieldValue("from")).intValue();
@@ -94,24 +141,49 @@ public class ParticlesHelper extends AbstractBlenderHelper {
 					result.setShape(new EmitterMeshConvexHullShape());
 					result.setShape(new EmitterMeshConvexHullShape());
 					break;
 					break;
 				default:
 				default:
-					LOGGER.warning("Default shape used! Unknown emitter shape value ('from' parameter): " + from);
+					LOGGER.warning("Default shape used! Unknown emitter shape value ('from' parameter: " + from + ')');
 			}
 			}
 			
 			
 			//reading acceleration
 			//reading acceleration
 			DynamicArray<Number> acc = (DynamicArray<Number>) particleSettings.getFieldValue("acc");
 			DynamicArray<Number> acc = (DynamicArray<Number>) particleSettings.getFieldValue("acc");
-			result.setInitialVelocity(new Vector3f(acc.get(0).floatValue(), acc.get(1).floatValue(), acc.get(2).floatValue()));
-			result.setGravity(0);//by default gravity is set to 0.1f so we need to disable it completely
-			// 2x2 texture animation
-			result.setImagesX(2);
-			result.setImagesY(2);
-			result.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f));   // red
-			result.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow
-			result.setStartSize(1.5f);
-			result.setEndSize(0.1f);
+			result.setGravity(-acc.get(0).floatValue(), -acc.get(1).floatValue(), -acc.get(2).floatValue());
+			
+			//setting the colors
+			result.setEndColor(new ColorRGBA(1f, 1f, 1f, 1f));
+			result.setStartColor(new ColorRGBA(1f, 1f, 1f, 1f));
+			
+			//reading size
+			float sizeFactor = nameSuffix=='B' ? 1.0f : 0.3f;
+			float size = ((Number)particleSettings.getFieldValue("size")).floatValue() * sizeFactor;
+			result.setStartSize(size);
+			result.setEndSize(size);
 			
 			
-			result.setLowLife(0.5f);
-		    result.setHighLife(3f);
-		    result.setVelocityVariation(0.3f);
+			//reading lifetime
+			int fps = dataRepository.getBlenderKey().getFps();
+			float lifetime = ((Number)particleSettings.getFieldValue("lifetime")).floatValue() / fps;
+			float randlife = ((Number)particleSettings.getFieldValue("randlife")).floatValue() / fps;
+			result.setLowLife(lifetime * (1.0f - randlife));
+		    result.setHighLife(lifetime);
+		    
+		    //preparing influencer
+		    ParticleInfluencer influencer;
+		    int phystype = ((Number)particleSettings.getFieldValue("phystype")).intValue();
+		    switch(phystype) {
+		    	case PART_PHYS_NEWTON:
+		    		influencer = new NewtonianParticleInfluencer();
+		    		((NewtonianParticleInfluencer)influencer).setNormalVelocity(((Number)particleSettings.getFieldValue("normfac")).floatValue());
+		    		((NewtonianParticleInfluencer)influencer).setVelocityVariation(((Number)particleSettings.getFieldValue("randfac")).floatValue());
+		    		((NewtonianParticleInfluencer)influencer).setSurfaceTangentFactor(((Number)particleSettings.getFieldValue("tanfac")).floatValue());
+		    		((NewtonianParticleInfluencer)influencer).setSurfaceTangentRotation(((Number)particleSettings.getFieldValue("tanphase")).floatValue());
+		    		break;
+		    	case PART_PHYS_BOIDS:
+		    	case PART_PHYS_KEYED://TODO: support other influencers
+		    		LOGGER.warning("Boids and Keyed particles physic not yet supported! Empty influencer used!");
+		    	case PART_PHYS_NO:
+	    		default:
+	    			influencer = new EmptyParticleInfluencer();
+		    }
+		    result.setParticleInfluencer(influencer);
 		}
 		}
 		return result;
 		return result;
 	}
 	}