Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/GetTrianglesContext.h
9917 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56#include <Jolt/Physics/Collision/Shape/Shape.h>78JPH_NAMESPACE_BEGIN910class PhysicsMaterial;1112/// Implementation of GetTrianglesStart/Next that uses a fixed list of vertices for the triangles. These are transformed into world space when getting the triangles.13class GetTrianglesContextVertexList14{15public:16/// Constructor, to be called in GetTrianglesStart17GetTrianglesContextVertexList(Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, Mat44Arg inLocalTransform, const Vec3 *inTriangleVertices, size_t inNumTriangleVertices, const PhysicsMaterial *inMaterial) :18mLocalToWorld(Mat44::sRotationTranslation(inRotation, inPositionCOM) * Mat44::sScale(inScale) * inLocalTransform),19mTriangleVertices(inTriangleVertices),20mNumTriangleVertices(inNumTriangleVertices),21mMaterial(inMaterial),22mIsInsideOut(ScaleHelpers::IsInsideOut(inScale))23{24static_assert(sizeof(GetTrianglesContextVertexList) <= sizeof(Shape::GetTrianglesContext), "GetTrianglesContext too small");25JPH_ASSERT(IsAligned(this, alignof(GetTrianglesContextVertexList)));26JPH_ASSERT(inNumTriangleVertices % 3 == 0);27}2829/// @see Shape::GetTrianglesNext30int GetTrianglesNext(int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials)31{32JPH_ASSERT(inMaxTrianglesRequested >= Shape::cGetTrianglesMinTrianglesRequested);3334int total_num_vertices = min(inMaxTrianglesRequested * 3, int(mNumTriangleVertices - mCurrentVertex));3536if (mIsInsideOut)37{38// Store triangles flipped39for (const Vec3 *v = mTriangleVertices + mCurrentVertex, *v_end = v + total_num_vertices; v < v_end; v += 3)40{41(mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);42(mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);43(mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);44}45}46else47{48// Store triangles49for (const Vec3 *v = mTriangleVertices + mCurrentVertex, *v_end = v + total_num_vertices; v < v_end; v += 3)50{51(mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);52(mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);53(mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);54}55}5657// Update the current vertex to point to the next vertex to get58mCurrentVertex += total_num_vertices;59int total_num_triangles = total_num_vertices / 3;6061// Store materials62if (outMaterials != nullptr)63for (const PhysicsMaterial **m = outMaterials, **m_end = outMaterials + total_num_triangles; m < m_end; ++m)64*m = mMaterial;6566return total_num_triangles;67}6869/// Helper function that creates a vertex list of a half unit sphere (top part)70template <class A>71static void sCreateHalfUnitSphereTop(A &ioVertices, int inDetailLevel)72{73sCreateUnitSphereHelper(ioVertices, Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), inDetailLevel);74sCreateUnitSphereHelper(ioVertices, Vec3::sAxisY(), -Vec3::sAxisX(), Vec3::sAxisZ(), inDetailLevel);75sCreateUnitSphereHelper(ioVertices, Vec3::sAxisY(), Vec3::sAxisX(), -Vec3::sAxisZ(), inDetailLevel);76sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), inDetailLevel);77}7879/// Helper function that creates a vertex list of a half unit sphere (bottom part)80template <class A>81static void sCreateHalfUnitSphereBottom(A &ioVertices, int inDetailLevel)82{83sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), inDetailLevel);84sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisY(), Vec3::sAxisX(), Vec3::sAxisZ(), inDetailLevel);85sCreateUnitSphereHelper(ioVertices, Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), inDetailLevel);86sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisY(), -Vec3::sAxisX(), -Vec3::sAxisZ(), inDetailLevel);87}8889/// Helper function that creates an open cylinder of half height 1 and radius 190template <class A>91static void sCreateUnitOpenCylinder(A &ioVertices, int inDetailLevel)92{93const Vec3 bottom_offset(0.0f, -2.0f, 0.0f);94int num_verts = 4 * (1 << inDetailLevel);95for (int i = 0; i < num_verts; ++i)96{97float angle1 = 2.0f * JPH_PI * (float(i) / num_verts);98float angle2 = 2.0f * JPH_PI * (float(i + 1) / num_verts);99100Vec3 t1(Sin(angle1), 1.0f, Cos(angle1));101Vec3 t2(Sin(angle2), 1.0f, Cos(angle2));102Vec3 b1 = t1 + bottom_offset;103Vec3 b2 = t2 + bottom_offset;104105ioVertices.push_back(t1);106ioVertices.push_back(b1);107ioVertices.push_back(t2);108109ioVertices.push_back(t2);110ioVertices.push_back(b1);111ioVertices.push_back(b2);112}113}114115private:116/// Recursive helper function for creating a sphere117template <class A>118static void sCreateUnitSphereHelper(A &ioVertices, Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, int inLevel)119{120Vec3 center1 = (inV1 + inV2).Normalized();121Vec3 center2 = (inV2 + inV3).Normalized();122Vec3 center3 = (inV3 + inV1).Normalized();123124if (inLevel > 0)125{126int new_level = inLevel - 1;127sCreateUnitSphereHelper(ioVertices, inV1, center1, center3, new_level);128sCreateUnitSphereHelper(ioVertices, center1, center2, center3, new_level);129sCreateUnitSphereHelper(ioVertices, center1, inV2, center2, new_level);130sCreateUnitSphereHelper(ioVertices, center3, center2, inV3, new_level);131}132else133{134ioVertices.push_back(inV1);135ioVertices.push_back(inV2);136ioVertices.push_back(inV3);137}138}139140Mat44 mLocalToWorld;141const Vec3 * mTriangleVertices;142size_t mNumTriangleVertices;143size_t mCurrentVertex = 0;144const PhysicsMaterial * mMaterial;145bool mIsInsideOut;146};147148/// Implementation of GetTrianglesStart/Next that uses a multiple fixed lists of vertices for the triangles. These are transformed into world space when getting the triangles.149class GetTrianglesContextMultiVertexList150{151public:152/// Constructor, to be called in GetTrianglesStart153GetTrianglesContextMultiVertexList(bool inIsInsideOut, const PhysicsMaterial *inMaterial) :154mMaterial(inMaterial),155mIsInsideOut(inIsInsideOut)156{157static_assert(sizeof(GetTrianglesContextMultiVertexList) <= sizeof(Shape::GetTrianglesContext), "GetTrianglesContext too small");158JPH_ASSERT(IsAligned(this, alignof(GetTrianglesContextMultiVertexList)));159}160161/// Add a mesh part and its transform162void AddPart(Mat44Arg inLocalToWorld, const Vec3 *inTriangleVertices, size_t inNumTriangleVertices)163{164JPH_ASSERT(inNumTriangleVertices % 3 == 0);165166mParts.push_back({ inLocalToWorld, inTriangleVertices, inNumTriangleVertices });167}168169/// @see Shape::GetTrianglesNext170int GetTrianglesNext(int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials)171{172JPH_ASSERT(inMaxTrianglesRequested >= Shape::cGetTrianglesMinTrianglesRequested);173174int total_num_vertices = 0;175int max_vertices_requested = inMaxTrianglesRequested * 3;176177// Loop over parts178for (; mCurrentPart < mParts.size(); ++mCurrentPart)179{180const Part &part = mParts[mCurrentPart];181182// Calculate how many vertices to take from this part183int part_num_vertices = min(max_vertices_requested, int(part.mNumTriangleVertices - mCurrentVertex));184if (part_num_vertices == 0)185break;186187max_vertices_requested -= part_num_vertices;188total_num_vertices += part_num_vertices;189190if (mIsInsideOut)191{192// Store triangles flipped193for (const Vec3 *v = part.mTriangleVertices + mCurrentVertex, *v_end = v + part_num_vertices; v < v_end; v += 3)194{195(part.mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);196(part.mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);197(part.mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);198}199}200else201{202// Store triangles203for (const Vec3 *v = part.mTriangleVertices + mCurrentVertex, *v_end = v + part_num_vertices; v < v_end; v += 3)204{205(part.mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);206(part.mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);207(part.mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);208}209}210211// Update the current vertex to point to the next vertex to get212mCurrentVertex += part_num_vertices;213214// Check if we completed this part215if (mCurrentVertex < part.mNumTriangleVertices)216break;217218// Reset current vertex for the next part219mCurrentVertex = 0;220}221222int total_num_triangles = total_num_vertices / 3;223224// Store materials225if (outMaterials != nullptr)226for (const PhysicsMaterial **m = outMaterials, **m_end = outMaterials + total_num_triangles; m < m_end; ++m)227*m = mMaterial;228229return total_num_triangles;230}231232private:233struct Part234{235Mat44 mLocalToWorld;236const Vec3 * mTriangleVertices;237size_t mNumTriangleVertices;238};239240StaticArray<Part, 3> mParts;241uint mCurrentPart = 0;242size_t mCurrentVertex = 0;243const PhysicsMaterial * mMaterial;244bool mIsInsideOut;245};246247JPH_NAMESPACE_END248249250