• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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