// 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-2025 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. // **************************************************************************** // This snippet illustrates how to use a standalone PxBVH. // It creates a small custom scene (no PxScene) and creates a PxBVH for the // scene objects. The BVH is then used to raytrace the scene. The snippet // also shows how to update the BVH after the objects have moved. // **************************************************************************** #include #include "PxPhysicsAPI.h" #include "foundation/PxArray.h" #include "../snippetcommon/SnippetPrint.h" #include "../snippetcommon/SnippetPVD.h" #include "../snippetutils/SnippetUtils.h" #ifdef RENDER_SNIPPET #include "../snippetrender/SnippetCamera.h" #include "../snippetrender/SnippetRender.h" #endif using namespace physx; // Change this to use either refit the full BVH or just a subset of nodes static const bool gUsePartialRefit = false; static PxDefaultAllocator gAllocator; static PxDefaultErrorCallback gErrorCallback; static PxFoundation* gFoundation = NULL; namespace { class CustomScene { public: CustomScene(); ~CustomScene(); void release(); void addGeom(const PxGeometry& geom, const PxTransform& pose); void createBVH(); void render(); bool raycast(const PxVec3& origin, const PxVec3& unitDir, float maxDist, PxGeomRaycastHit& hit) const; void updateObjects(); struct Object { PxGeometryHolder mGeom; PxTransform mPose; }; PxArray mObjects; PxBVH* mBVH; }; CustomScene::CustomScene() : mBVH(NULL) { } CustomScene::~CustomScene() { } void CustomScene::release() { PX_RELEASE(mBVH); mObjects.reset(); PX_DELETE_THIS; } void CustomScene::addGeom(const PxGeometry& geom, const PxTransform& pose) { Object obj; obj.mGeom.storeAny(geom); obj.mPose = pose; mObjects.pushBack(obj); } void CustomScene::updateObjects() { static float time = 0.0f; time += 0.01f; if(gUsePartialRefit) { // This version is more efficient if you have to update a small subset of nodes const PxU32 nbObjects = mObjects.size(); for(PxU32 i=0;iupdateBounds(i, newBounds); } mBVH->partialRefit(); } else { // This version is more efficient if you have to update all nodes PxBounds3* bounds = mBVH->getBoundsForModification(); const PxU32 nbObjects = mObjects.size(); for(PxU32 i=0;irefit(); } } void CustomScene::createBVH() { const PxU32 nbObjects = mObjects.size(); PxBounds3* bounds = new PxBounds3[nbObjects]; for(PxU32 i=0;iraycast(origin, unitDir, maxDist, CB); return CB.mStatus; } void CustomScene::render() { updateObjects(); #ifdef RENDER_SNIPPET const PxVec3 color(1.0f, 0.5f, 0.25f); const PxU32 nbObjects = mObjects.size(); for(PxU32 i=0;itraverse(drawBounds); const PxU32 screenWidth = Snippets::getScreenWidth(); const PxU32 screenHeight = Snippets::getScreenHeight(); Snippets::Camera* sCamera = Snippets::getCamera(); const PxVec3 camPos = sCamera->getEye(); const PxVec3 camDir = sCamera->getDir(); #if PX_DEBUG const PxU32 RAYTRACING_RENDER_WIDTH = 64; const PxU32 RAYTRACING_RENDER_HEIGHT = 64; #else const PxU32 RAYTRACING_RENDER_WIDTH = 256; const PxU32 RAYTRACING_RENDER_HEIGHT = 256; #endif const PxU32 textureWidth = RAYTRACING_RENDER_WIDTH; const PxU32 textureHeight = RAYTRACING_RENDER_HEIGHT; GLubyte* pixels = new GLubyte[textureWidth*textureHeight*4]; const float fScreenWidth = float(screenWidth)/float(RAYTRACING_RENDER_WIDTH); const float fScreenHeight = float(screenHeight)/float(RAYTRACING_RENDER_HEIGHT); GLubyte* buffer = pixels; for(PxU32 j=0;jrender(); } void initPhysics(bool /*interactive*/) { gFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gAllocator, gErrorCallback); const PxTolerancesScale scale; PxCookingParams params(scale); params.midphaseDesc.setToDefault(PxMeshMidPhase::eBVH34); // params.midphaseDesc.mBVH34Desc.quantized = false; params.meshPreprocessParams |= PxMeshPreprocessingFlag::eDISABLE_ACTIVE_EDGES_PRECOMPUTE; params.meshPreprocessParams |= PxMeshPreprocessingFlag::eDISABLE_CLEAN_MESH; gConvexMesh = createCylinderMesh(3.0f, 1.0f, params); { PxTriangleMeshDesc meshDesc; meshDesc.points.count = SnippetUtils::Bunny_getNbVerts(); meshDesc.points.stride = sizeof(PxVec3); meshDesc.points.data = SnippetUtils::Bunny_getVerts(); meshDesc.triangles.count = SnippetUtils::Bunny_getNbFaces(); meshDesc.triangles.stride = sizeof(int)*3; meshDesc.triangles.data = SnippetUtils::Bunny_getFaces(); gTriangleMesh = PxCreateTriangleMesh(params, meshDesc); } gScene = new CustomScene; gScene->addGeom(PxBoxGeometry(PxVec3(1.0f, 2.0f, 0.5f)), PxTransform(PxVec3(0.0f, 0.0f, 0.0f))); gScene->addGeom(PxSphereGeometry(1.5f), PxTransform(PxVec3(4.0f, 0.0f, 0.0f))); gScene->addGeom(PxCapsuleGeometry(1.0f, 1.0f), PxTransform(PxVec3(-4.0f, 0.0f, 0.0f))); gScene->addGeom(PxConvexMeshGeometry(gConvexMesh), PxTransform(PxVec3(0.0f, 0.0f, 4.0f))); gScene->addGeom(PxTriangleMeshGeometry(gTriangleMesh), PxTransform(PxVec3(0.0f, 0.0f, -4.0f))); gScene->createBVH(); initScene(); } void stepPhysics(bool /*interactive*/) { } void cleanupPhysics(bool /*interactive*/) { releaseScene(); PX_RELEASE(gScene); PX_RELEASE(gConvexMesh); PX_RELEASE(gFoundation); printf("SnippetStandaloneBVH done.\n"); } void keyPress(unsigned char /*key*/, const PxTransform& /*camera*/) { /* if(key >= 1 && key <= gScenarioCount) { gScenario = key - 1; releaseScene(); initScene(); } if(key == 'r' || key == 'R') { releaseScene(); initScene(); }*/ } int snippetMain(int, const char*const*) { printf("Standalone BVH snippet.\n"); #ifdef RENDER_SNIPPET extern void renderLoop(); renderLoop(); #else static const PxU32 frameCount = 100; initPhysics(false); for(PxU32 i=0; i