Path: blob/master/thirdparty/jolt_physics/Jolt/Geometry/Indexify.cpp
9913 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#include <Jolt/Jolt.h>56#include <Jolt/Geometry/Indexify.h>7#include <Jolt/Geometry/AABox.h>89JPH_NAMESPACE_BEGIN1011static JPH_INLINE const Float3 &sIndexifyGetFloat3(const TriangleList &inTriangles, uint32 inVertexIndex)12{13return inTriangles[inVertexIndex / 3].mV[inVertexIndex % 3];14}1516static JPH_INLINE Vec3 sIndexifyGetVec3(const TriangleList &inTriangles, uint32 inVertexIndex)17{18return Vec3::sLoadFloat3Unsafe(sIndexifyGetFloat3(inTriangles, inVertexIndex));19}2021static void sIndexifyVerticesBruteForce(const TriangleList &inTriangles, const uint32 *inVertexIndices, const uint32 *inVertexIndicesEnd, Array<uint32> &ioWeldedVertices, float inVertexWeldDistance)22{23float weld_dist_sq = Square(inVertexWeldDistance);2425// Compare every vertex26for (const uint32 *v1_idx = inVertexIndices; v1_idx < inVertexIndicesEnd; ++v1_idx)27{28Vec3 v1 = sIndexifyGetVec3(inTriangles, *v1_idx);2930// with every other vertex...31for (const uint32 *v2_idx = v1_idx + 1; v2_idx < inVertexIndicesEnd; ++v2_idx)32{33Vec3 v2 = sIndexifyGetVec3(inTriangles, *v2_idx);3435// If they're weldable36if ((v2 - v1).LengthSq() <= weld_dist_sq)37{38// Find the lowest indices both indices link to39uint32 idx1 = *v1_idx;40for (;;)41{42uint32 new_idx1 = ioWeldedVertices[idx1];43if (new_idx1 >= idx1)44break;45idx1 = new_idx1;46}47uint32 idx2 = *v2_idx;48for (;;)49{50uint32 new_idx2 = ioWeldedVertices[idx2];51if (new_idx2 >= idx2)52break;53idx2 = new_idx2;54}5556// Order the vertices57uint32 lowest = min(idx1, idx2);58uint32 highest = max(idx1, idx2);5960// Link highest to lowest61ioWeldedVertices[highest] = lowest;6263// Also update the vertices we started from to avoid creating long chains64ioWeldedVertices[*v1_idx] = lowest;65ioWeldedVertices[*v2_idx] = lowest;66break;67}68}69}70}7172static void sIndexifyVerticesRecursively(const TriangleList &inTriangles, uint32 *ioVertexIndices, uint inNumVertices, uint32 *ioScratch, Array<uint32> &ioWeldedVertices, float inVertexWeldDistance, uint inMaxRecursion)73{74// Check if we have few enough vertices to do a brute force search75// Or if we've recursed too deep (this means we chipped off a few vertices each iteration because all points are very close)76if (inNumVertices <= 8 || inMaxRecursion == 0)77{78sIndexifyVerticesBruteForce(inTriangles, ioVertexIndices, ioVertexIndices + inNumVertices, ioWeldedVertices, inVertexWeldDistance);79return;80}8182// Calculate bounds83AABox bounds;84for (const uint32 *v = ioVertexIndices, *v_end = ioVertexIndices + inNumVertices; v < v_end; ++v)85bounds.Encapsulate(sIndexifyGetVec3(inTriangles, *v));8687// Determine split plane88int split_axis = bounds.GetExtent().GetHighestComponentIndex();89float split_value = bounds.GetCenter()[split_axis];9091// Partition vertices92uint32 *v_read = ioVertexIndices, *v_write = ioVertexIndices, *v_end = ioVertexIndices + inNumVertices;93uint32 *scratch = ioScratch;94while (v_read < v_end)95{96// Calculate distance to plane97float distance_to_split_plane = sIndexifyGetFloat3(inTriangles, *v_read)[split_axis] - split_value;98if (distance_to_split_plane < -inVertexWeldDistance)99{100// Vertex is on the right side101*v_write = *v_read;102++v_read;103++v_write;104}105else if (distance_to_split_plane > inVertexWeldDistance)106{107// Vertex is on the wrong side, swap with the last vertex108--v_end;109std::swap(*v_read, *v_end);110}111else112{113// Vertex is too close to the split plane, it goes on both sides114*scratch++ = *v_read++;115}116}117118// Check if we made any progress119uint num_vertices_on_both_sides = (uint)(scratch - ioScratch);120if (num_vertices_on_both_sides == inNumVertices)121{122sIndexifyVerticesBruteForce(inTriangles, ioVertexIndices, ioVertexIndices + inNumVertices, ioWeldedVertices, inVertexWeldDistance);123return;124}125126// Calculate how we classified the vertices127uint num_vertices_left = (uint)(v_write - ioVertexIndices);128uint num_vertices_right = (uint)(ioVertexIndices + inNumVertices - v_end);129JPH_ASSERT(num_vertices_left + num_vertices_right + num_vertices_on_both_sides == inNumVertices);130memcpy(v_write, ioScratch, num_vertices_on_both_sides * sizeof(uint32));131132// Recurse133uint max_recursion = inMaxRecursion - 1;134sIndexifyVerticesRecursively(inTriangles, ioVertexIndices, num_vertices_left + num_vertices_on_both_sides, ioScratch, ioWeldedVertices, inVertexWeldDistance, max_recursion);135sIndexifyVerticesRecursively(inTriangles, ioVertexIndices + num_vertices_left, num_vertices_right + num_vertices_on_both_sides, ioScratch, ioWeldedVertices, inVertexWeldDistance, max_recursion);136}137138void Indexify(const TriangleList &inTriangles, VertexList &outVertices, IndexedTriangleList &outTriangles, float inVertexWeldDistance)139{140uint num_triangles = (uint)inTriangles.size();141uint num_vertices = num_triangles * 3;142143// Create a list of all vertex indices144Array<uint32> vertex_indices;145vertex_indices.resize(num_vertices);146for (uint i = 0; i < num_vertices; ++i)147vertex_indices[i] = i;148149// Link each vertex to itself150Array<uint32> welded_vertices;151welded_vertices.resize(num_vertices);152for (uint i = 0; i < num_vertices; ++i)153welded_vertices[i] = i;154155// A scope to free memory used by the scratch array156{157// Some scratch memory, used for the vertices that fall in both partitions158Array<uint32> scratch;159scratch.resize(num_vertices);160161// Recursively split the vertices162sIndexifyVerticesRecursively(inTriangles, vertex_indices.data(), num_vertices, scratch.data(), welded_vertices, inVertexWeldDistance, 32);163}164165// Do a pass to complete the welding, linking each vertex to the vertex it is welded to166// (and since we're going from 0 to N we can be sure that the vertex we're linking to is already linked to the lowest vertex)167uint num_resulting_vertices = 0;168for (uint i = 0; i < num_vertices; ++i)169{170JPH_ASSERT(welded_vertices[welded_vertices[i]] <= welded_vertices[i]);171welded_vertices[i] = welded_vertices[welded_vertices[i]];172if (welded_vertices[i] == i)173++num_resulting_vertices;174}175176// Collect the vertices177outVertices.clear();178outVertices.reserve(num_resulting_vertices);179for (uint i = 0; i < num_vertices; ++i)180if (welded_vertices[i] == i)181{182// New vertex183welded_vertices[i] = (uint32)outVertices.size();184outVertices.push_back(sIndexifyGetFloat3(inTriangles, i));185}186else187{188// Reused vertex, remap index189welded_vertices[i] = welded_vertices[welded_vertices[i]];190}191192// Create indexed triangles193outTriangles.clear();194outTriangles.reserve(num_triangles);195for (uint t = 0; t < num_triangles; ++t)196{197IndexedTriangle it;198it.mMaterialIndex = inTriangles[t].mMaterialIndex;199it.mUserData = inTriangles[t].mUserData;200for (int v = 0; v < 3; ++v)201it.mIdx[v] = welded_vertices[t * 3 + v];202if (!it.IsDegenerate(outVertices))203outTriangles.push_back(it);204}205}206207void Deindexify(const VertexList &inVertices, const IndexedTriangleList &inTriangles, TriangleList &outTriangles)208{209outTriangles.resize(inTriangles.size());210for (size_t t = 0; t < inTriangles.size(); ++t)211{212const IndexedTriangle &in = inTriangles[t];213Triangle &out = outTriangles[t];214out.mMaterialIndex = in.mMaterialIndex;215out.mUserData = in.mUserData;216for (int v = 0; v < 3; ++v)217out.mV[v] = inVertices[in.mIdx[v]];218}219}220221JPH_NAMESPACE_END222223224