OSDN Git Service

Support for Newtonian Physics in particles importing.
authorKaelthas_Spellsinger@o2.pl <Kaelthas_Spellsinger@o2.pl@75d07b2b-3a1a-0410-a2c5-0572b91ccdca>
Fri, 10 Jun 2011 16:21:08 +0000 (16:21 +0000)
committerKaelthas_Spellsinger@o2.pl <Kaelthas_Spellsinger@o2.pl@75d07b2b-3a1a-0410-a2c5-0572b91ccdca>
Fri, 10 Jun 2011 16:21:08 +0000 (16:21 +0000)
git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@7565 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MeshHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ParticlesHelper.java

index f273053..1aacb82 100644 (file)
@@ -31,6 +31,7 @@
  */\r
 package com.jme3.scene.plugins.blender.helpers.v249;\r
 \r
+import java.nio.ByteBuffer;\r
 import java.util.HashMap;\r
 import java.util.List;\r
 import java.util.Map;\r
@@ -39,12 +40,14 @@ import java.util.logging.Level;
 import java.util.logging.Logger;\r
 \r
 import com.jme3.asset.BlenderKey.FeaturesToLoad;\r
+import com.jme3.asset.TextureKey;\r
 import com.jme3.material.MatParam;\r
 import com.jme3.material.Material;\r
 import com.jme3.material.Material.MatParamTexture;\r
 import com.jme3.material.RenderState.BlendMode;\r
 import com.jme3.material.RenderState.FaceCullMode;\r
 import com.jme3.math.ColorRGBA;\r
+import com.jme3.math.FastMath;\r
 import com.jme3.scene.plugins.blender.data.Structure;\r
 import com.jme3.scene.plugins.blender.exception.BlenderFileException;\r
 import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;\r
@@ -53,8 +56,11 @@ import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType
 import com.jme3.scene.plugins.blender.utils.DynamicArray;\r
 import com.jme3.scene.plugins.blender.utils.Pointer;\r
 import com.jme3.shader.VarType;\r
+import com.jme3.texture.Image;\r
+import com.jme3.texture.Image.Format;\r
 import com.jme3.texture.Texture;\r
 import com.jme3.texture.Texture.WrapMode;\r
