1 /*
2 Copyright (c) 2013-2021 Timur Gafarov
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license (the "Software") to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 /**
30  * Copyright: Timur Gafarov 2013-2021.
31  * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
32  * Authors: Timur Gafarov
33  */
34 module dlib.geometry.trimesh;
35 
36 import std.stdio;
37 import std.math;
38 
39 import dlib.core.memory;
40 import dlib.container.array;
41 import dlib.math.vector;
42 import dlib.geometry.triangle;
43 
44 struct Index
45 {
46     uint a, b, c;
47 }
48 
49 struct FaceGroup
50 {
51     Array!Index indicesArray;
52     int materialIndex;
53 
54     @property Index[] indices() { return indicesArray.data; }
55 
56     void addFace(uint a, uint b, uint c)
57     {
58         indicesArray.insertBack(Index(a, b, c));
59     }
60 
61     void addFaces(Index[] inds)
62     {
63         indicesArray.insertBack(inds);
64     }
65 }
66 
67 /// Triangle mesh
68 class TriMesh
69 {
70     Array!(Vector3f) verticesArray;
71     Array!(Vector3f) normalsArray;
72     Array!(Vector3f) tangentsArray;
73     Array!(Vector2f) texcoordsArray;
74 
75     Array!FaceGroup facegroupsArray;
76 
77     @property Vector3f[] vertices()   { return verticesArray.data; }
78     @property Vector3f[] normals()    { return normalsArray.data; }
79     @property Vector3f[] tangents()   { return tangentsArray.data; }
80     @property Vector2f[] texcoords()  { return texcoordsArray.data; }
81     @property FaceGroup[] facegroups() { return facegroupsArray.data; }
82 
83     this()
84     {
85     }
86 
87     ~this()
88     {
89         verticesArray.free();
90         normalsArray.free();
91         tangentsArray.free();
92         texcoordsArray.free();
93 
94         foreach(fc; facegroupsArray)
95             fc.indicesArray.free();
96         facegroupsArray.free();
97     }
98 
99     void addVertex(Vector3f v)
100     {
101         verticesArray.insertBack(v);
102     }
103 
104     void addNormal(Vector3f n)
105     {
106         normalsArray.insertBack(n);
107     }
108 
109     void addTangent(Vector3f t)
110     {
111         tangentsArray.insertBack(t);
112     }
113 
114     void addTexcoord(Vector2f t)
115     {
116         texcoordsArray.insertBack(t);
117     }
118 
119     void addVertices(Vector3f[] verts)
120     {
121         verticesArray.insertBack(verts);
122     }
123 
124     void addNormals(Vector3f[] norms)
125     {
126         normalsArray.insertBack(norms);
127     }
128 
129     void addTangents(Vector3f[] tans)
130     {
131         tangentsArray.insertBack(tans);
132     }
133 
134     void addTexcoords(Vector2f[] texs)
135     {
136         texcoordsArray.insertBack(texs);
137     }
138 
139     FaceGroup* addFacegroup()
140     {
141         FaceGroup fg;
142         facegroupsArray.insertBack(fg);
143         return &facegroupsArray.data[$-1];
144     }
145 
146     Triangle getTriangle(uint facegroupIndex, uint triIndex)
147     {
148         Triangle tri;
149         Index triIdx = facegroupsArray[facegroupIndex].indicesArray[triIndex];
150 
151         tri.v[0] = verticesArray[triIdx.a];
152         tri.v[1] = verticesArray[triIdx.b];
153         tri.v[2] = verticesArray[triIdx.c];
154 
155         tri.n[0] = normalsArray[triIdx.a];
156         tri.n[1] = normalsArray[triIdx.b];
157         tri.n[2] = normalsArray[triIdx.c];
158 
159         if (texcoordsArray.length == verticesArray.length)
160         {
161             tri.t1[0] = texcoordsArray[triIdx.a];
162             tri.t1[1] = texcoordsArray[triIdx.b];
163             tri.t1[2] = texcoordsArray[triIdx.c];
164         }
165 
166         tri.normal = planeNormal(tri.v[0], tri.v[1], tri.v[2]);
167 
168         tri.barycenter = (tri.v[0] + tri.v[1] + tri.v[2]) / 3;
169 
170         tri.d = (tri.v[0].x * tri.normal.x +
171                  tri.v[0].y * tri.normal.y +
172                  tri.v[0].z * tri.normal.z);
173 
174         tri.edges[0] = tri.v[1] - tri.v[0];
175         tri.edges[1] = tri.v[2] - tri.v[1];
176         tri.edges[2] = tri.v[0] - tri.v[2];
177 
178         tri.materialIndex = facegroupsArray[facegroupIndex].materialIndex;
179 
180         return tri;
181     }
182 
183     /**
184      * Read-only triangle aggregate
185      */
186     int opApply(scope int delegate(ref Triangle) dg)
187     {
188         int result = 0;
189         for (uint fgi = 0; fgi < facegroupsArray.length; fgi++)
190         for (uint i = 0; i < facegroupsArray[fgi].indices.length; i++)
191         {
192             Triangle tri = getTriangle(fgi, i);
193             result = dg(tri);
194             if (result)
195                 break;
196         }
197         return result;
198     }
199 
200     void genTangents()
201     {
202         tangentsArray.free();
203 
204         Vector3f[] sTan = New!(Vector3f[])(verticesArray.length);
205         Vector3f[] tTan = New!(Vector3f[])(verticesArray.length);
206 
207         foreach(i, v; sTan)
208         {
209             sTan[i] = Vector3f(0.0f, 0.0f, 0.0f);
210             tTan[i] = Vector3f(0.0f, 0.0f, 0.0f);
211         }
212 
213         foreach(ref fg; facegroupsArray)
214         foreach(ref index; fg.indicesArray)
215         {
216             uint i0 = index.a;
217             uint i1 = index.b;
218             uint i2 = index.c;
219 
220             Vector3f v0 = verticesArray[i0];
221             Vector3f v1 = verticesArray[i1];
222             Vector3f v2 = verticesArray[i2];
223 
224             Vector2f w0 = texcoordsArray[i0];
225             Vector2f w1 = texcoordsArray[i1];
226             Vector2f w2 = texcoordsArray[i2];
227 
228             float x1 = v1.x - v0.x;
229             float x2 = v2.x - v0.x;
230             float y1 = v1.y - v0.y;
231             float y2 = v2.y - v0.y;
232             float z1 = v1.z - v0.z;
233             float z2 = v2.z - v0.z;
234 
235             float s1 = w1[0] - w0[0];
236             float s2 = w2[0] - w0[0];
237             float t1 = w1[1] - w0[1];
238             float t2 = w2[1] - w0[1];
239 
240             float r = (s1 * t2) - (s2 * t1);
241 
242             // Prevent division by zero
243             if (r == 0.0f)
244                 r = 1.0f;
245 
246             float oneOverR = 1.0f / r;
247 
248             Vector3f sDir = Vector3f((t2 * x1 - t1 * x2) * oneOverR,
249                                      (t2 * y1 - t1 * y2) * oneOverR,
250                                      (t2 * z1 - t1 * z2) * oneOverR);
251             Vector3f tDir = Vector3f((s1 * x2 - s2 * x1) * oneOverR,
252                                      (s1 * y2 - s2 * y1) * oneOverR,
253                                      (s1 * z2 - s2 * z1) * oneOverR);
254 
255             sTan[i0] += sDir;
256             tTan[i0] += tDir;
257 
258             sTan[i1] += sDir;
259             tTan[i1] += tDir;
260 
261             sTan[i2] += sDir;
262             tTan[i2] += tDir;
263         }
264 
265         tangentsArray.resize(vertices.length, Vector3f(0.0f, 0.0f, 0.0f));
266 
267         // Calculate vertex tangent
268         foreach(i, v; tangents)
269         {
270             Vector3f n = normalsArray[i];
271             Vector3f t = sTan[i];
272 
273             // Gram-Schmidt orthogonalize
274             Vector3f tangent = (t - n * dot(n, t));
275             tangent.normalize();
276             tangentsArray[i] = tangent;
277         }
278 
279         Delete(sTan);
280         Delete(tTan);
281     }
282 }