Browse Source

Cube mapping for textures support.
Providing proper texture mapping data to UVCoordinatesGenerator.

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

Kae..pl 14 years ago
parent
commit
843cce9b30

+ 26 - 0
engine/src/blender/com/jme3/scene/plugins/blender/DataRepository.java

@@ -48,6 +48,7 @@ import com.jme3.scene.plugins.blender.file.BlenderInputStream;
 import com.jme3.scene.plugins.blender.file.DnaBlockData;
 import com.jme3.scene.plugins.blender.file.FileBlockHeader;
 import com.jme3.scene.plugins.blender.file.Structure;
+import com.jme3.scene.plugins.blender.materials.MaterialContext;
 import com.jme3.scene.plugins.blender.modifiers.Modifier;
 
 /**
@@ -88,6 +89,8 @@ public class DataRepository {
     protected Map<Long, List<Modifier>> modifiers = new HashMap<Long, List<Modifier>>();
     /** A list of constraints for the specified object. */
     protected Map<Long, List<Constraint>> constraints = new HashMap<Long, List<Constraint>>();
+    /** A map of material contexts. */
+    protected Map<Material, MaterialContext> materialContexts = new HashMap<Material, MaterialContext>();
     /** A map og helpers that perform loading. */
     private Map<String, AbstractBlenderHelper> helpers = new HashMap<String, AbstractBlenderHelper>();
 
