1 | package pl.vorg.mowa.core.graphics; |
---|
2 | |
---|
3 | import com.framsticks.net.client3D.Log; |
---|
4 | |
---|
5 | /** |
---|
6 | * A set of helper metods useful with 3d objects. |
---|
7 | * |
---|
8 | * @author vorg |
---|
9 | */ |
---|
10 | public class GeometryUtils { |
---|
11 | public static void generateNormals(Geometry geometry) { |
---|
12 | VertexStream vertexStream = geometry.getVertexStream(); |
---|
13 | if (vertexStream == null) { |
---|
14 | Log.getInstance() |
---|
15 | .log("err", |
---|
16 | "GeometryUtils.generateNormals err: vertex stream not found"); |
---|
17 | return; |
---|
18 | } |
---|
19 | if (vertexStream.getAttribByName("normal") == null) { |
---|
20 | FloatVertexAttrib normalAttrib = new FloatVertexAttrib("normal"); |
---|
21 | vertexStream.addAttrib(normalAttrib); |
---|
22 | float[] normals = new float[((FloatVertexAttrib) vertexStream |
---|
23 | .getAttribByName("pos")).getBuffer().length]; |
---|
24 | normalAttrib.setBuffer(normals); |
---|
25 | } |
---|
26 | if (geometry.getPrimitiveType() == PrimitiveType.Triangles) { |
---|
27 | genSmoothTriangleNormals(geometry.getVertexStream()); |
---|
28 | } |
---|
29 | if (geometry.getPrimitiveType() == PrimitiveType.Quads) { |
---|
30 | genSmoothQuadNormals(geometry.getVertexStream()); |
---|
31 | } |
---|
32 | } |
---|
33 | |
---|
34 | private static void genSmoothTriangleNormals(VertexStream vertexStream) { |
---|
35 | IndexBuffer indexBuffer = vertexStream.getIndexBuffer(); |
---|
36 | int[] indices = indexBuffer.getBuffer(); |
---|
37 | FloatVertexAttrib posAttrib = (FloatVertexAttrib) vertexStream |
---|
38 | .getAttribByName("pos"); |
---|
39 | float[] positions = posAttrib.getBuffer(); |
---|
40 | FloatVertexAttrib normalAttrib = (FloatVertexAttrib) vertexStream |
---|
41 | .getAttribByName("normal"); |
---|
42 | float[] normals = normalAttrib.getBuffer(); |
---|
43 | normalAttrib.setBuffer(normals); |
---|
44 | Vec3[] faceNormalList = new Vec3[indices.length / 3]; |
---|
45 | |
---|
46 | for (int i = 0; i < indices.length; i += 3) { |
---|
47 | Vec3 a = new Vec3(positions[indices[i] * 3], |
---|
48 | positions[indices[i] * 3 + 1], |
---|
49 | positions[indices[i] * 3 + 2]); |
---|
50 | Vec3 b = new Vec3(positions[indices[i + 1] * 3], |
---|
51 | positions[indices[i + 1] * 3 + 1], |
---|
52 | positions[indices[i + 1] * 3 + 2]); |
---|
53 | Vec3 c = new Vec3(positions[indices[i + 2] * 3], |
---|
54 | positions[indices[i + 2] * 3 + 1], |
---|
55 | positions[indices[i + 2] * 3 + 2]); |
---|
56 | Vec3 bsa = Vec3.sub(b, a); |
---|
57 | Vec3 bsc = Vec3.sub(b, c); |
---|
58 | Vec3 n = Vec3.cross(bsc, bsa); |
---|
59 | n.normalize(); |
---|
60 | faceNormalList[i / 3] = n; |
---|
61 | } |
---|
62 | |
---|
63 | // For each vertice. |
---|
64 | for (int i = 0; i < positions.length; i += 3) { |
---|
65 | // Search faces containg the vertice and add a normal vector to it. |
---|
66 | float x = positions[i]; |
---|
67 | float y = positions[i + 1]; |
---|
68 | float z = positions[i + 2]; |
---|
69 | Vec3 vertNormal = new Vec3(); |
---|
70 | for (int j = 0; j < indices.length; j++) { |
---|
71 | if ((x == positions[indices[j] * 3]) |
---|
72 | && (y == positions[indices[j] * 3 + 1]) |
---|
73 | && (z == positions[indices[j] * 3 + 2])) { |
---|
74 | vertNormal.add(faceNormalList[j / 3]); |
---|
75 | } |
---|
76 | } |
---|
77 | vertNormal.normalize(); |
---|
78 | normals[i] = vertNormal.getX(); |
---|
79 | normals[i + 1] = vertNormal.getY(); |
---|
80 | normals[i + 2] = vertNormal.getZ(); |
---|
81 | } |
---|
82 | } |
---|
83 | |
---|
84 | private static void genSmoothQuadNormals(VertexStream vertexStream) { |
---|
85 | IndexBuffer indexBuffer = vertexStream.getIndexBuffer(); |
---|
86 | int[] indices = indexBuffer.getBuffer(); |
---|
87 | FloatVertexAttrib posAttrib = (FloatVertexAttrib) vertexStream |
---|
88 | .getAttribByName("pos"); |
---|
89 | float[] positions = posAttrib.getBuffer(); |
---|
90 | FloatVertexAttrib normalAttrib = (FloatVertexAttrib) vertexStream |
---|
91 | .getAttribByName("normal"); |
---|
92 | float[] normals = new float[positions.length]; |
---|
93 | normalAttrib.setBuffer(normals); |
---|
94 | Vec3[] faceNormalList = new Vec3[indices.length / 4]; |
---|
95 | |
---|
96 | for (int i = 0; i < indices.length; i += 4) { |
---|
97 | Vec3 a = new Vec3(positions[indices[i] * 3], |
---|
98 | positions[indices[i] * 3 + 1], |
---|
99 | positions[indices[i] * 3 + 2]); |
---|
100 | Vec3 b = new Vec3(positions[indices[i + 1] * 3], |
---|
101 | positions[indices[i + 1] * 3 + 1], |
---|
102 | positions[indices[i + 1] * 3 + 2]); |
---|
103 | Vec3 c = new Vec3(positions[indices[i + 2] * 3], |
---|
104 | positions[indices[i + 2] * 3 + 1], |
---|
105 | positions[indices[i + 2] * 3 + 2]); |
---|
106 | Vec3 bsa = Vec3.sub(b, a); |
---|
107 | Vec3 bsc = Vec3.sub(b, c); |
---|
108 | Vec3 n = Vec3.cross(bsc, bsa); |
---|
109 | n.normalize(); |
---|
110 | faceNormalList[i / 4] = n; |
---|
111 | } |
---|
112 | |
---|
113 | // For each vertice. |
---|
114 | for (int i = 0; i < positions.length; i += 3) { |
---|
115 | // Search faces containg the vertice and add a normal vector to it. |
---|
116 | float x = positions[i]; |
---|
117 | float y = positions[i + 1]; |
---|
118 | float z = positions[i + 2]; |
---|
119 | Vec3 vertNormal = new Vec3(); |
---|
120 | for (int j = 0; j < indices.length; j++) { |
---|
121 | if ((x == positions[indices[j] * 3]) |
---|
122 | && (y == positions[indices[j] * 3 + 1]) |
---|
123 | && (z == positions[indices[j] * 3 + 2])) { |
---|
124 | vertNormal.add(faceNormalList[j / 4]); |
---|
125 | } |
---|
126 | } |
---|
127 | vertNormal.normalize(); |
---|
128 | normals[i] = vertNormal.getX(); |
---|
129 | normals[i + 1] = vertNormal.getY(); |
---|
130 | normals[i + 2] = vertNormal.getZ(); |
---|
131 | } |
---|
132 | } |
---|
133 | |
---|
134 | // Isn't tested well. |
---|
135 | public static void generateTangents(Geometry geometry) { |
---|
136 | VertexStream vertexStream = geometry.getVertexStream(); |
---|
137 | if (vertexStream == null) { |
---|
138 | Log.getInstance() |
---|
139 | .log("err", |
---|
140 | "GeometryUtils.generateTangents err: vertex stream not found"); |
---|
141 | return; |
---|
142 | } |
---|
143 | if (vertexStream.getAttribByName("tangent") == null) { |
---|
144 | FloatVertexAttrib tangentAttrib = new FloatVertexAttrib("tangent"); |
---|
145 | vertexStream.addAttrib(tangentAttrib); |
---|
146 | float[] tangents = new float[((FloatVertexAttrib) vertexStream |
---|
147 | .getAttribByName("pos")).getBuffer().length]; |
---|
148 | tangentAttrib.setBuffer(tangents); |
---|
149 | } |
---|
150 | if (vertexStream.getAttribByName("normal") == null) { |
---|
151 | FloatVertexAttrib normalAttrib = new FloatVertexAttrib("normal"); |
---|
152 | vertexStream.addAttrib(normalAttrib); |
---|
153 | float[] normals = new float[((FloatVertexAttrib) vertexStream |
---|
154 | .getAttribByName("pos")).getBuffer().length]; |
---|
155 | normalAttrib.setBuffer(normals); |
---|
156 | } |
---|
157 | if (geometry.getPrimitiveType() == PrimitiveType.Triangles) { |
---|
158 | genTriangleTangents(geometry.getVertexStream()); |
---|
159 | } |
---|
160 | } |
---|
161 | |
---|
162 | private static void genTriangleTangents(VertexStream vertexStream) { |
---|
163 | IndexBuffer indexBuffer = vertexStream.getIndexBuffer(); |
---|
164 | int[] indices = indexBuffer.getBuffer(); |
---|
165 | FloatVertexAttrib posAttrib = (FloatVertexAttrib) vertexStream |
---|
166 | .getAttribByName("pos"); |
---|
167 | float[] positions = posAttrib.getBuffer(); |
---|
168 | FloatVertexAttrib texCoord0Attrib = (FloatVertexAttrib) vertexStream |
---|
169 | .getAttribByName("texCoord0"); |
---|
170 | float[] texCoords0 = texCoord0Attrib.getBuffer(); |
---|
171 | FloatVertexAttrib tangentAttrib = (FloatVertexAttrib) vertexStream |
---|
172 | .getAttribByName("tangent"); |
---|
173 | float[] tangents = tangentAttrib.getBuffer(); |
---|
174 | |
---|
175 | for (int i = 0; i < indices.length; i += 3) { |
---|
176 | int i1 = indices[i]; |
---|
177 | int i2 = indices[i + 1]; |
---|
178 | int i3 = indices[i + 2]; |
---|
179 | Vec3 pos1 = new Vec3(positions[i1] * 3, positions[i1 * 3 + 1], |
---|
180 | positions[i1 * 3 + 2]); |
---|
181 | Vec3 pos2 = new Vec3(positions[i2] * 3, positions[i2 * 3 + 1], |
---|
182 | positions[i2 * 3 + 2]); |
---|
183 | Vec3 pos3 = new Vec3(positions[i3] * 3, positions[i3 * 3 + 1], |
---|
184 | positions[i3 * 3 + 2]); |
---|
185 | Vec2 coord1 = new Vec2(texCoords0[i1 * 2], texCoords0[i1 * 2 + 1]); |
---|
186 | Vec2 coord2 = new Vec2(texCoords0[i2 * 2], texCoords0[i2 * 2 + 1]); |
---|
187 | Vec2 coord3 = new Vec2(texCoords0[i3 * 2], texCoords0[i3 * 2 + 1]); |
---|
188 | Vec3 v0 = Vec3.sub(pos1, pos2); |
---|
189 | Vec3 v1 = Vec3.sub(pos3, pos1); |
---|
190 | Vec3 normal = Vec3.normalized(Vec3.cross(v0, v1)); |
---|
191 | |
---|
192 | float dt0 = coord1.getT() - coord2.getT(); |
---|
193 | float dt1 = coord3.getT() - coord1.getT(); |
---|
194 | Vec3 tangent = Vec3.normalized(Vec3.sub(Vec3.mul(dt1, v0), |
---|
195 | Vec3.mul(dt0, v1))); |
---|
196 | |
---|
197 | float ds0 = coord1.getS() - coord2.getS(); |
---|
198 | float ds1 = coord3.getS() - coord1.getS(); |
---|
199 | Vec3 binormal = Vec3.normalized(Vec3.sub(Vec3.mul(ds1, v0), |
---|
200 | Vec3.mul(ds0, v1))); |
---|
201 | |
---|
202 | Vec3 tangentCross = Vec3.cross(tangent, binormal); |
---|
203 | if (Vec3.dot(tangentCross, normal) < 0.0f) { |
---|
204 | tangent = Vec3.neg(tangent); |
---|
205 | binormal = Vec3.neg(binormal); |
---|
206 | } |
---|
207 | |
---|
208 | tangents[i1 * 3] = tangents[i1 * 3] + tangent.getX(); |
---|
209 | tangents[i1 * 3 + 1] = tangents[i1 * 3 + 1] + tangent.getY(); |
---|
210 | tangents[i1 * 3 + 2] = tangents[i1 * 3 + 2] + tangent.getZ(); |
---|
211 | |
---|
212 | tangents[i2 * 3] = tangents[i2 * 3] + tangent.getX(); |
---|
213 | tangents[i2 * 3 + 1] = tangents[i2 * 3 + 1] + tangent.getY(); |
---|
214 | tangents[i2 * 3 + 2] = tangents[i2 * 3 + 2] + tangent.getZ(); |
---|
215 | |
---|
216 | tangents[i3 * 3] = tangents[i3 * 3] + tangent.getX(); |
---|
217 | tangents[i3 * 3 + 1] = tangents[i3 * 3 + 1] + tangent.getY(); |
---|
218 | tangents[i3 * 3 + 2] = tangents[i3 * 3 + 2] + tangent.getZ(); |
---|
219 | } |
---|
220 | |
---|
221 | for (int j = 0; j < tangents.length; j += 3) { |
---|
222 | Vec3 tangent = new Vec3(tangents[j], tangents[j + 1], |
---|
223 | tangents[j + 2]); |
---|
224 | tangent.normalize(); |
---|
225 | tangents[j] = tangent.getX(); |
---|
226 | tangents[j + 1] = tangent.getY(); |
---|
227 | tangents[j + 2] = tangent.getZ(); |
---|
228 | } |
---|
229 | |
---|
230 | } |
---|
231 | } |
---|