瀏覽代碼

The skyFactory now supports Equirectangular environment maps, as it's a pretty popular format.
It has been refactored to handle the 3 env map types : CubeMap, SphereMap, EquirectMap

Nehon 10 年之前
父節點
當前提交
05baf56130

+ 173 - 21
jme3-core/src/main/java/com/jme3/util/SkyFactory.java

@@ -55,6 +55,32 @@ import java.util.ArrayList;
  */
 public class SkyFactory {
 
+    
+    /**
+     * The type of map fed to the shader 
+     */
+    public enum EnvMapType{
+        /**
+         * The env map is a cube map see {@link TextureCubeMap} or 6 separate images that form a cube map
+         * The texture is either a {@link TextureCubeMap} or 6 {@link Texture2D}. 
+         * In the latter case, a TextureCubeMap is build from the 6 2d maps.
+         */
+        CubeMap,
+        /**
+         * The env map is a Sphere map. The texture is a Texture2D with the pixels arranged for
+         * <a href="http://en.wikipedia.org/wiki/Sphere_mapping">sphere
+         * mapping</a>.
+         */
+        SphereMap,
+        /**
+         * The env map is an Equirectangular map. A 2D textures with pixels 
+         * arranged for <a href="http://en.wikipedia.org/wiki/Equirectangular_projection">equirectangular 
+         * projection mapping.</a>.
+         * 
+         */
+        EquirectMap
+    }
+    
     /**
      * Create a sky with radius=10 using the given cubemap or spheremap texture.
      *
@@ -77,12 +103,33 @@ public class SkyFactory {
      * </ul>
      * @return a new spatial representing the sky, ready to be attached to the
      * scene graph
+     * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, com.jme3.texture.Texture, com.jme3.math.Vector3f, com.jme3.util.SkyFactory.EnvMapType)}
      */
+    @Deprecated 
     public static Spatial createSky(AssetManager assetManager, Texture texture,
             Vector3f normalScale, boolean sphereMap) {
         return createSky(assetManager, texture, normalScale, sphereMap, 10);
     }
 
+    /**
+     * Create a sky with radius=10 using the given cubemap or spheremap texture.
+     *
+     * For the sky to be visible, its radius must fall between the near and far
+     * planes of the camera's frustrum.
+     *
+     * @param assetManager from which to load materials
+     * @param texture to use
+     * @param normalScale The normal scale is multiplied by the 3D normal to get
+     * a texture coordinate. Use Vector3f.UNIT_XYZ to not apply and
+     * transformation to the normal.
+     * @param envMapType see {@link EnvMapType}
+     * @return a new spatial representing the sky, ready to be attached to the
+     * scene graph      
+     */
+    public static Spatial createSky(AssetManager assetManager, Texture texture,
+            Vector3f normalScale, EnvMapType envMapType) {
+        return createSky(assetManager, texture, normalScale, envMapType, 10);
+    }
     /**
      * Create a sky using the given cubemap or spheremap texture.
      *
@@ -105,9 +152,31 @@ public class SkyFactory {
      * frustrum
      * @return a new spatial representing the sky, ready to be attached to the
      * scene graph
+     * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, com.jme3.texture.Texture, com.jme3.math.Vector3f, com.jme3.util.SkyFactory.EnvMapType, int)}
      */
+    @Deprecated
     public static Spatial createSky(AssetManager assetManager, Texture texture,
             Vector3f normalScale, boolean sphereMap, int sphereRadius) {
+        return createSky(assetManager, texture, normalScale, sphereMap?EnvMapType.SphereMap:EnvMapType.CubeMap, sphereRadius);
+    }
+    
+     /**
+     * Create a sky using the given cubemap or spheremap texture.
+     *
+     * @param assetManager from which to load materials
+     * @param texture to use
+     * @param normalScale The normal scale is multiplied by the 3D normal to get
+     * a texture coordinate. Use Vector3f.UNIT_XYZ to not apply and
+     * transformation to the normal.
+     * @param envMapType see {@link EnvMapType}
+     * @param sphereRadius the sky sphere's radius: for the sky to be visible,
+     * its radius must fall between the near and far planes of the camera's
+     * frustrum
+     * @return a new spatial representing the sky, ready to be attached to the
+     * scene graph     
+     */
+     public static Spatial createSky(AssetManager assetManager, Texture texture,
+            Vector3f normalScale, EnvMapType envMapType, int sphereRadius) {
         if (texture == null) {
             throw new IllegalArgumentException("texture cannot be null");
         }
@@ -121,13 +190,19 @@ public class SkyFactory {
         Material skyMat = new Material(assetManager, "Common/MatDefs/Misc/Sky.j3md");
 
         skyMat.setVector3("NormalScale", normalScale);
-        if (sphereMap) {
-            skyMat.setBoolean("SphereMap", sphereMap);
-        } else if (!(texture instanceof TextureCubeMap)) {
-            // make sure its a cubemap
-            Image img = texture.getImage();
-            texture = new TextureCubeMap();
-            texture.setImage(img);
+        switch (envMapType){
+            case CubeMap : 
+                // make sure its a cubemap
+                Image img = texture.getImage();
+                texture = new TextureCubeMap();
+                texture.setImage(img);
+                break;
+            case SphereMap :     
+                skyMat.setBoolean("SphereMap", true);
+                break;
+            case EquirectMap : 
+                skyMat.setBoolean("EquirectMap", true);
+                break;
         }
         texture.setMagFilter(Texture.MagFilter.Bilinear);
         texture.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
@@ -136,6 +211,84 @@ public class SkyFactory {
 
         return sky;
     }
+     
+    /**
+    * Create a sky using the given cubemap or spheremap texture.
+    *
+    * @param assetManager from which to load materials
+    * @param texture to use    *
+    * @param sphereMap determines how the texture is used:<br>
+    * <ul>
+    * <li>true: The texture is a Texture2D with the pixels arranged for
+    * <a href="http://en.wikipedia.org/wiki/Sphere_mapping">sphere
+    * mapping</a>.</li>
+    * <li>false: The texture is either a TextureCubeMap or Texture2D. If it is
+    * a Texture2D then the image is taken from it and is inserted into a
+    * TextureCubeMap</li>
+    * </ul> 
+    * @return a new spatial representing the sky, ready to be attached to the
+    * scene graph
+    * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, com.jme3.texture.Texture, com.jme3.math.Vector3f, com.jme3.util.SkyFactory.EnvMapType)}
+    */  
+    @Deprecated
+    public static Spatial createSky(AssetManager assetManager, Texture texture, boolean sphereMap) {
+        return createSky(assetManager, texture, Vector3f.UNIT_XYZ,  sphereMap?EnvMapType.SphereMap:EnvMapType.CubeMap);
+    }
+
+    /**
+    * Create a sky using the given cubemap or spheremap texture.
+    *
+    * @param assetManager from which to load materials
+    * @param textureName the path to the texture asset to use    
+    * @param sphereMap determines how the texture is used:<br>
+    * <ul>
+    * <li>true: The texture is a Texture2D with the pixels arranged for
+    * <a href="http://en.wikipedia.org/wiki/Sphere_mapping">sphere
+    * mapping</a>.</li>
+    * <li>false: The texture is either a TextureCubeMap or Texture2D. If it is
+    * a Texture2D then the image is taken from it and is inserted into a
+    * TextureCubeMap</li>
+    * </ul> 
+    * @return a new spatial representing the sky, ready to be attached to the
+    * scene graph
+    * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, java.lang.String, com.jme3.math.Vector3f, com.jme3.util.SkyFactory.EnvMapType)}
+    */  
+    @Deprecated
+    public static Spatial createSky(AssetManager assetManager, String textureName, boolean sphereMap) {
+        return createSky(assetManager, textureName,  sphereMap?EnvMapType.SphereMap:EnvMapType.CubeMap);
+    }
+    
+    /**
+    * Create a sky using the given cubemap or spheremap texture.
+    *
+    * @param assetManager from which to load materials
+    * @param texture to use  
+    * @param envMapType see {@link EnvMapType}
+    * @return a new spatial representing the sky, ready to be attached to the
+    * scene graph    
+    */  
+    public static Spatial createSky(AssetManager assetManager, Texture texture, EnvMapType envMapType) {
+        return createSky(assetManager, texture, Vector3f.UNIT_XYZ, envMapType);
+    }
+    
+    /**
+    * Create a sky using the given cubemap or spheremap texture.
+    *
+    * @param assetManager from which to load materials
+    * @param textureName the path to the texture asset to use    
+    * @param envMapType see {@link EnvMapType}
+    * @return a new spatial representing the sky, ready to be attached to the
+    * scene graph    
+    */  
+    public static Spatial createSky(AssetManager assetManager, String textureName, EnvMapType envMapType) {
+        TextureKey key = new TextureKey(textureName, true);
+        key.setGenerateMips(false);
+        if (envMapType == EnvMapType.CubeMap) {
+            key.setTextureTypeHint(Texture.Type.CubeMap);
+        }
+        Texture tex = assetManager.loadTexture(key);
+        return createSky(assetManager, tex, envMapType);
+    }
 
     private static void checkImage(Image image) {
 //        if (image.getDepth() != 1)
@@ -282,21 +435,20 @@ public class SkyFactory {
         return sky;
     }
 
+    /**
+    * Create a cube-mapped sky using six textures.
+    *
+    * @param assetManager from which to load materials
+    * @param west texture for the western face of the cube
+    * @param east texture for the eastern face of the cube
+    * @param north texture for the northern face of the cube
+    * @param south texture for the southern face of the cube
+    * @param up texture for the top face of the cube
+    * @param down texture for the bottom face of the cube     * 
+    * @return a new spatial representing the sky, ready to be attached to the
+    * scene graph
+    */
     public static Spatial createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south, Texture up, Texture down) {
         return createSky(assetManager, west, east, north, south, up, down, Vector3f.UNIT_XYZ);
     }
-
-    public static Spatial createSky(AssetManager assetManager, Texture texture, boolean sphereMap) {
-        return createSky(assetManager, texture, Vector3f.UNIT_XYZ, sphereMap);
-    }
-
-    public static Spatial createSky(AssetManager assetManager, String textureName, boolean sphereMap) {
-        TextureKey key = new TextureKey(textureName, true);
-        key.setGenerateMips(false);
-        if (!sphereMap) {
-            key.setTextureTypeHint(Texture.Type.CubeMap);
-        }
-        Texture tex = assetManager.loadTexture(key);
-        return createSky(assetManager, tex, sphereMap);
-    }
 }

+ 2 - 0
jme3-core/src/main/resources/Common/MatDefs/Misc/Sky.j3md

@@ -2,6 +2,7 @@ MaterialDef Sky Plane {
     MaterialParameters {
         TextureCubeMap Texture
         Boolean SphereMap
+		Boolean EquirectMap
         Vector3 NormalScale
     }
     Technique {
@@ -20,6 +21,7 @@ MaterialDef Sky Plane {
 
         Defines {
             SPHERE_MAP : SphereMap
+			EQUIRECT_MAP : EquirectMap
         }
     }
     Technique {

+ 16 - 3
jme3-core/src/main/resources/Common/ShaderLib/Optics.glsllib

@@ -1,4 +1,4 @@
-#ifdef SPHERE_MAP
+#if defined(SPHERE_MAP) || defined(EQUIRECT_MAP)
 #define ENVMAP sampler2D
 #define TEXENV texture2D
 #else
@@ -23,10 +23,23 @@ vec2 Optics_SphereCoord(in vec3 dir){
     return (dir.xy * vec2(inv_two_p)) + vec2(0.5);
 }
 
+#define PI 3.141592653589793
+//const vec2 rads = vec2(1.0 / (PI * 2.0), 1.0 / PI);
+const vec2 rads = vec2(0.159154943091895, 0.318309886183790);
+vec2 Optics_LonLatCoords(in ENVMAP envMap, in vec3 dir){
+ float lon = atan(dir.z, dir.x)+ PI;
+ float lat = acos(dir.y); 
+ return vec2(lon, lat) * rads; 
+}
+
 vec4 Optics_GetEnvColor(in ENVMAP envMap, in vec3 dir){
     #ifdef SPHERE_MAP
     return texture2D(envMap, Optics_SphereCoord(dir));
     #else
-    return textureCube(envMap, dir);
+        #ifdef EQUIRECT_MAP
+            return texture2D(envMap, Optics_LonLatCoords(envMap,dir));            
+        #else
+            return textureCube(envMap, dir);
+        #endif
     #endif
-}
+}