Răsfoiți Sursa

- add test for TextureAtlas
- add GeometryBatchFactory method to create atlased/batched model

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9030 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

nor..67 14 ani în urmă
părinte
comite
58a08eb570

+ 71 - 0
engine/src/test/jme3test/tools/TestTextureAtlas.java

@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2009-2010 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 jme3test.tools;
+
+import jme3test.model.shape.*;
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.plugins.ZipLocator;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import jme3tools.optimize.GeometryBatchFactory;
+
+public class TestTextureAtlas extends SimpleApplication {
+
+    public static void main(String[] args){
+        TestTextureAtlas app = new TestTextureAtlas();
+        app.start();
+    }
+
+    @Override
+    public void simpleInitApp() {
+        assetManager.registerLocator("wildhouse.zip", ZipLocator.class.getName());
+        Spatial scene = assetManager.loadModel("main.scene");
+        
+        Geometry geom = GeometryBatchFactory.makeAtlasBatch(scene, assetManager, 4096);
+        
+        AmbientLight al = new AmbientLight();
+        scene.addLight(al);
+
+        DirectionalLight sun = new DirectionalLight();
+        sun.setDirection(new Vector3f(0.69077975f, -0.6277887f, -0.35875428f).normalizeLocal());
+        sun.setColor(ColorRGBA.White.clone().multLocal(2));
+        scene.addLight(sun);
+
+        rootNode.attachChild(geom);
+    }
+
+}

+ 108 - 3
engine/src/tools/jme3tools/optimize/GeometryBatchFactory.java

@@ -1,5 +1,7 @@
 package jme3tools.optimize;
 
+import com.jme3.asset.AssetManager;
+import com.jme3.material.MatParamTexture;
 import com.jme3.material.Material;
 import com.jme3.math.Matrix4f;
 import com.jme3.math.Transform;
@@ -10,15 +12,22 @@ import com.jme3.scene.VertexBuffer.Format;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.VertexBuffer.Usage;
 import com.jme3.scene.mesh.IndexBuffer;
