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