Home | History | Annotate | Download | only in textures
      1 package com.jme3.scene.plugins.blender.textures;
      2 
      3 import com.jme3.bounding.BoundingBox;
      4 import com.jme3.bounding.BoundingSphere;
      5 import com.jme3.math.FastMath;
      6 import com.jme3.math.Triangle;
      7 import com.jme3.math.Vector3f;
      8 import com.jme3.scene.Mesh;
      9 import com.jme3.scene.VertexBuffer;
     10 import com.jme3.scene.plugins.blender.textures.UVCoordinatesGenerator.BoundingTube;
     11 import java.nio.FloatBuffer;
     12 
     13 /**
     14  * This class helps with projection calculations.
     15  *
     16  * @author Marcin Roguski (Kaelthas)
     17  */
     18 /* package */class UVProjectionGenerator {
     19 	/**
     20 	 * Flat projection for 2D textures.
     21 	 *
     22 	 * @param mesh
     23 	 *            mesh that is to be projected
     24 	 * @param bb
     25 	 *            the bounding box for projecting
     26 	 * @return UV coordinates after the projection
     27 	 */
     28 	public static float[] flatProjection(Mesh mesh, BoundingBox bb) {
     29 		if (bb == null) {
     30 			bb = UVCoordinatesGenerator.getBoundingBox(mesh);
     31 		}
     32 		Vector3f min = bb.getMin(null);
     33 		float[] ext = new float[] { bb.getXExtent() * 2.0f, bb.getYExtent() * 2.0f };
     34 		FloatBuffer positions = mesh.getFloatBuffer(VertexBuffer.Type.Position);
     35 		float[] uvCoordinates = new float[positions.limit() / 3 * 2];
     36 		for (int i = 0, j = 0; i < positions.limit(); i += 3, j += 2) {
     37 			uvCoordinates[j] = (positions.get(i) - min.x) / ext[0];
     38 			uvCoordinates[j + 1] = (positions.get(i + 1) - min.y) / ext[1];
     39 			// skip the Z-coordinate
     40 		}
     41 		return uvCoordinates;
     42 	}
     43 
     44 	/**
     45 	 * Cube projection for 2D textures.
     46 	 *
     47 	 * @param mesh
     48 	 *            mesh that is to be projected
     49 	 * @param bb
     50 	 *            the bounding box for projecting
     51 	 * @return UV coordinates after the projection
     52 	 */
     53 	public static float[] cubeProjection(Mesh mesh, BoundingBox bb) {
     54 		Triangle triangle = new Triangle();
     55 		Vector3f x = new Vector3f(1, 0, 0);
     56 		Vector3f y = new Vector3f(0, 1, 0);
     57 		Vector3f z = new Vector3f(0, 0, 1);
     58 		Vector3f min = bb.getMin(null);
     59 		float[] ext = new float[] { bb.getXExtent() * 2.0f, bb.getYExtent() * 2.0f, bb.getZExtent() * 2.0f };
     60 
     61 		float[] uvCoordinates = new float[mesh.getTriangleCount() * 6];// 6 == 3 * 2
     62 		float borderAngle = (float) Math.sqrt(2.0f) / 2.0f;
     63 		for (int i = 0, pointIndex = 0; i < mesh.getTriangleCount(); ++i) {
     64 			mesh.getTriangle(i, triangle);
     65 			Vector3f n = triangle.getNormal();
     66 			float dotNX = Math.abs(n.dot(x));
     67 			float dorNY = Math.abs(n.dot(y));
     68 			float dotNZ = Math.abs(n.dot(z));
     69 			if (dotNX > borderAngle) {
     70 				if (dotNZ < borderAngle) {// discard X-coordinate
     71 					uvCoordinates[pointIndex++] = (triangle.get1().y - min.y) / ext[1];
     72 					uvCoordinates[pointIndex++] = (triangle.get1().z - min.z) / ext[2];
     73 					uvCoordinates[pointIndex++] = (triangle.get2().y - min.y) / ext[1];
     74 					uvCoordinates[pointIndex++] = (triangle.get2().z - min.z) / ext[2];
     75 					uvCoordinates[pointIndex++] = (triangle.get3().y - min.y) / ext[1];
     76 					uvCoordinates[pointIndex++] = (triangle.get3().z - min.z) / ext[2];
     77 				} else {// discard Z-coordinate
     78 					uvCoordinates[pointIndex++] = (triangle.get1().x - min.x) / ext[0];
     79 					uvCoordinates[pointIndex++] = (triangle.get1().y - min.y) / ext[1];
     80 					uvCoordinates[pointIndex++] = (triangle.get2().x - min.x) / ext[0];
     81 					uvCoordinates[pointIndex++] = (triangle.get2().y - min.y) / ext[1];
     82 					uvCoordinates[pointIndex++] = (triangle.get3().x - min.x) / ext[0];
     83 					uvCoordinates[pointIndex++] = (triangle.get3().y - min.y) / ext[1];
     84 				}
     85 			} else {
     86 				if (dorNY > borderAngle) {// discard Y-coordinate
     87 					uvCoordinates[pointIndex++] = (triangle.get1().x - min.x) / ext[0];
     88 					uvCoordinates[pointIndex++] = (triangle.get1().z - min.z) / ext[2];
     89 					uvCoordinates[pointIndex++] = (triangle.get2().x - min.x) / ext[0];
     90 					uvCoordinates[pointIndex++] = (triangle.get2().z - min.z) / ext[2];
     91 					uvCoordinates[pointIndex++] = (triangle.get3().x - min.x) / ext[0];
     92 					uvCoordinates[pointIndex++] = (triangle.get3().z - min.z) / ext[2];
     93 				} else {// discard Z-coordinate
     94 					uvCoordinates[pointIndex++] = (triangle.get1().x - min.x) / ext[0];
     95 					uvCoordinates[pointIndex++] = (triangle.get1().y - min.y) / ext[1];
     96 					uvCoordinates[pointIndex++] = (triangle.get2().x - min.x) / ext[0];
     97 					uvCoordinates[pointIndex++] = (triangle.get2().y - min.y) / ext[1];
     98 					uvCoordinates[pointIndex++] = (triangle.get3().x - min.x) / ext[0];
     99 					uvCoordinates[pointIndex++] = (triangle.get3().y - min.y) / ext[1];
    100 				}
    101 			}
    102 			triangle.setNormal(null);// clear the previous normal vector
    103 		}
    104 		return uvCoordinates;
    105 	}
    106 
    107 	/**
    108 	 * Tube projection for 2D textures.
    109 	 *
    110 	 * @param mesh
    111 	 *            mesh that is to be projected
    112 	 * @param bt
    113 	 *            the bounding tube for projecting
    114 	 * @return UV coordinates after the projection
    115 	 */
    116 	public static float[] tubeProjection(Mesh mesh, BoundingTube bt) {
    117 		FloatBuffer positions = mesh.getFloatBuffer(VertexBuffer.Type.Position);
    118 		float[] uvCoordinates = new float[positions.limit() / 3 * 2];
    119 		Vector3f v = new Vector3f();
    120 		float cx = bt.getCenter().x, cy = bt.getCenter().y;
    121 		Vector3f uBase = new Vector3f(0, -1, 0);
    122 
    123 		float vBase = bt.getCenter().z - bt.getHeight() * 0.5f;
    124 		for (int i = 0, j = 0; i < positions.limit(); i += 3, j += 2) {
    125 			// calculating U
    126 			v.set(positions.get(i)-cx, positions.get(i + 1)-cy, 0);
    127 			v.normalizeLocal();
    128 			float angle = v.angleBetween(uBase);// result between [0; PI]
    129 			if (v.x < 0) {// the angle should be greater than PI, we're on the other part of the image then
    130 				angle = FastMath.TWO_PI - angle;
    131 			}
    132 			uvCoordinates[j] = angle / FastMath.TWO_PI;
    133 
    134 			// calculating V
    135 			float z = positions.get(i + 2);
    136 			uvCoordinates[j + 1] = (z - vBase) / bt.getHeight();
    137 		}
    138 
    139 		//looking for splitted triangles
    140 		Triangle triangle = new Triangle();
    141 		for(int i=0;i<mesh.getTriangleCount();++i) {
    142 			mesh.getTriangle(i, triangle);
    143 			float sgn1 = Math.signum(triangle.get1().x-cx);
    144 			float sgn2 = Math.signum(triangle.get2().x-cx);
    145 			float sgn3 = Math.signum(triangle.get3().x-cx);
    146 			float xSideFactor = sgn1 + sgn2 + sgn3;
    147 			float ySideFactor = Math.signum(triangle.get1().y-cy)+
    148 					   Math.signum(triangle.get2().y-cy)+
    149 					   Math.signum(triangle.get3().y-cy);
    150 			if((xSideFactor>-3 || xSideFactor<3) && ySideFactor<0) {//the triangle is on the splitting plane
    151 				//indexOfUcoord = (indexOfTriangle*3 + indexOfTrianglesVertex)*2
    152 				if(sgn1==1.0f) {
    153 					uvCoordinates[i*3*2] += 1.0f;
    154 				}
    155 				if(sgn2==1.0f) {
    156 					uvCoordinates[(i*3+1)*2] += 1.0f;
    157 				}
    158 				if(sgn3==1.0f) {
    159 					uvCoordinates[(i*3+2)*2] += 1.0f;
    160 				}
    161 			}
    162 		}
    163 		return uvCoordinates;
    164 	}
    165 
    166 	/**
    167 	 * Sphere projection for 2D textures.
    168 	 *
    169 	 * @param mesh
    170 	 *            mesh that is to be projected
    171 	 * @param bb
    172 	 *            the bounding box for projecting
    173 	 * @return UV coordinates after the projection
    174 	 */
    175 	public static float[] sphereProjection(Mesh mesh, BoundingSphere bs) {
    176 		FloatBuffer positions = mesh.getFloatBuffer(VertexBuffer.Type.Position);
    177 		float[] uvCoordinates = new float[positions.limit() / 3 * 2];
    178 		Vector3f v = new Vector3f();
    179 		float cx = bs.getCenter().x, cy = bs.getCenter().y, cz = bs.getCenter().z;
    180 		Vector3f uBase = new Vector3f(0, -1, 0);
    181 		Vector3f vBase = new Vector3f(0, 0, -1);
    182 
    183 		for (int i = 0, j = 0; i < positions.limit(); i += 3, j += 2) {
    184 			// calculating U
    185 			v.set(positions.get(i)-cx, positions.get(i + 1)-cy, 0);
    186 			v.normalizeLocal();
    187 			float angle = v.angleBetween(uBase);// result between [0; PI]
    188 			if (v.x < 0) {// the angle should be greater than PI, we're on the other part of the image then
    189 				angle = FastMath.TWO_PI - angle;
    190 			}
    191 			uvCoordinates[j] = angle / FastMath.TWO_PI;
    192 
    193 			// calculating V
    194 			v.set(positions.get(i)-cx, positions.get(i + 1)-cy, positions.get(i + 2)-cz);
    195 			v.normalizeLocal();
    196 			angle = v.angleBetween(vBase);// result between [0; PI]
    197 			uvCoordinates[j+1] = angle / FastMath.PI;
    198 		}
    199 
    200 		//looking for splitted triangles
    201 		Triangle triangle = new Triangle();
    202 		for(int i=0;i<mesh.getTriangleCount();++i) {
    203 			mesh.getTriangle(i, triangle);
    204 			float sgn1 = Math.signum(triangle.get1().x-cx);
    205 			float sgn2 = Math.signum(triangle.get2().x-cx);
    206 			float sgn3 = Math.signum(triangle.get3().x-cx);
    207 			float xSideFactor = sgn1 + sgn2 + sgn3;
    208 			float ySideFactor = Math.signum(triangle.get1().y-cy)+
    209 					   Math.signum(triangle.get2().y-cy)+
    210 					   Math.signum(triangle.get3().y-cy);
    211 			if((xSideFactor>-3 || xSideFactor<3) && ySideFactor<0) {//the triangle is on the splitting plane
    212 				//indexOfUcoord = (indexOfTriangle*3 + indexOfTrianglesVertex)*2
    213 				if(sgn1==1.0f) {
    214 					uvCoordinates[i*3*2] += 1.0f;
    215 				}
    216 				if(sgn2==1.0f) {
    217 					uvCoordinates[(i*3+1)*2] += 1.0f;
    218 				}
    219 				if(sgn3==1.0f) {
    220 					uvCoordinates[(i*3+2)*2] += 1.0f;
    221 				}
    222 			}
    223 		}
    224 		return uvCoordinates;
    225 	}
    226 }
    227