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 }