• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	 */
flatProjection(Mesh mesh, BoundingBox bb)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 	 */
cubeProjection(Mesh mesh, BoundingBox bb)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 	 */
tubeProjection(Mesh mesh, BoundingTube bt)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 	 */
sphereProjection(Mesh mesh, BoundingSphere bs)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