+import com.jme3.texture.Texture;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.IntMap.Entry;
+import com.jme3.util.TangentBinormalGenerator;
 import java.nio.Buffer;
 import java.nio.FloatBuffer;
 import java.nio.ShortBuffer;
 import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import jme3tools.optimize.TextureAtlas.TextureAtlasTile;
 
 public class GeometryBatchFactory {
 
+    private static final Logger logger = Logger.getLogger(GeometryBatchFactory.class.getName());
+
     private static void doTransformVerts(FloatBuffer inBuf, int offset, FloatBuffer outBuf, Matrix4f transform) {
         Vector3f pos = new Vector3f();
 
@@ -61,12 +70,24 @@ public class GeometryBatchFactory {
 
     /**
      * Merges all geometries in the collection into
-     * the output mesh. Does not take into account materials.
+     * the output mesh. Creates a new material using the TextureAtlas.
      * 
      * @param geometries
      * @param outMesh
      */
     public static void mergeGeometries(Collection<Geometry> geometries, Mesh outMesh) {
+        mergeGeometries(geometries, outMesh, null);
+    }
+
+    /**
+     * Merges all geometries in the collection into
+     * the output mesh. Creates a new material using the TextureAtlas.
+     * 
+     * @param geometries
+     * @param outMesh
+     * @param atlas the TextureAtlas to use
+     */
+    public static void mergeGeometries(Collection<Geometry> geometries, Mesh outMesh, TextureAtlas atlas) {
         int[] compsForBuf = new int[VertexBuffer.Type.values().length];
         Format[] formatForBuf = new Format[compsForBuf.length];
 
@@ -161,7 +182,7 @@ public class GeometryBatchFactory {
                 if (inBuf == null || outBuf == null) {
                     continue;
                 }
-                
+
                 if (Type.Index.ordinal() == bufType) {
                     int components = compsForBuf[bufType];
 
@@ -182,6 +203,20 @@ public class GeometryBatchFactory {
                     FloatBuffer inPos = (FloatBuffer) inBuf.getData();
                     FloatBuffer outPos = (FloatBuffer) outBuf.getData();
                     doTransformNorms(inPos, globalVertIndex, outPos, worldMatrix);
+                } else if (Type.TexCoord.ordinal() == bufType && atlas != null) {
+                    Texture tex = getMaterialTexture(geom, "DiffuseMap");
+                    if (tex == null) {
+                        tex = getMaterialTexture(geom, "ColorMap");
+
+                    }
+                    if (tex != null && tex.getKey() != null) {
+                        TextureAtlasTile tile = atlas.getAtlasTile(tex.getKey().getName());
+                        if (tile != null) {
+                            FloatBuffer inPos = (FloatBuffer) inBuf.getData();
+                            FloatBuffer outPos = (FloatBuffer) outBuf.getData();
+                            tile.transformTextureCoords(inPos, globalVertIndex, outPos);
+                        }
+                    }
                 } else {
                     for (int vert = 0; vert < geomVertCount; vert++) {
                         int curGlobalVertIndex = globalVertIndex + vert;
@@ -288,6 +323,76 @@ public class GeometryBatchFactory {
         return retVal;
     }
 
+    public static Geometry makeAtlasBatch(Spatial spat, AssetManager mgr, int atlasSize) {
+        List<Geometry> geometries = new ArrayList<Geometry>();
+        gatherGeoms(spat, geometries);
+        //TODO: specular etc. maps, needs to use main atlas for locations
+        TextureAtlas atlas = new TextureAtlas(atlasSize, atlasSize);
+        for (Geometry geometry : geometries) {
+            Texture diffuse = getMaterialTexture(geometry, "DiffuseMap");
+            Texture normal = getMaterialTexture(geometry, "NormalMap");
+            Texture specular = getMaterialTexture(geometry, "SpecularMap");
+            if (diffuse == null) {
+                diffuse = getMaterialTexture(geometry, "ColorMap");
+
+            }
+            if (diffuse != null && diffuse.getKey() != null) {
+                String keyName = diffuse.getKey().getName();
+                if (!atlas.addTexture(diffuse, "DiffuseMap")) {
+                    logger.log(Level.WARNING, "Adding diffuse texture {0} to atlas failed, atlas full?", keyName);
+                }
+                if (normal != null && normal.getKey() != null) {
+                    atlas.addTexture(diffuse, "NormalMap", keyName);
+                }
+                if (specular != null && specular.getKey() != null) {
+                    atlas.addTexture(specular, "SpecularMap", keyName);
+                }
+            }
+        }
+        Geometry geom = new Geometry();
+        Mesh mesh = new Mesh();
+        mergeGeometries(geometries, mesh, atlas);
+        TangentBinormalGenerator.generate(mesh);
+        mesh.updateCounts();
+        mesh.updateBound();
+        geom.setMesh(mesh);
+//        geom.setMesh(new Box(1,1,1));
+
+//        Material mat = new Material(mgr, "Common/MatDefs/Light/Lighting.j3md");
+//        Texture diffuseMap = atlas.getAtlasTexture("DiffuseMap");
+//        Texture normalMap = atlas.getAtlasTexture("NormalMap");
+//        Texture specularMap = atlas.getAtlasTexture("SpecularMap");
+//        if (diffuseMap != null) {
+//            mat.setTexture("DiffuseMap", diffuseMap);
+//        }
+//        if (normalMap != null) {
+//            mat.setTexture("NormalMap", normalMap);
+//        }
+//        if (specularMap != null) {
+//            mat.setTexture("SpecularMap", specularMap);
+//        }
+//        mat.setFloat("Shininess", 16.0f);
+        
+        Material mat = new Material(mgr, "Common/MatDefs/Misc/Unshaded.j3md");
+        mat.setTexture("ColorMap", atlas.getAtlasTexture("DiffuseMap"));
+        
+        geom.setMaterial(mat);
+        return geom;
+    }
+
+    private static Texture getMaterialTexture(Geometry geometry, String mapName) {
+        Material mat = geometry.getMaterial();
+        if (mat == null || mat.getParam(mapName) == null || !(mat.getParam(mapName) instanceof MatParamTexture)) {
+            return null;
+        }
+        MatParamTexture param = (MatParamTexture) mat.getParam(mapName);
+        Texture texture = param.getTextureValue();
+        if (texture == null) {
+            return null;
+        }
+        return texture;
+    }
+
     private static void gatherGeoms(Spatial scene, List<Geometry> geoms) {
         if (scene instanceof Node) {
             Node node = (Node) scene;
@@ -335,7 +440,7 @@ public class GeometryBatchFactory {
 
         // Since the scene is returned unaltered the transform must be reset
         scene.setLocalTransform(Transform.IDENTITY);
-        
+
         return scene;
     }
 

+ 7 - 1
engine/src/tools/jme3tools/optimize/TextureAtlas.java

@@ -182,7 +182,7 @@ public class TextureAtlas {
             Texture2D tex = new Texture2D(new Image(format, atlasWidth, atlasHeight, BufferUtils.createByteBuffer(image)));
             tex.setMagFilter(Texture.MagFilter.Bilinear);
             tex.setMinFilter(Texture.MinFilter.BilinearNearestMipMap);
-            tex.setWrap(Texture.WrapMode.Repeat);
+            tex.setWrap(Texture.WrapMode.Clamp);
             return tex;
         }
         return null;
@@ -267,6 +267,12 @@ public class TextureAtlas {
             float h = (float) getHeight() / (float) atlasHeight;
             Vector2f location = new Vector2f(x, y);
             Vector2f scale = new Vector2f(w, h);
+//            if (previousLocation.x > 1) {
+//                previousLocation.x = previousLocation.x - (int) previousLocation.x;
+//            }
+//            if (previousLocation.y > 1) {
+//                previousLocation.y = previousLocation.y - (int) previousLocation.y;
+//            }
             return location.addLocal(previousLocation.multLocal(scale));
         }