@@ -394,6 +397,29 @@ public class DataRepository {
     public List<Constraint> getConstraints(Long objectOMA) {
     	return constraints.get(objectOMA);
     }
+    
+	/**
+	 * This method sets the material context for the given material.
+	 * If the context is already set it will be replaced.
+	 * @param material
+	 *        the material
+	 * @param materialContext
+	 *        the material's context
+	 */
+	public void setMaterialContext(Material material, MaterialContext materialContext) {
+		this.materialContexts.put(material, materialContext);
+	}
+
+	/**
+	 * This method returns the material context for the given material.
+	 * If no context exists then <b>null</b> is returned.
+	 * @param material
+	 *        the material
+	 * @return material's context
+	 */
+	public MaterialContext getMaterialContext(Material material) {
+		return materialContexts.get(material);
+	}
 
     /**
      * This metod returns the default material.

+ 48 - 17
engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialContext.java

@@ -13,23 +13,25 @@ import com.jme3.scene.plugins.blender.file.Structure;
 import com.jme3.scene.plugins.blender.textures.TextureHelper;
 import com.jme3.texture.Texture.Type;
 
-/*package*/final class MaterialContext {
+public final class MaterialContext {
 	private static final Logger LOGGER = Logger.getLogger(MaterialContext.class.getName());
 	
-	public final String name;
-	public final List<Structure> mTexs;
-	public final List<Structure> textures;
-	public final int texturesCount;
-	public final Type textureType;
-	public final int textureCoordinatesType;
+	/*package*/ final String name;
+	/*package*/ final List<Structure> mTexs;
+	/*package*/ final List<Structure> textures;
+	/*package*/ final int texturesCount;
+	/*package*/ final Type textureType;
 	
-	public final boolean shadeless;
-	public final boolean vertexColor;
-	public final boolean transparent;
-	public final boolean vtangent;
+	/*package*/ final boolean shadeless;
+	/*package*/ final boolean vertexColor;
+	/*package*/ final boolean transparent;
+	/*package*/ final boolean vtangent;
+	
+	/*package*/ int uvCoordinatesType = -1;
+	/*package*/ int projectionType;
 	
 	@SuppressWarnings("unchecked")
-	public MaterialContext(Structure structure, DataRepository dataRepository) throws BlenderFileException {
+	/*package*/ MaterialContext(Structure structure, DataRepository dataRepository) throws BlenderFileException {
 		name = structure.getName();
 		
 		int mode = ((Number) structure.getFieldValue("mode")).intValue();
@@ -43,16 +45,16 @@ import com.jme3.texture.Texture.Type;
 		DynamicArray<Pointer> mtexsArray = (DynamicArray<Pointer>) structure.getFieldValue("mtex");
 		int separatedTextures = ((Number) structure.getFieldValue("septex")).intValue();
 		Type firstTextureType = null;
-		int texco = -1;
 		for (int i = 0; i < mtexsArray.getTotalSize(); ++i) {
 			Pointer p = mtexsArray.get(i);
 			if (p.isNotNull() && (separatedTextures & 1 << i) == 0) {
 				Structure mtex = p.fetchData(dataRepository.getInputStream()).get(0);
 				
 				//the first texture determines the texture coordinates type
-				if(texco == -1) {
-					texco = ((Number) mtex.getFieldValue("texco")).intValue();
-				} else if(texco != ((Number) mtex.getFieldValue("texco")).intValue()) {
+				if(uvCoordinatesType == -1) {
+					uvCoordinatesType = ((Number) mtex.getFieldValue("texco")).intValue();
+					projectionType = ((Number) mtex.getFieldValue("mapping")).intValue();
+				} else if(uvCoordinatesType != ((Number) mtex.getFieldValue("texco")).intValue()) {
 					LOGGER.log(Level.WARNING, "The texture with index: {0} has different UV coordinates type than the first texture! This texture will NOT be loaded!", i+1);
 					continue;
 				}
@@ -79,10 +81,39 @@ import com.jme3.texture.Texture.Type;
 		}
 		
 		this.texturesCount = mTexs.size();
-		this.textureCoordinatesType = texco;
 		this.textureType = firstTextureType;
 	}
 	
+	/**
+	 * This method returns the current material's texture UV coordinates type.
+	 * @return uv coordinates type
+	 */
+	public int getUvCoordinatesType() {
+		return uvCoordinatesType;
+	}
+	
+	/**
+	 * This method returns the proper projection type for the material's texture.
+	 * This applies only to 2D textures.
+	 * @return texture's projection type
+	 */
+	public int getProjectionType() {
+		return projectionType;
+	}
+
+	/**
+	 * This method returns current material's texture dimension.
+	 * @return the material's texture dimension
+	 */
+	public int getTextureDimension() {
+		return this.textureType == Type.TwoDimensional ? 2 : 3;
+	}
+	
+	/**
+	 * This method determines the type of the texture.
+	 * @param texType texture type (from blender)
+	 * @return texture type (used by jme)
+	 */
 	private Type getType(int texType) {
 		switch (texType) {
 			case TextureHelper.TEX_IMAGE:// (it is first because probably this will be most commonly used)

+ 13 - 2
engine/src/blender/com/jme3/scene/plugins/blender/materials/MaterialHelper.java

@@ -178,6 +178,16 @@ public class MaterialHelper extends AbstractBlenderHelper {
 		this.faceCullMode = faceCullMode;
 	}
 
+	/**
+	 * This method converts the material structure to jme Material.
+	 * @param structure
+	 *        structure with material data
+	 * @param dataRepository
+	 *        the data repository
+	 * @return jme material
+	 * @throws BlenderFileException
+	 *         an exception is throw when problems with blend file occur
+	 */
 	public Material toMaterial(Structure structure, DataRepository dataRepository) throws BlenderFileException {
 		LOGGER.log(Level.INFO, "Loading material.");
 		if (structure == null) {
@@ -216,7 +226,7 @@ public class MaterialHelper extends AbstractBlenderHelper {
 
 						// NOTE: Enable mipmaps FOR ALL TEXTURES EVER
 						texture.setMinFilter(MinFilter.Trilinear);
-//TODO: textures merging
+
 						if ((mapto & 0x01) != 0) {// Col
 							// Map to COLOR channel or DIFFUSE
 							// Set diffuse to white so it doesn't get multiplied by texture
@@ -228,7 +238,7 @@ public class MaterialHelper extends AbstractBlenderHelper {
 							float colfac = ((Number) mtex.getFieldValue("colfac")).floatValue();
 							texture = textureHelper.blendTexture(new float[] {1, 1, 1}, texture, color, colfac, blendType, negateTexture, dataRepository);
 							texture.setWrap(WrapMode.Repeat);
-							
+							//TODO: textures merging
 							if (materialContext.shadeless) {
 								texturesMap.put(firstTextureType==Type.ThreeDimensional ? TEXTURE_TYPE_3D : TEXTURE_TYPE_COLOR, texture);
 							} else {
@@ -316,6 +326,7 @@ public class MaterialHelper extends AbstractBlenderHelper {
 			result.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
 		}
 		
+		dataRepository.setMaterialContext(result, materialContext);
 		dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, result);
 		return result;
 	}

+ 19 - 3
engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java

@@ -63,6 +63,7 @@ import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
 import com.jme3.scene.plugins.blender.file.DynamicArray;
 import com.jme3.scene.plugins.blender.file.Pointer;
 import com.jme3.scene.plugins.blender.file.Structure;
+import com.jme3.scene.plugins.blender.materials.MaterialContext;
 import com.jme3.scene.plugins.blender.materials.MaterialHelper;
 import com.jme3.scene.plugins.blender.objects.Properties;
 import com.jme3.scene.plugins.blender.textures.TextureHelper;
@@ -391,9 +392,24 @@ public class MeshHelper extends AbstractBlenderHelper {
 			for(Geometry geom : geometries) {
 				geom.getMesh().setBuffer(uvCoordsBuffer);
 			}
-		} else {//TODO: get the proper texture coordinates type
-			UVCoordinatesGenerator.generateUVCoordinates(UVCoordinatesGenerator.TEXCO_ORCO, 
-					com.jme3.texture.Texture.Type.ThreeDimensional, geometries);
+		} else {
+			Map<Material, List<Geometry>> materialMap = new HashMap<Material, List<Geometry>>();
+			for(Geometry geom : geometries) {
+				Material material = geom.getMaterial();
+				List<Geometry> geomsWithCommonMaterial = materialMap.get(material);
+				if(geomsWithCommonMaterial==null) {
+					geomsWithCommonMaterial = new ArrayList<Geometry>();
+					materialMap.put(material, geomsWithCommonMaterial);
+				}
+				geomsWithCommonMaterial.add(geom);
+				
+			}
+			for(Entry<Material, List<Geometry>> entry : materialMap.entrySet()) {
+				MaterialContext materialContext = dataRepository.getMaterialContext(entry.getKey());
+				UVCoordinatesGenerator.generateUVCoordinates(materialContext.getUvCoordinatesType(), 
+						materialContext.getProjectionType(),
+						materialContext.getTextureDimension(), entry.getValue());
+			}
 		}
 		
 		dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, geometries);

+ 142 - 45
engine/src/blender/com/jme3/scene/plugins/blender/textures/UVCoordinatesGenerator.java

@@ -38,6 +38,7 @@ import java.util.logging.Logger;
 import com.jme3.bounding.BoundingBox;
 import com.jme3.bounding.BoundingSphere;
 import com.jme3.bounding.BoundingVolume;
+import com.jme3.math.Triangle;
 import com.jme3.math.Vector2f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.Geometry;
@@ -45,7 +46,6 @@ import com.jme3.scene.Mesh;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.VertexBuffer.Format;
 import com.jme3.scene.VertexBuffer.Usage;
-import com.jme3.texture.Texture.Type;
 import com.jme3.util.BufferUtils;
 
 /**
@@ -55,6 +55,7 @@ import com.jme3.util.BufferUtils;
 public class UVCoordinatesGenerator {
 	private static final Logger	LOGGER						= Logger.getLogger(UVCoordinatesGenerator.class.getName());
 
+	// texture UV coordinates types
 	public static final int		TEXCO_ORCO					= 1;
 	public static final int		TEXCO_REFL					= 2;
 	public static final int		TEXCO_NORM					= 4;
@@ -70,49 +71,61 @@ public class UVCoordinatesGenerator {
 	public static final int		TEXCO_TANGENT				= 4096;
 	// still stored in vertex->accum, 1 D
 	public static final int		TEXCO_PARTICLE_OR_STRAND	= 8192;													// strand is used
-																														// for normal
-																														// materials,
-																														// particle for halo
-																														// materials
 	public static final int		TEXCO_STRESS				= 16384;
 	public static final int		TEXCO_SPEED					= 32768;
 
+	// 2D texture mapping (projection)
+	public static final int		PROJECTION_FLAT				= 0;
+	public static final int		PROJECTION_CUBE				= 1;
+	public static final int		PROJECTION_TUBE				= 2;
+	public static final int		PROJECTION_SPHERE			= 3;
+
 	/**
-	 * This method generates UV coordinates for the given geometries.
+	 * This method generates UV coordinates for the given mesh.
+	 * IMPORTANT! This method assumes that all geometries represent one node.
+	 * Each containing mesh with separate material.
+	 * So all meshes have the same reference to vertex table which stores all their vertices.
 	 * @param texco
 	 *        texture coordinates type
-	 * @param textureType
-	 *        the type of the texture (only 2D and 3D)
+	 * @param projection
+	 *        the projection type for 2D textures
+	 * @param textureDimension
+	 *        the dimension of the texture (only 2D and 3D)
 	 * @param geometries
-	 *        a list of geometries that will have coordinates applied
+	 *        a list of geometries the UV coordinates will be applied to
 	 */
-	public static void generateUVCoordinates(int texco, Type textureType, List<Geometry> geometries) {
-		for (Geometry geometry : geometries) {
-			UVCoordinatesGenerator.generateUVCoordinates(texco, textureType, geometry.getMesh());
+	public static void generateUVCoordinates(int texco, int projection, int textureDimension, List<Geometry> geometries) {
+		if (textureDimension != 2 && textureDimension != 3) {
+			throw new IllegalStateException("Unsupported texture dimension: " + textureDimension);
 		}
-	}
 
-	/**
-	 * This method generates UV coordinates for the given mesh.
-	 * @param texco
-	 *        texture coordinates type
-	 * @param textureType
-	 *        the type of the texture (only 2D and 3D)
-	 * @param mesh
-	 *        a mesh that will have coordinates applied
-	 */
-	public static void generateUVCoordinates(int texco, Type textureType, Mesh mesh) {
-		VertexBuffer result = null;
+		VertexBuffer result = new VertexBuffer(VertexBuffer.Type.TexCoord);
+		Mesh mesh = geometries.get(0).getMesh();
+		BoundingBox bb = UVCoordinatesGenerator.getBoundingBox(geometries);
+
 		switch (texco) {
 			case TEXCO_ORCO:
-				if (textureType == Type.TwoDimensional) {
-
-				} else if (textureType == Type.ThreeDimensional) {
-					BoundingBox bb = UVCoordinatesGenerator.getBoundingBox(mesh);
-
-					result = new VertexBuffer(com.jme3.scene.VertexBuffer.Type.TexCoord);
-					FloatBuffer positions = mesh.getFloatBuffer(com.jme3.scene.VertexBuffer.Type.Position);
-					float[] uvCoordinates = BufferUtils.getFloatArray(positions);
+				float[] uvCoordinates = null;
+				if (textureDimension == 2) {
+					switch (projection) {
+						case PROJECTION_FLAT:
+							uvCoordinates = UVCoordinatesGenerator.flatProjection(mesh, bb);
+							break;
+						case PROJECTION_CUBE:
+							uvCoordinates = UVCoordinatesGenerator.cubeProjection(mesh, bb);
+							break;
+						case PROJECTION_TUBE:
+							uvCoordinates = UVCoordinatesGenerator.tubeProjection(mesh, bb);
+							break;
+						case PROJECTION_SPHERE:
+							uvCoordinates = UVCoordinatesGenerator.sphereProjection(mesh, bb);
+							break;
+						default:
+							throw new IllegalStateException("Unknown projection type: " + projection);
+					}
+				} else {
+					FloatBuffer positions = mesh.getFloatBuffer(VertexBuffer.Type.Position);
+					uvCoordinates = BufferUtils.getFloatArray(positions);
 					Vector3f min = bb.getMin(null);
 					float[] ext = new float[] { bb.getXExtent() * 2, bb.getYExtent() * 2, bb.getZExtent() * 2 };
 
@@ -122,10 +135,22 @@ public class UVCoordinatesGenerator {
 						uvCoordinates[i + 1] = (uvCoordinates[i + 1] - min.y) / ext[1];
 						uvCoordinates[i + 2] = (uvCoordinates[i + 2] - min.z) / ext[2];
 					}
-
-					result.setupData(Usage.Static, 3, Format.Float, BufferUtils.createFloatBuffer(uvCoordinates));
+					result.setupData(Usage.Static, textureDimension, Format.Float, BufferUtils.createFloatBuffer(uvCoordinates));
+				}
+				result.setupData(Usage.Static, textureDimension, Format.Float, BufferUtils.createFloatBuffer(uvCoordinates));
+				break;
+			case TEXCO_UV:
+				if (textureDimension == 2) {
+					FloatBuffer uvCoordinatesBuffer = BufferUtils.createFloatBuffer(mesh.getVertexCount() << 1);
+					Vector2f[] data = new Vector2f[] { new Vector2f(0, 1), new Vector2f(0, 0), new Vector2f(1, 0) };
+					for (int i = 0; i < mesh.getVertexCount(); ++i) {
+						Vector2f uv = data[i % 3];
+						uvCoordinatesBuffer.put(uv.x);
+						uvCoordinatesBuffer.put(uv.y);
+					}
+					result.setupData(Usage.Static, textureDimension, Format.Float, uvCoordinatesBuffer);
 				} else {
-					throw new IllegalStateException("Unsupported texture type: " + textureType);
+
 				}
 				break;
 			case TEXCO_GLOB:
@@ -133,8 +158,6 @@ public class UVCoordinatesGenerator {
 				break;
 			case TEXCO_TANGENT:
 
-				break;
-			case TEXCO_UV:
 				break;
 			case TEXCO_STRESS:
 
@@ -157,38 +180,110 @@ public class UVCoordinatesGenerator {
 				throw new IllegalStateException("Unknown texture coordinates value: " + texco);
 		}
 
-		mesh.clearBuffer(VertexBuffer.Type.TexCoord);// in case there are coordinates already set
-		mesh.setBuffer(result);
+		// each mesh will have the same coordinates
+		for (Geometry geometry : geometries) {
+			mesh = geometry.getMesh();
+			mesh.clearBuffer(VertexBuffer.Type.TexCoord);// in case there are coordinates already set
+			mesh.setBuffer(result);
+		}
 	}
 
 	/**
 	 * Flat projection for 2D textures.
 	 * @param mesh
 	 *        mesh that is to be projected
+	 * @param bb
+	 *        the bounding box for projecting
 	 * @return UV coordinates after the projection
 	 */
-	public Vector2f[] flatProjection(Mesh mesh) {
-		return null;// TODO: implement
+	private static float[] flatProjection(Mesh mesh, BoundingBox bb) {
+		if (bb == null) {
+			bb = UVCoordinatesGenerator.getBoundingBox(mesh);
+		}
+		Vector3f min = bb.getMin(null);
+		float[] ext = new float[] { bb.getXExtent() * 2.0f, bb.getYExtent() * 2.0f };
+		FloatBuffer positions = mesh.getFloatBuffer(com.jme3.scene.VertexBuffer.Type.Position);
+		float[] uvCoordinates = new float[positions.limit() / 3 * 2];
+		for (int i = 0, j = 0; i < positions.limit(); i += 3, j += 2) {
+			uvCoordinates[j] = (positions.get(i) - min.x) / ext[0];
+			uvCoordinates[j + 1] = (positions.get(i + 1) - min.y) / ext[1];
+			// skip the Z-coordinate
+		}
+		return uvCoordinates;
 	}
 
 	/**
 	 * Cube projection for 2D textures.
 	 * @param mesh
 	 *        mesh that is to be projected
+	 * @param bb
+	 *        the bounding box for projecting
 	 * @return UV coordinates after the projection
 	 */
-	public Vector2f[] cubeProjection(Mesh mesh) {
-		return null;// TODO: implement
+	private static float[] cubeProjection(Mesh mesh, BoundingBox bb) {
+		Triangle triangle = new Triangle();
+		Vector3f x = new Vector3f(1, 0, 0);
+		Vector3f y = new Vector3f(0, 1, 0);
+		Vector3f z = new Vector3f(0, 0, 1);
+		Vector3f min = bb.getMin(null);
+		float[] ext = new float[] { bb.getXExtent() * 2.0f, bb.getYExtent() * 2.0f, bb.getZExtent() * 2.0f };
+
+		float[] uvCoordinates = new float[mesh.getTriangleCount() * 6];// 6 == 3 * 2
+		float borderAngle = (float)Math.sqrt(2.0f)/2.0f;
+		for (int i = 0, pointIndex = 0; i < mesh.getTriangleCount(); ++i) {
+			mesh.getTriangle(i, triangle);
+			Vector3f n = triangle.getNormal();
+			float dotNX = Math.abs(n.dot(x));
+			float dorNY = Math.abs(n.dot(y));
+			float dotNZ = Math.abs(n.dot(z));
+			if (dotNX > borderAngle) {
+				if (dotNZ < borderAngle) {// discard X-coordinate
+					uvCoordinates[pointIndex++] = (triangle.get1().y - min.y) / ext[1];
+					uvCoordinates[pointIndex++] = (triangle.get1().z - min.z) / ext[2];
+					uvCoordinates[pointIndex++] = (triangle.get2().y - min.y) / ext[1];
+					uvCoordinates[pointIndex++] = (triangle.get2().z - min.z) / ext[2];
+					uvCoordinates[pointIndex++] = (triangle.get3().y - min.y) / ext[1];
+					uvCoordinates[pointIndex++] = (triangle.get3().z - min.z) / ext[2];
+				} else {// discard Z-coordinate
+					uvCoordinates[pointIndex++] = (triangle.get1().x - min.x) / ext[0];
+					uvCoordinates[pointIndex++] = (triangle.get1().y - min.y) / ext[1];
+					uvCoordinates[pointIndex++] = (triangle.get2().x - min.x) / ext[0];
+					uvCoordinates[pointIndex++] = (triangle.get2().y - min.y) / ext[1];
+					uvCoordinates[pointIndex++] = (triangle.get3().x - min.x) / ext[0];
+					uvCoordinates[pointIndex++] = (triangle.get3().y - min.y) / ext[1];
+				}
+			} else {
+				if (dorNY > borderAngle) {// discard Y-coordinate
+					uvCoordinates[pointIndex++] = (triangle.get1().x - min.x) / ext[0];
+					uvCoordinates[pointIndex++] = (triangle.get1().z - min.z) / ext[2];
+					uvCoordinates[pointIndex++] = (triangle.get2().x - min.x) / ext[0];
+					uvCoordinates[pointIndex++] = (triangle.get2().z - min.z) / ext[2];
+					uvCoordinates[pointIndex++] = (triangle.get3().x - min.x) / ext[0];
+					uvCoordinates[pointIndex++] = (triangle.get3().z - min.z) / ext[2];
+				} else {// discard Z-coordinate
+					uvCoordinates[pointIndex++] = (triangle.get1().x - min.x) / ext[0];
+					uvCoordinates[pointIndex++] = (triangle.get1().y - min.y) / ext[1];
+					uvCoordinates[pointIndex++] = (triangle.get2().x - min.x) / ext[0];
+					uvCoordinates[pointIndex++] = (triangle.get2().y - min.y) / ext[1];
+					uvCoordinates[pointIndex++] = (triangle.get3().x - min.x) / ext[0];
+					uvCoordinates[pointIndex++] = (triangle.get3().y - min.y) / ext[1];
+				}
+			}
+			triangle.setNormal(null);//clear the previous normal vector
+		}
+		return uvCoordinates;
 	}
 
 	/**
 	 * Tube projection for 2D textures.
 	 * @param mesh
 	 *        mesh that is to be projected
+	 * @param bb
+	 *        the bounding box for projecting
 	 * @return UV coordinates after the projection
 	 */
 
-	public Vector2f[] tubeProjection(Mesh mesh) {
+	private static float[] tubeProjection(Mesh mesh, BoundingBox bb) {
 		return null;// TODO: implement
 	}
 
@@ -196,9 +291,11 @@ public class UVCoordinatesGenerator {
 	 * Sphere projection for 2D textures.
 	 * @param mesh
 	 *        mesh that is to be projected
+	 * @param bb
+	 *        the bounding box for projecting
 	 * @return UV coordinates after the projection
 	 */
-	public Vector2f[] sphereProjection(Mesh mesh) {
+	private static float[] sphereProjection(Mesh mesh, BoundingBox bb) {
 		return null;// TODO: implement
 		// Vector2f[] uvTable = new Vector2f[vertexList.size()];
 		// Ray ray = new Ray();