+import com.jme3.util.BufferUtils;\r
 \r
 public class MaterialHelper extends AbstractBlenderHelper {\r
        private static final Logger             LOGGER                                  = Logger.getLogger(MaterialHelper.class.getName());\r
@@ -67,6 +73,12 @@ public class MaterialHelper extends AbstractBlenderHelper {
        public static final String              TEXTURE_TYPE_GLOW               = "GlowMap";\r
        public static final String              TEXTURE_TYPE_ALPHA              = "AlphaMap";\r
 \r
+       public static final Integer             ALPHA_MASK_NONE                 = Integer.valueOf(0);\r
+       public static final Integer             ALPHA_MASK_CIRCLE               = Integer.valueOf(1);\r
+       public static final Integer             ALPHA_MASK_CONE                 = Integer.valueOf(2);\r
+       public static final Integer             ALPHA_MASK_HYPERBOLE    = Integer.valueOf(3);\r
+       protected final Map<Integer, IAlphaMask> alphaMasks = new HashMap<Integer, IAlphaMask>();\r
+       \r
        /**\r
         * The type of the material's diffuse shader.\r
         */\r
@@ -93,6 +105,64 @@ public class MaterialHelper extends AbstractBlenderHelper {
         */\r
        public MaterialHelper(String blenderVersion) {\r
                super(blenderVersion);\r
+               //setting alpha masks\r
+               alphaMasks.put(ALPHA_MASK_NONE, new IAlphaMask() {\r
+                       @Override\r
+                       public void setImageSize(int width, int height) {}\r
+                       \r
+                       @Override\r
+                       public byte getAlpha(float x, float y) {\r
+                               return (byte)255;\r
+                       }\r
+               });\r
+               alphaMasks.put(ALPHA_MASK_CIRCLE, new IAlphaMask() {\r
+                       private float r;\r
+                       private float[] center;\r
+                       \r
+                       @Override\r
+                       public void setImageSize(int width, int height) {\r
+                               r = Math.min(width, height) * 0.5f;\r
+                               center = new float[] {width*0.5f, height * 0.5f};\r
+                       }\r
+                       \r
+                       @Override\r
+                       public byte getAlpha(float x, float y) {\r
+                               float d = FastMath.abs(FastMath.sqrt((x-center[0])*(x-center[0]) + (y-center[1])*(y-center[1])));\r
+                               return (byte)(d>=r ? 0 : 255);\r
+                       }\r
+               });\r
+               alphaMasks.put(ALPHA_MASK_CONE, new IAlphaMask() {\r
+                       private float r;\r
+                       private float[] center;\r
+                       \r
+                       @Override\r
+                       public void setImageSize(int width, int height) {\r
+                               r = Math.min(width, height) * 0.5f;\r
+                               center = new float[] {width*0.5f, height * 0.5f};\r
+                       }\r
+                       \r
+                       @Override\r
+                       public byte getAlpha(float x, float y) {\r
+                               float d = FastMath.abs(FastMath.sqrt((x-center[0])*(x-center[0]) + (y-center[1])*(y-center[1])));\r
+                               return (byte)(d>=r ? 0 : -255.0f*d/r+255.0f);\r
+                       }\r
+               });\r
+               alphaMasks.put(ALPHA_MASK_HYPERBOLE, new IAlphaMask() {\r
+                       private float r;\r
+                       private float[] center;\r
+                       \r
+                       @Override\r
+                       public void setImageSize(int width, int height) {\r
+                               r = Math.min(width, height) * 0.5f;\r
+                               center = new float[] {width*0.5f, height * 0.5f};\r
+                       }\r
+                       \r
+                       @Override\r
+                       public byte getAlpha(float x, float y) {\r
+                               float d = FastMath.abs(FastMath.sqrt((x-center[0])*(x-center[0]) + (y-center[1])*(y-center[1]))) / r;\r
+                               return d>=1.0f ? 0 : (byte)((-FastMath.sqrt((2.0f-d)*d)+1.0f)*255.0f);\r
+                       }\r
+               });\r
        }\r
 \r
        /**\r
@@ -287,13 +357,36 @@ public class MaterialHelper extends AbstractBlenderHelper {
         * @param dataRepository the data repository\r
         * @return material converted into particles-usable material\r
         */\r
-       public Material getParticlesMaterial(Material material, DataRepository dataRepository) {\r
+       public Material getParticlesMaterial(Material material, Integer alphaMaskIndex, DataRepository dataRepository) {\r
                Material result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");\r
                \r
                //copying texture\r
                MatParam diffuseMap = material.getParam("DiffuseMap");\r
                if(diffuseMap!=null) {\r
-                       Texture texture = (Texture) diffuseMap.getValue();\r
+                       Texture texture = ((Texture) diffuseMap.getValue()).clone();\r
+                       \r
+                       //applying alpha mask to the texture\r
+                       Image image = texture.getImage();\r
+                       ByteBuffer sourceBB = image.getData(0);\r
+                       sourceBB.rewind();\r
+                       int w = image.getWidth();\r
+                       int h = image.getHeight();\r
+                       ByteBuffer bb = BufferUtils.createByteBuffer(w * h * 4);\r
+                       IAlphaMask iAlphaMask = alphaMasks.get(alphaMaskIndex);\r
+                       iAlphaMask.setImageSize(w, h);\r
+                       \r
+                       for(int x=0;x<w;++x) {\r
+                               for(int y=0;y<h;++y) {\r
+                                       bb.put(sourceBB.get());\r
+                                       bb.put(sourceBB.get());\r
+                                       bb.put(sourceBB.get());\r
+                                       bb.put(iAlphaMask.getAlpha(x, y));\r
+                               }\r
+                       }\r
+\r
+                       image = new Image(Format.RGBA8, w, h, bb);\r
+                       texture.setImage(image);\r
+                       \r
                        result.setTextureParam("Texture", VarType.Texture2D, texture);\r
                }\r
                \r
@@ -303,9 +396,17 @@ public class MaterialHelper extends AbstractBlenderHelper {
                        ColorRGBA color = (ColorRGBA) glowColor.getValue();\r
                        result.setParam("GlowColor", VarType.Vector3, color);\r
                }\r
-               //material.setTexture("Texture", dataRepository.getAssetManager().loadTexture("Effects/Explosion/flame.png"));\r
                return result;\r
        }\r
+       \r
+       protected byte calculateAlpha(float x, float y) {\r
+               return (byte)255;\r
+       }\r
+       \r
+       protected Texture loadParticleAlphaMapTexture(DataRepository dataRepository) {\r
+               TextureKey textureKey = new TextureKey(this.getClass().getPackage().getName().replace('.', '/') + "/particle_alpha_map.png");\r
+               return dataRepository.getAssetManager().loadTexture(textureKey);\r
+       }\r
 \r
        /**\r
         * This method indicates if the material has a texture of a specified type.\r
@@ -586,4 +687,9 @@ public class MaterialHelper extends AbstractBlenderHelper {
                        }\r
                }\r
        }\r
+       \r
+       protected static interface IAlphaMask {\r
+               void setImageSize(int width, int height);\r
+               byte getAlpha(float x, float y);\r
+       }\r
 }\r
index 13f427f..9dd35f5 100644 (file)
@@ -301,13 +301,13 @@ public class MeshHelper extends AbstractBlenderHelper {
 \r
                        // creating vertices indices for this mesh\r
                        List<Integer> indexList = meshEntry.getValue();\r
-                       int[] indices = new int[indexList.size()];\r
-                       for (int i = 0; i < indexList.size(); ++i) {\r
-                               indices[i] = indexList.get(i).intValue();\r
+                       short[] indices = new short[indexList.size()];//TODO: check if the model doesn't have more than 32767 vertices\r
+                       for (int i = 0; i < indexList.size(); ++i) {//if yes then mesh.getVertices method must be changed to accept other than ShortBuffer\r
+                               indices[i] = indexList.get(i).shortValue();\r
                        }\r
 \r
                        // setting vertices\r
-                       mesh.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(indices));\r
+                       mesh.setBuffer(Type.Index, 1, BufferUtils.createShortBuffer(indices));\r
                        mesh.setBuffer(verticesBuffer);\r
                        mesh.setBuffer(verticesBind);\r
 \r
index bd266eb..67c34c6 100644 (file)
@@ -235,28 +235,42 @@ public class ModifierHelper extends AbstractBlenderHelper {
                }\r
        }\r
        \r
+       /**\r
+        * This method applies particles emitter to the given node.\r
+        * @param node the particles emitter node\r
+        * @param modifier the modifier containing the emitter data\r
+        * @param dataRepository the data repository\r
+        * @return node with particles' emitter applied\r
+        */\r
        protected Node applyParticleSystemModifierData(Node node, Modifier modifier, DataRepository dataRepository) {\r
                MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
                ParticleEmitter emitter = (ParticleEmitter) modifier.getJmeModifierRepresentation();\r
                emitter = emitter.clone();\r
 \r
+               //veryfying the alpha function for particles' texture\r
+               Integer alphaFunction = MaterialHelper.ALPHA_MASK_HYPERBOLE;\r
+               char nameSuffix = emitter.getName().charAt(emitter.getName().length()-1);\r
+               if(nameSuffix=='B' || nameSuffix=='N') {\r
+                       alphaFunction = MaterialHelper.ALPHA_MASK_NONE;\r
+               }\r
+               //removing the type suffix from the name\r
+               emitter.setName(emitter.getName().substring(0, emitter.getName().length()-1));\r
+               \r
                //applying emitter shape\r
                EmitterShape emitterShape = emitter.getShape();\r
-               if(emitterShape instanceof EmitterMeshVertexShape) {\r
-                       List<Mesh> meshes = new ArrayList<Mesh>();\r
-                       for(Spatial spatial : node.getChildren()) {\r
-                               if(spatial instanceof Geometry) {\r
-                                       Mesh mesh = ((Geometry) spatial).getMesh();\r
-                                       if(mesh != null) {\r
-                                               meshes.add(mesh);\r
-                                               Material material = materialHelper.getParticlesMaterial(((Geometry) spatial).getMaterial(), dataRepository);\r
-                                               emitter.setMaterial(material);//TODO: rozbić na kilka części\r
-                                       }\r
+               List<Mesh> meshes = new ArrayList<Mesh>();\r
+               for(Spatial spatial : node.getChildren()) {\r
+                       if(spatial instanceof Geometry) {\r
+                               Mesh mesh = ((Geometry) spatial).getMesh();\r
+                               if(mesh != null) {\r
+                                       meshes.add(mesh);\r
+                                       Material material = materialHelper.getParticlesMaterial(((Geometry) spatial).getMaterial(), alphaFunction, dataRepository);\r
+                                       emitter.setMaterial(material);//TODO: divide into several pieces\r
                                }\r
                        }\r
-                       if(meshes.size()>0) {\r
-                               ((EmitterMeshVertexShape) emitterShape).setMeshes(meshes);\r
-                       }\r
+               }\r
+               if(meshes.size()>0 && emitterShape instanceof EmitterMeshVertexShape) {\r
+                       ((EmitterMeshVertexShape) emitterShape).setMeshes(meshes);\r
                }\r
                \r
                node.attachChild(emitter);\r
index d068b06..1300fed 100644 (file)
@@ -7,8 +7,10 @@ import com.jme3.effect.EmitterMeshFaceShape;
 import com.jme3.effect.EmitterMeshVertexShape;\r
 import com.jme3.effect.ParticleEmitter;\r
 import com.jme3.effect.ParticleMesh.Type;\r
+import com.jme3.effect.influencers.EmptyParticleInfluencer;\r
+import com.jme3.effect.influencers.ParticleInfluencer;\r
+import com.jme3.effect.influencers.NewtonianParticleInfluencer;\r
 import com.jme3.math.ColorRGBA;\r
-import com.jme3.math.Vector3f;\r
 import com.jme3.scene.plugins.blender.data.Structure;\r
 import com.jme3.scene.plugins.blender.exception.BlenderFileException;\r
 import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;\r
@@ -62,6 +64,24 @@ public class ParticlesHelper extends AbstractBlenderHelper {
        public static final int PART_FROM_PARTICLE      =3;\r
        public static final int PART_FROM_CHILD         =4;\r
        \r
+       // part->phystype\r
+       public static final int PART_PHYS_NO    =       0;\r
+       public static final int PART_PHYS_NEWTON=       1;\r
+       public static final int PART_PHYS_KEYED =       2;\r
+       public static final int PART_PHYS_BOIDS =       3;\r
+       \r
+       // part->draw_as\r
+       public static final int PART_DRAW_NOT   =       0;\r
+       public static final int PART_DRAW_DOT   =       1;\r
+       public static final int PART_DRAW_CIRC  =       2;\r
+       public static final int PART_DRAW_CROSS =       3;\r
+       public static final int PART_DRAW_AXIS  =       4;\r
+       public static final int PART_DRAW_LINE  =       5;\r
+       public static final int PART_DRAW_PATH  =       6;\r
+       public static final int PART_DRAW_OB    =       7;\r
+       public static final int PART_DRAW_GR    =       8;\r
+       public static final int PART_DRAW_BB    =       9;\r
+       \r
        /**\r
         * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
         * different blender versions.\r
@@ -78,8 +98,35 @@ public class ParticlesHelper extends AbstractBlenderHelper {
                Pointer pParticleSettings = (Pointer) particleSystem.getFieldValue("part");\r
                if(!pParticleSettings.isNull()) {\r
                        Structure particleSettings = pParticleSettings.fetchData(dataRepository.getInputStream()).get(0);\r
+                       \r
                        int totPart = ((Number) particleSettings.getFieldValue("totpart")).intValue();\r
-                       result = new ParticleEmitter(particleSettings.getName(), Type.Triangle, totPart);\r
+                       \r
+                       //draw type will be stored temporarily in the name (it is used during modifier applying operation)\r
+                       int drawAs = ((Number)particleSettings.getFieldValue("draw_as")).intValue();\r
+                       char nameSuffix;//P - point, L - line, N - None, B - Bilboard\r
+                       switch(drawAs) {\r
+                               case PART_DRAW_NOT:\r
+                                       nameSuffix = 'N';\r
+                                       totPart = 0;//no need to generate particles in this case\r
+                                       break;\r
+                               case PART_DRAW_BB:\r
+                                       nameSuffix = 'B';\r
+                                       break;\r
+                               case PART_DRAW_OB:\r
+                               case PART_DRAW_GR:\r
+                                       nameSuffix = 'P';\r
+                                       LOGGER.warning("Neither object nor group particles supported yet! Using point representation instead!");//TODO: support groups and aobjects\r
+                                       break;\r
+                               case PART_DRAW_LINE:\r
+                                       nameSuffix = 'L';\r
+                                       LOGGER.warning("Lines not yet supported! Using point representation instead!");//TODO: support lines\r
+                               default://all others are rendered as points in blender\r
+                                       nameSuffix = 'P';\r
+                       }\r
+                       result = new ParticleEmitter(particleSettings.getName()+nameSuffix, Type.Triangle, totPart);\r
+                       if(nameSuffix=='N') {\r
+                               return result;//no need to set anything else\r
+                       }\r
                        \r
                        //setting the emitters shape (the shapes meshes will be set later during modifier applying operation)\r
                        int from = ((Number)particleSettings.getFieldValue("from")).intValue();\r
@@ -94,24 +141,49 @@ public class ParticlesHelper extends AbstractBlenderHelper {
                                        result.setShape(new EmitterMeshConvexHullShape());\r
                                        break;\r
                                default:\r
-                                       LOGGER.warning("Default shape used! Unknown emitter shape value ('from' parameter): " + from);\r
+                                       LOGGER.warning("Default shape used! Unknown emitter shape value ('from' parameter: " + from + ')');\r
                        }\r
                        \r
                        //reading acceleration\r
                        DynamicArray<Number> acc = (DynamicArray<Number>) particleSettings.getFieldValue("acc");\r
-                       result.setInitialVelocity(new Vector3f(acc.get(0).floatValue(), acc.get(1).floatValue(), acc.get(2).floatValue()));\r
-                       result.setGravity(0);//by default gravity is set to 0.1f so we need to disable it completely\r
-                       // 2x2 texture animation\r
-                       result.setImagesX(2);\r
-                       result.setImagesY(2);\r
-                       result.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f));   // red\r
-                       result.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow\r
-                       result.setStartSize(1.5f);\r
-                       result.setEndSize(0.1f);\r
+                       result.setGravity(-acc.get(0).floatValue(), -acc.get(1).floatValue(), -acc.get(2).floatValue());\r
+                       \r
+                       //setting the colors\r
+                       result.setEndColor(new ColorRGBA(1f, 1f, 1f, 1f));\r
+                       result.setStartColor(new ColorRGBA(1f, 1f, 1f, 1f));\r
+                       \r
+                       //reading size\r
+                       float sizeFactor = nameSuffix=='B' ? 1.0f : 0.3f;\r
+                       float size = ((Number)particleSettings.getFieldValue("size")).floatValue() * sizeFactor;\r
+                       result.setStartSize(size);\r
+                       result.setEndSize(size);\r
                        \r
-                       result.setLowLife(0.5f);\r
-                   result.setHighLife(3f);\r
-                   result.setVelocityVariation(0.3f);\r
+                       //reading lifetime\r
+                       int fps = dataRepository.getBlenderKey().getFps();\r
+                       float lifetime = ((Number)particleSettings.getFieldValue("lifetime")).floatValue() / fps;\r
+                       float randlife = ((Number)particleSettings.getFieldValue("randlife")).floatValue() / fps;\r
+                       result.setLowLife(lifetime * (1.0f - randlife));\r
+                   result.setHighLife(lifetime);\r
+                   \r
+                   //preparing influencer\r
+                   ParticleInfluencer influencer;\r
+                   int phystype = ((Number)particleSettings.getFieldValue("phystype")).intValue();\r
+                   switch(phystype) {\r
+                       case PART_PHYS_NEWTON:\r
+                               influencer = new NewtonianParticleInfluencer();\r
+                               ((NewtonianParticleInfluencer)influencer).setNormalVelocity(((Number)particleSettings.getFieldValue("normfac")).floatValue());\r
+                               ((NewtonianParticleInfluencer)influencer).setVelocityVariation(((Number)particleSettings.getFieldValue("randfac")).floatValue());\r
+                               ((NewtonianParticleInfluencer)influencer).setSurfaceTangentFactor(((Number)particleSettings.getFieldValue("tanfac")).floatValue());\r
+                               ((NewtonianParticleInfluencer)influencer).setSurfaceTangentRotation(((Number)particleSettings.getFieldValue("tanphase")).floatValue());\r
+                               break;\r
+                       case PART_PHYS_BOIDS:\r
+                       case PART_PHYS_KEYED://TODO: support other influencers\r
+                               LOGGER.warning("Boids and Keyed particles physic not yet supported! Empty influencer used!");\r
+                       case PART_PHYS_NO:\r
+                       default:\r
+                               influencer = new EmptyParticleInfluencer();\r
+                   }\r
+                   result.setParticleInfluencer(influencer);\r
                }\r
                return result;\r
        }\r