Mesh.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Logger.h>
  9. #include <Mathematics/Matrix.h>
  10. #include <Mathematics/IndexAttribute.h>
  11. #include <Mathematics/VertexAttribute.h>
  12. #include <Mathematics/Vector2.h>
  13. #include <Mathematics/Vector3.h>
  14. // The Mesh class is designed to support triangulations of surfaces of a small
  15. // number of topologies. See the documents
  16. // https://www.geometrictools.com/MeshDifferentialGeometry.pdf
  17. // https://www.geometrictools.com/MeshFactory.pdf
  18. // for details.
  19. //
  20. // You must set the vertex attribute sources before calling Update().
  21. //
  22. // The semantic "position" is required and its source must be an array
  23. // of Real with at least 3 channels so that positions are computed as
  24. // Vector3<Real>.
  25. //
  26. // The positions are assumed to be parameterized by texture coordinates
  27. // (u,v); the position is thought of as a function P(u,v). If texture
  28. // coordinates are provided, the semantic must be "tcoord". If texture
  29. // coordinates are not provided, default texture coordinates are computed
  30. // internally as described in the mesh factory document.
  31. //
  32. // The frame for the tangent space is optional. All vectors in the frame
  33. // must have sources that are arrays of Real with at least 3 channels per
  34. // attribute. If normal vectors are provided, the semantic must be
  35. // "normal".
  36. //
  37. // Two options are supported for tangent vectors. The first option is
  38. // that the tangents are surface derivatives dP/du and dP/dv, which are
  39. // not necessarily unit length or orthogonal. The semantics must be
  40. // "dpdu" and "dpdv". The second option is that the tangents are unit
  41. // length and orthogonal, with the infrequent possibility that a vertex
  42. // is degenerate in that dP/du and dP/dv are linearly dependent. The
  43. // semantics must be "tangent" and "bitangent".
  44. //
  45. // For each provided vertex attribute, a derived class can initialize
  46. // that attribute by overriding one of the Initialize*() functions whose
  47. // stubs are defined in this class.
  48. namespace WwiseGTE
  49. {
  50. enum class MeshTopology
  51. {
  52. ARBITRARY,
  53. RECTANGLE,
  54. CYLINDER,
  55. TORUS,
  56. DISK,
  57. SPHERE
  58. };
  59. class MeshDescription
  60. {
  61. public:
  62. // Constructor for MeshTopology::ARBITRARY. The members topology,
  63. // numVertices, and numTriangles are set in the obvious manner. The
  64. // members numRows and numCols are set to zero. The remaining members
  65. // must be set explicitly by the client.
  66. MeshDescription(uint32_t inNumVertices, uint32_t inNumTriangles)
  67. :
  68. topology(MeshTopology::ARBITRARY),
  69. numVertices(inNumVertices),
  70. numTriangles(inNumTriangles),
  71. wantDynamicTangentSpaceUpdate(false),
  72. wantCCW(true),
  73. hasTangentSpaceVectors(false),
  74. allowUpdateFrame(false),
  75. numRows(0),
  76. numCols(0),
  77. rMax(0),
  78. cMax(0),
  79. rIncrement(0),
  80. constructed(false)
  81. {
  82. LogAssert(numVertices >= 3 && numTriangles >= 1, "Invalid input.");
  83. }
  84. // Constructor for topologies other than MeshTopology::ARBITRARY.
  85. // Compute the number of vertices and triangles for the mesh based on
  86. // the requested number of rows and columns. If the number of rows or
  87. // columns is invalid for the specified topology, they are modified to
  88. // be valid, in which case inNumRows/numRows and inNumCols/numCols can
  89. // differ. If the input topology is MeshTopology::ARBITRARY, then
  90. // inNumRows and inNumCols are assigned to numVertices and
  91. // numTriangles, respectively, and numRows and numCols are set to
  92. // zero. The remaining members must be set explicitly by the client.
  93. MeshDescription(MeshTopology inTopology, uint32_t inNumRows, uint32_t inNumCols)
  94. :
  95. topology(inTopology),
  96. wantDynamicTangentSpaceUpdate(false),
  97. wantCCW(true),
  98. hasTangentSpaceVectors(false),
  99. allowUpdateFrame(false),
  100. constructed(false)
  101. {
  102. switch (topology)
  103. {
  104. case MeshTopology::ARBITRARY:
  105. numVertices = inNumRows;
  106. numTriangles = inNumCols;
  107. numRows = 0;
  108. numCols = 0;
  109. rMax = 0;
  110. cMax = 0;
  111. rIncrement = 0;
  112. break;
  113. case MeshTopology::RECTANGLE:
  114. numRows = std::max(inNumRows, 2u);
  115. numCols = std::max(inNumCols, 2u);
  116. rMax = numRows - 1;
  117. cMax = numCols - 1;
  118. rIncrement = numCols;
  119. numVertices = (rMax + 1) * (cMax + 1);
  120. numTriangles = 2 * rMax * cMax;
  121. break;
  122. case MeshTopology::CYLINDER:
  123. numRows = std::max(inNumRows, 2u);
  124. numCols = std::max(inNumCols, 3u);
  125. rMax = numRows - 1;
  126. cMax = numCols;
  127. rIncrement = numCols + 1;
  128. numVertices = (rMax + 1) * (cMax + 1);
  129. numTriangles = 2 * rMax * cMax;
  130. break;
  131. case MeshTopology::TORUS:
  132. numRows = std::max(inNumRows, 2u);
  133. numCols = std::max(inNumCols, 3u);
  134. rMax = numRows;
  135. cMax = numCols;
  136. rIncrement = numCols + 1;
  137. numVertices = (rMax + 1) * (cMax + 1);
  138. numTriangles = 2 * rMax * cMax;
  139. break;
  140. case MeshTopology::DISK:
  141. numRows = std::max(inNumRows, 1u);
  142. numCols = std::max(inNumCols, 3u);
  143. rMax = numRows - 1;
  144. cMax = numCols;
  145. rIncrement = numCols + 1;
  146. numVertices = (rMax + 1) * (cMax + 1) + 1;
  147. numTriangles = 2 * rMax * cMax + numCols;
  148. break;
  149. case MeshTopology::SPHERE:
  150. numRows = std::max(inNumRows, 1u);
  151. numCols = std::max(inNumCols, 3u);
  152. rMax = numRows - 1;
  153. cMax = numCols;
  154. rIncrement = numCols + 1;
  155. numVertices = (rMax + 1) * (cMax + 1) + 2;
  156. numTriangles = 2 * rMax * cMax + 2 * numCols;
  157. break;
  158. }
  159. }
  160. MeshTopology topology;
  161. uint32_t numVertices;
  162. uint32_t numTriangles;
  163. std::vector<VertexAttribute> vertexAttributes;
  164. IndexAttribute indexAttribute;
  165. bool wantDynamicTangentSpaceUpdate; // default: false
  166. bool wantCCW; // default: true
  167. // For internal use only.
  168. bool hasTangentSpaceVectors;
  169. bool allowUpdateFrame;
  170. uint32_t numRows, numCols;
  171. uint32_t rMax, cMax, rIncrement;
  172. // After an attempt to construct a Mesh or Mesh-derived object,
  173. // examine this value to determine whether the construction was
  174. // successful.
  175. bool constructed;
  176. };
  177. template <typename Real>
  178. class Mesh
  179. {
  180. public:
  181. // Construction and destruction. This constructor is for ARBITRARY
  182. // topology. The vertices and indices must already be assigned by the
  183. // client. Derived classes use the protected constructor, but
  184. // assignment of vertices and indices occurs in the derived-class
  185. // constructors.
  186. Mesh(MeshDescription const& description, std::vector<MeshTopology> const& validTopologies)
  187. :
  188. mDescription(description),
  189. mPositions(nullptr),
  190. mNormals(nullptr),
  191. mTangents(nullptr),
  192. mBitangents(nullptr),
  193. mDPDUs(nullptr),
  194. mDPDVs(nullptr),
  195. mTCoords(nullptr),
  196. mPositionStride(0),
  197. mNormalStride(0),
  198. mTangentStride(0),
  199. mBitangentStride(0),
  200. mDPDUStride(0),
  201. mDPDVStride(0),
  202. mTCoordStride(0)
  203. {
  204. mDescription.constructed = false;
  205. for (auto const& topology : validTopologies)
  206. {
  207. if (mDescription.topology == topology)
  208. {
  209. mDescription.constructed = true;
  210. break;
  211. }
  212. }
  213. LogAssert(mDescription.indexAttribute.source != nullptr,
  214. "The mesh needs triangles/indices in Mesh constructor.");
  215. // Set sources for the requested vertex attributes.
  216. mDescription.hasTangentSpaceVectors = false;
  217. mDescription.allowUpdateFrame = mDescription.wantDynamicTangentSpaceUpdate;
  218. for (auto const& attribute : mDescription.vertexAttributes)
  219. {
  220. if (attribute.source != nullptr && attribute.stride > 0)
  221. {
  222. if (attribute.semantic == "position")
  223. {
  224. mPositions = reinterpret_cast<Vector3<Real>*>(attribute.source);
  225. mPositionStride = attribute.stride;
  226. continue;
  227. }
  228. if (attribute.semantic == "normal")
  229. {
  230. mNormals = reinterpret_cast<Vector3<Real>*>(attribute.source);
  231. mNormalStride = attribute.stride;
  232. continue;
  233. }
  234. if (attribute.semantic == "tangent")
  235. {
  236. mTangents = reinterpret_cast<Vector3<Real>*>(attribute.source);
  237. mTangentStride = attribute.stride;
  238. mDescription.hasTangentSpaceVectors = true;
  239. continue;
  240. }
  241. if (attribute.semantic == "bitangent")
  242. {
  243. mBitangents = reinterpret_cast<Vector3<Real>*>(attribute.source);
  244. mBitangentStride = attribute.stride;
  245. mDescription.hasTangentSpaceVectors = true;
  246. continue;
  247. }
  248. if (attribute.semantic == "dpdu")
  249. {
  250. mDPDUs = reinterpret_cast<Vector3<Real>*>(attribute.source);
  251. mDPDUStride = attribute.stride;
  252. mDescription.hasTangentSpaceVectors = true;
  253. continue;
  254. }
  255. if (attribute.semantic == "dpdv")
  256. {
  257. mDPDVs = reinterpret_cast<Vector3<Real>*>(attribute.source);
  258. mDPDVStride = attribute.stride;
  259. mDescription.hasTangentSpaceVectors = true;
  260. continue;
  261. }
  262. if (attribute.semantic == "tcoord")
  263. {
  264. mTCoords = reinterpret_cast<Vector2<Real>*>(attribute.source);
  265. mTCoordStride = attribute.stride;
  266. continue;
  267. }
  268. }
  269. }
  270. LogAssert(mPositions != nullptr, "The mesh needs positions in Mesh constructor.");
  271. // The initial value of allowUpdateFrame is the client request
  272. // about wanting dynamic tangent-space updates. If the vertex
  273. // attributes do not include tangent-space vectors, then dynamic
  274. // updates are not necessary. If tangent-space vectors are
  275. // present, the update algorithm requires texture coordinates
  276. // (mTCoords must be nonnull) or must compute local coordinates
  277. // (mNormals must be nonnull).
  278. if (mDescription.allowUpdateFrame)
  279. {
  280. if (!mDescription.hasTangentSpaceVectors)
  281. {
  282. mDescription.allowUpdateFrame = false;
  283. }
  284. if (!mTCoords && !mNormals)
  285. {
  286. mDescription.allowUpdateFrame = false;
  287. }
  288. }
  289. if (mDescription.allowUpdateFrame)
  290. {
  291. mUTU.resize(mDescription.numVertices);
  292. mDTU.resize(mDescription.numVertices);
  293. }
  294. }
  295. virtual ~Mesh()
  296. {
  297. }
  298. // No copying or assignment is allowed.
  299. Mesh(Mesh const&) = delete;
  300. Mesh& operator=(Mesh const&) = delete;
  301. // Member accessors.
  302. inline MeshDescription const& GetDescription() const
  303. {
  304. return mDescription;
  305. }
  306. // If the underlying geometric data varies dynamically, call this
  307. // function to update whatever vertex attributes are specified by
  308. // the vertex pool.
  309. void Update()
  310. {
  311. LogAssert(mDescription.constructed, "The Mesh object failed the construction.");
  312. UpdatePositions();
  313. if (mDescription.allowUpdateFrame)
  314. {
  315. UpdateFrame();
  316. }
  317. else if (mNormals)
  318. {
  319. UpdateNormals();
  320. }
  321. // else: The mesh has no frame data, so there is nothing to do.
  322. }
  323. protected:
  324. // Access the vertex attributes.
  325. inline Vector3<Real>& Position(uint32_t i)
  326. {
  327. char* positions = reinterpret_cast<char*>(mPositions);
  328. return *reinterpret_cast<Vector3<Real>*>(positions + i * mPositionStride);
  329. }
  330. inline Vector3<Real>& Normal(uint32_t i)
  331. {
  332. char* normals = reinterpret_cast<char*>(mNormals);
  333. return *reinterpret_cast<Vector3<Real>*>(normals + i * mNormalStride);
  334. }
  335. inline Vector3<Real>& Tangent(uint32_t i)
  336. {
  337. char* tangents = reinterpret_cast<char*>(mTangents);
  338. return *reinterpret_cast<Vector3<Real>*>(tangents + i * mTangentStride);
  339. }
  340. inline Vector3<Real>& Bitangent(uint32_t i)
  341. {
  342. char* bitangents = reinterpret_cast<char*>(mBitangents);
  343. return *reinterpret_cast<Vector3<Real>*>(bitangents + i * mBitangentStride);
  344. }
  345. inline Vector3<Real>& DPDU(uint32_t i)
  346. {
  347. char* dpdus = reinterpret_cast<char*>(mDPDUs);
  348. return *reinterpret_cast<Vector3<Real>*>(dpdus + i * mDPDUStride);
  349. }
  350. inline Vector3<Real>& DPDV(uint32_t i)
  351. {
  352. char* dpdvs = reinterpret_cast<char*>(mDPDVs);
  353. return *reinterpret_cast<Vector3<Real>*>(dpdvs + i * mDPDVStride);
  354. }
  355. inline Vector2<Real>& TCoord(uint32_t i)
  356. {
  357. char* tcoords = reinterpret_cast<char*>(mTCoords);
  358. return *reinterpret_cast<Vector2<Real>*>(tcoords + i * mTCoordStride);
  359. }
  360. // Compute the indices for non-arbitrary topologies. This function is
  361. // called by derived classes.
  362. void ComputeIndices()
  363. {
  364. uint32_t t = 0;
  365. for (uint32_t r = 0, i = 0; r < mDescription.rMax; ++r)
  366. {
  367. uint32_t v0 = i, v1 = v0 + 1;
  368. i += mDescription.rIncrement;
  369. uint32_t v2 = i, v3 = v2 + 1;
  370. for (uint32_t c = 0; c < mDescription.cMax; ++c, ++v0, ++v1, ++v2, ++v3)
  371. {
  372. if (mDescription.wantCCW)
  373. {
  374. mDescription.indexAttribute.SetTriangle(t++, v0, v1, v2);
  375. mDescription.indexAttribute.SetTriangle(t++, v1, v3, v2);
  376. }
  377. else
  378. {
  379. mDescription.indexAttribute.SetTriangle(t++, v0, v2, v1);
  380. mDescription.indexAttribute.SetTriangle(t++, v1, v2, v3);
  381. }
  382. }
  383. }
  384. if (mDescription.topology == MeshTopology::DISK)
  385. {
  386. uint32_t v0 = 0, v1 = 1, v2 = mDescription.numVertices - 1;
  387. for (unsigned int c = 0; c < mDescription.numCols; ++c, ++v0, ++v1)
  388. {
  389. if (mDescription.wantCCW)
  390. {
  391. mDescription.indexAttribute.SetTriangle(t++, v0, v2, v1);
  392. }
  393. else
  394. {
  395. mDescription.indexAttribute.SetTriangle(t++, v0, v1, v2);
  396. }
  397. }
  398. }
  399. else if (mDescription.topology == MeshTopology::SPHERE)
  400. {
  401. uint32_t v0 = 0, v1 = 1, v2 = mDescription.numVertices - 2;
  402. for (uint32_t c = 0; c < mDescription.numCols; ++c, ++v0, ++v1)
  403. {
  404. if (mDescription.wantCCW)
  405. {
  406. mDescription.indexAttribute.SetTriangle(t++, v0, v2, v1);
  407. }
  408. else
  409. {
  410. mDescription.indexAttribute.SetTriangle(t++, v0, v1, v2);
  411. }
  412. }
  413. v0 = (mDescription.numRows - 1) * mDescription.numCols;
  414. v1 = v0 + 1;
  415. v2 = mDescription.numVertices - 1;
  416. for (uint32_t c = 0; c < mDescription.numCols; ++c, ++v0, ++v1)
  417. {
  418. if (mDescription.wantCCW)
  419. {
  420. mDescription.indexAttribute.SetTriangle(t++, v0, v2, v1);
  421. }
  422. else
  423. {
  424. mDescription.indexAttribute.SetTriangle(t++, v0, v1, v2);
  425. }
  426. }
  427. }
  428. }
  429. // The Update() function allows derived classes to use algorithms
  430. // different from least-squares fitting to compute the normals (when
  431. // no tangent-space information is requested) or to compute the frame
  432. // (normals and tangent space). The UpdatePositions() is a stub; the
  433. // base-class has no knowledge about how positions should be modified.
  434. // A derived class, however, might choose to use dynamic updating
  435. // and override UpdatePositions(). The base-class UpdateNormals()
  436. // computes vertex normals as averages of area-weighted triangle
  437. // normals (nonparametric approach). The base-class UpdateFrame()
  438. // uses a least-squares algorithm for estimating the tangent space
  439. // (parametric approach).
  440. virtual void UpdatePositions()
  441. {
  442. }
  443. virtual void UpdateNormals()
  444. {
  445. // Compute normal vector as normalized weighted averages of triangle
  446. // normal vectors.
  447. // Set the normals to zero to allow accumulation of triangle normals.
  448. Vector3<Real> zero{ (Real)0, (Real)0, (Real)0 };
  449. for (uint32_t i = 0; i < mDescription.numVertices; ++i)
  450. {
  451. Normal(i) = zero;
  452. }
  453. // Accumulate the triangle normals.
  454. for (uint32_t t = 0; t < mDescription.numTriangles; ++t)
  455. {
  456. // Get the positions for the triangle.
  457. uint32_t v0, v1, v2;
  458. mDescription.indexAttribute.GetTriangle(t, v0, v1, v2);
  459. Vector3<Real> P0 = Position(v0);
  460. Vector3<Real> P1 = Position(v1);
  461. Vector3<Real> P2 = Position(v2);
  462. // Get the edge vectors.
  463. Vector3<Real> E1 = P1 - P0;
  464. Vector3<Real> E2 = P2 - P0;
  465. // Compute a triangle normal show length is twice the area of the
  466. // triangle.
  467. Vector3<Real> triangleNormal = Cross(E1, E2);
  468. // Accumulate the triangle normals.
  469. Normal(v0) += triangleNormal;
  470. Normal(v1) += triangleNormal;
  471. Normal(v2) += triangleNormal;
  472. }
  473. // Normalize the normals.
  474. for (uint32_t i = 0; i < mDescription.numVertices; ++i)
  475. {
  476. Normalize(Normal(i), true);
  477. }
  478. }
  479. virtual void UpdateFrame()
  480. {
  481. if (!mTCoords)
  482. {
  483. // We need to compute vertex normals first in order to compute
  484. // local texture coordinates. The vertex normals are recomputed
  485. // later based on estimated tangent vectors.
  486. UpdateNormals();
  487. }
  488. // Use the least-squares algorithm to estimate the tangent-space vectors
  489. // and, if requested, normal vectors.
  490. Matrix<2, 2, Real> zero2x2; // initialized to zero
  491. Matrix<3, 2, Real> zero3x2; // initialized to zero
  492. std::fill(mUTU.begin(), mUTU.end(), zero2x2);
  493. std::fill(mDTU.begin(), mDTU.end(), zero3x2);
  494. for (uint32_t t = 0; t < mDescription.numTriangles; ++t)
  495. {
  496. // Get the positions and differences for the triangle.
  497. uint32_t v0, v1, v2;
  498. mDescription.indexAttribute.GetTriangle(t, v0, v1, v2);
  499. Vector3<Real> P0 = Position(v0);
  500. Vector3<Real> P1 = Position(v1);
  501. Vector3<Real> P2 = Position(v2);
  502. Vector3<Real> D10 = P1 - P0;
  503. Vector3<Real> D20 = P2 - P0;
  504. Vector3<Real> D21 = P2 - P1;
  505. if (mTCoords)
  506. {
  507. // Get the texture coordinates and differences for the triangle.
  508. Vector2<Real> C0 = TCoord(v0);
  509. Vector2<Real> C1 = TCoord(v1);
  510. Vector2<Real> C2 = TCoord(v2);
  511. Vector2<Real> U10 = C1 - C0;
  512. Vector2<Real> U20 = C2 - C0;
  513. Vector2<Real> U21 = C2 - C1;
  514. // Compute the outer products.
  515. Matrix<2, 2, Real> outerU10 = OuterProduct(U10, U10);
  516. Matrix<2, 2, Real> outerU20 = OuterProduct(U20, U20);
  517. Matrix<2, 2, Real> outerU21 = OuterProduct(U21, U21);
  518. Matrix<3, 2, Real> outerD10 = OuterProduct(D10, U10);
  519. Matrix<3, 2, Real> outerD20 = OuterProduct(D20, U20);
  520. Matrix<3, 2, Real> outerD21 = OuterProduct(D21, U21);
  521. // Keep a running sum of U^T*U and D^T*U.
  522. mUTU[v0] += outerU10 + outerU20;
  523. mUTU[v1] += outerU10 + outerU21;
  524. mUTU[v2] += outerU20 + outerU21;
  525. mDTU[v0] += outerD10 + outerD20;
  526. mDTU[v1] += outerD10 + outerD21;
  527. mDTU[v2] += outerD20 + outerD21;
  528. }
  529. else
  530. {
  531. // Compute local coordinates and differences for the triangle.
  532. Vector3<Real> basis[3];
  533. basis[0] = Normal(v0);
  534. ComputeOrthogonalComplement(1, basis, true);
  535. Vector2<Real> U10{ Dot(basis[1], D10), Dot(basis[2], D10) };
  536. Vector2<Real> U20{ Dot(basis[1], D20), Dot(basis[2], D20) };
  537. mUTU[v0] += OuterProduct(U10, U10) + OuterProduct(U20, U20);
  538. mDTU[v0] += OuterProduct(D10, U10) + OuterProduct(D20, U20);
  539. basis[0] = Normal(v1);
  540. ComputeOrthogonalComplement(1, basis, true);
  541. Vector2<Real> U01{ Dot(basis[1], D10), Dot(basis[2], D10) };
  542. Vector2<Real> U21{ Dot(basis[1], D21), Dot(basis[2], D21) };
  543. mUTU[v1] += OuterProduct(U01, U01) + OuterProduct(U21, U21);
  544. mDTU[v1] += OuterProduct(D10, U01) + OuterProduct(D21, U21);
  545. basis[0] = Normal(v2);
  546. ComputeOrthogonalComplement(1, basis, true);
  547. Vector2<Real> U02{ Dot(basis[1], D20), Dot(basis[2], D20) };
  548. Vector2<Real> U12{ Dot(basis[1], D21), Dot(basis[2], D21) };
  549. mUTU[v2] += OuterProduct(U02, U02) + OuterProduct(U12, U12);
  550. mDTU[v2] += OuterProduct(D20, U02) + OuterProduct(D21, U12);
  551. }
  552. }
  553. for (uint32_t i = 0; i < mDescription.numVertices; ++i)
  554. {
  555. Matrix<3, 2, Real> jacobian = mDTU[i] * Inverse(mUTU[i]);
  556. Vector3<Real> basis[3];
  557. basis[0] = { jacobian(0, 0), jacobian(1, 0), jacobian(2, 0) };
  558. basis[1] = { jacobian(0, 1), jacobian(1, 1), jacobian(2, 1) };
  559. if (mDPDUs)
  560. {
  561. DPDU(i) = basis[0];
  562. }
  563. if (mDPDVs)
  564. {
  565. DPDV(i) = basis[1];
  566. }
  567. ComputeOrthogonalComplement(2, basis, true);
  568. if (mNormals)
  569. {
  570. Normal(i) = basis[2];
  571. }
  572. if (mTangents)
  573. {
  574. Tangent(i) = basis[0];
  575. }
  576. if (mBitangents)
  577. {
  578. Bitangent(i) = basis[1];
  579. }
  580. }
  581. }
  582. // Constructor inputs.
  583. // The client requests this via the constructor; however, if it is
  584. // requested and the vertex attributes do not contain entries for
  585. // "tangent", "bitangent", "dpdu", or "dpdv", then this member is
  586. // set to false.
  587. MeshDescription mDescription;
  588. // Copied from mVertexAttributes when available.
  589. Vector3<Real>* mPositions;
  590. Vector3<Real>* mNormals;
  591. Vector3<Real>* mTangents;
  592. Vector3<Real>* mBitangents;
  593. Vector3<Real>* mDPDUs;
  594. Vector3<Real>* mDPDVs;
  595. Vector2<Real>* mTCoords;
  596. size_t mPositionStride;
  597. size_t mNormalStride;
  598. size_t mTangentStride;
  599. size_t mBitangentStride;
  600. size_t mDPDUStride;
  601. size_t mDPDVStride;
  602. size_t mTCoordStride;
  603. // When dynamic tangent-space updates are requested, the update algorithm
  604. // requires texture coordinates (user-specified or non-local). It is
  605. // possible to create a vertex-adjacent set (with indices into the
  606. // vertex array) for each mesh vertex; however, instead we rely on a
  607. // triangle iteration and incrementally store the information needed for
  608. // the estimation of the tangent space. Each vertex has associated
  609. // matrices D and U, but we need to store only U^T*U and D^T*U. See the
  610. // PDF for details.
  611. std::vector<Matrix<2, 2, Real>> mUTU;
  612. std::vector<Matrix<3, 2, Real>> mDTU;
  613. };
  614. }