Path: blob/master/thirdparty/jolt_physics/Jolt/Renderer/DebugRenderer.cpp
9906 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#include <Jolt/Jolt.h>56#ifdef JPH_DEBUG_RENDERER78#include <Jolt/Renderer/DebugRenderer.h>9#include <Jolt/Core/Profiler.h>10#include <Jolt/Geometry/OrientedBox.h>1112JPH_NAMESPACE_BEGIN1314DebugRenderer *DebugRenderer::sInstance = nullptr;1516// Number of LOD levels to create17static const int sMaxLevel = 4;1819// Distance for each LOD level, these are tweaked for an object of approx. size 1. Use the lod scale to scale these distances.20static const float sLODDistanceForLevel[] = { 5.0f, 10.0f, 40.0f, cLargeFloat };2122DebugRenderer::Triangle::Triangle(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, ColorArg inColor)23{24// Set position25inV1.StoreFloat3(&mV[0].mPosition);26inV2.StoreFloat3(&mV[1].mPosition);27inV3.StoreFloat3(&mV[2].mPosition);2829// Set color30mV[0].mColor = mV[1].mColor = mV[2].mColor = inColor;3132// Calculate normal33Vec3 normal = (inV2 - inV1).Cross(inV3 - inV1);34float normal_len = normal.Length();35if (normal_len > 0.0f)36normal /= normal_len;37Float3 normal3;38normal.StoreFloat3(&normal3);39mV[0].mNormal = mV[1].mNormal = mV[2].mNormal = normal3;4041// Reset UV's42mV[0].mUV = mV[1].mUV = mV[2].mUV = { 0, 0 };43}4445DebugRenderer::Triangle::Triangle(Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, ColorArg inColor, Vec3Arg inUVOrigin, Vec3Arg inUVDirection)46{47// Set position48inV1.StoreFloat3(&mV[0].mPosition);49inV2.StoreFloat3(&mV[1].mPosition);50inV3.StoreFloat3(&mV[2].mPosition);5152// Set color53mV[0].mColor = mV[1].mColor = mV[2].mColor = inColor;5455// Calculate normal56Vec3 normal = (inV2 - inV1).Cross(inV3 - inV1).Normalized();57Float3 normal3;58normal.StoreFloat3(&normal3);59mV[0].mNormal = mV[1].mNormal = mV[2].mNormal = normal3;6061// Set UV's62Vec3 uv1 = inV1 - inUVOrigin;63Vec3 uv2 = inV2 - inUVOrigin;64Vec3 uv3 = inV3 - inUVOrigin;65Vec3 axis2 = normal.Cross(inUVDirection);66mV[0].mUV = { inUVDirection.Dot(uv1), axis2.Dot(uv1) };67mV[1].mUV = { inUVDirection.Dot(uv2), axis2.Dot(uv2) };68mV[2].mUV = { inUVDirection.Dot(uv3), axis2.Dot(uv3) };69}7071DebugRenderer::DebugRenderer()72{73// Store singleton74JPH_ASSERT(sInstance == nullptr);75sInstance = this;76}7778DebugRenderer::~DebugRenderer()79{80JPH_ASSERT(sInstance == this);81sInstance = nullptr;82}8384void DebugRenderer::DrawWireBox(const AABox &inBox, ColorArg inColor)85{86JPH_PROFILE_FUNCTION();8788// 8 vertices89RVec3 v1(Real(inBox.mMin.GetX()), Real(inBox.mMin.GetY()), Real(inBox.mMin.GetZ()));90RVec3 v2(Real(inBox.mMin.GetX()), Real(inBox.mMin.GetY()), Real(inBox.mMax.GetZ()));91RVec3 v3(Real(inBox.mMin.GetX()), Real(inBox.mMax.GetY()), Real(inBox.mMin.GetZ()));92RVec3 v4(Real(inBox.mMin.GetX()), Real(inBox.mMax.GetY()), Real(inBox.mMax.GetZ()));93RVec3 v5(Real(inBox.mMax.GetX()), Real(inBox.mMin.GetY()), Real(inBox.mMin.GetZ()));94RVec3 v6(Real(inBox.mMax.GetX()), Real(inBox.mMin.GetY()), Real(inBox.mMax.GetZ()));95RVec3 v7(Real(inBox.mMax.GetX()), Real(inBox.mMax.GetY()), Real(inBox.mMin.GetZ()));96RVec3 v8(Real(inBox.mMax.GetX()), Real(inBox.mMax.GetY()), Real(inBox.mMax.GetZ()));9798// 12 edges99DrawLine(v1, v2, inColor);100DrawLine(v1, v3, inColor);101DrawLine(v1, v5, inColor);102DrawLine(v2, v4, inColor);103DrawLine(v2, v6, inColor);104DrawLine(v3, v4, inColor);105DrawLine(v3, v7, inColor);106DrawLine(v4, v8, inColor);107DrawLine(v5, v6, inColor);108DrawLine(v5, v7, inColor);109DrawLine(v6, v8, inColor);110DrawLine(v7, v8, inColor);111}112113void DebugRenderer::DrawWireBox(const OrientedBox &inBox, ColorArg inColor)114{115JPH_PROFILE_FUNCTION();116117// 8 vertices118RVec3 v1(inBox.mOrientation * Vec3(-inBox.mHalfExtents.GetX(), -inBox.mHalfExtents.GetY(), -inBox.mHalfExtents.GetZ()));119RVec3 v2(inBox.mOrientation * Vec3(-inBox.mHalfExtents.GetX(), -inBox.mHalfExtents.GetY(), inBox.mHalfExtents.GetZ()));120RVec3 v3(inBox.mOrientation * Vec3(-inBox.mHalfExtents.GetX(), inBox.mHalfExtents.GetY(), -inBox.mHalfExtents.GetZ()));121RVec3 v4(inBox.mOrientation * Vec3(-inBox.mHalfExtents.GetX(), inBox.mHalfExtents.GetY(), inBox.mHalfExtents.GetZ()));122RVec3 v5(inBox.mOrientation * Vec3(inBox.mHalfExtents.GetX(), -inBox.mHalfExtents.GetY(), -inBox.mHalfExtents.GetZ()));123RVec3 v6(inBox.mOrientation * Vec3(inBox.mHalfExtents.GetX(), -inBox.mHalfExtents.GetY(), inBox.mHalfExtents.GetZ()));124RVec3 v7(inBox.mOrientation * Vec3(inBox.mHalfExtents.GetX(), inBox.mHalfExtents.GetY(), -inBox.mHalfExtents.GetZ()));125RVec3 v8(inBox.mOrientation * Vec3(inBox.mHalfExtents.GetX(), inBox.mHalfExtents.GetY(), inBox.mHalfExtents.GetZ()));126127// 12 edges128DrawLine(v1, v2, inColor);129DrawLine(v1, v3, inColor);130DrawLine(v1, v5, inColor);131DrawLine(v2, v4, inColor);132DrawLine(v2, v6, inColor);133DrawLine(v3, v4, inColor);134DrawLine(v3, v7, inColor);135DrawLine(v4, v8, inColor);136DrawLine(v5, v6, inColor);137DrawLine(v5, v7, inColor);138DrawLine(v6, v8, inColor);139DrawLine(v7, v8, inColor);140}141142void DebugRenderer::DrawWireBox(RMat44Arg inMatrix, const AABox &inBox, ColorArg inColor)143{144JPH_PROFILE_FUNCTION();145146// 8 vertices147RVec3 v1 = inMatrix * Vec3(inBox.mMin.GetX(), inBox.mMin.GetY(), inBox.mMin.GetZ());148RVec3 v2 = inMatrix * Vec3(inBox.mMin.GetX(), inBox.mMin.GetY(), inBox.mMax.GetZ());149RVec3 v3 = inMatrix * Vec3(inBox.mMin.GetX(), inBox.mMax.GetY(), inBox.mMin.GetZ());150RVec3 v4 = inMatrix * Vec3(inBox.mMin.GetX(), inBox.mMax.GetY(), inBox.mMax.GetZ());151RVec3 v5 = inMatrix * Vec3(inBox.mMax.GetX(), inBox.mMin.GetY(), inBox.mMin.GetZ());152RVec3 v6 = inMatrix * Vec3(inBox.mMax.GetX(), inBox.mMin.GetY(), inBox.mMax.GetZ());153RVec3 v7 = inMatrix * Vec3(inBox.mMax.GetX(), inBox.mMax.GetY(), inBox.mMin.GetZ());154RVec3 v8 = inMatrix * Vec3(inBox.mMax.GetX(), inBox.mMax.GetY(), inBox.mMax.GetZ());155156// 12 edges157DrawLine(v1, v2, inColor);158DrawLine(v1, v3, inColor);159DrawLine(v1, v5, inColor);160DrawLine(v2, v4, inColor);161DrawLine(v2, v6, inColor);162DrawLine(v3, v4, inColor);163DrawLine(v3, v7, inColor);164DrawLine(v4, v8, inColor);165DrawLine(v5, v6, inColor);166DrawLine(v5, v7, inColor);167DrawLine(v6, v8, inColor);168DrawLine(v7, v8, inColor);169}170171void DebugRenderer::DrawMarker(RVec3Arg inPosition, ColorArg inColor, float inSize)172{173JPH_PROFILE_FUNCTION();174175Vec3 dx(inSize, 0, 0);176Vec3 dy(0, inSize, 0);177Vec3 dz(0, 0, inSize);178DrawLine(inPosition - dy, inPosition + dy, inColor);179DrawLine(inPosition - dx, inPosition + dx, inColor);180DrawLine(inPosition - dz, inPosition + dz, inColor);181}182183void DebugRenderer::DrawArrow(RVec3Arg inFrom, RVec3Arg inTo, ColorArg inColor, float inSize)184{185JPH_PROFILE_FUNCTION();186187// Draw base line188DrawLine(inFrom, inTo, inColor);189190if (inSize > 0.0f)191{192// Draw arrow head193Vec3 dir = Vec3(inTo - inFrom);194float len = dir.Length();195if (len != 0.0f)196dir = dir * (inSize / len);197else198dir = Vec3(inSize, 0, 0);199Vec3 perp = inSize * dir.GetNormalizedPerpendicular();200DrawLine(inTo - dir + perp, inTo, inColor);201DrawLine(inTo - dir - perp, inTo, inColor);202}203}204205void DebugRenderer::DrawCoordinateSystem(RMat44Arg inTransform, float inSize)206{207JPH_PROFILE_FUNCTION();208209DrawArrow(inTransform.GetTranslation(), inTransform * Vec3(inSize, 0, 0), Color::sRed, 0.1f * inSize);210DrawArrow(inTransform.GetTranslation(), inTransform * Vec3(0, inSize, 0), Color::sGreen, 0.1f * inSize);211DrawArrow(inTransform.GetTranslation(), inTransform * Vec3(0, 0, inSize), Color::sBlue, 0.1f * inSize);212}213214void DebugRenderer::DrawPlane(RVec3Arg inPoint, Vec3Arg inNormal, ColorArg inColor, float inSize)215{216// Create orthogonal basis217Vec3 perp1 = inNormal.Cross(Vec3::sAxisY()).NormalizedOr(Vec3::sAxisX());218Vec3 perp2 = perp1.Cross(inNormal).Normalized();219perp1 = inNormal.Cross(perp2);220221// Calculate corners222RVec3 corner1 = inPoint + inSize * (perp1 + perp2);223RVec3 corner2 = inPoint + inSize * (perp1 - perp2);224RVec3 corner3 = inPoint + inSize * (-perp1 - perp2);225RVec3 corner4 = inPoint + inSize * (-perp1 + perp2);226227// Draw cross228DrawLine(corner1, corner3, inColor);229DrawLine(corner2, corner4, inColor);230231// Draw square232DrawLine(corner1, corner2, inColor);233DrawLine(corner2, corner3, inColor);234DrawLine(corner3, corner4, inColor);235DrawLine(corner4, corner1, inColor);236237// Draw normal238DrawArrow(inPoint, inPoint + inSize * inNormal, inColor, 0.1f * inSize);239}240241void DebugRenderer::DrawWireTriangle(RVec3Arg inV1, RVec3Arg inV2, RVec3Arg inV3, ColorArg inColor)242{243JPH_PROFILE_FUNCTION();244245DrawLine(inV1, inV2, inColor);246DrawLine(inV2, inV3, inColor);247DrawLine(inV3, inV1, inColor);248}249250void DebugRenderer::DrawWireSphere(RVec3Arg inCenter, float inRadius, ColorArg inColor, int inLevel)251{252RMat44 matrix = RMat44::sTranslation(inCenter) * Mat44::sScale(inRadius);253254DrawWireUnitSphere(matrix, inColor, inLevel);255}256257void DebugRenderer::DrawWireUnitSphere(RMat44Arg inMatrix, ColorArg inColor, int inLevel)258{259JPH_PROFILE_FUNCTION();260261DrawWireUnitSphereRecursive(inMatrix, inColor, Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), inLevel);262DrawWireUnitSphereRecursive(inMatrix, inColor, -Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), inLevel);263DrawWireUnitSphereRecursive(inMatrix, inColor, Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), inLevel);264DrawWireUnitSphereRecursive(inMatrix, inColor, -Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), inLevel);265DrawWireUnitSphereRecursive(inMatrix, inColor, Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), inLevel);266DrawWireUnitSphereRecursive(inMatrix, inColor, -Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), inLevel);267DrawWireUnitSphereRecursive(inMatrix, inColor, Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), inLevel);268DrawWireUnitSphereRecursive(inMatrix, inColor, -Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), inLevel);269}270271void DebugRenderer::DrawWireUnitSphereRecursive(RMat44Arg inMatrix, ColorArg inColor, Vec3Arg inDir1, Vec3Arg inDir2, Vec3Arg inDir3, int inLevel)272{273if (inLevel == 0)274{275RVec3 d1 = inMatrix * inDir1;276RVec3 d2 = inMatrix * inDir2;277RVec3 d3 = inMatrix * inDir3;278279DrawLine(d1, d2, inColor);280DrawLine(d2, d3, inColor);281DrawLine(d3, d1, inColor);282}283else284{285Vec3 center1 = (inDir1 + inDir2).Normalized();286Vec3 center2 = (inDir2 + inDir3).Normalized();287Vec3 center3 = (inDir3 + inDir1).Normalized();288289DrawWireUnitSphereRecursive(inMatrix, inColor, inDir1, center1, center3, inLevel - 1);290DrawWireUnitSphereRecursive(inMatrix, inColor, center1, center2, center3, inLevel - 1);291DrawWireUnitSphereRecursive(inMatrix, inColor, center1, inDir2, center2, inLevel - 1);292DrawWireUnitSphereRecursive(inMatrix, inColor, center3, center2, inDir3, inLevel - 1);293}294}295296void DebugRenderer::Create8thSphereRecursive(Array<uint32> &ioIndices, Array<Vertex> &ioVertices, Vec3Arg inDir1, uint32 &ioIdx1, Vec3Arg inDir2, uint32 &ioIdx2, Vec3Arg inDir3, uint32 &ioIdx3, const Float2 &inUV, SupportFunction inGetSupport, int inLevel)297{298if (inLevel == 0)299{300if (ioIdx1 == 0xffffffff)301{302ioIdx1 = (uint32)ioVertices.size();303Float3 position, normal;304inGetSupport(inDir1).StoreFloat3(&position);305inDir1.StoreFloat3(&normal);306ioVertices.push_back({ position, normal, inUV, Color::sWhite });307}308309if (ioIdx2 == 0xffffffff)310{311ioIdx2 = (uint32)ioVertices.size();312Float3 position, normal;313inGetSupport(inDir2).StoreFloat3(&position);314inDir2.StoreFloat3(&normal);315ioVertices.push_back({ position, normal, inUV, Color::sWhite });316}317318if (ioIdx3 == 0xffffffff)319{320ioIdx3 = (uint32)ioVertices.size();321Float3 position, normal;322inGetSupport(inDir3).StoreFloat3(&position);323inDir3.StoreFloat3(&normal);324ioVertices.push_back({ position, normal, inUV, Color::sWhite });325}326327ioIndices.push_back(ioIdx1);328ioIndices.push_back(ioIdx2);329ioIndices.push_back(ioIdx3);330}331else332{333Vec3 center1 = (inDir1 + inDir2).Normalized();334Vec3 center2 = (inDir2 + inDir3).Normalized();335Vec3 center3 = (inDir3 + inDir1).Normalized();336337uint32 idx1 = 0xffffffff;338uint32 idx2 = 0xffffffff;339uint32 idx3 = 0xffffffff;340341Create8thSphereRecursive(ioIndices, ioVertices, inDir1, ioIdx1, center1, idx1, center3, idx3, inUV, inGetSupport, inLevel - 1);342Create8thSphereRecursive(ioIndices, ioVertices, center1, idx1, center2, idx2, center3, idx3, inUV, inGetSupport, inLevel - 1);343Create8thSphereRecursive(ioIndices, ioVertices, center1, idx1, inDir2, ioIdx2, center2, idx2, inUV, inGetSupport, inLevel - 1);344Create8thSphereRecursive(ioIndices, ioVertices, center3, idx3, center2, idx2, inDir3, ioIdx3, inUV, inGetSupport, inLevel - 1);345}346}347348void DebugRenderer::Create8thSphere(Array<uint32> &ioIndices, Array<Vertex> &ioVertices, Vec3Arg inDir1, Vec3Arg inDir2, Vec3Arg inDir3, const Float2 &inUV, SupportFunction inGetSupport, int inLevel)349{350uint32 idx1 = 0xffffffff;351uint32 idx2 = 0xffffffff;352uint32 idx3 = 0xffffffff;353354Create8thSphereRecursive(ioIndices, ioVertices, inDir1, idx1, inDir2, idx2, inDir3, idx3, inUV, inGetSupport, inLevel);355}356357DebugRenderer::Batch DebugRenderer::CreateCylinder(float inTop, float inBottom, float inTopRadius, float inBottomRadius, int inLevel)358{359Array<Vertex> cylinder_vertices;360Array<uint32> cylinder_indices;361362for (int q = 0; q < 4; ++q)363{364Float2 uv = (q & 1) == 0? Float2(0.25f, 0.75f) : Float2(0.25f, 0.25f);365366uint32 center_start_idx = (uint32)cylinder_vertices.size();367368Float3 nt(0.0f, 1.0f, 0.0f);369Float3 nb(0.0f, -1.0f, 0.0f);370cylinder_vertices.push_back({ Float3(0.0f, inTop, 0.0f), nt, uv, Color::sWhite });371cylinder_vertices.push_back({ Float3(0.0f, inBottom, 0.0f), nb, uv, Color::sWhite });372373uint32 vtx_start_idx = (uint32)cylinder_vertices.size();374375int num_parts = 1 << inLevel;376for (int i = 0; i <= num_parts; ++i)377{378// Calculate top and bottom vertex379float angle = 0.5f * JPH_PI * (float(q) + float(i) / num_parts);380float s = Sin(angle);381float c = Cos(angle);382Float3 vt(inTopRadius * s, inTop, inTopRadius * c);383Float3 vb(inBottomRadius * s, inBottom, inBottomRadius * c);384385// Calculate normal386Vec3 edge = Vec3(vt) - Vec3(vb);387Float3 n;388edge.Cross(Vec3(s, 0, c).Cross(edge)).Normalized().StoreFloat3(&n);389390cylinder_vertices.push_back({ vt, nt, uv, Color::sWhite });391cylinder_vertices.push_back({ vb, nb, uv, Color::sWhite });392cylinder_vertices.push_back({ vt, n, uv, Color::sWhite });393cylinder_vertices.push_back({ vb, n, uv, Color::sWhite });394}395396for (int i = 0; i < num_parts; ++i)397{398uint32 start = vtx_start_idx + 4 * i;399400// Top401cylinder_indices.push_back(center_start_idx);402cylinder_indices.push_back(start);403cylinder_indices.push_back(start + 4);404405// Bottom406cylinder_indices.push_back(center_start_idx + 1);407cylinder_indices.push_back(start + 5);408cylinder_indices.push_back(start + 1);409410// Side411cylinder_indices.push_back(start + 2);412cylinder_indices.push_back(start + 3);413cylinder_indices.push_back(start + 7);414415cylinder_indices.push_back(start + 2);416cylinder_indices.push_back(start + 7);417cylinder_indices.push_back(start + 6);418}419}420421return CreateTriangleBatch(cylinder_vertices, cylinder_indices);422}423424void DebugRenderer::CreateQuad(Array<uint32> &ioIndices, Array<Vertex> &ioVertices, Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, Vec3Arg inV4)425{426// Make room427uint32 start_idx = uint32(ioVertices.size());428ioVertices.resize(start_idx + 4);429Vertex *vertices = &ioVertices[start_idx];430431// Set position432inV1.StoreFloat3(&vertices[0].mPosition);433inV2.StoreFloat3(&vertices[1].mPosition);434inV3.StoreFloat3(&vertices[2].mPosition);435inV4.StoreFloat3(&vertices[3].mPosition);436437// Set color438vertices[0].mColor = vertices[1].mColor = vertices[2].mColor = vertices[3].mColor = Color::sWhite;439440// Calculate normal441Vec3 normal = (inV2 - inV1).Cross(inV3 - inV1).Normalized();442Float3 normal3;443normal.StoreFloat3(&normal3);444vertices[0].mNormal = vertices[1].mNormal = vertices[2].mNormal = vertices[3].mNormal = normal3;445446// Set UV's447vertices[0].mUV = { 0, 0 };448vertices[1].mUV = { 2, 0 };449vertices[2].mUV = { 2, 2 };450vertices[3].mUV = { 0, 2 };451452// Set indices453ioIndices.push_back(start_idx);454ioIndices.push_back(start_idx + 1);455ioIndices.push_back(start_idx + 2);456457ioIndices.push_back(start_idx);458ioIndices.push_back(start_idx + 2);459ioIndices.push_back(start_idx + 3);460}461462void DebugRenderer::Initialize()463{464// Box465{466Array<Vertex> box_vertices;467Array<uint32> box_indices;468469// Get corner points470Vec3 v0 = Vec3(-1, 1, -1);471Vec3 v1 = Vec3( 1, 1, -1);472Vec3 v2 = Vec3( 1, 1, 1);473Vec3 v3 = Vec3(-1, 1, 1);474Vec3 v4 = Vec3(-1, -1, -1);475Vec3 v5 = Vec3( 1, -1, -1);476Vec3 v6 = Vec3( 1, -1, 1);477Vec3 v7 = Vec3(-1, -1, 1);478479// Top480CreateQuad(box_indices, box_vertices, v0, v3, v2, v1);481482// Bottom483CreateQuad(box_indices, box_vertices, v4, v5, v6, v7);484485// Left486CreateQuad(box_indices, box_vertices, v0, v4, v7, v3);487488// Right489CreateQuad(box_indices, box_vertices, v2, v6, v5, v1);490491// Front492CreateQuad(box_indices, box_vertices, v3, v7, v6, v2);493494// Back495CreateQuad(box_indices, box_vertices, v0, v1, v5, v4);496497mBox = new Geometry(CreateTriangleBatch(box_vertices, box_indices), AABox(Vec3(-1, -1, -1), Vec3(1, 1, 1)));498}499500// Support function that returns a unit sphere501auto sphere_support = [](Vec3Arg inDirection) { return inDirection; };502503// Construct geometries504mSphere = new Geometry(AABox(Vec3(-1, -1, -1), Vec3(1, 1, 1)));505mCapsuleBottom = new Geometry(AABox(Vec3(-1, -1, -1), Vec3(1, 0, 1)));506mCapsuleTop = new Geometry(AABox(Vec3(-1, 0, -1), Vec3(1, 1, 1)));507mCapsuleMid = new Geometry(AABox(Vec3(-1, -1, -1), Vec3(1, 1, 1)));508mOpenCone = new Geometry(AABox(Vec3(-1, 0, -1), Vec3(1, 1, 1)));509mCylinder = new Geometry(AABox(Vec3(-1, -1, -1), Vec3(1, 1, 1)));510511// Iterate over levels512for (int level = sMaxLevel; level >= 1; --level)513{514// Determine at which distance this level should be active515float distance = sLODDistanceForLevel[sMaxLevel - level];516517// Sphere518mSphere->mLODs.push_back({ CreateTriangleBatchForConvex(sphere_support, level), distance });519520// Capsule bottom half sphere521{522Array<Vertex> capsule_bottom_vertices;523Array<uint32> capsule_bottom_indices;524Create8thSphere(capsule_bottom_indices, capsule_bottom_vertices, -Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), Float2(0.25f, 0.25f), sphere_support, level);525Create8thSphere(capsule_bottom_indices, capsule_bottom_vertices, -Vec3::sAxisY(), Vec3::sAxisX(), Vec3::sAxisZ(), Float2(0.25f, 0.75f), sphere_support, level);526Create8thSphere(capsule_bottom_indices, capsule_bottom_vertices, Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), Float2(0.25f, 0.25f), sphere_support, level);527Create8thSphere(capsule_bottom_indices, capsule_bottom_vertices, -Vec3::sAxisY(), -Vec3::sAxisX(), -Vec3::sAxisZ(), Float2(0.25f, 0.75f), sphere_support, level);528mCapsuleBottom->mLODs.push_back({ CreateTriangleBatch(capsule_bottom_vertices, capsule_bottom_indices), distance });529}530531// Capsule top half sphere532{533Array<Vertex> capsule_top_vertices;534Array<uint32> capsule_top_indices;535Create8thSphere(capsule_top_indices, capsule_top_vertices, Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), Float2(0.25f, 0.75f), sphere_support, level);536Create8thSphere(capsule_top_indices, capsule_top_vertices, Vec3::sAxisY(), -Vec3::sAxisX(), Vec3::sAxisZ(), Float2(0.25f, 0.25f), sphere_support, level);537Create8thSphere(capsule_top_indices, capsule_top_vertices, Vec3::sAxisY(), Vec3::sAxisX(), -Vec3::sAxisZ(), Float2(0.25f, 0.25f), sphere_support, level);538Create8thSphere(capsule_top_indices, capsule_top_vertices, -Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), Float2(0.25f, 0.75f), sphere_support, level);539mCapsuleTop->mLODs.push_back({ CreateTriangleBatch(capsule_top_vertices, capsule_top_indices), distance });540}541542// Capsule middle part543{544Array<Vertex> capsule_mid_vertices;545Array<uint32> capsule_mid_indices;546for (int q = 0; q < 4; ++q)547{548Float2 uv = (q & 1) == 0? Float2(0.25f, 0.25f) : Float2(0.25f, 0.75f);549550uint32 start_idx = (uint32)capsule_mid_vertices.size();551552int num_parts = 1 << level;553for (int i = 0; i <= num_parts; ++i)554{555float angle = 0.5f * JPH_PI * (float(q) + float(i) / num_parts);556float s = Sin(angle);557float c = Cos(angle);558Float3 vt(s, 1.0f, c);559Float3 vb(s, -1.0f, c);560Float3 n(s, 0, c);561562capsule_mid_vertices.push_back({ vt, n, uv, Color::sWhite });563capsule_mid_vertices.push_back({ vb, n, uv, Color::sWhite });564}565566for (int i = 0; i < num_parts; ++i)567{568uint32 start = start_idx + 2 * i;569570capsule_mid_indices.push_back(start);571capsule_mid_indices.push_back(start + 1);572capsule_mid_indices.push_back(start + 3);573574capsule_mid_indices.push_back(start);575capsule_mid_indices.push_back(start + 3);576capsule_mid_indices.push_back(start + 2);577}578}579mCapsuleMid->mLODs.push_back({ CreateTriangleBatch(capsule_mid_vertices, capsule_mid_indices), distance });580}581582// Open cone583{584Array<Vertex> open_cone_vertices;585Array<uint32> open_cone_indices;586for (int q = 0; q < 4; ++q)587{588Float2 uv = (q & 1) == 0? Float2(0.25f, 0.25f) : Float2(0.25f, 0.75f);589590uint32 start_idx = (uint32)open_cone_vertices.size();591592int num_parts = 2 << level;593Float3 vt(0, 0, 0);594for (int i = 0; i <= num_parts; ++i)595{596// Calculate bottom vertex597float angle = 0.5f * JPH_PI * (float(q) + float(i) / num_parts);598float s = Sin(angle);599float c = Cos(angle);600Float3 vb(s, 1.0f, c);601602// Calculate normal603// perpendicular = Y cross vb (perpendicular to the plane in which 0, y and vb exists)604// normal = perpendicular cross vb (normal to the edge 0 vb)605Vec3 normal = Vec3(s, -Square(s) - Square(c), c).Normalized();606Float3 n; normal.StoreFloat3(&n);607608open_cone_vertices.push_back({ vt, n, uv, Color::sWhite });609open_cone_vertices.push_back({ vb, n, uv, Color::sWhite });610}611612for (int i = 0; i < num_parts; ++i)613{614uint32 start = start_idx + 2 * i;615616open_cone_indices.push_back(start);617open_cone_indices.push_back(start + 1);618open_cone_indices.push_back(start + 3);619}620}621mOpenCone->mLODs.push_back({ CreateTriangleBatch(open_cone_vertices, open_cone_indices), distance });622}623624// Cylinder625mCylinder->mLODs.push_back({ CreateCylinder(1.0f, -1.0f, 1.0f, 1.0f, level), distance });626}627}628629AABox DebugRenderer::sCalculateBounds(const Vertex *inVertices, int inVertexCount)630{631AABox bounds;632for (const Vertex *v = inVertices, *v_end = inVertices + inVertexCount; v < v_end; ++v)633bounds.Encapsulate(Vec3(v->mPosition));634return bounds;635}636637DebugRenderer::Batch DebugRenderer::CreateTriangleBatch(const VertexList &inVertices, const IndexedTriangleNoMaterialList &inTriangles)638{639JPH_PROFILE_FUNCTION();640641Array<Vertex> vertices;642643// Create render vertices644vertices.resize(inVertices.size());645for (size_t v = 0; v < inVertices.size(); ++v)646{647vertices[v].mPosition = inVertices[v];648vertices[v].mNormal = Float3(0, 0, 0);649vertices[v].mUV = Float2(0, 0);650vertices[v].mColor = Color::sWhite;651}652653// Calculate normals654for (size_t i = 0; i < inTriangles.size(); ++i)655{656const IndexedTriangleNoMaterial &tri = inTriangles[i];657658// Calculate normal of face659Vec3 vtx[3];660for (int j = 0; j < 3; ++j)661vtx[j] = Vec3::sLoadFloat3Unsafe(vertices[tri.mIdx[j]].mPosition);662Vec3 normal = ((vtx[1] - vtx[0]).Cross(vtx[2] - vtx[0])).Normalized();663664// Add normal to all vertices in face665for (int j = 0; j < 3; ++j)666(Vec3::sLoadFloat3Unsafe(vertices[tri.mIdx[j]].mNormal) + normal).StoreFloat3(&vertices[tri.mIdx[j]].mNormal);667}668669// Renormalize vertex normals670for (size_t i = 0; i < vertices.size(); ++i)671Vec3::sLoadFloat3Unsafe(vertices[i].mNormal).Normalized().StoreFloat3(&vertices[i].mNormal);672673return CreateTriangleBatch(&vertices[0], (int)vertices.size(), &inTriangles[0].mIdx[0], (int)(3 * inTriangles.size()));674}675676DebugRenderer::Batch DebugRenderer::CreateTriangleBatchForConvex(SupportFunction inGetSupport, int inLevel, AABox *outBounds)677{678JPH_PROFILE_FUNCTION();679680Array<Vertex> vertices;681Array<uint32> indices;682Create8thSphere(indices, vertices, Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), Float2(0.25f, 0.25f), inGetSupport, inLevel);683Create8thSphere(indices, vertices, Vec3::sAxisY(), -Vec3::sAxisX(), Vec3::sAxisZ(), Float2(0.25f, 0.75f), inGetSupport, inLevel);684Create8thSphere(indices, vertices, -Vec3::sAxisY(), Vec3::sAxisX(), Vec3::sAxisZ(), Float2(0.25f, 0.75f), inGetSupport, inLevel);685Create8thSphere(indices, vertices, -Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), Float2(0.25f, 0.25f), inGetSupport, inLevel);686Create8thSphere(indices, vertices, Vec3::sAxisY(), Vec3::sAxisX(), -Vec3::sAxisZ(), Float2(0.25f, 0.75f), inGetSupport, inLevel);687Create8thSphere(indices, vertices, -Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), Float2(0.25f, 0.25f), inGetSupport, inLevel);688Create8thSphere(indices, vertices, Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), Float2(0.25f, 0.25f), inGetSupport, inLevel);689Create8thSphere(indices, vertices, -Vec3::sAxisY(), -Vec3::sAxisX(), -Vec3::sAxisZ(), Float2(0.25f, 0.75f), inGetSupport, inLevel);690691if (outBounds != nullptr)692*outBounds = sCalculateBounds(&vertices[0], (int)vertices.size());693694return CreateTriangleBatch(vertices, indices);695}696697DebugRenderer::GeometryRef DebugRenderer::CreateTriangleGeometryForConvex(SupportFunction inGetSupport)698{699GeometryRef geometry;700701// Iterate over levels702for (int level = sMaxLevel; level >= 1; --level)703{704// Determine at which distance this level should be active705float distance = sLODDistanceForLevel[sMaxLevel - level];706707// Create triangle batch and only calculate bounds for highest LOD level708AABox bounds;709Batch batch = CreateTriangleBatchForConvex(inGetSupport, level, geometry == nullptr? &bounds : nullptr);710711// Construct geometry in the first iteration712if (geometry == nullptr)713geometry = new Geometry(bounds);714715// Add the LOD716geometry->mLODs.push_back({ batch, distance });717}718719return geometry;720}721722void DebugRenderer::DrawBox(const AABox &inBox, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)723{724JPH_PROFILE_FUNCTION();725726RMat44 m = RMat44::sScale(Vec3::sMax(inBox.GetExtent(), Vec3::sReplicate(1.0e-6f))); // Prevent div by zero when one of the edges has length 0727m.SetTranslation(RVec3(inBox.GetCenter()));728DrawGeometry(m, inColor, mBox, ECullMode::CullBackFace, inCastShadow, inDrawMode);729}730731void DebugRenderer::DrawBox(RMat44Arg inMatrix, const AABox &inBox, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)732{733JPH_PROFILE_FUNCTION();734735Mat44 m = Mat44::sScale(Vec3::sMax(inBox.GetExtent(), Vec3::sReplicate(1.0e-6f))); // Prevent div by zero when one of the edges has length 0736m.SetTranslation(inBox.GetCenter());737DrawGeometry(inMatrix * m, inColor, mBox, ECullMode::CullBackFace, inCastShadow, inDrawMode);738}739740void DebugRenderer::DrawSphere(RVec3Arg inCenter, float inRadius, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)741{742JPH_PROFILE_FUNCTION();743744RMat44 matrix = RMat44::sTranslation(inCenter) * Mat44::sScale(inRadius);745746DrawUnitSphere(matrix, inColor, inCastShadow, inDrawMode);747}748749void DebugRenderer::DrawUnitSphere(RMat44Arg inMatrix, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)750{751JPH_PROFILE_FUNCTION();752753DrawGeometry(inMatrix, inColor, mSphere, ECullMode::CullBackFace, inCastShadow, inDrawMode);754}755756void DebugRenderer::DrawCapsule(RMat44Arg inMatrix, float inHalfHeightOfCylinder, float inRadius, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)757{758JPH_PROFILE_FUNCTION();759760Mat44 scale_matrix = Mat44::sScale(inRadius);761762// Calculate world space bounding box763AABox local_bounds(Vec3(-inRadius, -inHalfHeightOfCylinder - inRadius, -inRadius), Vec3(inRadius, inHalfHeightOfCylinder + inRadius, inRadius));764AABox world_bounds = local_bounds.Transformed(inMatrix);765766float radius_sq = Square(inRadius);767768// Draw bottom half sphere769RMat44 bottom_matrix = inMatrix * Mat44::sTranslation(Vec3(0, -inHalfHeightOfCylinder, 0)) * scale_matrix;770DrawGeometry(bottom_matrix, world_bounds, radius_sq, inColor, mCapsuleBottom, ECullMode::CullBackFace, inCastShadow, inDrawMode);771772// Draw top half sphere773RMat44 top_matrix = inMatrix * Mat44::sTranslation(Vec3(0, inHalfHeightOfCylinder, 0)) * scale_matrix;774DrawGeometry(top_matrix, world_bounds, radius_sq, inColor, mCapsuleTop, ECullMode::CullBackFace, inCastShadow, inDrawMode);775776// Draw middle part777DrawGeometry(inMatrix * Mat44::sScale(Vec3(inRadius, inHalfHeightOfCylinder, inRadius)), world_bounds, radius_sq, inColor, mCapsuleMid, ECullMode::CullBackFace, inCastShadow, inDrawMode);778}779780void DebugRenderer::DrawCylinder(RMat44Arg inMatrix, float inHalfHeight, float inRadius, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)781{782JPH_PROFILE_FUNCTION();783784Mat44 local_transform(Vec4(inRadius, 0, 0, 0), Vec4(0, inHalfHeight, 0, 0), Vec4(0, 0, inRadius, 0), Vec4(0, 0, 0, 1));785RMat44 transform = inMatrix * local_transform;786787DrawGeometry(transform, mCylinder->mBounds.Transformed(transform), Square(inRadius), inColor, mCylinder, ECullMode::CullBackFace, inCastShadow, inDrawMode);788}789790void DebugRenderer::DrawOpenCone(RVec3Arg inTop, Vec3Arg inAxis, Vec3Arg inPerpendicular, float inHalfAngle, float inLength, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)791{792JPH_PROFILE_FUNCTION();793794JPH_ASSERT(inAxis.IsNormalized(1.0e-4f));795JPH_ASSERT(inPerpendicular.IsNormalized(1.0e-4f));796JPH_ASSERT(abs(inPerpendicular.Dot(inAxis)) < 1.0e-4f);797798Vec3 axis = Sign(inHalfAngle) * inLength * inAxis;799float scale = inLength * Tan(abs(inHalfAngle));800if (scale != 0.0f)801{802Vec3 perp1 = scale * inPerpendicular;803Vec3 perp2 = scale * inAxis.Cross(inPerpendicular);804RMat44 transform(Vec4(perp1, 0), Vec4(axis, 0), Vec4(perp2, 0), inTop);805DrawGeometry(transform, inColor, mOpenCone, ECullMode::Off, inCastShadow, inDrawMode);806}807}808809DebugRenderer::Geometry *DebugRenderer::CreateSwingLimitGeometry(int inNumSegments, const Vec3 *inVertices)810{811// Allocate space for vertices812int num_vertices = 2 * inNumSegments;813Vertex *vertices_start = (Vertex *)JPH_STACK_ALLOC(num_vertices * sizeof(Vertex));814Vertex *vertices = vertices_start;815816for (int i = 0; i < inNumSegments; ++i)817{818// Get output vertices819Vertex &top = *(vertices++);820Vertex &bottom = *(vertices++);821822// Get local position823const Vec3 &pos = inVertices[i];824825// Get local normal826const Vec3 &prev_pos = inVertices[(i + inNumSegments - 1) % inNumSegments];827const Vec3 &next_pos = inVertices[(i + 1) % inNumSegments];828Vec3 normal = 0.5f * (next_pos.Cross(pos).NormalizedOr(Vec3::sZero()) + pos.Cross(prev_pos).NormalizedOr(Vec3::sZero()));829830// Store top vertex831top.mPosition = { 0, 0, 0 };832normal.StoreFloat3(&top.mNormal);833top.mColor = Color::sWhite;834top.mUV = { 0, 0 };835836// Store bottom vertex837pos.StoreFloat3(&bottom.mPosition);838normal.StoreFloat3(&bottom.mNormal);839bottom.mColor = Color::sWhite;840bottom.mUV = { 0, 0 };841}842843// Allocate space for indices844int num_indices = 3 * inNumSegments;845uint32 *indices_start = (uint32 *)JPH_STACK_ALLOC(num_indices * sizeof(uint32));846uint32 *indices = indices_start;847848// Calculate indices849for (int i = 0; i < inNumSegments; ++i)850{851int first = 2 * i;852int second = (first + 3) % num_vertices;853int third = first + 1;854855// Triangle856*indices++ = first;857*indices++ = second;858*indices++ = third;859}860861// Convert to triangle batch862return new Geometry(CreateTriangleBatch(vertices_start, num_vertices, indices_start, num_indices), sCalculateBounds(vertices_start, num_vertices));863}864865void DebugRenderer::DrawSwingConeLimits(RMat44Arg inMatrix, float inSwingYHalfAngle, float inSwingZHalfAngle, float inEdgeLength, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)866{867JPH_PROFILE_FUNCTION();868869// Assert sane input870JPH_ASSERT(inSwingYHalfAngle >= 0.0f && inSwingYHalfAngle <= JPH_PI);871JPH_ASSERT(inSwingZHalfAngle >= 0.0f && inSwingZHalfAngle <= JPH_PI);872JPH_ASSERT(inEdgeLength > 0.0f);873874// Check cache875SwingConeLimits limits { inSwingYHalfAngle, inSwingZHalfAngle };876GeometryRef &geometry = mSwingConeLimits[limits];877if (geometry == nullptr)878{879SwingConeBatches::iterator it = mPrevSwingConeLimits.find(limits);880if (it != mPrevSwingConeLimits.end())881geometry = it->second;882}883if (geometry == nullptr)884{885// Number of segments to draw the cone with886const int num_segments = 64;887int half_num_segments = num_segments / 2;888889// The y and z values of the quaternion are limited to an ellipse, e1 and e2 are the radii of this ellipse890float e1 = Sin(0.5f * inSwingZHalfAngle);891float e2 = Sin(0.5f * inSwingYHalfAngle);892893// Check if the limits will draw something894if ((e1 <= 0.0f && e2 <= 0.0f) || (e2 >= 1.0f && e1 >= 1.0f))895return;896897// Calculate squared values898float e1_sq = Square(e1);899float e2_sq = Square(e2);900901// Calculate local space vertices for shape902Vec3 ls_vertices[num_segments];903int tgt_vertex = 0;904for (int side_iter = 0; side_iter < 2; ++side_iter)905for (int segment_iter = 0; segment_iter < half_num_segments; ++segment_iter)906{907float y, z;908if (e2_sq > e1_sq)909{910// Trace the y value of the quaternion911y = e2 - 2.0f * segment_iter * e2 / half_num_segments;912913// Calculate the corresponding z value of the quaternion914float z_sq = e1_sq - e1_sq / e2_sq * Square(y);915z = z_sq <= 0.0f? 0.0f : sqrt(z_sq);916}917else918{919// Trace the z value of the quaternion920z = -e1 + 2.0f * segment_iter * e1 / half_num_segments;921922// Calculate the corresponding y value of the quaternion923float y_sq = e2_sq - e2_sq / e1_sq * Square(z);924y = y_sq <= 0.0f? 0.0f : sqrt(y_sq);925}926927// If we're tracing the opposite side, flip the values928if (side_iter == 1)929{930z = -z;931y = -y;932}933934// Create quaternion935Vec3 q_xyz(0, y, z);936float w = sqrt(1.0f - q_xyz.LengthSq());937Quat q(Vec4(q_xyz, w));938939// Store vertex940ls_vertices[tgt_vertex++] = q.RotateAxisX();941}942943geometry = CreateSwingLimitGeometry(num_segments, ls_vertices);944}945946DrawGeometry(inMatrix * Mat44::sScale(inEdgeLength), inColor, geometry, ECullMode::Off, inCastShadow, inDrawMode);947}948949void DebugRenderer::DrawSwingPyramidLimits(RMat44Arg inMatrix, float inMinSwingYAngle, float inMaxSwingYAngle, float inMinSwingZAngle, float inMaxSwingZAngle, float inEdgeLength, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)950{951JPH_PROFILE_FUNCTION();952953// Assert sane input954JPH_ASSERT(inMinSwingYAngle <= inMaxSwingYAngle && inMinSwingZAngle <= inMaxSwingZAngle);955JPH_ASSERT(inEdgeLength > 0.0f);956957// Check cache958SwingPyramidLimits limits { inMinSwingYAngle, inMaxSwingYAngle, inMinSwingZAngle, inMaxSwingZAngle };959GeometryRef &geometry = mSwingPyramidLimits[limits];960if (geometry == nullptr)961{962SwingPyramidBatches::iterator it = mPrevSwingPyramidLimits.find(limits);963if (it != mPrevSwingPyramidLimits.end())964geometry = it->second;965}966if (geometry == nullptr)967{968// Number of segments to draw the cone with969const int num_segments = 64;970int quarter_num_segments = num_segments / 4;971972// Note that this is q = Quat::sRotation(Vec3::sAxisZ(), z) * Quat::sRotation(Vec3::sAxisY(), y) with q.x set to zero so we don't introduce twist973// This matches the calculation in SwingTwistConstraintPart::ClampSwingTwist974auto get_axis = [](float inY, float inZ) {975float hy = 0.5f * inY;976float hz = 0.5f * inZ;977float cos_hy = Cos(hy);978float cos_hz = Cos(hz);979return Quat(0, Sin(hy) * cos_hz, cos_hy * Sin(hz), cos_hy * cos_hz).Normalized().RotateAxisX();980};981982// Calculate local space vertices for shape983Vec3 ls_vertices[num_segments];984int tgt_vertex = 0;985for (int segment_iter = 0; segment_iter < quarter_num_segments; ++segment_iter)986ls_vertices[tgt_vertex++] = get_axis(inMinSwingYAngle, inMaxSwingZAngle - (inMaxSwingZAngle - inMinSwingZAngle) * segment_iter / quarter_num_segments);987for (int segment_iter = 0; segment_iter < quarter_num_segments; ++segment_iter)988ls_vertices[tgt_vertex++] = get_axis(inMinSwingYAngle + (inMaxSwingYAngle - inMinSwingYAngle) * segment_iter / quarter_num_segments, inMinSwingZAngle);989for (int segment_iter = 0; segment_iter < quarter_num_segments; ++segment_iter)990ls_vertices[tgt_vertex++] = get_axis(inMaxSwingYAngle, inMinSwingZAngle + (inMaxSwingZAngle - inMinSwingZAngle) * segment_iter / quarter_num_segments);991for (int segment_iter = 0; segment_iter < quarter_num_segments; ++segment_iter)992ls_vertices[tgt_vertex++] = get_axis(inMaxSwingYAngle - (inMaxSwingYAngle - inMinSwingYAngle) * segment_iter / quarter_num_segments, inMaxSwingZAngle);993994geometry = CreateSwingLimitGeometry(num_segments, ls_vertices);995}996997DrawGeometry(inMatrix * Mat44::sScale(inEdgeLength), inColor, geometry, ECullMode::Off, inCastShadow, inDrawMode);998}9991000void DebugRenderer::DrawPie(RVec3Arg inCenter, float inRadius, Vec3Arg inNormal, Vec3Arg inAxis, float inMinAngle, float inMaxAngle, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)1001{1002if (inMinAngle >= inMaxAngle)1003return;10041005JPH_PROFILE_FUNCTION();10061007JPH_ASSERT(inAxis.IsNormalized(1.0e-4f));1008JPH_ASSERT(inNormal.IsNormalized(1.0e-4f));1009JPH_ASSERT(abs(inNormal.Dot(inAxis)) < 1.0e-4f);10101011// Pies have a unique batch based on the difference between min and max angle1012float delta_angle = inMaxAngle - inMinAngle;1013GeometryRef &geometry = mPieLimits[delta_angle];1014if (geometry == nullptr)1015{1016PieBatces::iterator it = mPrevPieLimits.find(delta_angle);1017if (it != mPrevPieLimits.end())1018geometry = it->second;1019}1020if (geometry == nullptr)1021{1022int num_parts = (int)ceil(64.0f * delta_angle / (2.0f * JPH_PI));10231024Float3 normal = { 0, 1, 0 };1025Float3 center = { 0, 0, 0 };10261027// Allocate space for vertices1028int num_vertices = num_parts + 2;1029Vertex *vertices_start = (Vertex *)JPH_STACK_ALLOC(num_vertices * sizeof(Vertex));1030Vertex *vertices = vertices_start;10311032// Center of circle1033*vertices++ = { center, normal, { 0, 0 }, Color::sWhite };10341035// Outer edge of pie1036for (int i = 0; i <= num_parts; ++i)1037{1038float angle = float(i) / float(num_parts) * delta_angle;10391040Float3 pos = { Cos(angle), 0, Sin(angle) };1041*vertices++ = { pos, normal, { 0, 0 }, Color::sWhite };1042}10431044// Allocate space for indices1045int num_indices = num_parts * 3;1046uint32 *indices_start = (uint32 *)JPH_STACK_ALLOC(num_indices * sizeof(uint32));1047uint32 *indices = indices_start;10481049for (int i = 0; i < num_parts; ++i)1050{1051*indices++ = 0;1052*indices++ = i + 1;1053*indices++ = i + 2;1054}10551056// Convert to triangle batch1057geometry = new Geometry(CreateTriangleBatch(vertices_start, num_vertices, indices_start, num_indices), sCalculateBounds(vertices_start, num_vertices));1058}10591060// Construct matrix that transforms pie into world space1061RMat44 matrix = RMat44(Vec4(inRadius * inAxis, 0), Vec4(inRadius * inNormal, 0), Vec4(inRadius * inNormal.Cross(inAxis), 0), inCenter) * Mat44::sRotationY(-inMinAngle);10621063DrawGeometry(matrix, inColor, geometry, ECullMode::Off, inCastShadow, inDrawMode);1064}10651066void DebugRenderer::DrawTaperedCylinder(RMat44Arg inMatrix, float inTop, float inBottom, float inTopRadius, float inBottomRadius, ColorArg inColor, ECastShadow inCastShadow, EDrawMode inDrawMode)1067{1068TaperedCylinder tapered_cylinder { inTop, inBottom, inTopRadius, inBottomRadius };10691070GeometryRef &geometry = mTaperedCylinders[tapered_cylinder];1071if (geometry == nullptr)1072{1073TaperedCylinderBatces::iterator it = mPrevTaperedCylinders.find(tapered_cylinder);1074if (it != mPrevTaperedCylinders.end())1075geometry = it->second;1076}1077if (geometry == nullptr)1078{1079float max_radius = max(inTopRadius, inBottomRadius);1080geometry = new Geometry(AABox(Vec3(-max_radius, inBottom, -max_radius), Vec3(max_radius, inTop, max_radius)));10811082for (int level = sMaxLevel; level >= 1; --level)1083geometry->mLODs.push_back({ CreateCylinder(inTop, inBottom, inTopRadius, inBottomRadius, level), sLODDistanceForLevel[sMaxLevel - level] });1084}10851086DrawGeometry(inMatrix, inColor, geometry, ECullMode::CullBackFace, inCastShadow, inDrawMode);1087}10881089void DebugRenderer::NextFrame()1090{1091mPrevSwingConeLimits.clear();1092std::swap(mSwingConeLimits, mPrevSwingConeLimits);10931094mPrevSwingPyramidLimits.clear();1095std::swap(mSwingPyramidLimits, mPrevSwingPyramidLimits);10961097mPrevPieLimits.clear();1098std::swap(mPieLimits, mPrevPieLimits);10991100mPrevTaperedCylinders.clear();1101std::swap(mTaperedCylinders, mPrevTaperedCylinders);1102}11031104JPH_NAMESPACE_END11051106#endif // JPH_DEBUG_RENDERER110711081109