1 package com.jme3.util; 2 3 import com.jme3.asset.AssetManager; 4 import com.jme3.asset.TextureKey; 5 import com.jme3.bounding.BoundingSphere; 6 import com.jme3.material.Material; 7 import com.jme3.math.Vector3f; 8 import com.jme3.renderer.queue.RenderQueue.Bucket; 9 import com.jme3.scene.Geometry; 10 import com.jme3.scene.Spatial; 11 import com.jme3.scene.shape.Sphere; 12 import com.jme3.texture.Image; 13 import com.jme3.texture.Image.Format; 14 import com.jme3.texture.Texture; 15 import com.jme3.texture.TextureCubeMap; 16 import java.nio.ByteBuffer; 17 import java.util.ArrayList; 18 19 /** 20 * <code>SkyFactory</code> is used to create jME {@link Spatial}s that can 21 * be attached to the scene to display a sky image in the background. 22 * 23 * @author Kirill Vainer 24 */ 25 public class SkyFactory { 26 27 /** 28 * Creates a sky using the given texture (cubemap or spheremap). 29 * 30 * @param assetManager The asset manager to use to load materials 31 * @param texture Texture to use for the sky 32 * @param normalScale The normal scale is multiplied by the 3D normal 33 * to get a texture coordinate. Use Vector3f.UNIT_XYZ to not apply 34 * and transformation to the normal. 35 * @param sphereMap The way the texture is used 36 * depends on this value:<br> 37 * <ul> 38 * <li>true: Its a Texture2D with the pixels arranged for 39 * <a href="http://en.wikipedia.org/wiki/Sphere_mapping">sphere mapping</a>.</li> 40 * <li>false: Its either a TextureCubeMap or Texture2D. If its a Texture2D 41 * then the image is taken from it and is inserted into a TextureCubeMap</li> 42 * </ul> 43 * @return A spatial representing the sky 44 */ createSky(AssetManager assetManager, Texture texture, Vector3f normalScale, boolean sphereMap)45 public static Spatial createSky(AssetManager assetManager, Texture texture, Vector3f normalScale, boolean sphereMap) { 46 return createSky(assetManager, texture, normalScale, sphereMap, 10); 47 } 48 49 /** 50 * Creates a sky using the given texture (cubemap or spheremap). 51 * 52 * @param assetManager The asset manager to use to load materials 53 * @param texture Texture to use for the sky 54 * @param normalScale The normal scale is multiplied by the 3D normal 55 * to get a texture coordinate. Use Vector3f.UNIT_XYZ to not apply 56 * and transformation to the normal. 57 * @param sphereMap The way the texture is used 58 * depends on this value:<br> 59 * <ul> 60 * <li>true: Its a Texture2D with the pixels arranged for 61 * <a href="http://en.wikipedia.org/wiki/Sphere_mapping">sphere mapping</a>.</li> 62 * <li>false: Its either a TextureCubeMap or Texture2D. If its a Texture2D 63 * then the image is taken from it and is inserted into a TextureCubeMap</li> 64 * </ul> 65 * @param sphereRadius If specified, this will be the sky sphere's radius. 66 * This should be the camera's near plane for optimal quality. 67 * @return A spatial representing the sky 68 */ createSky(AssetManager assetManager, Texture texture, Vector3f normalScale, boolean sphereMap, int sphereRadius)69 public static Spatial createSky(AssetManager assetManager, Texture texture, Vector3f normalScale, boolean sphereMap, int sphereRadius) { 70 if (texture == null) { 71 throw new IllegalArgumentException("texture cannot be null"); 72 } 73 final Sphere sphereMesh = new Sphere(10, 10, sphereRadius, false, true); 74 75 Geometry sky = new Geometry("Sky", sphereMesh); 76 sky.setQueueBucket(Bucket.Sky); 77 sky.setCullHint(Spatial.CullHint.Never); 78 sky.setModelBound(new BoundingSphere(Float.POSITIVE_INFINITY, Vector3f.ZERO)); 79 80 Material skyMat = new Material(assetManager, "Common/MatDefs/Misc/Sky.j3md"); 81 82 skyMat.setVector3("NormalScale", normalScale); 83 if (sphereMap) { 84 skyMat.setBoolean("SphereMap", sphereMap); 85 } else if (!(texture instanceof TextureCubeMap)) { 86 // make sure its a cubemap 87 Image img = texture.getImage(); 88 texture = new TextureCubeMap(); 89 texture.setImage(img); 90 } 91 skyMat.setTexture("Texture", texture); 92 sky.setMaterial(skyMat); 93 94 return sky; 95 } 96 checkImage(Image image)97 private static void checkImage(Image image) { 98 // if (image.getDepth() != 1) 99 // throw new IllegalArgumentException("3D/Array images not allowed"); 100 101 if (image.getWidth() != image.getHeight()) { 102 throw new IllegalArgumentException("Image width and height must be the same"); 103 } 104 105 if (image.getMultiSamples() != 1) { 106 throw new IllegalArgumentException("Multisample textures not allowed"); 107 } 108 } 109 checkImagesForCubeMap(Image... images)110 private static void checkImagesForCubeMap(Image... images) { 111 if (images.length == 1) { 112 return; 113 } 114 115 Format fmt = images[0].getFormat(); 116 int width = images[0].getWidth(); 117 int height = images[0].getHeight(); 118 119 ByteBuffer data = images[0].getData(0); 120 int size = data != null ? data.capacity() : 0; 121 122 checkImage(images[0]); 123 124 for (int i = 1; i < images.length; i++) { 125 Image image = images[i]; 126 checkImage(images[i]); 127 if (image.getFormat() != fmt) { 128 throw new IllegalArgumentException("Images must have same format"); 129 } 130 if (image.getWidth() != width || image.getHeight() != height) { 131 throw new IllegalArgumentException("Images must have same resolution"); 132 } 133 ByteBuffer data2 = image.getData(0); 134 if (data2 != null){ 135 if (data2.capacity() != size) { 136 throw new IllegalArgumentException("Images must have same size"); 137 } 138 } 139 } 140 } 141 createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south, Texture up, Texture down, Vector3f normalScale)142 public static Spatial createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south, Texture up, Texture down, Vector3f normalScale) { 143 return createSky(assetManager, west, east, north, south, up, down, normalScale, 10); 144 } 145 createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south, Texture up, Texture down, Vector3f normalScale, int sphereRadius)146 public static Spatial createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south, Texture up, Texture down, Vector3f normalScale, int sphereRadius) { 147 final Sphere sphereMesh = new Sphere(10, 10, sphereRadius, false, true); 148 Geometry sky = new Geometry("Sky", sphereMesh); 149 sky.setQueueBucket(Bucket.Sky); 150 sky.setCullHint(Spatial.CullHint.Never); 151 sky.setModelBound(new BoundingSphere(Float.POSITIVE_INFINITY, Vector3f.ZERO)); 152 153 Image westImg = west.getImage(); 154 Image eastImg = east.getImage(); 155 Image northImg = north.getImage(); 156 Image southImg = south.getImage(); 157 Image upImg = up.getImage(); 158 Image downImg = down.getImage(); 159 160 checkImagesForCubeMap(westImg, eastImg, northImg, southImg, upImg, downImg); 161 162 Image cubeImage = new Image(westImg.getFormat(), westImg.getWidth(), westImg.getHeight(), null); 163 164 cubeImage.addData(westImg.getData(0)); 165 cubeImage.addData(eastImg.getData(0)); 166 167 cubeImage.addData(downImg.getData(0)); 168 cubeImage.addData(upImg.getData(0)); 169 170 cubeImage.addData(southImg.getData(0)); 171 cubeImage.addData(northImg.getData(0)); 172 173 if (westImg.getEfficentData() != null){ 174 // also consilidate efficient data 175 ArrayList<Object> efficientData = new ArrayList<Object>(6); 176 efficientData.add(westImg.getEfficentData()); 177 efficientData.add(eastImg.getEfficentData()); 178 efficientData.add(downImg.getEfficentData()); 179 efficientData.add(upImg.getEfficentData()); 180 efficientData.add(southImg.getEfficentData()); 181 efficientData.add(northImg.getEfficentData()); 182 cubeImage.setEfficentData(efficientData); 183 } 184 185 TextureCubeMap cubeMap = new TextureCubeMap(cubeImage); 186 cubeMap.setAnisotropicFilter(0); 187 cubeMap.setMagFilter(Texture.MagFilter.Bilinear); 188 cubeMap.setMinFilter(Texture.MinFilter.NearestNoMipMaps); 189 cubeMap.setWrap(Texture.WrapMode.EdgeClamp); 190 191 Material skyMat = new Material(assetManager, "Common/MatDefs/Misc/Sky.j3md"); 192 skyMat.setTexture("Texture", cubeMap); 193 skyMat.setVector3("NormalScale", normalScale); 194 sky.setMaterial(skyMat); 195 196 return sky; 197 } 198 createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south, Texture up, Texture down)199 public static Spatial createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south, Texture up, Texture down) { 200 return createSky(assetManager, west, east, north, south, up, down, Vector3f.UNIT_XYZ); 201 } 202 createSky(AssetManager assetManager, Texture texture, boolean sphereMap)203 public static Spatial createSky(AssetManager assetManager, Texture texture, boolean sphereMap) { 204 return createSky(assetManager, texture, Vector3f.UNIT_XYZ, sphereMap); 205 } 206 createSky(AssetManager assetManager, String textureName, boolean sphereMap)207 public static Spatial createSky(AssetManager assetManager, String textureName, boolean sphereMap) { 208 TextureKey key = new TextureKey(textureName, true); 209 key.setGenerateMips(true); 210 key.setAsCube(!sphereMap); 211 Texture tex = assetManager.loadTexture(key); 212 return createSky(assetManager, tex, sphereMap); 213 } 214 } 215