// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. #include "RenderPhysX3Debug.h" #include "RendererColor.h" #include "common/PxRenderBuffer.h" #include "foundation/PxSimpleTypes.h" #include "SampleCamera.h" #include "geometry/PxConvexMesh.h" #include "geometry/PxConvexMeshGeometry.h" #include "geometry/PxCapsuleGeometry.h" #include "geometry/PxSphereGeometry.h" #include "geometry/PxBoxGeometry.h" #include "PsUtilities.h" #include "PsString.h" using namespace physx; using namespace SampleRenderer; using namespace SampleFramework; RenderPhysX3Debug::RenderPhysX3Debug(Renderer& renderer, SampleAssetManager& assetmanager) : SamplePointDebugRender (renderer, assetmanager), SampleLineDebugRender (renderer, assetmanager), SampleTriangleDebugRender (renderer, assetmanager) { } RenderPhysX3Debug::~RenderPhysX3Debug() { } void RenderPhysX3Debug::update(const PxRenderBuffer& debugRenderable) { // Points const PxU32 numPoints = debugRenderable.getNbPoints(); if(numPoints) { const PxDebugPoint* PX_RESTRICT points = debugRenderable.getPoints(); checkResizePoint(numPoints); for(PxU32 i=0; itransform(verts[i]); } return true; } // PT: this comes from RendererCapsuleShape.cpp. Maybe we could grab the data from there instead of duplicating. But it protects us from external changes. static const PxVec3 gCapsuleVertices[] = { PxVec3(0.0000f, -2.0000f, -0.0000f), PxVec3(0.3827f, -1.9239f, -0.0000f), PxVec3(0.2706f, -1.9239f, 0.2706f), PxVec3(-0.0000f, -1.9239f, 0.3827f), PxVec3(-0.2706f, -1.9239f, 0.2706f), PxVec3(-0.3827f, -1.9239f, -0.0000f), PxVec3(-0.2706f, -1.9239f, -0.2706f), PxVec3(0.0000f, -1.9239f, -0.3827f), PxVec3(0.2706f, -1.9239f, -0.2706f), PxVec3(0.7071f, -1.7071f, -0.0000f), PxVec3(0.5000f, -1.7071f, 0.5000f), PxVec3(-0.0000f, -1.7071f, 0.7071f), PxVec3(-0.5000f, -1.7071f, 0.5000f), PxVec3(-0.7071f, -1.7071f, -0.0000f), PxVec3(-0.5000f, -1.7071f, -0.5000f), PxVec3(0.0000f, -1.7071f, -0.7071f), PxVec3(0.5000f, -1.7071f, -0.5000f), PxVec3(0.9239f, -1.3827f, -0.0000f), PxVec3(0.6533f, -1.3827f, 0.6533f), PxVec3(-0.0000f, -1.3827f, 0.9239f), PxVec3(-0.6533f, -1.3827f, 0.6533f), PxVec3(-0.9239f, -1.3827f, -0.0000f), PxVec3(-0.6533f, -1.3827f, -0.6533f), PxVec3(0.0000f, -1.3827f, -0.9239f), PxVec3(0.6533f, -1.3827f, -0.6533f), PxVec3(1.0000f, -1.0000f, -0.0000f), PxVec3(0.7071f, -1.0000f, 0.7071f), PxVec3(-0.0000f, -1.0000f, 1.0000f), PxVec3(-0.7071f, -1.0000f, 0.7071f), PxVec3(-1.0000f, -1.0000f, -0.0000f), PxVec3(-0.7071f, -1.0000f, -0.7071f), PxVec3(0.0000f, -1.0000f, -1.0000f), PxVec3(0.7071f, -1.0000f, -0.7071f), PxVec3(1.0000f, 1.0000f, 0.0000f), PxVec3(0.7071f, 1.0000f, 0.7071f), PxVec3(-0.0000f, 1.0000f, 1.0000f), PxVec3(-0.7071f, 1.0000f, 0.7071f), PxVec3(-1.0000f, 1.0000f, -0.0000f), PxVec3(-0.7071f, 1.0000f, -0.7071f), PxVec3(0.0000f, 1.0000f, -1.0000f), PxVec3(0.7071f, 1.0000f, -0.7071f), PxVec3(0.9239f, 1.3827f, 0.0000f), PxVec3(0.6533f, 1.3827f, 0.6533f), PxVec3(-0.0000f, 1.3827f, 0.9239f), PxVec3(-0.6533f, 1.3827f, 0.6533f), PxVec3(-0.9239f, 1.3827f, -0.0000f), PxVec3(-0.6533f, 1.3827f, -0.6533f), PxVec3(0.0000f, 1.3827f, -0.9239f), PxVec3(0.6533f, 1.3827f, -0.6533f), PxVec3(0.7071f, 1.7071f, 0.0000f), PxVec3(0.5000f, 1.7071f, 0.5000f), PxVec3(-0.0000f, 1.7071f, 0.7071f), PxVec3(-0.5000f, 1.7071f, 0.5000f), PxVec3(-0.7071f, 1.7071f, 0.0000f), PxVec3(-0.5000f, 1.7071f, -0.5000f), PxVec3(0.0000f, 1.7071f, -0.7071f), PxVec3(0.5000f, 1.7071f, -0.5000f), PxVec3(0.3827f, 1.9239f, 0.0000f), PxVec3(0.2706f, 1.9239f, 0.2706f), PxVec3(-0.0000f, 1.9239f, 0.3827f), PxVec3(-0.2706f, 1.9239f, 0.2706f), PxVec3(-0.3827f, 1.9239f, 0.0000f), PxVec3(-0.2706f, 1.9239f, -0.2706f), PxVec3(0.0000f, 1.9239f, -0.3827f), PxVec3(0.2706f, 1.9239f, -0.2706f), PxVec3(0.0000f, 2.0000f, 0.0000f), }; static const PxU8 gCapsuleIndices[] = { 1, 0, 2, 2, 0, 3, 3, 0, 4, 4, 0, 5, 5, 0, 6, 6, 0, 7, 7, 0, 8, 8, 0, 1, 9, 1, 10, 10, 1, 2, 10, 2, 11, 11, 2, 3, 11, 3, 12, 12, 3, 4, 12, 4, 13, 13, 4, 5, 13, 5, 14, 14, 5, 6, 14, 6, 15, 15, 6, 7, 15, 7, 16, 16, 7, 8, 16, 8, 9, 9, 8, 1, 17, 9, 18, 18, 9, 10, 18, 10, 19, 19, 10, 11, 19, 11, 20, 20, 11, 12, 20, 12, 21, 21, 12, 13, 21, 13, 22, 22, 13, 14, 22, 14, 23, 23, 14, 15, 23, 15, 24, 24, 15, 16, 24, 16, 17, 17, 16, 9, 25, 17, 26, 26, 17, 18, 26, 18, 27, 27, 18, 19, 27, 19, 28, 28, 19, 20, 28, 20, 29, 29, 20, 21, 29, 21, 30, 30, 21, 22, 30, 22, 31, 31, 22, 23, 31, 23, 32, 32, 23, 24, 32, 24, 25, 25, 24, 17, 33, 25, 34, 34, 25, 26, 34, 26, 35, 35, 26, 27, 35, 27, 36, 36, 27, 28, 36, 28, 37, 37, 28, 29, 37, 29, 38, 38, 29, 30, 38, 30, 39, 39, 30, 31, 39, 31, 40, 40, 31, 32, 40, 32, 33, 33, 32, 25, 41, 33, 42, 42, 33, 34, 42, 34, 43, 43, 34, 35, 43, 35, 44, 44, 35, 36, 44, 36, 45, 45, 36, 37, 45, 37, 46, 46, 37, 38, 46, 38, 47, 47, 38, 39, 47, 39, 48, 48, 39, 40, 48, 40, 41, 41, 40, 33, 49, 41, 50, 50, 41, 42, 50, 42, 51, 51, 42, 43, 51, 43, 52, 52, 43, 44, 52, 44, 53, 53, 44, 45, 53, 45, 54, 54, 45, 46, 54, 46, 55, 55, 46, 47, 55, 47, 56, 56, 47, 48, 56, 48, 49, 49, 48, 41, 57, 49, 58, 58, 49, 50, 58, 50, 59, 59, 50, 51, 59, 51, 60, 60, 51, 52, 60, 52, 61, 61, 52, 53, 61, 53, 62, 62, 53, 54, 62, 54, 63, 63, 54, 55, 63, 55, 64, 64, 55, 56, 64, 56, 57, 57, 56, 49, 65, 57, 58, 65, 58, 59, 65, 59, 60, 65, 60, 61, 65, 61, 62, 65, 62, 63, 65, 63, 64, 65, 64, 57, }; static const PxU32 gNumCapsuleIndices = PX_ARRAY_SIZE(gCapsuleIndices); static PX_FORCE_INLINE void fixCapsuleVertex(PxVec3& p, PxF32 radius, PxF32 halfHeight) { const PxF32 sign = p.y > 0 ? 1.0f : -1.0f; p.y -= sign; p *= radius; p.y += halfHeight*sign; } void RenderPhysX3Debug::addSphere(const PxSphereGeometry& sg, const PxTransform& tr, const RendererColor& color, PxU32 renderFlags) { addSphere(tr.p, sg.radius, color, renderFlags); } void RenderPhysX3Debug::addSphere(const PxVec3& sphereCenter, float sphereRadius, const RendererColor& color, PxU32 renderFlags) { const PxU32 nbVerts = NB_CIRCLE_PTS; PxVec3 pts[NB_CIRCLE_PTS]; if(renderFlags & RENDER_DEBUG_WIREFRAME) { generatePolygon(nbVerts, pts, ORIENTATION_XY, sphereRadius, 0.0f); addCircle(nbVerts, pts, color, sphereCenter); generatePolygon(nbVerts, pts, ORIENTATION_XZ, sphereRadius, 0.0f); addCircle(nbVerts, pts, color, sphereCenter); generatePolygon(nbVerts, pts, ORIENTATION_YZ, sphereRadius, 0.0f); addCircle(nbVerts, pts, color, sphereCenter); } if(renderFlags & RENDER_DEBUG_SOLID) { const PxF32 halfHeight = 0.0f; for(PxU32 i=0;i MAX_TEMP_VERTEX_BUFFER) return false; const float stepTheta = PxTwoPi / float(nSeg); const float stepPhi = PxPi / float(nSeg); // compute sphere vertices on the temporary buffer nbVerts = 0; for (int i = 0; i <= nSeg; i++) { const float theta = float(i) * stepTheta; const float cosi = cos(theta); const float sini = sin(theta); for (int j = -halfSeg; j <= halfSeg; j++) { const float phi = float(j) * stepPhi; const float sinj = sin( phi); const float cosj = cos( phi); const float y = cosj * cosi; const float x = sinj; const float z = cosj * sini; tempVertexBuffer[nbVerts] = PxVec3(x,y,z); tempNormalBuffer[nbVerts] = PxVec3(x,y,z).getNormalized(); nbVerts++; } } nbVerts = 0; // now create triangle soup data for (int i = 0; i < nSeg; i++) { for (int j = 0; j < nSeg; j++) { // add one triangle verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * i + j]; normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * i + j]; nbVerts++; verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * i + j+1]; normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * i + j+1]; nbVerts++; verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * (i+1) + j+1]; normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * (i+1) + j+1]; nbVerts++; // add another triangle verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * i + j]; normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * i + j]; nbVerts++; verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * (i+1) + j+1]; normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * (i+1) + j+1]; nbVerts++; verts[nbVerts] = tempVertexBuffer[ (nSeg+1) * (i+1) + j]; normals[nbVerts] = tempNormalBuffer[ (nSeg+1) * (i+1) + j]; nbVerts++; } } return true; } void RenderPhysX3Debug::addSphereExt(const PxVec3& sphereCenter, float sphereRadius, const RendererColor& color, PxU32 renderFlags) { if(renderFlags & RENDER_DEBUG_WIREFRAME) { const PxU32 nbVerts = NB_CIRCLE_PTS; PxVec3 pts[NB_CIRCLE_PTS]; generatePolygon(nbVerts, pts, ORIENTATION_XY, sphereRadius, 0.0f); addCircle(nbVerts, pts, color, sphereCenter); generatePolygon(nbVerts, pts, ORIENTATION_XZ, sphereRadius, 0.0f); addCircle(nbVerts, pts, color, sphereCenter); generatePolygon(nbVerts, pts, ORIENTATION_YZ, sphereRadius, 0.0f); addCircle(nbVerts, pts, color, sphereCenter); } if(renderFlags & RENDER_DEBUG_SOLID) { static bool initDone = false; static PxU32 nbVerts; static PxVec3 verts[MAX_TEMP_VERTEX_BUFFER*6]; static PxVec3 normals[MAX_TEMP_VERTEX_BUFFER*6]; if (!initDone) { generateSphere(16, nbVerts, verts, normals); initDone = true; } PxU32 i = 0; while ( i < nbVerts ) { addTriangle( sphereCenter + sphereRadius * verts[i], sphereCenter + sphereRadius * verts[i+1], sphereCenter + sphereRadius * verts[i+2], normals[i], normals[i+1], normals[i+2], color); i += 3; } } } #undef MAX_TEMP_VERTEX_BUFFFER static inline PxU32 minArgument(const PxVec3 &v) { PxU32 j = 0; if ( v[j] > v[1]) j = 1; if ( v[j] > v[2]) j = 2; return j; } static inline PxVec3 abs(const PxVec3 &v) { return PxVec3( PxAbs(v.x), PxAbs(v.y), PxAbs(v.z)); } void RenderPhysX3Debug::addConeExt(float r0, float r1, const PxVec3& p0, const PxVec3& p1 , const RendererColor& color, PxU32 renderFlags) { PxVec3 axis = p1 - p0; PxReal length = axis.magnitude(); PxReal rdiff = r0 - r1; PxReal sinAngle = rdiff / length; PxReal x0 = r0 * sinAngle; PxReal x1 = r1 * sinAngle; PxVec3 center = 0.5f * (p0 + p1); if (length < fabs(rdiff)) return; PxReal r0p = sqrt(r0 * r0 - x0 * x0); PxReal r1p = sqrt(r1 * r1 - x1 * x1); if (length == 0.0f) axis = PxVec3(1,0,0); else axis.normalize(); PxVec3 axis1(0.0f); axis1[minArgument(abs(axis))] = 1.0f; axis1 = axis1.cross(axis); axis1.normalize(); PxVec3 axis2 = axis.cross(axis1); axis2.normalize(); PxMat44 m; m.column0 = PxVec4(axis, 0.0f); m.column1 = PxVec4(axis1, 0.0f); m.column2 = PxVec4(axis2, 0.0f); m.column3 = PxVec4(center, 1.0f); PxTransform tr(m); #define NUM_CONE_VERTS 72 const PxU32 nbVerts = NUM_CONE_VERTS; PxVec3 pts0[NUM_CONE_VERTS] ; PxVec3 pts1[NUM_CONE_VERTS]; PxVec3 normals[NUM_CONE_VERTS] ; const float step = PxTwoPi / float(nbVerts); for (PxU32 i = 0; i < nbVerts; i++) { const float angle = float(i) * step; const float x = cosf(angle); const float y = sinf(angle); PxVec3 p = PxVec3(0.0f, x, y); pts0[i] = tr.transform(r0p * p + PxVec3(-0.5f * length + x0,0,0)); pts1[i] = tr.transform(r1p * p + PxVec3(0.5f * length + x1, 0, 0)); normals[i] = tr.q.rotate(p.getNormalized()); normals[i] = x0 * axis + r0p * normals[i]; normals[i].normalize(); } #undef NUM_CONE_VERTS if(renderFlags & RENDER_DEBUG_WIREFRAME) { for(PxU32 i=0;i(geom), tr, color, renderFlags); } break; case PxGeometryType::eSPHERE: { addSphere(static_cast(geom), tr, color, renderFlags); } break; case PxGeometryType::eCAPSULE: { addCapsule(static_cast(geom), tr, color, renderFlags); } break; case PxGeometryType::eCONVEXMESH: { addConvex(static_cast(geom), tr, color, renderFlags); } break; case PxGeometryType::ePLANE: case PxGeometryType::eTRIANGLEMESH: case PxGeometryType::eHEIGHTFIELD: default: { PX_ASSERT(!"Not supported!"); break; } } } void RenderPhysX3Debug::addConvex(const PxConvexMeshGeometry& cg, const PxTransform& tr, const RendererColor& color, PxU32 renderFlags) { const PxConvexMesh& mesh = *cg.convexMesh; const PxMat33 rot = PxMat33(tr.q) * cg.scale.toMat33(); // PT: you can't use PxTransform with a non-uniform scaling const PxMat44 globalPose(rot, tr.p); const PxU32 polygonCount = mesh.getNbPolygons(); const PxU8* indexBuffer = mesh.getIndexBuffer(); const PxVec3* vertexBuffer = mesh.getVertices(); if(renderFlags & RENDER_DEBUG_WIREFRAME) { for(PxU32 i=0; i