diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/module/destructible/fracture | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'APEX_1.4/module/destructible/fracture')
63 files changed, 12969 insertions, 0 deletions
diff --git a/APEX_1.4/module/destructible/fracture/Actor.cpp b/APEX_1.4/module/destructible/fracture/Actor.cpp new file mode 100644 index 00000000..1eb12b66 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Actor.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include <DestructibleActorImpl.h> +#include <RenderMeshAsset.h> +#include <DestructibleStructure.h> + +#include "../fracture/Actor.h" + +#include "FracturePattern.h" +#include "SimScene.h" +#include "Compound.h" +#include "Mesh.h" + +namespace nvidia +{ +namespace fracture +{ + +Actor::Actor(base::SimScene* scene, DestructibleActorImpl* actor): + base::Actor(scene), + mActor(actor), + mRenderResourcesDirty(false), + mMinRadius(0.f), + mRadiusMultiplier(1.f), + mImpulseScale(1.f), + mSheetFracture(true) +{ + if(actor == NULL) + { + const uint32_t numSectors = 10; + const float sectorRand = 0.3f; + const float firstSegmentSize = 0.06f; + const float segmentScale = 1.4f; + const float segmentRand = 0.3f; + const float size = 10.f; + const float radius = size; + const float thickness = size; + mDefaultFracturePattern = (FracturePattern*)mScene->createFracturePattern(); + mDefaultFracturePattern->createGlass(radius,thickness,numSectors,sectorRand,firstSegmentSize,segmentScale,segmentRand); + } + else + { + // create fracture pattern + const nvidia::destructible::DestructibleActorParamNS::RuntimeFracture_Type& params = actor->getParams()->destructibleParameters.runtimeFracture; + const uint32_t numSectors = params.glass.numSectors; + const float sectorRand = params.glass.sectorRand; + const float firstSegmentSize = params.glass.firstSegmentSize; + const float segmentScale = params.glass.segmentScale; + const float segmentRand = params.glass.segmentRand; + const float size = actor->getBounds().getDimensions().maxElement(); + const float radius = size; + const float thickness = size; + mDefaultFracturePattern = (FracturePattern*)mScene->createFracturePattern(); + mDefaultFracturePattern->createGlass(radius,thickness,(int32_t)numSectors,sectorRand,firstSegmentSize,segmentScale,segmentRand); + // attachment + mAttachmentFlags.posX = (uint32_t)params.attachment.posX; + mAttachmentFlags.negX = (uint32_t)params.attachment.negX; + mAttachmentFlags.posY = (uint32_t)params.attachment.posY; + mAttachmentFlags.negY = (uint32_t)params.attachment.negY; + mAttachmentFlags.posZ = (uint32_t)params.attachment.posZ; + mAttachmentFlags.negZ = (uint32_t)params.attachment.negZ; + // other + mDepthLimit = params.depthLimit; + mDestroyIfAtDepthLimit = params.destroyIfAtDepthLimit; + mImpulseScale = params.impulseScale; + mMinConvexSize = params.minConvexSize; + mSheetFracture = params.sheetFracture; + } +} + +Actor::~Actor() +{ + PX_DELETE(mDefaultFracturePattern); + mDefaultFracturePattern = NULL; +} + +Compound* Actor::createCompound() +{ + base::Compound* c = mScene->createCompound((base::FracturePattern*)mDefaultFracturePattern); + addCompound(c); + return (Compound*)c; +} + +Compound* Actor::createCompoundFromChunk(const destructible::DestructibleActorImpl& actor, uint32_t partIndex) +{ + Mesh RTmesh; + RTmesh.loadFromRenderMesh(*actor.getDestructibleAsset()->getRenderMeshAsset(),partIndex); + + // Fix texture v's (different between right hand and left hand) + RTmesh.flipV(); + + PxTransform pose(actor.getChunkPose(partIndex)); + pose.p = actor.getStructure()->getChunkWorldCentroid(actor.getChunk(partIndex)); + + Compound* c = createCompound(); + + c->createFromMesh(&RTmesh,pose,actor.getChunkLinearVelocity(partIndex),actor.getChunkAngularVelocity(partIndex),-1,actor.getScale()); + + const DestructibleActorParamNS::BehaviorGroup_Type& behaviorGroup = actor.getBehaviorGroup(partIndex); + mMinRadius = behaviorGroup.damageSpread.minimumRadius; + mRadiusMultiplier = behaviorGroup.damageSpread.radiusMultiplier; + + // attachment + //const DestructibleActorParamNS::RuntimeFracture_Type& params = mActor->getParams()->destructibleParameters.runtimeFracture; + DestructibleParameters& params = mActor->getDestructibleParameters(); + mAttachmentFlags.posX |= params.rtFractureParameters.attachment.posX; + mAttachmentFlags.negX |= params.rtFractureParameters.attachment.negX; + mAttachmentFlags.posY |= params.rtFractureParameters.attachment.posY; + mAttachmentFlags.negY |= params.rtFractureParameters.attachment.negY; + mAttachmentFlags.posZ |= params.rtFractureParameters.attachment.posZ; + mAttachmentFlags.negZ |= params.rtFractureParameters.attachment.negZ; + + attachBasedOnFlags(c); + + mRenderResourcesDirty = true; + + return c; +} + +bool Actor::patternFracture(const PxVec3& hitLocation, const PxVec3& dirIn, float scale, float vel, float radiusIn) +{ + int compoundNr = -1; + int convexNr = -1; + PxVec3 normal; + float dist; + bool ret = false; + PxVec3 dir = dirIn; + + mScene->getScene()->lockWrite(); + + bool hit = false; + if (dir.magnitudeSquared() < 0.5f) + { + dir = PxVec3(1.f,0.f,0.f); + hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal); + if(!hit) + { + dir = PxVec3(0.f,1.f,0.f); + hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal); + if(!hit) + { + dir = PxVec3(0.f,0.f,1.f); + hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal); + } + } + } + else + { + hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal); + } + if (hit) + { + float radius = mMinRadius + mRadiusMultiplier*radiusIn; + float impulseMagn = scale*vel*mImpulseScale; + + if (mSheetFracture) + { + normal = ((Compound*)mCompounds[(uint32_t)compoundNr])->mNormal; + } + PxVec3 a(0.f,0.f,1.f); + normal.normalize(); + a -= a.dot(normal)*normal; + if( a.magnitudeSquared() < 0.1f ) + { + a = PxVec3(0.f,1.f,0.f); + a -= a.dot(normal)*normal; + } + a.normalize(); + PxVec3 b(normal.cross(a)); + PxMat33 trans(a,b,normal); + ret = base::Actor::patternFracture(hitLocation,dir,compoundNr,trans,radius,impulseMagn,impulseMagn); + } + + mScene->getScene()->unlockWrite(); + + mRenderResourcesDirty = true; + + return ret; +} + +bool Actor::patternFracture(const DamageEvent& damageEvent) +{ + mDamageEvent.position = damageEvent.position; + mDamageEvent.direction = damageEvent.direction; + mDamageEvent.damage = damageEvent.damage; + mDamageEvent.radius = damageEvent.radius; + return patternFracture(damageEvent.position, damageEvent.direction, 1.f, damageEvent.damage, damageEvent.radius); +} + +bool Actor::patternFracture(const FractureEvent& fractureEvent, bool fractureOnLoad) +{ + createCompoundFromChunk(*mActor,fractureEvent.chunkIndexInAsset); + if(fractureOnLoad) + { + patternFracture(mDamageEvent.position, mDamageEvent.direction, 1.f, mDamageEvent.damage, mDamageEvent.radius); + //patternFracture(fractureEvent.position,fractureEvent.hitDirection,1.f,fractureEvent.impulse.magnitude()/mActor->getChunkMass(fractureEvent.chunkIndexInAsset),1); + } + return true; +} + +bool Actor::rayCast(const PxVec3& orig, const PxVec3& dir, float &dist) const +{ + int compoundNr = 0; + int convexNr = 0; + PxVec3 n; + bool ret = false; + + mScene->getScene()->lockRead(); + ret = base::Actor::rayCast(orig,dir,dist,compoundNr,convexNr,n); + mScene->getScene()->unlockRead(); + + return ret; +} + +void Actor::attachBasedOnFlags(base::Compound* c) +{ + PxBounds3 b; + c->getLocalBounds(b); + // Determine sheet face + if (mSheetFracture) + { + PxVec3 dim = b.getDimensions(); + if ( dim.x < dim.y && dim.x < dim.z ) + { + ((Compound*)c)->mNormal = PxVec3(1.f,0.f,0.f); + } + else if ( dim.y < dim.x && dim.y < dim.z ) + { + ((Compound*)c)->mNormal = PxVec3(0.f,1.f,0.f); + } + else + { + ((Compound*)c)->mNormal = PxVec3(0.f,0.f,1.f); + } + } + // Attach + const float w = 0.01f*b.getDimensions().maxElement(); + nvidia::Array<PxBounds3> bounds; + bounds.reserve(6); + if (mAttachmentFlags.posX) + { + PxBounds3 a(b); + a.minimum.x = a.maximum.x-w; + bounds.pushBack(a); + } + if (mAttachmentFlags.negX) + { + PxBounds3 a(b); + a.maximum.x = a.minimum.x+w; + bounds.pushBack(a); + } + if (mAttachmentFlags.posY) + { + PxBounds3 a(b); + a.minimum.y = a.maximum.y-w; + bounds.pushBack(a); + } + if (mAttachmentFlags.negY) + { + PxBounds3 a(b); + a.maximum.y = a.minimum.y+w; + bounds.pushBack(a); + } + if (mAttachmentFlags.posZ) + { + PxBounds3 a(b); + a.minimum.z = a.maximum.z-w; + bounds.pushBack(a); + } + if (mAttachmentFlags.negZ) + { + PxBounds3 a(b); + a.maximum.z = a.minimum.z+w; + bounds.pushBack(a); + } + c->attachLocal(bounds); +} + +} +} +#endif diff --git a/APEX_1.4/module/destructible/fracture/Actor.h b/APEX_1.4/module/destructible/fracture/Actor.h new file mode 100644 index 00000000..f23e4b88 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Actor.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef RT_ACTOR_H +#define RT_ACTOR_H + +#include "ActorBase.h" + +namespace nvidia +{ +namespace destructible +{ + class DestructibleActorImpl; + struct DamageEvent; + struct FractureEvent; +} + +using namespace destructible; +namespace fracture +{ + +class Compound; +class FracturePattern; +class Renderable; + +class Actor : public base::Actor +{ + friend class SimScene; + friend class Renderable; +protected: + Actor(base::SimScene* scene, DestructibleActorImpl* actor); +public: + virtual ~Actor(); + + Compound* createCompound(); + + Compound* createCompoundFromChunk(const destructible::DestructibleActorImpl& destructibleActor, uint32_t partIndex); + + bool patternFracture(const PxVec3& hitLocation, const PxVec3& dir, float scale = 1.f, float vel = 0.f, float radius = 0.f); + bool patternFracture(const DamageEvent& damageEvent); + bool patternFracture(const FractureEvent& fractureEvent, bool fractureOnLoad = true); + + bool rayCast(const PxVec3& orig, const PxVec3& dir, float &dist) const; + + DestructibleActorImpl* getDestructibleActor() {return mActor;} + +protected: + void attachBasedOnFlags(base::Compound* c); + + FracturePattern* mDefaultFracturePattern; + DestructibleActorImpl* mActor; + bool mRenderResourcesDirty; + + float mMinRadius; + float mRadiusMultiplier; + float mImpulseScale; + bool mSheetFracture; + + struct AttachmentFlags + { + AttachmentFlags() : + posX(0), negX(0), posY(0), negY(0), posZ(0), negZ(0) {} + + uint32_t posX : 1; + uint32_t negX : 1; + uint32_t posY : 1; + uint32_t negY : 1; + uint32_t posZ : 1; + uint32_t negZ : 1; + }mAttachmentFlags; + + struct MyDamageEvent + { + PxVec3 position; + PxVec3 direction; + float damage; + float radius; + }; + MyDamageEvent mDamageEvent; + +}; + +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Compound.cpp b/APEX_1.4/module/destructible/fracture/Compound.cpp new file mode 100644 index 00000000..2d49f19d --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Compound.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "ApexActor.h" +#include "DestructibleScene.h" +#include "DestructibleActorImpl.h" +#include "SimScene.h" +#include "Actor.h" +#include "PxShape.h" + +#include "Compound.h" + +namespace nvidia +{ + +namespace fracture +{ + +void Compound::applyShapeTemplate(PxShape* shape) +{ + if( shape && mActor) + { + DestructibleActorImpl* dactor = ((Actor*)mActor)->getDestructibleActor(); + { + PhysX3DescTemplateImpl physX3Template; + dactor->getPhysX3Template(physX3Template); + physX3Template.apply(shape); + } + } +} + +::nvidia::destructible::DestructibleActorImpl* Compound::getDestructibleActor() const +{ + ::nvidia::destructible::DestructibleActorImpl* dactor = NULL; + if(mActor) + dactor = ((Actor*)mActor)->getDestructibleActor(); + return dactor; +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Compound.h b/APEX_1.4/module/destructible/fracture/Compound.h new file mode 100644 index 00000000..8f07c393 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Compound.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef COMPOUND_H +#define COMPOUND_H + +#include "CompoundBase.h" + +namespace nvidia +{ +namespace fracture +{ + +class Compound : public base::Compound +{ + friend class SimScene; + friend class Actor; +protected: + Compound(SimScene* scene, const base::FracturePattern *pattern, const base::FracturePattern *secondaryPattern = NULL, float contactOffset = 0.005f, float restOffset = -0.001f): + nvidia::fracture::base::Compound((base::SimScene*)scene,pattern,secondaryPattern,contactOffset,restOffset) {} +public: + virtual void applyShapeTemplate(PxShape* shape); + virtual ::nvidia::destructible::DestructibleActorImpl* getDestructibleActor() const; +}; + +} +} + + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/CompoundCreator.cpp b/APEX_1.4/module/destructible/fracture/CompoundCreator.cpp new file mode 100644 index 00000000..14a29b7b --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/CompoundCreator.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "CompoundCreator.h" + +namespace nvidia +{ +namespace fracture +{ + +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/CompoundCreator.h b/APEX_1.4/module/destructible/fracture/CompoundCreator.h new file mode 100644 index 00000000..40198fe6 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/CompoundCreator.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef COMPOUND_CREATOR_H +#define COMPOUND_CREATOR_H + +#include <PxVec3.h> +#include <PxTransform.h> +#include <PsArray.h> + +#include "CompoundCreatorBase.h" + +namespace nvidia +{ +namespace fracture +{ + +class CompoundCreator : public base::CompoundCreator +{ + friend class SimScene; +protected: + CompoundCreator(base::SimScene* scene): base::CompoundCreator((base::SimScene*)scene) {} +}; + +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/CompoundGeometry.cpp b/APEX_1.4/module/destructible/fracture/CompoundGeometry.cpp new file mode 100644 index 00000000..9429174a --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/CompoundGeometry.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "CompoundGeometry.h" + +namespace nvidia +{ +namespace fracture +{ + +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/CompoundGeometry.h b/APEX_1.4/module/destructible/fracture/CompoundGeometry.h new file mode 100644 index 00000000..689be78c --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/CompoundGeometry.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef COMPOUND_GEOMETRY +#define COMPOUND_GEOMETRY + +#include <PxVec3.h> +#include <PxPlane.h> +#include <PsArray.h> + +#include "CompoundGeometryBase.h" + +namespace nvidia +{ +namespace fracture +{ + +class CompoundGeometry : public nvidia::fracture::base::CompoundGeometry +{ +}; + +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Convex.cpp b/APEX_1.4/module/destructible/fracture/Convex.cpp new file mode 100644 index 00000000..4fc5de4c --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Convex.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "Convex.h" + +namespace nvidia +{ +namespace fracture +{ + +} +} + +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Convex.h b/APEX_1.4/module/destructible/fracture/Convex.h new file mode 100644 index 00000000..40717e67 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Convex.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef CONVEX +#define CONVEX + +#include "ConvexBase.h" + +namespace nvidia +{ +namespace fracture +{ + +class Convex : public base::Convex +{ + friend class SimScene; +protected: + Convex(base::SimScene* scene): base::Convex(scene) {} +public: +}; + +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/ActorBase.cpp b/APEX_1.4/module/destructible/fracture/Core/ActorBase.cpp new file mode 100644 index 00000000..2c88a262 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/ActorBase.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "ActorBase.h" + +#include <PxMat44.h> +#include "PxRigidBodyExt.h" +#include "PxScene.h" + +#include "SimSceneBase.h" +#include "CompoundBase.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace nvidia; + +Actor::Actor(SimScene* scene): + mScene(scene), + mMinConvexSize(scene->mMinConvexSize), + mDepthLimit(100), + mDestroyIfAtDepthLimit(false) +{ + +} + +Actor::~Actor() +{ + PxScene* pxScene = mScene->getScene(); + if(pxScene != NULL) + { + pxScene->lockWrite(); + } + clear(); + if(pxScene != NULL) + { + pxScene->unlockWrite(); + } + mScene->removeActor(this); +} + +void Actor::clear() +{ + for (uint32_t i = 0; i < mCompounds.size(); i++) { + PX_DELETE(mCompounds[i]); + } + mCompounds.clear(); +} + +void Actor::addCompound(Compound *c) +{ + mCompounds.pushBack(c); + PxRigidDynamic *a = c->getPxActor(); + if (a) { +// a->setContactReportFlags(Px_NOTIFY_ON_TOUCH_FORCE_THRESHOLD | Px_NOTIFY_ON_START_TOUCH_FORCE_THRESHOLD); + a->setContactReportThreshold(mScene->mFractureForceThreshold); + } + c->mActor = this; + ++(mScene->mSceneVersion); +} + +void Actor::removeCompound(Compound *c) +{ + uint32_t num = 0; + for (uint32_t i = 0; i < mCompounds.size(); i++) { + if (mCompounds[i] != c) { + mCompounds[num] = mCompounds[i]; + num++; + } + } + if (mScene->mPickActor == c->getPxActor()) + mScene->mPickActor = NULL; + + c->clear(); + //delCompoundList.push_back(c); + //delete c; + mScene->delCompoundList.pushBack(c); + mCompounds.resize(num); + ++mScene->mSceneVersion; +} + +void Actor::preSim(float dt) +{ + uint32_t num = 0; + for (uint32_t i = 0; i < (uint32_t)mCompounds.size(); i++) { + mCompounds[i]->step(dt); + if (mCompounds[i]->getLifeFrames() == 0) { + mCompounds[i]->clear(); + //delCompoundList.push_back(mCompounds[i]); + //delete mCompounds[i]; + mScene->delCompoundList.pushBack(mCompounds[i]); + } + else { + mCompounds[num] = mCompounds[i]; + num++; + } + } + mCompounds.resize(num); +} + +void Actor::postSim(float /*dt*/) +{ +} + +bool Actor::rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &compoundNr, int &convexNr, PxVec3 &normal) const +{ + dist = PX_MAX_F32; + compoundNr = -1; + convexNr = -1; + + for (uint32_t i = 0; i < mCompounds.size(); i++) { + float d; + int cNr; + PxVec3 n; + if (mCompounds[i]->rayCast(orig, dir, d, cNr, n)) { + if (d < dist) { + dist = d; + compoundNr = (int)i; + convexNr = cNr; + normal = n; + } + } + } + return compoundNr >= 0; +} + +bool Actor::patternFracture(const PxVec3 &orig, const PxVec3 &dir, const PxMat33 patternTransform, float impactRadius, float radialImpulse, float directionalImpulse) +{ + float dist; + float objectSize = 0.0f; + int actorNr; + int compoundNr; + int convexNr; + PxVec3 normal; + + // do global rayCast. + if (!mScene->rayCast(orig, dir, dist, actorNr, compoundNr, convexNr, normal)) + return false; + if (mScene->mActors[(uint32_t)actorNr] != this) + return false; + + mScene->debugPoints.clear(); + nvidia::Array<Compound*> compounds; + + mScene->profileBegin("patternFracture"); + bool OK = mCompounds[(uint32_t)compoundNr]->patternFracture(orig + dir * dist, mMinConvexSize, + compounds, patternTransform, mScene->debugPoints, impactRadius, radialImpulse, normal * directionalImpulse); + mScene->profileEnd("patternFracture"); + if (!OK) + return false; + + if (compounds.empty()) + return false; + + if (mCompounds[(uint32_t)compoundNr]->getPxActor() == mScene->mPickActor) + mScene->mPickActor = NULL; + + PxBounds3 bounds; + mCompounds[(uint32_t)compoundNr]->getWorldBounds(bounds); + objectSize = bounds.getDimensions().magnitude(); + + //delCompoundList.push_back( mCompounds[compoundNr]); + mScene->delCompoundList.pushBack( mCompounds[(uint32_t)compoundNr]); + mCompounds[(uint32_t)compoundNr]->clear(); + //delete mCompounds[compoundNr]; + + mCompounds[(uint32_t)compoundNr] = compounds[0]; + + for (uint32_t i = 1; i < compounds.size(); i++) + mCompounds.pushBack(compounds[i]); + + ++mScene->mSceneVersion; + + + // playShatterSound(objectSize); + //if (fluidSim) + //fluidSim->mistPS->seedDustParticles((PxVec3*)&debugPoints[0], debugPoints.size(), seedDustRadius, seedDustNumPerSite, dustMinLife, dustMaxLife, 0.0f, 1.0f); + + uint32_t numConvexes = 0; + for (uint32_t i = 0; i < mCompounds.size(); i++) + numConvexes += mCompounds[i]->getConvexes().size(); + + //printf("\n------- pattern fracture------\n"); + //printf("i compounds, %i convexes after fracture\n", mCompounds.size(), numConvexes); + + return true; +} + +bool Actor::patternFracture(const PxVec3 &hitLocation, const PxVec3 &normal, const int &compoundNr, const PxMat33 patternTransform, float impactRadius, float radialImpulse, float directionalImpulse) +{ + float objectSize = 0.0f; + + mScene->debugPoints.clear(); + nvidia::Array<Compound*> compounds; + + mScene->profileBegin("patternFracture"); + bool OK = mCompounds[(uint32_t)compoundNr]->patternFracture(hitLocation, mMinConvexSize, + compounds, patternTransform, mScene->debugPoints, impactRadius, radialImpulse, normal * directionalImpulse); + mScene->profileEnd("patternFracture"); + if (!OK) + return false; + + if (compounds.empty()) + return false; + + if (mCompounds[(uint32_t)compoundNr]->getPxActor() == mScene->mPickActor) + mScene->mPickActor = NULL; + + PxBounds3 bounds; + mCompounds[(uint32_t)compoundNr]->getWorldBounds(bounds); + objectSize = bounds.getDimensions().magnitude(); + + //delCompoundList.push_back( mCompounds[compoundNr]); + mScene->delCompoundList.pushBack( mCompounds[(uint32_t)compoundNr]); + mCompounds[(uint32_t)compoundNr]->clear(); + //delete mCompounds[compoundNr]; + + mCompounds[(uint32_t)compoundNr] = compounds[0]; + + for (uint32_t i = 1; i < compounds.size(); i++) + mCompounds.pushBack(compounds[i]); + + ++mScene->mSceneVersion; + + + // playShatterSound(objectSize); + //if (fluidSim) + //fluidSim->mistPS->seedDustParticles((PxVec3*)&debugPoints[0], debugPoints.size(), seedDustRadius, seedDustNumPerSite, dustMinLife, dustMaxLife, 0.0f, 1.0f); + + uint32_t numConvexes = 0; + for (uint32_t i = 0; i < mCompounds.size(); i++) + numConvexes += mCompounds[i]->getConvexes().size(); + + //printf("\n------- pattern fracture------\n"); + //printf("i compounds, %i convexes after fracture\n", mCompounds.size(), numConvexes); + + return true; +} + +bool Actor::findCompound(const Compound* c, int& compoundNr) +{ + for(uint32_t i = 0; i < mCompounds.size(); i++) + { + if(mCompounds[i] == c) + { + compoundNr = (int32_t)i; + return true; + } + } + return false; +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/ActorBase.h b/APEX_1.4/module/destructible/fracture/Core/ActorBase.h new file mode 100644 index 00000000..38fc4843 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/ActorBase.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef ACTOR_BASE_H +#define ACTOR_BASE_H + +#include <PsArray.h> +#include <PsUserAllocated.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +class SimScene; +class Compound; + +class Actor : public UserAllocated +{ + friend class SimScene; + friend class Compound; +protected: + Actor(SimScene* scene); +public: + virtual ~Actor(); + + void clear(); + void addCompound(Compound *m); + void removeCompound(Compound *m); + + bool findCompound(const Compound* c, int& compoundNr); + + void preSim(float dt); + void postSim(float dt); + + bool rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &compoundNr, int &convexNr, PxVec3 &normal) const; + + // performs raycast + bool patternFracture(const PxVec3 &orig, const PxVec3 &dir, + const PxMat33 patternTransform, float impactRadius = 0.0f, float radialImpulse = 0.0f, float directionalImpulse = 0.0f); + + // take in raycast results + bool patternFracture(const PxVec3 &hitLocation, const PxVec3 &normal, const int &compoundNr, + const PxMat33 patternTransform, float impactRadius = 0.0f, float radialImpulse = 0.0f, float directionalImpulse = 0.0f); + + nvidia::Array<Compound*> getCompounds() { return mCompounds; } + +protected: + SimScene* mScene; + nvidia::Array<Compound*> mCompounds; + + float mMinConvexSize; + uint32_t mDepthLimit; + bool mDestroyIfAtDepthLimit; +}; + +} +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundBase.cpp b/APEX_1.4/module/destructible/fracture/Core/CompoundBase.cpp new file mode 100644 index 00000000..8e273564 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/CompoundBase.cpp @@ -0,0 +1,686 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "FracturePatternBase.h" +#include "MeshBase.h" +#include "CompoundGeometryBase.h" +#include "CompoundCreatorBase.h" +#include "PxConvexMeshGeometry.h" +#include "PxRigidBodyExt.h" +#include "PxMat44.h" +#include "PxScene.h" +#include "PxShape.h" + +#include "SimSceneBase.h" +#include "CompoundBase.h" +#include "ActorBase.h" +#include "ConvexBase.h" +#include "PsMathUtils.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace physx; + +//vector<PxVec3> tmpPoints; +void Compound::appendUniformSamplesOfConvexPolygon(PxVec3* vertices, int numV, float area, nvidia::Array<PxVec3>& samples, nvidia::Array<PxVec3>* normals) { + using namespace physx::shdfnd; + PxVec3& p0 = vertices[0]; + PxVec3 normal; + if (numV < 3) { + normal = PxVec3(0.0f,1.0f,0.0f); + } else { + normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]); + normal.normalize(); + } + for (int i = 1; i < numV-1; i++) { + PxVec3& p1 = vertices[i]; + PxVec3& p2 = vertices[i+1]; + float tarea = 0.5f*((p1-p0).cross(p2-p0)).magnitude(); + float aa = tarea / area; + int np = (int)physx::shdfnd::floor(aa); + + if (rand(0.0f,1.0f) <= aa-np) np++; + + for (int j = 0; j < np; j++) { + float r1 = rand(0.0f,1.0f); + float sr1 = PxSqrt(r1); + float r2 = rand(0.0f, 1.0f); + + PxVec3 p = (1 - sr1) * p0 + (sr1 * (1 - r2)) * p1 + (sr1 * r2) * p2; + samples.pushBack(p); + if (normals) normals->pushBack(normal); + + } + } +} + +// -------------------------------------------------------------------------------------------- +Compound::Compound(SimScene *scene, const FracturePattern *pattern, const FracturePattern *secondaryPattern, float contactOffset, float restOffset) +{ + mScene = scene; + mActor = NULL; + mPxActor = NULL; + mFracturePattern = pattern; + mSecondardFracturePattern = secondaryPattern; + mContactOffset = contactOffset; + mRestOffset = restOffset; + mLifeFrames = -1; // live forever + mDepth = 0; + clear(); +} + +// -------------------------------------------------------------------------------------------- +Compound::~Compound() +{ + clear(); +} + +// -------------------------------------------------------------------------------------------- +#define SHAPE_BUFFER_SIZE 100 + +void Compound::clear() +{ + if (mPxActor != NULL) { + // Unmap all shapes for this actor + const uint32_t shapeCount = mPxActor->getNbShapes(); + physx::PxShape* shapeBuffer[SHAPE_BUFFER_SIZE]; + for (uint32_t shapeStartIndex = 0; shapeStartIndex < shapeCount; shapeStartIndex += SHAPE_BUFFER_SIZE) + { + uint32_t shapesRead = mPxActor->getShapes(shapeBuffer, SHAPE_BUFFER_SIZE, shapeStartIndex); + for (uint32_t shapeBufferIndex = 0; shapeBufferIndex < shapesRead; ++shapeBufferIndex) + { + mScene->unmapShape(*shapeBuffer[shapeBufferIndex]); + } + } + // release the actor + mPxActor->release(); + mPxActor = NULL; + } + for (uint32_t i = 0; i < mConvexes.size(); i++) { + if (mConvexes[i]->decreaseRefCounter() <= 0) { + convexRemoved(mConvexes[i]); //mScene->getConvexRenderer().remove(mConvexes[i]); + PX_DELETE(mConvexes[i]); + } + } + + mConvexes.clear(); + mEdges.clear(); + + //mShader = NULL; + //mShaderMat.init(); + + mKinematicVel = PxVec3(0.0f, 0.0f, 0.0f); + mAttachmentBounds.clear(); + + mAdditionalImpactNormalImpulse = 0.0f; + mAdditionalImpactRadialImpulse = 0.0f; +} + +// -------------------------------------------------------------------------------------------- +void Compound::setKinematic(const PxVec3 &vel) +{ + if (mPxActor == NULL) + return; + + mPxActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true); + mKinematicVel = vel; +} + +// -------------------------------------------------------------------------------------------- +void Compound::step(float dt) +{ + //if (mPxActor == NULL) + // return; + + if (!mKinematicVel.isZero()) { + PxTransform pose = mPxActor->getGlobalPose(); + pose.p += mKinematicVel * dt; + mPxActor->setKinematicTarget(pose); + } + + if (mLifeFrames > 0) + mLifeFrames--; +} + +// -------------------------------------------------------------------------------------------- +bool Compound::createFromConvex(Convex* convex, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes) +{ + return createFromConvexes(&convex, 1, pose, vel, omega, copyConvexes); +} + +// -------------------------------------------------------------------------------------------- +bool Compound::createFromConvexes(Convex** convexes, int numConvexes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes) +{ + if (numConvexes == 0) + return false; + + clear(); + PxVec3 center(0.0f, 0.0f, 0.0f); + for (int i = 0; i < numConvexes; i++) + center += convexes[i]->getCenter(); + center /= (float)numConvexes; + + nvidia::Array<PxShape*> shapes; + + for (int i = 0; i < numConvexes; i++) { + Convex *c; + if (copyConvexes) { + c = mScene->createConvex(); + c->createFromConvex(convexes[i]); + } + else + c = convexes[i]; + + c->increaseRefCounter(); + mConvexes.pushBack(c); + + PxVec3 off = c->centerAtZero(); + c->setMaterialOffset(c->getMaterialOffset() + off); + c->setLocalPose(PxTransform(off - center)); + + if (convexes[i]->isGhostConvex()) + continue; + + bool reused = c->getPxConvexMesh() != NULL; + + mScene->profileBegin("cook convex meshes"); //Profiler::getInstance()->begin("cook convex meshes"); + PxConvexMesh* mesh = c->createPxConvexMesh(this, mScene->getPxPhysics(), mScene->getPxCooking()); + mScene->profileEnd("cook convex meshes"); //Profiler::getInstance()->end("cook convex meshes"); + + if (mesh == NULL) { + if (c->decreaseRefCounter() <= 0) + PX_DELETE(c); + mConvexes.popBack(); + continue; + } + + if (!c->hasExplicitVisMesh()) + c->createVisMeshFromConvex(); + + if (!reused) + convexAdded(c); //mScene->getConvexRenderer().add(c); + +#if (PX_PHYSICS_VERSION_MAJOR == 3) && (PX_PHYSICS_VERSION_MINOR < 3) + PxShape *shape = mScene->getPxPhysics()->createShape( + PxConvexMeshGeometry(mesh), + *mScene->getPxDefaultMaterial(), + true, + c->getLocalPose()); +#else + PxShape *shape = mScene->getPxPhysics()->createShape( + PxConvexMeshGeometry(mesh), + *mScene->getPxDefaultMaterial(), + true + ); + shape->setLocalPose(c->getLocalPose()); +#endif + + shape->setContactOffset(mContactOffset); + shape->setRestOffset(mRestOffset); + + mScene->mapShapeToConvex(*shape, *c); + + shapes.pushBack(shape); + } + + if (shapes.empty()) + { + return false; + } + + createPxActor(shapes, pose, vel, omega); + //if (!createPxActor(shapes, pose, vel, omega)) + /*int foo = 0*/; + + //createPointSamples(applyForcePointAreaPerSample); + + return true; +} + +// -------------------------------------------------------------------------------------------- +bool Compound::createFromGeometry(const CompoundGeometry &geom, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega) +{ + clear(); + + nvidia::Array<PxShape*> shapes; + + for (int i = 0; i < (int)geom.convexes.size(); i++) { + Convex *c = mScene->createConvex(); + c->createFromGeometry(geom, i); + c->increaseRefCounter(); + mConvexes.pushBack(c); + + PxVec3 off = c->centerAtZero(); + c->setMaterialOffset(c->getMaterialOffset() + off); + c->createVisMeshFromConvex(); + c->setLocalPose(PxTransform(off)); + + bool reused = c->getPxConvexMesh() != NULL; + + PxConvexMesh* mesh = c->createPxConvexMesh(this, mScene->getPxPhysics(), mScene->getPxCooking()); + if (mesh == NULL) { + if (c->decreaseRefCounter() <= 0) + PX_DELETE(c); + mConvexes.popBack(); + continue; + } + + if (!reused) + convexAdded(c); //mScene->getConvexRenderer().add(c); + +#if (PX_PHYSICS_VERSION_MAJOR == 3) && (PX_PHYSICS_VERSION_MINOR < 3) + PxShape *shape = mScene->getPxPhysics()->createShape( + PxConvexMeshGeometry(mesh), + *mScene->getPxDefaultMaterial(), + true, + c->getLocalPose()); +#else + PxShape *shape = mScene->getPxPhysics()->createShape( + PxConvexMeshGeometry(mesh), + *mScene->getPxDefaultMaterial(), + true + ); + shape->setLocalPose(c->getLocalPose()); +#endif + + shape->setContactOffset(mContactOffset); + shape->setRestOffset(mRestOffset); + + mScene->mapShapeToConvex(*shape, *c); + + shapes.pushBack(shape); + } + + if (shapes.empty()) + return false; + + createPxActor(shapes, pose, vel, omega); + return true; +} + +// -------------------------------------------------------------------------------------------- +void Compound::createFromMesh(const Mesh *mesh, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, int submeshNr, const PxVec3& scale) +{ + const nvidia::Array<PxVec3> &verts = mesh->getVertices(); + const nvidia::Array<PxVec3> &normals = mesh->getNormals(); + const nvidia::Array<PxVec2> &texcoords = mesh->getTexCoords(); + const nvidia::Array<uint32_t> &indices = mesh->getIndices(); + + if (verts.empty() || indices.empty()) + return; + + if (submeshNr >= 0 && submeshNr >= (int)mesh->getSubMeshes().size()) + return; + + PxBounds3 bounds; + mesh->getBounds(bounds, submeshNr); + PxMat33 scaleMat(PxMat33::createDiagonal(scale)); + bounds = PxBounds3::transformSafe(scaleMat, bounds); + + PxVec3 dims = bounds.getDimensions() * 1.01f; + PxVec3 center = bounds.getCenter(); + + mScene->getCompoundCreator()->createBox(dims); + createFromGeometry(mScene->getCompoundCreator()->getGeometry(), pose, vel, omega); + PxTransform trans(-center); + + if (submeshNr < 0) + mConvexes[0]->setExplicitVisMeshFromTriangles((int32_t)verts.size(), &verts[0], &normals[0], &texcoords[0], (int32_t)indices.size(), &indices[0], &trans, &scale); + else { + const Mesh::SubMesh &sm = mesh->getSubMeshes()[(uint32_t)submeshNr]; + mConvexes[0]->setExplicitVisMeshFromTriangles((int32_t)verts.size(), &verts[0], &normals[0], &texcoords[0], sm.numIndices, &indices[(uint32_t)sm.firstIndex], &trans, &scale); + } +} + +// -------------------------------------------------------------------------------------------- +bool Compound::createPxActor(nvidia::Array<PxShape*> &shapes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega) +{ + if (shapes.empty()) + return false; + + for(uint32_t i = 0; i < shapes.size(); i++) + { + applyShapeTemplate(shapes[i]); + } + + PxRigidDynamic* body = mScene->getPxPhysics()->createRigidDynamic(pose); + if (body == NULL) + return false; + + body->setSleepThreshold(getSleepingThresholdRB()); + + physx::PxActorFlags actorFlags = body->getActorFlags(); + actorFlags |= physx::PxActorFlag::eSEND_SLEEP_NOTIFIES; + body->setActorFlags(actorFlags); + + mScene->getScene()->addActor(*body); + + for (uint32_t i = 0; i < shapes.size(); i++) + body->attachShape(*shapes[i]); + + //KS - we clamp the mass in the range [minMass, maxMass]. This helps to improve stability + PxRigidBodyExt::updateMassAndInertia(*body, 1000.0f); +/* + const float maxMass = 50.f; + const float minMass = 1.f; + + float mass = PxMax(PxMin(maxMass, body->getMass()), minMass); + PxRigidBodyExt::setMassAndUpdateInertia(*body, mass); +*/ + + + body->setLinearVelocity(vel); + body->setAngularVelocity(omega); + + mPxActor = body; + for (uint32_t i = 0; i < mConvexes.size(); i++) + mConvexes[i]->setPxActor(mPxActor); + return true; +} + +// -------------------------------------------------------------------------------------------- +bool Compound::rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &convexNr, PxVec3 &normal) +{ + dist = PX_MAX_F32; + convexNr = -1; + + for (uint32_t i = 0; i < mConvexes.size(); i++) { + float d; + PxVec3 n; + if (mConvexes[i]->rayCast(orig, dir, d, n)) { + if (d < dist) { + dist = d; + convexNr = (int32_t)i; + normal = n; + } + } + } + return convexNr >= 0; +} + +// -------------------------------------------------------------------------------------------- +void Compound::getRestBounds(PxBounds3 &bounds) const +{ + bounds.setEmpty(); + PxBounds3 bi; + for (uint32_t i = 0; i < mConvexes.size(); i++) { + Convex *c = mConvexes[i]; + PxBounds3 bi = c->getBounds(); + bi = PxBounds3::transformSafe(c->getLocalPose(), bi); + bounds.include(bi); + } +} + +// -------------------------------------------------------------------------------------------- +void Compound::getWorldBounds(PxBounds3 &bounds) const +{ + bounds.setEmpty(); + PxBounds3 bi; + for (uint32_t i = 0; i < mConvexes.size(); i++) { + mConvexes[i]->getWorldBounds(bi); + bounds.include(bi); + } +} + +// -------------------------------------------------------------------------------------------- +void Compound::getLocalBounds(PxBounds3 &bounds) const +{ + bounds.setEmpty(); + PxBounds3 bi; + for (uint32_t i = 0; i < mConvexes.size(); i++) { + mConvexes[i]->getLocalBounds(bi); + bounds.include(bi); + } +} + +// -------------------------------------------------------------------------------------------- +bool Compound::isAttached() +{ + if (mAttachmentBounds.empty()) + return false; + + PxBounds3 b; + for (uint32_t i = 0; i < mConvexes.size(); i++) { + Convex *c = mConvexes[i]; + b = c->getBounds(); + b.minimum += c->getMaterialOffset(); + b.maximum += c->getMaterialOffset(); + for (uint32_t j = 0; j < mAttachmentBounds.size(); j++) { + if (b.intersects(mAttachmentBounds[j])) + return true; + } + } + return false; +} + +// -------------------------------------------------------------------------------------------- +bool Compound::patternFracture(const PxVec3 &pos, float minConvexSize, nvidia::Array<Compound*> &compounds, + const PxMat33 &patternTransform, nvidia::Array<PxVec3>& debugPoints, float impactRadius, + float radialImpulse, const PxVec3 &directedImpulse) +{ + if (mFracturePattern == NULL) + return false; + + if (mDepth >= mActor->mDepthLimit) + { + if (mActor->mDestroyIfAtDepthLimit) + { + mActor->removeCompound(this); + } + else + { + PxTransform pose = mPxActor->getGlobalPose(); + // additional impulse + PxVec3 imp(0.0f, 0.0f, 0.0f); + PxVec3 n = pose.p - pos; + n.normalize(); + imp += n * radialImpulse; + imp += directedImpulse; + // prevent small pieces from getting too fast + const float minMass = 1.0f; + float mass = getPxActor()->getMass(); + if (mass < minMass) + imp *= mass / minMass; + PxRigidBodyExt::addForceAtPos(*getPxActor(), imp, pos, PxForceMode::eIMPULSE); + } + return false; + } + + compounds.clear(); + + //Profiler *p = Profiler::getInstance(); + + PxVec3 hit = pos; + PxTransform pose = mPxActor->getGlobalPose(); + PxVec3 localHit = pose.transformInv(hit); + PxVec3 lv = mPxActor->getLinearVelocity(); + PxVec3 av = mPxActor->getAngularVelocity(); + +// localHit = -pose.t; // foo + + nvidia::Array<Convex*> newConvexes; + nvidia::Array<int> compoundSizes; + nvidia::Array<PxVec3>& crackNormals = mScene->getCrackNormals(); + crackNormals.clear(); + + mScene->profileBegin("getCompoundIntersection"); //Profiler::getInstance()->begin("getCompoundIntersection"); + mFracturePattern->getCompoundIntersection(this, PxMat44(patternTransform, localHit), impactRadius, minConvexSize, compoundSizes, newConvexes); + mScene->profileEnd("getCompoundIntersection"); //Profiler::getInstance()->end("getCompoundIntersection"); + + if (compoundSizes.empty()) + { + return false; + } + + int debugPointsStart = (int32_t)debugPoints.size(); + + uint32_t convexNr = 0; + for (uint32_t i = 0; i < compoundSizes.size(); i++) { + uint32_t num = (uint32_t)compoundSizes[i]; + + PxVec3 off(0.0f, 0.0f, 0.0f); + for (uint32_t j = 0; j < num; j++) { + off += newConvexes[convexNr+j]->getCenter(); + + //PxVec3 pp = pose.p + pose.rotate(newConvexes[convexNr+j]->getCenter()); + //debugPoints.push_back(pp); + } + off /= (float)num; + + addDust(newConvexes,debugPoints,(int32_t&)convexNr,(int32_t&)num); + + mScene->profileBegin("create new compounds"); //Profiler::getInstance()->begin("create new compounds"); + + Compound *m = mScene->createCompound(mSecondardFracturePattern ? mSecondardFracturePattern : mFracturePattern); + + m->mActor = mActor; + m->mDepth = mDepth+1; + m->mNormal = mNormal; + + PxVec3 v = lv + av.cross(pose.rotate(off)); + PxTransform posei = pose; + posei.p += pose.rotate(off); + + if (m->createFromConvexes(&newConvexes[convexNr], (int32_t)num, posei, v, av, false)) { + m->mAttachmentBounds = mAttachmentBounds; + if (m->isAttached()) + { + m->getPxActor()->setActorFlag(physx::PxActorFlag::eSEND_SLEEP_NOTIFIES, false); + m->getPxActor()->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true); + } + compounds.pushBack(m); + } + else + { + PX_DELETE(m); + return false; + } + + // decrement depth if outside fracture radius + if (impactRadius > 0.f) + { + const nvidia::Array<Convex*>& convexes = m->getConvexes(); + for (uint32_t i = 0; i < convexes.size(); i++) + { + if (convexes[i]->getIsFarConvex()) + { + m->mDepth--; + break; + } + } + } + + // additional impulse + PxVec3 imp(0.0f, 0.0f, 0.0f); + PxVec3 n = posei.p - hit; + n.normalize(); + imp += n * radialImpulse; + imp += directedImpulse; + + // prevent small pieces from getting too fast + const float minMass = 1.0f; + float mass = m->getPxActor()->getMass(); + if (mass < minMass) + imp *= mass / minMass; + + if (!m->isAttached()) + PxRigidBodyExt::addForceAtPos(*m->getPxActor(), imp, hit, PxForceMode::eIMPULSE); +// m->getPxActor()->addForce(imp / mass, PxForceMode::PxForceMode::eIMPULSE); + + copyShaders(m); + + mScene->profileEnd("create new compounds"); //Profiler::getInstance()->end("create new compounds"); + + convexNr += num; + } + + spawnParticles(crackNormals,debugPoints,debugPointsStart,radialImpulse); + + return true; +} + +// -------------------------------------------------------------------------------------------- +void Compound::attach(const nvidia::Array<PxBounds3> &bounds) +{ + mAttachmentBounds.resize(bounds.size()); + + PxTransform t = getPxActor()->getGlobalPose().getInverse(); + for (uint32_t i = 0; i < bounds.size(); i++) { + PxVec3 a = t.transform(bounds[i].minimum); + PxVec3 b = t.transform(bounds[i].maximum); + mAttachmentBounds[i].minimum = PxVec3(PxMin(a.x,b.x),PxMin(a.y,b.y),PxMin(a.z,b.z)); + mAttachmentBounds[i].maximum = PxVec3(PxMax(a.x,b.x),PxMax(a.y,b.y),PxMax(a.z,b.z)); + } + + if (isAttached()) + mPxActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true); +} + +// -------------------------------------------------------------------------------------------- +void Compound::attachLocal(const nvidia::Array<PxBounds3> &bounds) +{ + mAttachmentBounds.resize(bounds.size()); + + for (uint32_t i = 0; i < bounds.size(); i++) { + mAttachmentBounds[i] = bounds[i]; + } + + if (isAttached()) + mPxActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true); +} + +void Compound::createPointSamples(float area) { + + pointSamples.clear(); + for (uint32_t i = 0; i < mConvexes.size(); i++) { + Convex* c = mConvexes[i]; + const nvidia::Array<Convex::Face> &faces = c->getFaces(); + const nvidia::Array<int> &indices = c->getIndices(); + const nvidia::Array<PxVec3> &verts = c->getVertices(); + + + + for (uint32_t k = 0; k < faces.size(); k++) { + const Convex::Face& f = faces[k]; + /*int nv = f.numIndices;*/ + + /* + PxVec3 avg(0.0f); + for (int q = 0; q < f.numIndices; q++) { + avg += verts[indices[f.firstIndex+q]]; + } + avg /= f.numIndices; + pointSamples.pushBack(avg); + */ + nvidia::Array<PxVec3>& tmpPoints = mScene->getTmpPoints(); + tmpPoints.clear(); + for (int q = 0; q < f.numIndices; q++) { + tmpPoints.pushBack(verts[(uint32_t)indices[uint32_t(f.firstIndex+q)]]); + } + appendUniformSamplesOfConvexPolygon(&tmpPoints[0], (int32_t)tmpPoints.size(), area, pointSamples); + + } + + } +} + + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundBase.h b/APEX_1.4/module/destructible/fracture/Core/CompoundBase.h new file mode 100644 index 00000000..d21f2edc --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/CompoundBase.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef COMPOUNDBASE +#define COMPOUNDBASE + +#define DEMO_MODE 1 +#define TECHNICAL_MODE 0 + +#include <PxVec3.h> +#include <PxPlane.h> +#include <PxBounds3.h> +#include <PxTransform.h> +#include <PsArray.h> +#include <PxRigidDynamic.h> +#include <PsUserAllocated.h> + + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +class Convex; +class FracturePattern; +class Mesh; +class SimScene; +class CompoundGeometry; +class Actor; + +// ----------------------------------------------------------------------------------- +class Compound : public UserAllocated +{ + friend class SimScene; + friend class Actor; +protected: + Compound(SimScene* scene, const FracturePattern *pattern, const FracturePattern *secondaryPattern = NULL, float contactOffset = 0.005f, float restOffset = -0.001f); +public: + virtual ~Compound(); + + virtual bool createFromConvexes(Convex** convexes, int numConvexes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes = true); + bool createFromConvex(Convex* convex, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes = true); + bool createFromGeometry(const CompoundGeometry &geom, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega); + void createFromMesh(const Mesh *mesh, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, int submeshNr = -1, const PxVec3& scale = PxVec3(1.f)); + //bool createFromXml(XMLParser *p, float scale, const PxTransform &trans, bool ignoreVisualMesh = false); + + virtual void applyShapeTemplate(PxShape* /*shape*/) {} + + bool rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &convexNr, PxVec3 &normal); + void setLifeFrames(int frames) { mLifeFrames = frames == 0 ? 1 : frames; } + int getLifeFrames() { return mLifeFrames; } + + bool patternFracture(const PxVec3 &pos, float minConvexSize, nvidia::Array<Compound*> &compounds, + const PxMat33 &patternTransform, nvidia::Array<PxVec3>& debugPoints, float impactRadius, float radialImpulse, const PxVec3 &directedImpulse); + // impactRadius controls partial fracture. For impactRadius == 0.0f the fracture is global + + // event notification + virtual void spawnParticles(nvidia::Array<PxVec3>& /*crackNormals*/,nvidia::Array<PxVec3>& /*debugPoints*/,int /*debugPointsStart*/, float /*radialImpulse*/) {} + virtual void convexAdded(Convex* /*c*/) {} + virtual void convexRemoved(Convex* /*c*/) {} + + bool decompose(FracturePattern *pattern, nvidia::Array<Compound*> &compounds); + void attach(const nvidia::Array<PxBounds3> &bounds); + void attachLocal(const nvidia::Array<PxBounds3> &bounds); + + const nvidia::Array<Convex*>& getConvexes() const { return mConvexes; } + const nvidia::Array<PxBounds3>& getAttachmentBounds() const { return mAttachmentBounds; } + + PxRigidDynamic* getPxActor() { return mPxActor; } + void getWorldBounds(PxBounds3 &bounds) const; + void getLocalBounds(PxBounds3 &bounds) const; + void getRestBounds(PxBounds3 &bounds) const; + + //void setShader(Shader* shader, const ShaderMaterial &mat) { mShader = shader; mShaderMat = mat; } + //Shader* getShader() const { return mShader; } + //const ShaderMaterial& getShaderMat() { return mShaderMat; } + + void setKinematic(const PxVec3 &vel); + void step(float dt); + + virtual void draw(bool /*useShader*/, bool /*debug*/ = false) {} + + virtual void clear(); + + void setAdditionalImpactImpulse(float radial, float normal) { + mAdditionalImpactRadialImpulse = radial; mAdditionalImpactNormalImpulse = normal; + } + float getAdditionalImpactRadialImpulse() const { return mAdditionalImpactRadialImpulse; } + float getAdditionalImpactNormalImpulse() const { return mAdditionalImpactNormalImpulse; } + + virtual void copyShaders(Compound*) {} + +protected: + void createPointSamples(float area); + + bool isAttached(); + + bool createPxActor(nvidia::Array<PxShape*> &shapes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega); + + virtual void addDust(nvidia::Array<Convex*>& /*newConvexes*/,nvidia::Array<PxVec3>& /*debugPoints*/,int& /*convexNr*/,int& /*num*/) {} + + static void appendUniformSamplesOfConvexPolygon(PxVec3* vertices, int numV, float area, nvidia::Array<PxVec3>& samples, nvidia::Array<PxVec3>* normals = NULL); + + virtual float getSleepingThresholdRB() {return 0.1f;} + + struct Edge { + void init(int c0, int c1) { + this->c0 = c0; this->c1 = c1; + restLen = 0.0f; + deleted = false; + } + int c0, c1; + float restLen; + bool deleted; + }; + + nvidia::Array<Convex*> mConvexes; + nvidia::Array<Edge> mEdges; + + SimScene *mScene; + Actor *mActor; + PxRigidDynamic *mPxActor; + const FracturePattern *mFracturePattern; + const FracturePattern *mSecondardFracturePattern; + PxVec3 mKinematicVel; + nvidia::Array<PxBounds3> mAttachmentBounds; + + //Shader *mShader; + //ShaderMaterial mShaderMat; + + float mContactOffset; + float mRestOffset; + + int mLifeFrames; + + float mAdditionalImpactNormalImpulse; + float mAdditionalImpactRadialImpulse; + + nvidia::Array<PxVec3> pointSamples; + + uint32_t mDepth; // fracture depth + PxVec3 mNormal; // normal use with mSheetFracture +}; + +}}} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.cpp b/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.cpp new file mode 100644 index 00000000..d68df78f --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.cpp @@ -0,0 +1,805 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "CompoundCreatorBase.h" +#include <algorithm> +#include <PxAssert.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace nvidia; + +int CompoundCreator::tetFaceIds[4][3] = {{0,1,3},{1,2,3},{2,0,3},{0,2,1}}; +int CompoundCreator::tetEdgeVerts[6][2] = {{0,1},{1,2},{2,0},{0,3},{1,3},{2,3}}; +int CompoundCreator::tetFaceEdges[4][3] = {{0,4,3},{1,5,4},{2,3,5},{0,2,1}}; + +#define CONVEX_THRESHOLD (PxPi + 0.05f) + +// ----------------------------------------------------------------------------- +void CompoundCreator::createTorus(float r0, float r1, int numSegs0, int numSegs1, const PxTransform *trans) +{ + mGeom.clear(); + CompoundGeometry::Convex c; + PxVec3 nr0,nr1,nz; + nz = PxVec3(0.0f, 0.0f, 1.0f); + PxVec3 p,n; + PxTransform t = PxTransform(PxIdentity); + if (trans) + t = *trans; + + nvidia::Array<PxVec3> normals; + + float dphi0 = PxTwoPi / (float)numSegs0; + float dphi1 = PxTwoPi / (float)numSegs1; + for (int i = 0; i < numSegs0; i++) { + nr0 = PxVec3(PxCos(i*dphi0), PxSin(i*dphi0), 0.0f); + nr1 = PxVec3(PxCos((i+1)*dphi0), PxSin((i+1)*dphi0), 0.0f); + mGeom.initConvex(c); + c.numVerts = 2*numSegs1; + normals.clear(); + for (int j = 0; j < numSegs1; j++) { + p = nr0 * (r0 + r1 * PxCos(j*dphi1)) + nz * r1 * PxSin(j*dphi1); + mGeom.vertices.pushBack(t.transform(p)); + n = nr0 * (PxCos(j*dphi1)) + nz * PxSin(j*dphi1); + normals.pushBack(t.rotate(n)); + + p = nr1 * (r0 + r1 * PxCos(j*dphi1)) + nz * r1 * PxSin(j*dphi1); + mGeom.vertices.pushBack(t.transform(p)); + n = nr1 * (PxCos(j*dphi1)) + nz * PxSin(j*dphi1); + normals.pushBack(t.rotate(n)); + } + + c.numFaces = 2 + numSegs1; + mGeom.indices.pushBack(numSegs1); // face size + mGeom.indices.pushBack(CompoundGeometry::FF_INVISIBLE); // face flags + for (int j = 0; j < numSegs1; j++) + mGeom.indices.pushBack(2*j); + mGeom.indices.pushBack(numSegs1); // face size + mGeom.indices.pushBack(CompoundGeometry::FF_INVISIBLE); // face flags + for (int j = 0; j < numSegs1; j++) { + mGeom.indices.pushBack(2*(numSegs1-1-j) + 1); + } + for (int j = 0; j < numSegs1; j++) { + int k = (j+1)%numSegs1; + mGeom.indices.pushBack(4); // face size + mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE | CompoundGeometry::FF_HAS_NORMALS); + int i0 = 2*j; + int i1 = 2*j+1; + int i2 = 2*k+1; + int i3 = 2*k; + mGeom.indices.pushBack(i0); + mGeom.indices.pushBack(i1); + mGeom.indices.pushBack(i2); + mGeom.indices.pushBack(i3); + mGeom.normals.pushBack(normals[(uint32_t)i0]); + mGeom.normals.pushBack(normals[(uint32_t)i1]); + mGeom.normals.pushBack(normals[(uint32_t)i2]); + mGeom.normals.pushBack(normals[(uint32_t)i3]); + } + c.numNeighbors = 2; + mGeom.neighbors.pushBack((i + (numSegs0-1)) % numSegs0); + mGeom.neighbors.pushBack((i + 1) % numSegs0); + mGeom.convexes.pushBack(c); + } +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::createCylinder(float r, float h, int numSegs, const PxTransform *trans) +{ + PxTransform t = PxTransform(PxIdentity); + if (trans) + t = *trans; + + mGeom.clear(); + CompoundGeometry::Convex c; + mGeom.initConvex(c); + + float dphi = PxTwoPi / (float)numSegs; + c.numVerts = 2*numSegs; + mGeom.vertices.resize((uint32_t)c.numVerts); + + for (int i = 0; i < numSegs; i++) { + PxVec3 p0(r * PxCos(i*dphi), r * PxSin(i*dphi), -0.5f * h); + PxVec3 p1(r * PxCos(i*dphi), r * PxSin(i*dphi), 0.5f * h); + mGeom.vertices[2*(uint32_t)i] = t.transform(p0); + mGeom.vertices[2*(uint32_t)i+1] = t.transform(p1); + } + + c.numFaces = 2 + numSegs; + + mGeom.indices.pushBack(numSegs); + mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE); + for (int i = 0; i < numSegs; i++) + mGeom.indices.pushBack(2*(numSegs-1-i)); + mGeom.indices.pushBack(numSegs); + mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE); + for (int i = 0; i < numSegs; i++) + mGeom.indices.pushBack(2*i+1); + + for (int i = 0; i < numSegs; i++) { + int j = (i+1) % numSegs; + + PxVec3 n0(PxCos(i*dphi),PxSin(i*dphi),0.0f); + PxVec3 n1(PxCos(j*dphi),PxSin(j*dphi),0.0f); + + n0 = t.rotate(n0); + n1 = t.rotate(n1); + //n0*=-1; + //n1*=-1; + mGeom.indices.pushBack(4); + mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE | CompoundGeometry::FF_HAS_NORMALS); + mGeom.indices.pushBack(2*i); + mGeom.indices.pushBack(2*j); + mGeom.indices.pushBack(2*j+1); + mGeom.indices.pushBack(2*i+1); + mGeom.normals.pushBack(n0); + mGeom.normals.pushBack(n1); + mGeom.normals.pushBack(n1); + mGeom.normals.pushBack(n0); + } + mGeom.convexes.pushBack(c); +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::createBox(const PxVec3 &dims, const PxTransform *trans) +{ + PxTransform t = PxTransform(PxIdentity); + if (trans) + t = *trans; + + mGeom.clear(); + CompoundGeometry::Convex c; + mGeom.initConvex(c); + + c.numVerts = 8; + mGeom.vertices.clear(); + mGeom.vertices.pushBack(t.transform(PxVec3(-0.5f * dims.x, -0.5f * dims.y, -0.5f * dims.z))); + mGeom.vertices.pushBack(t.transform(PxVec3( 0.5f * dims.x, -0.5f * dims.y, -0.5f * dims.z))); + mGeom.vertices.pushBack(t.transform(PxVec3( 0.5f * dims.x, 0.5f * dims.y, -0.5f * dims.z))); + mGeom.vertices.pushBack(t.transform(PxVec3(-0.5f * dims.x, 0.5f * dims.y, -0.5f * dims.z))); + mGeom.vertices.pushBack(t.transform(PxVec3(-0.5f * dims.x, -0.5f * dims.y, 0.5f * dims.z))); + mGeom.vertices.pushBack(t.transform(PxVec3( 0.5f * dims.x, -0.5f * dims.y, 0.5f * dims.z))); + mGeom.vertices.pushBack(t.transform(PxVec3( 0.5f * dims.x, 0.5f * dims.y, 0.5f * dims.z))); + mGeom.vertices.pushBack(t.transform(PxVec3(-0.5f * dims.x, 0.5f * dims.y, 0.5f * dims.z))); + + static int faceIds[6][4] = {{0,1,5,4},{1,2,6,5},{2,3,7,6},{3,0,4,7},{0,3,2,1},{4,5,6,7}}; + + c.numFaces = 6; + for (int i = 0; i < 6; i++) { + mGeom.indices.pushBack(4); + mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE); + for (int j = 0; j < 4; j++) + mGeom.indices.pushBack(faceIds[i][j]); + } + mGeom.convexes.pushBack(c); +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::createSphere(const PxVec3 &dims, int resolution, const PxTransform *trans) +{ + PxTransform t = PxTransform(PxIdentity); + if (trans) + t = *trans; + + if (resolution < 2) resolution = 2; + int numSegs0 = 2*resolution; + int numSegs1 = resolution; + + float rx = 0.5f * dims.x; + float ry = 0.5f * dims.y; + float rz = 0.5f * dims.z; + + mGeom.clear(); + CompoundGeometry::Convex c; + mGeom.initConvex(c); + + float dphi = PxTwoPi / (float)numSegs0; + float dteta = PxPi / (float)numSegs1; + PxVec3 p, n; + + for (int i = 1; i < numSegs1; i++) { + for (int j = 0; j < numSegs0; j++) { + float phi = j * dphi; + float teta = -PxHalfPi + i * dteta; + p = PxVec3(PxCos(phi)*PxCos(teta), PxSin(phi)*PxCos(teta), PxSin(teta)); + mGeom.vertices.pushBack(PxVec3(p.x * rx, p.y * ry, p.z * rz)); + } + } + int bottomNr = (int32_t)mGeom.vertices.size(); + mGeom.vertices.pushBack(PxVec3(0.0f, 0.0f, -rz)); + int topNr = (int32_t)mGeom.vertices.size(); + mGeom.vertices.pushBack(PxVec3(0.0f, 0.0f, +rz)); + + c.numVerts = (int32_t)mGeom.vertices.size(); + + for (int i = 0; i < numSegs1-2; i++) { + for (int j = 0; j < numSegs0; j++) { + mGeom.indices.pushBack(4); // face size + mGeom.indices.pushBack(CompoundGeometry::FF_HAS_NORMALS | CompoundGeometry::FF_OBJECT_SURFACE); + int i0 = i*numSegs0 + j; + int i1 = i*numSegs0 + (j+1)%numSegs0; + int i2 = (i+1)*numSegs0 + (j+1)%numSegs0; + int i3 = (i+1)*numSegs0 + j; + mGeom.indices.pushBack(i0); + mGeom.indices.pushBack(i1); + mGeom.indices.pushBack(i2); + mGeom.indices.pushBack(i3); + n = mGeom.vertices[(uint32_t)i0]; n.normalize(); mGeom.normals.pushBack(n); + n = mGeom.vertices[(uint32_t)i1]; n.normalize(); mGeom.normals.pushBack(n); + n = mGeom.vertices[(uint32_t)i2]; n.normalize(); mGeom.normals.pushBack(n); + n = mGeom.vertices[(uint32_t)i3]; n.normalize(); mGeom.normals.pushBack(n); + c.numFaces++; + } + } + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < numSegs0; j++) { + mGeom.indices.pushBack(3); // face size + mGeom.indices.pushBack(CompoundGeometry::FF_HAS_NORMALS | CompoundGeometry::FF_OBJECT_SURFACE); + int i0,i1,i2; + if (i == 0) { + i0 = j; + i1 = bottomNr; + i2 = (j+1)%numSegs0; + } + else { + i0 = (numSegs1-2)*numSegs0 + j; + i1 = (numSegs1-2)*numSegs0 + (j+1)%numSegs0; + i2 = topNr; + } + mGeom.indices.pushBack(i0); + mGeom.indices.pushBack(i1); + mGeom.indices.pushBack(i2); + n = mGeom.vertices[(uint32_t)i0]; n.normalize(); mGeom.normals.pushBack(n); + n = mGeom.vertices[(uint32_t)i1]; n.normalize(); mGeom.normals.pushBack(n); + n = mGeom.vertices[(uint32_t)i2]; n.normalize(); mGeom.normals.pushBack(n); + c.numFaces++; + } + } + mGeom.convexes.pushBack(c); +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::fromTetraMesh(const nvidia::Array<PxVec3> &tetVerts, const nvidia::Array<int> &tetIndices) +{ + mTetVertices = tetVerts; + mTetIndices = tetIndices; + deleteColors(); + + computeTetNeighbors(); + computeTetEdges(); + colorTets(); + colorsToConvexes(); +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::computeTetNeighbors() +{ + uint32_t numTets = mTetIndices.size() / 4; + + struct TetFace { + void init(int i0, int i1, int i2, int faceNr, int tetNr) { + if (i0 > i1) { int i = i0; i0 = i1; i1 = i; } + if (i1 > i2) { int i = i1; i1 = i2; i2 = i; } + if (i0 > i1) { int i = i0; i0 = i1; i1 = i; } + this->i0 = i0; this->i1 = i1; this->i2 = i2; + this->faceNr = faceNr; this->tetNr = tetNr; + } + bool operator < (const TetFace &f) const { + if (i0 < f.i0) return true; + if (i0 > f.i0) return false; + if (i1 < f.i1) return true; + if (i1 > f.i1) return false; + return i2 < f.i2; + } + bool operator == (const TetFace &f) const { + return i0 == f.i0 && i1 == f.i1 && i2 == f.i2; + } + int i0,i1,i2; + int faceNr, tetNr; + }; + nvidia::Array<TetFace> faces(numTets * 4); + + for (uint32_t i = 0; i < numTets; i++) { + int ids[4]; + ids[0] = mTetIndices[4*i]; + ids[1] = mTetIndices[4*i+1]; + ids[2] = mTetIndices[4*i+2]; + ids[3] = mTetIndices[4*i+3]; + for (uint32_t j = 0; j < 4; j++) { + int i0 = ids[(uint32_t)tetFaceIds[j][0]]; + int i1 = ids[(uint32_t)tetFaceIds[j][1]]; + int i2 = ids[(uint32_t)tetFaceIds[j][2]]; + faces[4*i+j].init(i0,i1,i2, (int32_t)j, (int32_t)i); + } + } + std::sort(faces.begin(), faces.end()); + + mTetNeighbors.clear(); + mTetNeighbors.resize(numTets * 4, -1); + uint32_t i = 0; + while (i < faces.size()) { + TetFace &f0 = faces[i]; + i++; + if (i < faces.size() && faces[i] == f0) { + TetFace &f1 = faces[i]; + mTetNeighbors[uint32_t(4*f0.tetNr + f0.faceNr)] = f1.tetNr; + mTetNeighbors[uint32_t(4*f1.tetNr + f1.faceNr)] = f0.tetNr; + while (i < faces.size() && faces[i] == f0) + i++; + } + } +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::computeTetEdges() +{ + uint32_t numTets = mTetIndices.size() / 4; + + struct SortEdge { + void init(int i0, int i1, int edgeNr, int tetNr) { + if (i0 < i1) { this->i0 = i0; this->i1 = i1; } + else { this->i0 = i1; this->i1 = i0; } + this->edgeNr = edgeNr; this->tetNr = tetNr; + } + bool operator < (const SortEdge &e) const { + if (i0 < e.i0) return true; + if (i0 > e.i0) return false; + return i1 < e.i1; + } + bool operator == (const SortEdge &e) const { + return i0 == e.i0 && i1 == e.i1; + } + int i0,i1; + int edgeNr, tetNr; + }; + nvidia::Array<SortEdge> edges(numTets * 6); + + for (uint32_t i = 0; i < numTets; i++) { + int ids[4]; + ids[0] = mTetIndices[4*i]; + ids[1] = mTetIndices[4*i+1]; + ids[2] = mTetIndices[4*i+2]; + ids[3] = mTetIndices[4*i+3]; + for (uint32_t j = 0; j < 6; j++) { + int i0 = ids[(uint32_t)tetEdgeVerts[j][0]]; + int i1 = ids[(uint32_t)tetEdgeVerts[j][1]]; + edges[6*i + j].init(i0,i1, (int32_t)j, (int32_t)i); + } + } + std::sort(edges.begin(), edges.end()); + + mTetEdgeNrs.clear(); + mTetEdgeNrs.resize(numTets * 6, -1); + mTetEdges.clear(); + mEdgeTetNrs.clear(); + mEdgeTetAngles.clear(); + TetEdge te; + + struct ChainVert { + int adjVert0; + int adjVert1; + int tet0; + int tet1; + float dihed0; + float dihed1; + int mark; + }; + ChainVert cv; + cv.mark = 0; + nvidia::Array<ChainVert> chainVerts(mTetVertices.size(), cv); + nvidia::Array<int> chainVertNrs; + + int mark = 1; + + uint32_t i = 0; + while (i < edges.size()) { + SortEdge &e0 = edges[i]; + int edgeNr = (int32_t)mTetEdges.size(); + te.init(e0.i0, e0.i1); + te.firstTet = (int32_t)mEdgeTetNrs.size(); + te.numTets = 0; + mark++; + chainVertNrs.clear(); + do { + SortEdge &e = edges[i]; + mTetEdgeNrs[uint32_t(6 * e.tetNr + e.edgeNr)] = edgeNr; + int i2 = -1; + int i3 = -1; + for (uint32_t j = 0; j < 4; j++) { + int id = mTetIndices[4 * (uint32_t)e.tetNr + j]; + if (id != e0.i0 && id != e0.i1) { + if (i2 < 0) i2 = id; + else i3 = id; + } + } + PX_ASSERT(i2 >= 0 && i3 >= 0); + + // dihedral angle at edge + PxVec3 &p0 = mTetVertices[(uint32_t)e0.i0]; + PxVec3 &p1 = mTetVertices[(uint32_t)e0.i1]; + PxVec3 &p2 = mTetVertices[(uint32_t)i2]; + PxVec3 &p3 = mTetVertices[(uint32_t)i3]; + PxVec3 n2 = (p1-p0).cross(p2-p0); n2.normalize(); + if ((p3-p0).dot(n2) > 0.0f) n2 = -n2; + PxVec3 n3 = (p1-p0).cross(p3-p0); n3.normalize(); + if ((p2-p0).dot(n3) > 0.0f) n3 = -n3; + float dot = n2.dot(n3); + float dihed = PxPi - PxAcos(dot); + + // chain for ordering tets of edge correctly + ChainVert &cv2 = chainVerts[(uint32_t)i2]; + ChainVert &cv3 = chainVerts[(uint32_t)i3]; + if (cv2.mark != mark) { cv2.adjVert0 = -1; cv2.adjVert1 = -1; cv2.mark = mark; } + if (cv3.mark != mark) { cv3.adjVert0 = -1; cv3.adjVert1 = -1; cv3.mark = mark; } + + if (cv2.adjVert0 < 0) { cv2.adjVert0 = i3; cv2.tet0 = e.tetNr; cv2.dihed0 = dihed; } + else { cv2.adjVert1 = i3; cv2.tet1 = e.tetNr; cv2.dihed1 = dihed; } + if (cv3.adjVert0 < 0) { cv3.adjVert0 = i2; cv3.tet0 = e.tetNr; cv3.dihed0 = dihed; } + else { cv3.adjVert1 = i2; cv3.tet1 = e.tetNr; cv3.dihed1 = dihed; } + + chainVertNrs.pushBack(i2); + chainVertNrs.pushBack(i3); + i++; + } + while (i < edges.size() && edges[i] == e0); + + te.numTets = (int32_t)chainVertNrs.size() / 2; + // find chain start; + int startVertNr = -1; + for (uint32_t j = 0; j < chainVertNrs.size(); j++) { + ChainVert &cv = chainVerts[(uint32_t)chainVertNrs[j]]; + if (cv.adjVert0 < 0 || cv.adjVert1 < 0) { + startVertNr = chainVertNrs[j]; + break; + } + } + te.onSurface = startVertNr >= 0; + mTetEdges.pushBack(te); + + int curr = startVertNr; + if (curr < 0) curr = chainVertNrs[0]; + int prev = -1; + + // collect adjacent tetrahedra + for (int j = 0; j < te.numTets; j++) { + ChainVert &cv = chainVerts[(uint32_t)curr]; + int next; + if (cv.adjVert0 == prev) { + next = cv.adjVert1; + mEdgeTetNrs.pushBack(cv.tet1); + mEdgeTetAngles.pushBack(cv.dihed1); + } + else { + next = cv.adjVert0; + mEdgeTetNrs.pushBack(cv.tet0); + mEdgeTetAngles.pushBack(cv.dihed0); + } + prev = curr; + curr = next; + } + } +} + +// ----------------------------------------------------------------------------- +bool CompoundCreator::tetHasColor(int tetNr, int color) +{ + int nr = mTetFirstColor[(uint32_t)tetNr]; + while (nr >= 0) { + if (mTetColors[(uint32_t)nr].color == color) + return true; + nr = mTetColors[(uint32_t)nr].next; + } + return false; +} + +// ----------------------------------------------------------------------------- +bool CompoundCreator::tetAddColor(int tetNr, int color) +{ + if (tetHasColor(tetNr, color)) + return false; + Color c; + c.color = color; + c.next = mTetFirstColor[(uint32_t)tetNr]; + + if (mTetColorsFirstEmpty <= 0) { // new entry + mTetFirstColor[(uint32_t)tetNr] = (int32_t)mTetColors.size(); + mTetColors.pushBack(c); + } + else { // take from empty list + int newNr = mTetColorsFirstEmpty; + mTetFirstColor[(uint32_t)tetNr] = newNr; + mTetColorsFirstEmpty = mTetColors[(uint32_t)newNr].next; + mTetColors[(uint32_t)newNr] = c; + } + return true; +} + +// ----------------------------------------------------------------------------- +bool CompoundCreator::tetRemoveColor(int tetNr, int color) +{ + int nr = mTetFirstColor[(uint32_t)tetNr]; + int prev = -1; + while (nr >= 0) { + if (mTetColors[(uint32_t)nr].color == color) { + if (prev < 0) + mTetFirstColor[(uint32_t)tetNr] = mTetColors[(uint32_t)nr].next; + else + mTetColors[(uint32_t)prev].next = mTetColors[(uint32_t)nr].next; + + // add to empty list + mTetColors[(uint32_t)nr].next = mTetColorsFirstEmpty; + mTetColorsFirstEmpty = nr; + return true; + } + prev = nr; + nr = mTetColors[(uint32_t)nr].next; + } + return false; +} + +// ----------------------------------------------------------------------------- +int CompoundCreator::tetNumColors(int tetNr) +{ + int num = 0; + int nr = mTetFirstColor[(uint32_t)tetNr]; + while (nr >= 0) { + num++; + nr = mTetColors[(uint32_t)nr].next; + } + return num; +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::deleteColors() +{ + mTetFirstColor.resize(mTetIndices.size()/4, -1); + mTetColors.clear(); + mTetColorsFirstEmpty = -1; +} + +// ----------------------------------------------------------------------------- +bool CompoundCreator::tryTet(int tetNr, int color) +{ + if (tetNr < 0) + return false; + + //if (mTetColors[tetNr] >= 0) + // return false; + + if (tetHasColor(tetNr, color)) + return false; + + mTestEdges.clear(); + mAddedTets.clear(); + + tetAddColor(tetNr, color); + mAddedTets.pushBack(tetNr); + + for (int i = 0; i < 6; i++) + mTestEdges.pushBack(mTetEdgeNrs[uint32_t(6*tetNr+i)]); + + bool failed = false; + + while (mTestEdges.size() > 0) { + int edgeNr = mTestEdges[mTestEdges.size()-1]; + mTestEdges.popBack(); + + TetEdge &e = mTetEdges[(uint32_t)edgeNr]; + bool anyOtherCol = false; + float sumAng = 0.0f; + for (int i = 0; i < e.numTets; i++) { + int edgeTetNr = mEdgeTetNrs[uint32_t(e.firstTet + i)]; + if (tetHasColor(edgeTetNr, color)) + sumAng += mEdgeTetAngles[uint32_t(e.firstTet + i)]; + else if (tetNumColors(edgeTetNr) > 0) + anyOtherCol = true; + } + if (sumAng < CONVEX_THRESHOLD) + continue; + +// if (e.onSurface || anyOtherCol) { + if (e.onSurface) { + failed = true; + break; + } + + for (int i = 0; i < e.numTets; i++) { + int edgeTetNr = mEdgeTetNrs[uint32_t(e.firstTet + i)]; + if (!tetHasColor(edgeTetNr, color)) { + tetAddColor(edgeTetNr, color); + mAddedTets.pushBack(edgeTetNr); + for (int j = 0; j < 6; j++) + mTestEdges.pushBack(mTetEdgeNrs[uint32_t(6*edgeTetNr+j)]); + } + } + } + if (failed) { + for (uint32_t i = 0; i < mAddedTets.size(); i++) + tetRemoveColor(mAddedTets[i], color); + mAddedTets.clear(); + return false; + } + + return true; +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::colorTets() +{ + int numTets = (int32_t)mTetIndices.size() / 4; + deleteColors(); + + int color = 0; + nvidia::Array<int> edges; + nvidia::Array<int> faces; + + for (int i = 0; i < numTets; i++) { + if (tetNumColors(i) > 0) + continue; + + tetAddColor(i, color); + faces.clear(); + faces.pushBack(4*i); + faces.pushBack(4*i+1); + faces.pushBack(4*i+2); + faces.pushBack(4*i+3); + + while (faces.size() > 0) { + int faceNr = faces[faces.size()-1]; + faces.popBack(); + + int adjTetNr = mTetNeighbors[(uint32_t)faceNr]; + + if (adjTetNr < 0) + continue; + + //if (tetNumColors(adjTetNr) > 0) + // continue; + + if (!tryTet(adjTetNr, color)) + continue; + + for (uint32_t j = 0; j < mAddedTets.size(); j++) { + int addedTet = mAddedTets[j]; + for (int k = 0; k < 4; k++) { + int adj = mTetNeighbors[uint32_t(4*addedTet+k)]; + if (adj >= 0 && !tetHasColor(adj, color)) + faces.pushBack(4*addedTet+k); + } + } + } + color++; + } +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::colorsToConvexes() +{ + mGeom.clear(); + + int numTets = (int32_t)mTetIndices.size() / 4; + int numColors = 0; + for (uint32_t i = 0; i < mTetColors.size(); i++) { + int color = mTetColors[i].color; + if (color >= numColors) + numColors = color+1; + } + + nvidia::Array<bool> colorVisited((uint32_t)numColors, false); + nvidia::Array<int> queue; + nvidia::Array<int> globalToLocal(mTetVertices.size(), -1); + + nvidia::Array<int> tetMarks((uint32_t)numTets, 0); + nvidia::Array<int> vertMarks(mTetVertices.size(), 0); + int mark = 1; + + nvidia::Array<int> colorToConvexNr; + + CompoundGeometry::Convex c; + + for (uint32_t i = 0; i < (uint32_t)numTets; i++) { + int nr = mTetFirstColor[i]; + while (nr >= 0) { + uint32_t color = (uint32_t)mTetColors[(uint32_t)nr].color; + nr = mTetColors[(uint32_t)nr].next; + + if (colorVisited[color]) + continue; + colorVisited[color] = true; + + if ((uint32_t)colorToConvexNr.size() <= color) + colorToConvexNr.resize(color+1, -1); + colorToConvexNr[color] = (int32_t)mGeom.convexes.size(); + + queue.clear(); + queue.pushBack((int32_t)i); + + mGeom.initConvex(c); + mark++; + c.numVerts = 0; + + // flood fill + while (!queue.empty()) { + uint32_t tetNr = (uint32_t)queue[queue.size()-1]; + queue.popBack(); + if (tetMarks[tetNr] == mark) + continue; + tetMarks[tetNr] = mark; + + for (uint32_t j = 0; j < 4; j++) { + int adjNr = mTetNeighbors[4*tetNr + j]; + if (adjNr < 0 || !tetHasColor(adjNr, (int32_t)color)) { + // create new face + mGeom.indices.pushBack(3); // face size + int flags = 0; + if (adjNr < 0) flags |= CompoundGeometry::FF_OBJECT_SURFACE; + mGeom.indices.pushBack(flags); + + for (uint32_t k = 0; k < 3; k++) { + uint32_t id = (uint32_t)mTetIndices[4*tetNr + tetFaceIds[j][k]]; + if (vertMarks[id] != mark) { + vertMarks[id] = mark; + globalToLocal[id] = c.numVerts; + c.numVerts++; + mGeom.vertices.pushBack(mTetVertices[id]); + } + mGeom.indices.pushBack(globalToLocal[id]); + } + c.numFaces++; + } + if (adjNr >= 0) { + // add neighbors + int colNr = mTetFirstColor[(uint32_t)adjNr]; + while (colNr >= 0) { + int adjColor = mTetColors[(uint32_t)colNr].color; + colNr = mTetColors[(uint32_t)colNr].next; + if (adjColor != (int32_t)color) { + bool isNew = true; + for (int k = 0; k < c.numNeighbors; k++) { + if (mGeom.neighbors[uint32_t(c.firstNeighbor+k)] == adjColor) { + isNew = false; + break; + } + } + if (isNew) { + mGeom.neighbors.pushBack(adjColor); + c.numNeighbors++; + } + } + } + } + if (adjNr < 0 || !tetHasColor(adjNr, (int32_t)color) || tetMarks[(uint32_t)adjNr] == mark) + continue; + queue.pushBack(adjNr); + } + } + mGeom.convexes.pushBack(c); + } + } + + for (uint32_t i = 0; i < mGeom.neighbors.size(); i++) { + if (mGeom.neighbors[i] >= 0) + mGeom.neighbors[i] = colorToConvexNr[(uint32_t)mGeom.neighbors[i]]; + } +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.h b/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.h new file mode 100644 index 00000000..0805fc67 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef COMPOUND_CREATOR_BASE_H +#define COMPOUND_CREATOR_BASE_H + +// Matthias Muller-Fischer + +#include <PxVec3.h> +#include <PxTransform.h> +#include <PsArray.h> +#include <PsUserAllocated.h> + +#include "CompoundGeometryBase.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + class SimScene; + +// --------------------------------------------------------------------------------------- +class CompoundCreator : public UserAllocated { + friend class nvidia::fracture::base::SimScene; +public: + // direct + void createTorus(float r0, float r1, int numSegs0, int numSegs1, const PxTransform *trans = NULL); + void createCylinder(float r, float h, int numSegs, const PxTransform *trans = NULL); + void createBox(const PxVec3 &dims, const PxTransform *trans = NULL); + void createSphere(const PxVec3 &dims, int resolution = 5, const PxTransform *trans = NULL); + void fromTetraMesh(const nvidia::Array<PxVec3> &tetVerts, const nvidia::Array<int> &tetIndices); + + const CompoundGeometry &getGeometry() { return mGeom; } + + virtual void debugDraw() {} + +protected: + CompoundCreator(SimScene* scene): mScene(scene) {} + virtual ~CompoundCreator() {} + + SimScene* mScene; + + static int tetFaceIds[4][3]; + static int tetEdgeVerts[6][2]; + static int tetFaceEdges[4][3]; + + void computeTetNeighbors(); + void computeTetEdges(); + void colorTets(); + void colorsToConvexes(); + + bool tetHasColor(int tetNr, int color); + bool tetAddColor(int tetNr, int color); + bool tetRemoveColor(int tetNr, int color); + int tetNumColors(int tetNr); + void deleteColors(); + + bool tryTet(int tetNr, int color); + + // from tet mesh + nvidia::Array<PxVec3> mTetVertices; + nvidia::Array<int> mTetIndices; + nvidia::Array<int> mTetNeighbors; + + nvidia::Array<int> mTetFirstColor; + struct Color { + int color; + int next; + }; + int mTetColorsFirstEmpty; + nvidia::Array<Color> mTetColors; + + struct TetEdge { + void init(int i0, int i1) { this->i0 = i0; this->i1 = i1; firstTet = 0; numTets = 0; onSurface = false; } + int i0, i1; + int firstTet, numTets; + bool onSurface; + }; + nvidia::Array<TetEdge> mTetEdges; + nvidia::Array<int> mTetEdgeNrs; + nvidia::Array<int> mEdgeTetNrs; + nvidia::Array<float> mEdgeTetAngles; + + nvidia::Array<int> mAddedTets; + nvidia::Array<int> mTestEdges; + + // input + nvidia::Array<PxVec3> mVertices; + nvidia::Array<int> mIndices; + + // output + CompoundGeometry mGeom; +}; + +}}} + +#endif +#endif diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.cpp b/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.cpp new file mode 100644 index 00000000..014a37bb --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "CompoundGeometryBase.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +// ------------------------------------------------------------------------------- +void CompoundGeometry::clear() +{ + convexes.clear(); + vertices.clear();; + normals.clear(); + indices.clear(); + neighbors.clear(); + planes.clear(); +} + +// ------------------------------------------------------------------------------- +bool CompoundGeometry::loadFromFile(const char * /*filename*/) +{ + return true; +} + +// ------------------------------------------------------------------------------- +bool CompoundGeometry::saveFromFile(const char * /*filename*/) +{ + return true; +} + +// ------------------------------------------------------------------------------- +void CompoundGeometry::initConvex(Convex &c) +{ + c.firstVert = (int32_t)vertices.size(); + c.numVerts = 0; + c.firstNormal = (int32_t)normals.size(); + c.firstIndex = (int32_t)indices.size(); + c.numFaces = 0; + c.firstPlane = 0; + c.firstNeighbor = (int32_t)neighbors.size(); + c.numNeighbors = 0; +} + +// ------------------------------------------------------------------------------- +void CompoundGeometry::derivePlanes() +{ + planes.clear(); + PxPlane p; + + for (uint32_t i = 0; i < convexes.size(); i++) { + Convex &c = convexes[i]; + c.firstPlane = (int32_t)planes.size(); + int *ids = &indices[(uint32_t)c.firstIndex]; + PxVec3 *verts = &vertices[(uint32_t)c.firstVert]; + for (int j = 0; j < c.numFaces; j++) { + int num = *ids++; + ids++; //int flags = *ids++; + if (num < 3) + p = PxPlane(1.0f, 0.0f, 0.0f, 0.0f); + else { + p.n = PxVec3(0.0f, 0.0f, 0.0f); + for (int k = 1; k < num-1; k++) { + const PxVec3 &p0 = verts[ids[0]]; + const PxVec3 &p1 = verts[ids[k]]; + const PxVec3 &p2 = verts[ids[k+1]]; + p.n += (p1-p0).cross(p2-p1); + } + p.n.normalize(); + p.d = p.n.dot(verts[ids[0]]); + } + planes.pushBack(p); + ids += num; + } + } +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.h b/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.h new file mode 100644 index 00000000..30452676 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef COMPOUND_GEOMETRY_BASE +#define COMPOUND_GEOMETRY_BASE + +#include <PxVec3.h> +#include <PxPlane.h> +#include <PsArray.h> +#include <PsUserAllocated.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +// ----------------------------------------------------------------------------------- +class CompoundGeometry : public UserAllocated +{ +public: + CompoundGeometry() {} + virtual ~CompoundGeometry() {} + bool loadFromFile(const char *filename); + bool saveFromFile(const char *filename); + void clear(); + void derivePlanes(); + + virtual void debugDraw(int /*maxConvexes*/ = 0) const {} + + struct Convex { // init using CompoundGeometry::initConvex() + int firstVert; + int numVerts; + int firstNormal; // one per face index! If not provided (see face flags) face normal is used + int firstIndex; + int numFaces; + int firstPlane; + int firstNeighbor; + int numNeighbors; + }; + + void initConvex(Convex &c); + + nvidia::Array<Convex> convexes; + nvidia::Array<PxVec3> vertices; + nvidia::Array<PxVec3> normals; // one per face and vertex! + // face size, face flags, id, id, .., face size, face flags, id .. + nvidia::Array<int> indices; + nvidia::Array<int> neighbors; + + nvidia::Array<PxPlane> planes; // derived for faster cuts + + enum FaceFlags { + FF_OBJECT_SURFACE = 1, + FF_HAS_NORMALS = 2, + FF_INVISIBLE = 4, + FF_NEW = 8, + }; +}; + +} +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/ConvexBase.cpp b/APEX_1.4/module/destructible/fracture/Core/ConvexBase.cpp new file mode 100644 index 00000000..35906cc7 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/ConvexBase.cpp @@ -0,0 +1,1371 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "PxPhysics.h" +#include "PxCooking.h" +#include "PxDefaultStreams.h" +#include "PxShape.h" +#include "PxMath.h" +#include "PxRigidDynamic.h" +#include "PxConvexMesh.h" +#include "PxMat44.h" +#include "PsMathUtils.h" +#include "PxVec2.h" + +#include "CompoundGeometryBase.h" +#include "SimSceneBase.h" +#include "PolygonTriangulatorBase.h" +#include "MeshClipperBase.h" + +#include "ConvexBase.h" + +#define COOK_TRIANGLES 0 + +#include <algorithm> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace physx; + +// -------------------------------------------------------------------------------------------- +Convex::Convex(SimScene* scene) +{ + mScene = scene; + mPxConvexMesh = NULL; + mPxActor = NULL; + mLocalPose = PxTransform(PxIdentity); + mParent = NULL; + mNewConvex = NULL; + mRefCounter = 0; + mIsFarConvex = false; + clear(); +} + +// -------------------------------------------------------------------------------------------- +Convex::~Convex() +{ + clear(); + if (mNewConvex != NULL) + PX_DELETE(mNewConvex); +} + +// -------------------------------------------------------------------------------------------- +void Convex::clear() +{ + mFaces.clear(); + mIndices.clear(); + mVertices.clear(); + mNormals.clear(); + mPlanes.clear(); + + mVisVertices.clear(); + mVisNormals.clear(); + mVisTangents.clear(); + mVisTexCoords.clear(); + mVisTriIndices.clear(); + + mHasExplicitVisMesh = false; + mIsGhostConvex = false; + mVisPolyStarts.clear(); + mVisPolyIndices.clear(); + mVisPolyNeighbors.clear(); + + if (mPxConvexMesh != NULL) + mPxConvexMesh->release(); + + mPxConvexMesh = NULL; + mPxActor = NULL; + mLocalPose = PxTransform(PxIdentity); + + mBounds.setEmpty(); + mMaterialOffset = PxVec3(0.0f, 0.0f, 0.0f); + mTexScale = 1.0f; + + mUse2dTexture = false; + mIndestructible = false; + mMaterialId = 0; + mSurfaceMaterialId = 0; + mModelIslandNr = 0; + + mVolume = 0.0f; + mVolumeDirty = true; +} + +// -------------------------------------------------------------------------------------------- +void Convex::createFromConvex(const Convex *convex, const PxTransform *trans) +{ + clear(); + mVertices = convex->mVertices; + mFaces = convex->mFaces; + clearFraceFlags(CompoundGeometry::FF_NEW); + + mIndices = convex->mIndices; + mNormals = convex->mNormals; + mMaterialOffset = convex->mMaterialOffset; + mTexScale = convex->mTexScale; + mIsGhostConvex = convex->mIsGhostConvex; + mLocalPose = convex->mLocalPose; + + if (trans != NULL) { + for (uint32_t i = 0; i < mVertices.size(); i++) + mVertices[i] = trans->transform(mVertices[i]); + for (uint32_t i = 0; i < mNormals.size(); i++) + mNormals[i] = trans->rotate(mNormals[i]); + mMaterialOffset -= trans->p; + } + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void Convex::transform(const PxMat44 &trans) +{ + for (uint32_t i = 0; i < mVertices.size(); i++) + mVertices[i] = trans.transform(mVertices[i]); + for (uint32_t i = 0; i < mNormals.size(); i++) + mNormals[i] = trans.rotate(mNormals[i]); + mMaterialOffset -= trans.getPosition(); + + if (mHasExplicitVisMesh) { + for (uint32_t i = 0; i < mVisVertices.size(); i++) + mVisVertices[i] = trans.transform(mVisVertices[i]); + for (uint32_t i = 0; i < mVisNormals.size(); i++) + mVisNormals[i] = trans.rotate(mVisNormals[i]); + } + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void Convex::createFromGeometry(const CompoundGeometry &geom, int convexNr, const PxMat44 *trans) +{ + clear(); + const CompoundGeometry::Convex &c = geom.convexes[(uint32_t)convexNr]; + + PxMat44 t = PxMat44(PxIdentity); + + if (trans) + t = *trans; + + mVertices.resize((uint32_t)c.numVerts); + for (int i = 0; i < c.numVerts; i++) + mVertices[(uint32_t)i] = t.transform(geom.vertices[uint32_t(c.firstVert + i)]); + + mFaces.resize((uint32_t)c.numFaces); + int num = 0; + const int *id = &geom.indices[(uint32_t)c.firstIndex]; + const PxVec3 *normals = (geom.normals.size() > 0) ? &geom.normals[(uint32_t)c.firstNormal] : NULL; + + for (uint32_t i = 0; i < (uint32_t)c.numFaces; i++) { + Face &f = mFaces[i]; + f.init(); + f.firstIndex = num; + f.numIndices = *id++; + f.flags = *id++; + for (int j = 0; j < f.numIndices; j++) + mIndices.pushBack(*id++); + if (f.flags & CompoundGeometry::FF_HAS_NORMALS) { + f.firstNormal = (int32_t)mNormals.size(); + for (int j = 0; j < f.numIndices; j++) { + mNormals.pushBack(t.rotate(*normals)); + normals++; + } + } + num += f.numIndices; + } + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void Convex::setPxActor(PxRigidActor *actor) +{ + mPxActor = actor; +} + +// -------------------------------------------------------------------------------------------- +void Convex::setLocalPose(const PxTransform &pose) +{ + mLocalPose = pose; +} + +// -------------------------------------------------------------------------------------------- +PxVec3 Convex::getCenter() const +{ + PxVec3 center(0.0f, 0.0f, 0.0f); + + if (mVertices.empty()) + return center; + + uint32_t numVerts = mVertices.size(); + for (uint32_t i = 0; i < numVerts; i++) + center += mVertices[i]; + center /= (float)numVerts; + + return center; +} + +// -------------------------------------------------------------------------------------------- +PxVec3 Convex::centerAtZero() +{ + PxVec3 center = getCenter(); + for (uint32_t i = 0; i < mVertices.size(); i++) + mVertices[i] -= center; + finalize(); + return center; +} + +// -------------------------------------------------------------------------------------------- +PxTransform Convex::getGlobalPose() const +{ + if (mPxActor == NULL) + return mLocalPose; + else + return mPxActor->getGlobalPose() * mLocalPose; +} + +// -------------------------------------------------------------------------------------------- +PxTransform Convex::getLocalPose() const +{ + return mLocalPose; +} + +// -------------------------------------------------------------------------------------------- +bool Convex::rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, PxVec3 &normal) const +{ + PxVec3 o,d; + PxTransform pose = getGlobalPose(); + d = pose.rotateInv(dir); + o = pose.transformInv(orig); + + if (mHasExplicitVisMesh) + return rayCastVisMesh(o,d, dist, normal); + else + return rayCastConvex(o,d, dist, normal); +} + +// -------------------------------------------------------------------------------------------- +bool Convex::rayCastConvex(const PxVec3 &orig, const PxVec3 &dir, float &dist, PxVec3 &normal) const +{ + float maxEntry = -PX_MAX_F32; + float minExit = PX_MAX_F32; + normal = PxVec3(0.0f, 1.0f, 0.0f); + + for (uint32_t i = 0; i < mPlanes.size(); i++) { + const PxPlane &plane = mPlanes[i]; + float dot = plane.n.dot(dir); + if (dot == 0.0f) + continue; + + float t = (plane.d - orig.dot(plane.n)) / dot; + if (dot < 0.0f) { + if (t > maxEntry) { + maxEntry = t; + normal = plane.n; + } + } + else { + minExit = PxMin(minExit, t); + } + } + + if (maxEntry > minExit) { + dist = PX_MAX_F32; + return false; + } + + dist = maxEntry; + normal.normalize(); + return dist >= 0.0f; +} + +// -------------------------------------------------------------------------------------------- +bool Convex::rayCastVisMesh(const PxVec3 &orig, const PxVec3 &dir, float &dist, PxVec3 &normal) const +{ + normal = PxVec3(0.0f, 1.0f, 0.0f); + dist = PX_MAX_F32; + int minTri = -1; + + for (uint32_t i = 0; i < mVisTriIndices.size(); i += 3) { + const PxVec3 &p0 = mVisVertices[(uint32_t)mVisTriIndices[i]]; + const PxVec3 &p1 = mVisVertices[(uint32_t)mVisTriIndices[i+1]]; + const PxVec3 &p2 = mVisVertices[(uint32_t)mVisTriIndices[i+2]]; + PxVec3 n = (p1-p0).cross(p2-p0); + float t = dir.dot(n); + if (t >= 0.0f) + continue; + t = n.dot(p0 - orig) / t; + if (t < 0.0f) + continue; + + // hit inside triangle? + PxVec3 hit = orig + t * dir; + float b2 = (p1-p0).cross(hit-p0).dot(n); + float b0 = (p2-p1).cross(hit-p1).dot(n); + float b1 = (p0-p2).cross(hit-p2).dot(n); + if (b0 < 0.0f || b1 < 0.0f || b2 < 0.0f) + continue; + + float d = (orig - hit).magnitude(); + + if (d < dist) { + dist = d; + minTri = (int32_t)i / 3; + normal = n; + } + } + normal.normalize(); + return minTri >= 0; +} + +// -------------------------------------------------------------------------------------------- +bool Convex::collide(const PxVec3 &pos, float r, float &penetration, PxVec3 &surfaceNormal, PxVec3 &surfaceVel) const +{ + PxVec3 p = getGlobalPose().transformInv(pos); + + float minDist = PX_MAX_F32; + int minPlane = -1; + + for (uint32_t i = 0; i < mPlanes.size(); i++) { + const PxPlane &plane = mPlanes[i]; + float dist = plane.d - p.dot(plane.n) + r; + if (dist < 0.0f) + return false; + if (dist < minDist) { + minDist = dist; + minPlane = (int32_t)i; + } + } + + if (minPlane < 0) + return false; + else { + PxPlane plane = mPlanes[(uint32_t)minPlane]; + surfaceNormal = plane.n; + penetration = minDist; + surfaceVel = PxVec3(0.0f, 0.0f, 0.0f); + + if (mPxActor != NULL) { + PxRigidDynamic *actor = mPxActor->is<physx::PxRigidDynamic>(); + if (actor != NULL) { + surfaceNormal = getGlobalPose().rotate(surfaceNormal); + surfaceVel = actor->getLinearVelocity() + actor->getAngularVelocity().cross(surfaceNormal * plane.d); + } + } + return true; + } +} + +// -------------------------------------------------------------------------------------------- +void Convex::finalize() +{ + updateBounds(); + updatePlanes(); +} + +// -------------------------------------------------------------------------------------------- +void Convex::updateBounds() +{ + mBounds.setEmpty(); + for (uint32_t i = 0; i < mVertices.size(); i++) + mBounds.include(mVertices[i]); +} + +// -------------------------------------------------------------------------------------------- +void Convex::updatePlanes() +{ + uint32_t numFaces = mFaces.size(); + mPlanes.resize(numFaces); + + for (uint32_t i = 0; i < numFaces; i++) { + Face &f = mFaces[i]; + if (f.numIndices < 3) { // should not happen + mPlanes[i].n = PxVec3(0.0f, 1.0f, 0.0f); + mPlanes[i].d = 0.0f; + continue; + } + PxVec3 n(0.0f, 0.0f, 0.0f); + PxVec3 &p0 = mVertices[(uint32_t)mIndices[(uint32_t)f.firstIndex]]; + for (int j = 1; j < f.numIndices-1; j++) { + PxVec3 &p1 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j)]]; + PxVec3 &p2 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j+1)]]; + n += (p1-p0).cross(p2-p0); + } + n.normalize(); + mPlanes[i].n = n; + mPlanes[i].d = mPlanes[i].n.dot(p0); + } +} + +// -------------------------------------------------------------------------------------------- +void Convex::getWorldBounds(PxBounds3 &bounds) const +{ + bounds = PxBounds3::transformSafe(getGlobalPose(), mBounds); +} + +// -------------------------------------------------------------------------------------------- +void Convex::getLocalBounds(PxBounds3 &bounds) const +{ + bounds = mBounds; +} + +// -------------------------------------------------------------------------------------------- +void Convex::intersectWithConvex(const PxPlane *planes, int numPlanes, const PxMat44 &trans, bool &empty) +{ + empty = false; + + PxMat33 M(trans.getBasis(0), trans.getBasis(1), trans.getBasis(2)); + PxMat33 M1 = M.getInverse(); + PxMat33 M1T = M1.getTranspose(); + + for (int i = 0; i < numPlanes; i++) { + PxPlane p; + p.n = M1T.transform(planes[i].n); + p.d = planes[i].d + trans.getPosition().dot(p.n); + float len = p.n.normalize(); + p.d /= len; + cut(p.n, p.d, empty); + if (empty) + return; + } +} + +// -------------------------------------------------------------------------------------------- +bool Convex::cut(const PxVec3 &localPlaneN, float localPlaneD, bool &cutEmpty, bool setNewFaceFlag) +{ + float eps = 1e-4f; + + //bool pos = false; + //bool neg = false; + + PxVec3 pn = localPlaneN; + float pd = localPlaneD; + + // does the plane pass through the convex? + float minD = PX_MAX_F32; + float maxD = -PX_MAX_F32; + + for (uint32_t i = 0; i < mVertices.size(); i++) { + float dot = mVertices[i].dot(pn); + if (dot < minD) minD = dot; + if (dot > maxD) maxD = dot; + } + + cutEmpty = minD > pd - eps; + if (cutEmpty || maxD < pd + eps) + return false; + + // new: avoid singular cases + for (uint32_t i = 0; i < mVertices.size(); i++) { + float dot = mVertices[i].dot(pn); + if (fabs(dot - pd) < 1e-5f) + pd += 1e-5f; + } + + // member so the memory does not have to be re-allocated for every cut + if (mNewConvex == NULL) + mNewConvex = mScene->createConvex(); + mNewConvex->clear(); + + // create vertices + uint32_t numFaces = mFaces.size(); + nvidia::Array<int> newNr(mVertices.size(), -1); + + struct Cut { + void set(int i0, int i1, int newId) { + this->i0 = i0; this->i1 = i1; this->newId = newId; next = -1; + } + bool is(int i0, int i1) { + return (this->i0 == i0 && this->i1 == i1) || (this->i0 == i1 && this->i1 == i0); + } + int i0, i1; + int newId; + int next; + }; + nvidia::Array<Cut> cuts; + + for (uint32_t i = 0; i < numFaces; i++) { + Face &f = mFaces[i]; + int *ids = &mIndices[(uint32_t)f.firstIndex]; + mNewConvex->mFaces.resize(mNewConvex->mFaces.size() + 1); + Face &newFace = mNewConvex->mFaces[mNewConvex->mFaces.size()-1]; + newFace.init(); + newFace.flags = f.flags; + newFace.firstIndex = (int32_t)mNewConvex->mIndices.size(); + bool hasNormals = (f.flags & CompoundGeometry::FF_HAS_NORMALS) != 0; + if (hasNormals) + newFace.firstNormal = (int32_t)mNewConvex->mNormals.size(); + + int cutNrs[2]; + uint32_t numCuts = 0; + bool winding = false; + + for (int j = 0; j < f.numIndices; j++) { + int j1 = (j+1)%f.numIndices; + int i0 = ids[j]; + int i1 = ids[j1]; + PxVec3 &p0 = mVertices[(uint32_t)i0]; + PxVec3 &p1 = mVertices[(uint32_t)i1]; + PxVec3 n0,n1; + if (hasNormals) { + n0 = mNormals[uint32_t(f.firstNormal+j)]; + n1 = mNormals[uint32_t(f.firstNormal+j1)]; + } + bool sign0 = p0.dot(pn) >= pd; + bool sign1 = p1.dot(pn) >= pd; + if (!sign0) { + if (newNr[(uint32_t)i0] < 0) { + newNr[(uint32_t)i0] = (int32_t)mNewConvex->mVertices.size(); + mNewConvex->mVertices.pushBack(p0); + } + mNewConvex->mIndices.pushBack(newNr[(uint32_t)i0]); + if (hasNormals) + mNewConvex->mNormals.pushBack(n0); + if (numCuts == 1) + winding = true; + } + + // cut? + if (sign0 != sign1) { + // do we have the cut vertex already? + uint32_t totalCuts = cuts.size(); + uint32_t k = 0; + while (k < totalCuts && !cuts[k].is(i0,i1)) + k++; + + float t = (pd - p0.dot(pn)) / (p1 - p0).dot(pn); + // create new cut vertex + if (k == totalCuts) { + cuts.resize(totalCuts+1); + cuts[totalCuts].set(i0, i1, (int32_t)mNewConvex->mVertices.size()); + PxVec3 p = p0 + (p1-p0) * t; + mNewConvex->mVertices.pushBack(p); + } + mNewConvex->mIndices.pushBack(cuts[k].newId); + if (hasNormals) { + PxVec3 n = n0 + (n1-n0) * t; + n.normalize(); + mNewConvex->mNormals.pushBack(n); + } + if (numCuts >= 2) { // numerical problems! + cutEmpty = true; + return false; + } + cutNrs[numCuts] = (int32_t)k; + numCuts++; + } + } + + if (numCuts == 1) { // numerical problems! + cutEmpty = true; + return false; + } + + if (numCuts == 2) { + Cut &cut0 = cuts[(uint32_t)cutNrs[0]]; + Cut &cut1 = cuts[(uint32_t)cutNrs[1]]; + if (winding) { + cut0.next = cutNrs[1]; + } + else { + cut1.next = cutNrs[0]; + } + } + + // check whether the new convex got a new face + + newFace.numIndices = (int32_t)mNewConvex->mIndices.size() - newFace.firstIndex; + if (newFace.numIndices == 0) + mNewConvex->mFaces.popBack(); + else if (newFace.numIndices < 3) { + cutEmpty = true; + return false; + } + } + + // create closing face + Face closingFace; + closingFace.init(); + closingFace.firstIndex = (int32_t)mNewConvex->mIndices.size(); + + int nr = 0; + for (uint32_t i = 0; i < cuts.size(); i++) { + mNewConvex->mIndices.pushBack(cuts[(uint32_t)nr].newId); + closingFace.numIndices++; + nr = cuts[(uint32_t)nr].next; + + if (nr < 0) { // numerical problems + cutEmpty = true; + return false; + } + } + if (closingFace.numIndices < 3) { + cutEmpty = true; + return false; + } + if (setNewFaceFlag) + closingFace.flags |= CompoundGeometry::FF_NEW; + + mNewConvex->mFaces.pushBack(closingFace); + + mVertices = mNewConvex->mVertices; + mIndices = mNewConvex->mIndices; + mFaces = mNewConvex->mFaces; + mNormals = mNewConvex->mNormals; + mVolumeDirty = true; + finalize(); + + return true; +} + +// -------------------------------------------------------------------------------------------- +PxConvexMesh* Convex::createPxConvexMesh(Compound *parent, PxPhysics *pxPhysics, PxCooking *pxCooking) +{ + mParent = parent; + + if (mVertices.empty()) + return NULL; + + if (mPxConvexMesh != NULL) + return mPxConvexMesh; + + mPxConvexMesh = NULL; + mPxActor = NULL; + +#if COOK_TRIANGLES + // create tri mesh + // in this tri mesh vertices are shared in contrast to the tri mesh for rendering + nvidia::Array<uint32_t> indices; + for (int i = 0; i < (int)mFaces.size(); i++) { + Face &f = mFaces[i]; + if (f.numIndices < 3) + continue; + int *ids = &mIndices[f.firstIndex]; + for (int j = 1; j < f.numIndices-1; j++) { + indices.pushBack(ids[0]); + indices.pushBack(ids[j]); + indices.pushBack(ids[j+1]); + } + } + + physx::PxConvexMeshDesc meshDesc; + meshDesc.setToDefault(); + meshDesc.points.count = mVertices.size(); + meshDesc.points.stride = sizeof(PxVec3); + meshDesc.points.data = &mVertices[0]; + meshDesc.triangles.count = indices.size() / 3; + meshDesc.triangles.stride = 3*sizeof(uint32_t); + meshDesc.triangles.data = &indices[0]; +#else + nvidia::Array<physx::PxHullPolygon> polygons; + polygons.reserve(mFaces.size()); + if (mPlanes.size() != mFaces.size()) + updatePlanes(); + + for (uint32_t i = 0; i < mFaces.size(); i++) { + Face &f = mFaces[i]; + if (f.numIndices < 3) + continue; + physx::PxHullPolygon p; + p.mIndexBase = (uint16_t)f.firstIndex; + p.mNbVerts = (uint16_t)f.numIndices; + p.mPlane[0] = mPlanes[i].n.x; + p.mPlane[1] = mPlanes[i].n.y; + p.mPlane[2] = mPlanes[i].n.z; + p.mPlane[3] = -mPlanes[i].d; + polygons.pushBack(p); + } + + physx::PxConvexMeshDesc meshDesc; + meshDesc.setToDefault(); + meshDesc.points.count = mVertices.size(); + meshDesc.points.stride = sizeof(PxVec3); + meshDesc.points.data = &mVertices[0]; + meshDesc.indices.count = mIndices.size(); + meshDesc.indices.data = &mIndices[0]; + meshDesc.indices.stride = sizeof(uint32_t); + meshDesc.polygons.count = mFaces.size(); + meshDesc.polygons.data = &polygons[0]; + meshDesc.polygons.stride = sizeof(physx::PxHullPolygon); + +#endif + + // Cooking from memory + PxDefaultMemoryOutputStream outBuffer; + if (!pxCooking->cookConvexMesh(meshDesc, outBuffer)) + return NULL; + + PxDefaultMemoryInputData inBuffer(outBuffer.getData(), outBuffer.getSize()); + mPxConvexMesh = pxPhysics->createConvexMesh(inBuffer); + + return mPxConvexMesh; +} + +// -------------------------------------------------------------------------------------------- +void Convex::setMaterialOffset(const PxVec3 &offset) +{ + if (mHasExplicitVisMesh) { + for (uint32_t i = 0; i < mVisVertices.size(); i++) + mVisVertices[i] += mMaterialOffset - offset; + } + mMaterialOffset = offset; +} + +// -------------------------------------------------------------------------------------------- +void Convex::createVisMeshFromConvex() +{ + // vertices are duplicated for each face to get sharp edges with multiple normals + mHasExplicitVisMesh = false; + mVisVertices.clear(); + mVisNormals.clear(); + mVisTangents.clear(); + mVisTriIndices.clear(); + mVisTexCoords.clear(); + PxVec3 n; + PxVec3 t0, t1; + + for (uint32_t i = 0; i < mFaces.size(); i++) { + Face &f = mFaces[i]; + if (f.flags & CompoundGeometry::FF_INVISIBLE) + continue; + if (f.numIndices < 3) + continue; + // normal + int *ids = &mIndices[(uint32_t)f.firstIndex]; + if (!(f.flags & CompoundGeometry::FF_HAS_NORMALS)) { + n = (mVertices[(uint32_t)ids[1]] - mVertices[(uint32_t)ids[0]]).cross(mVertices[(uint32_t)ids[2]] - mVertices[(uint32_t)ids[0]]); + n.normalize(); + } + // tangents + if (fabs(n.x) < fabs(n.y) && fabs(n.x) < fabs(n.z)) + t0 = PxVec3(1.0f, 0.0f, 0.0f); + else if (fabs(n.y) < fabs(n.z)) + t0 = PxVec3(0.0f, 1.0f, 0.0); + else + t0 = PxVec3(0.0f, 0.0f, 1.0f); + t1 = n.cross(t0); + t1.normalize(); + t0 = t1.cross(n); + + int firstVertNr = (int32_t)mVisVertices.size(); + for (int j = 0; j < f.numIndices; j++) { + PxVec3 p = mVertices[(uint32_t)ids[(uint32_t)j]]; + mVisVertices.pushBack(p); + if (f.flags & CompoundGeometry::FF_HAS_NORMALS) { + mVisNormals.pushBack(mNormals[uint32_t(f.firstNormal + j)]); + mVisTangents.pushBack(PxVec3(0.0f, 0.0f, 0.0f)); // on surface, not bump map + } + else { + mVisNormals.pushBack(n); + mVisTangents.pushBack(t0); // internal face, bump map + } + mVisTexCoords.pushBack(p.dot(t0) * mTexScale); + mVisTexCoords.pushBack(p.dot(t1) * mTexScale); + } + for (int j = 1; j < f.numIndices-1; j++) { + mVisTriIndices.pushBack(firstVertNr); + mVisTriIndices.pushBack(firstVertNr+j); + mVisTriIndices.pushBack(firstVertNr+j+1); + } + } +} + +// -------------------------------------------------------------------------------------------- +struct Edge { + // not using indices for edge match but positions + // so duplicated vertices are handled as one vertex + bool smaller(const PxVec3 &v0, const PxVec3 &v1) const { + if (v0.x < v1.x) return true; + if (v0.x > v1.x) return false; + if (v0.y < v1.y) return true; + if (v0.y > v1.y) return false; + return (v0.z < v1.z); + } + void set(const PxVec3 &v0, const PxVec3 &v1, int faceNr, int edgeNr) { + if (smaller(v0,v1)) { this->v0 = v0; this->v1 = v1; } + else { this->v0 = v1; this->v1 = v0; } + this->faceNr = faceNr; this->edgeNr = edgeNr; + } + bool operator < (const Edge &e) const { + if (smaller(v0, e.v0)) return true; + if (v0 == e.v0 && smaller(v1, e.v1)) return true; + return false; + } + bool operator == (const Edge &e) const { return v0 == e.v0 && v1 == e.v1; } + PxVec3 v0,v1; + int faceNr, edgeNr; +}; + +// -------------------------------------------------------------------------------------------- +bool Convex::computeVisMeshNeighbors() +{ + uint32_t numIndices = mVisPolyIndices.size(); + uint32_t numPolygons = mVisPolyStarts.size()-1; + + nvidia::Array<Edge> edges(numIndices); + + for (uint32_t i = 0; i < numPolygons; i++) { + int first = mVisPolyStarts[i]; + int num = mVisPolyStarts[i+1] - first; + for (int j = 0; j < num; j++) { + edges[uint32_t(first + j)].set( + mVisVertices[(uint32_t)mVisPolyIndices[uint32_t(first + j)]], + mVisVertices[(uint32_t)mVisPolyIndices[uint32_t(first + (j+1)%num)]], (int32_t)i, first + j); + } + } + std::sort(edges.begin(), edges.end()); + + mVisPolyNeighbors.resize(numIndices); + bool manifold = true; + uint32_t i = 0; + while (i < edges.size()) { + Edge &e0 = edges[i]; + i++; + if (i < edges.size() && edges[i] == e0) { + Edge &e1 = edges[i]; + mVisPolyNeighbors[(uint32_t)e0.edgeNr] = e1.faceNr; + mVisPolyNeighbors[(uint32_t)e1.edgeNr] = e0.faceNr; + i++; + } + while (i < edges.size() && edges[i] == e0) { + manifold = false; + i++; + } + } + return manifold; +} + +// -------------------------------------------------------------------------------------------- +bool Convex::setExplicitVisMeshFromTriangles(int numVertices, const PxVec3 *vertices, const PxVec3 *normals, const PxVec2 *texcoords, + int numIndices, const uint32_t *indices, PxTransform *trans, const PxVec3* scale) +{ + mHasExplicitVisMesh = true; + + // reduce to vertices referenced by indices + // needed if submesh is provided + nvidia::Array<int> oldToNew((uint32_t)numVertices, -1); + mVisVertices.clear(); + mVisNormals.clear(); + mVisTangents.clear(); + mVisTexCoords.clear(); + + const float scaleMagn = scale ? scale->magnitude() : 1.f; + + for (int i = 0; i < numIndices; i++) { + uint32_t id = (uint32_t)indices[(uint32_t)i]; + if (oldToNew[id] < 0) { + oldToNew[id] = (int32_t)mVisVertices.size(); + + PxVec3 p = vertices[id]; + PxVec3 n = normals[id]; + if (scale != NULL) + { + p.x = scale->x*p.x; + p.y = scale->y*p.y; + p.z = scale->z*p.z; + n.x = scale->x*n.x/scaleMagn; + n.y = scale->y*n.y/scaleMagn; + n.z = scale->z*n.z/scaleMagn; + } + if (trans != NULL) { + p = trans->transform(p); + n = trans->rotate(n); + } + mVisVertices.pushBack(p); + mVisNormals.pushBack(n); + mVisTangents.pushBack(PxVec3(0.0f, 0.0f, 0.0f)); // on surface, no bump map + mVisTexCoords.pushBack(texcoords[id].x); // to do, get as input + mVisTexCoords.pushBack(texcoords[id].y); + } + } + + uint32_t numTris = (uint32_t)numIndices / 3; + mVisPolyStarts.resize(numTris+1); + for (uint32_t i = 0; i < numTris+1; i++) + mVisPolyStarts[i] = 3*(int32_t)i; + + mVisPolyIndices.resize((uint32_t)numIndices); + for (uint32_t i = 0; i < (uint32_t)numIndices; i++) + mVisPolyIndices[i] = oldToNew[(uint32_t)indices[i]]; + + mVisTriIndices.clear(); + + bool manifold = computeVisMeshNeighbors(); + createVisTrisFromPolys(); + computeVisTangentsFromPoly(); + + return manifold; +} + +// -------------------------------------------------------------------------------------------- +bool Convex::setExplicitVisMeshFromPolygons(int numVertices, const PxVec3 *vertices, const PxVec3 *normals, const PxVec3 *tangents, const float *texCoords, + int numPolygons, const int *polyStarts, + int numIndices, const int *indices, PxTransform *trans, const PxVec3* scale) +{ + mHasExplicitVisMesh = true; + + mVisVertices.resize((uint32_t)numVertices); + mVisNormals.resize((uint32_t)numVertices); + mVisTangents.resize((uint32_t)numVertices); + mVisTexCoords.resize(2*(uint32_t)numVertices); + + const float scaleMagn = scale ? scale->magnitude() : 1.f; + + for (uint32_t i = 0; i < (uint32_t)numVertices; i++) { + if (trans != NULL) { + mVisVertices[i] = trans->transform(vertices[i]); + mVisNormals[i] = trans->rotate(normals[i]); + if (tangents != NULL) + mVisTangents[i] = trans->rotate(tangents[i]); + else + mVisTangents[i] = PxVec3(0.0f, 0.0f, 0.0f); + } + else { + mVisVertices[i] = vertices[i]; + mVisNormals[i] = normals[i]; + if (tangents != NULL) + mVisTangents[i] = tangents[i]; + else + mVisTangents[i] = PxVec3(0.0f, 0.0f, 0.0f); + } + if (texCoords != NULL) { + mVisTexCoords[2*i] = texCoords[2*i]; + mVisTexCoords[2*i+1] = texCoords[2*i+1]; + } + if (scale != NULL) + { + mVisVertices[i].x *= scale->x; + mVisVertices[i].y *= scale->y; + mVisVertices[i].z *= scale->z; + mVisNormals[i].x *= scale->x/scaleMagn; + mVisNormals[i].y *= scale->y/scaleMagn; + mVisNormals[i].z *= scale->z/scaleMagn; + } + } + + mVisPolyStarts.resize((uint32_t)numPolygons+1); + for (uint32_t i = 0; i < (uint32_t)numPolygons+1; i++) + mVisPolyStarts[i] = polyStarts[i]; + + mVisPolyIndices.resize((uint32_t)numIndices); + for (uint32_t i = 0; i < (uint32_t)numIndices; i++) + mVisPolyIndices[i] = indices[i]; + + bool manifold = computeVisMeshNeighbors(); + createVisTrisFromPolys(); + computeVisTangentsFromPoly(); + + return manifold; +} + +// -------------------------------------------------------------------------------------------- +void Convex::computeVisTangentsFromPoly() { + // Must be called after createVisTrisFromPolys + //Adapt from Lengyel, Eric. "Computing Tangent Space Basis Vectors for an Arbitrary Mesh". Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html + + uint32_t numTris = mVisTriIndices.size() / 3; + int* tris = &mVisTriIndices[0]; + uint32_t numV = mVisVertices.size(); + + for (uint32_t i = 0; i < numTris; i++) + { + uint32_t i0 = (uint32_t)tris[0]; + uint32_t i1 = (uint32_t)tris[1]; + uint32_t i2 = (uint32_t)tris[2]; + + PxVec3& v0 = mVisVertices[i0]; + PxVec3& v1 = mVisVertices[i1]; + PxVec3& v2 = mVisVertices[i2]; + + + float* tex0 = &mVisTexCoords[2*i0]; + float* tex1 = &mVisTexCoords[2*i1]; + float* tex2 = &mVisTexCoords[2*i2]; + + float x0 = v1.x - v0.x; + float x1 = v2.x - v0.x; + float y0 = v1.y - v0.y; + float y1 = v2.y - v0.y; + float z1 = v1.z - v0.z; + float z2 = v2.z - v0.z; + + float s0 = tex1[0] - tex0[0]; + float s1 = tex2[0] - tex0[0]; + float t0 = tex1[1] - tex0[1]; + float t1 = tex2[1] - tex0[1]; + + float idet = 1.0f / (s0*t1 - s1*t0); + PxVec3 t = idet*PxVec3(t1*x0 - t0*x1,t1*y0 - t0*y1,t1*z1 - t0*z2); + //PxVec3 b = idet*PxVec3(s0*x1 - s1*x0,s0*y1 - s1*y0,s0*z2 - s1*z1); + +/* if ( (i0 == 0) || (i1 == 0) || (i2 == 0) ) { + cout<<t[0]<<" "<<t[1]<<" "<<t[2]<<endl; + ok= true; + }*/ + mVisTangents[i0] += t; + mVisTangents[i1] += t; + mVisTangents[i2] += t; + + tris+=3; + } + //cout<<"OK = "<<ok<<endl; + + for (uint32_t i = 0; i < numV; i++) + { + PxVec3& n = mVisNormals[i]; + PxVec3& t = mVisTangents[i]; + + + // Gram-Schmidt orthogonalize + t = (t - n * n.dot(t)); + t.normalize(); + + if (!t.isFinite()) t = PxVec3(0.0f, 0.0f, 0.0f); + + mVisTexCoords[2*i] += 5.0f; + } +} + +// -------------------------------------------------------------------------------------------- +void Convex::createVisTrisFromPolys() +{ + mVisTriIndices.clear(); + for (uint32_t i = 0; i < mVisPolyStarts.size()-1; i++) { + uint32_t first = (uint32_t)mVisPolyStarts[i]; + uint32_t num = (uint32_t)mVisPolyStarts[i+1] - first; + if (num == 3) { + mVisTriIndices.pushBack(mVisPolyIndices[first]); + mVisTriIndices.pushBack(mVisPolyIndices[first+1]); + mVisTriIndices.pushBack(mVisPolyIndices[first+2]); + continue; + } + PolygonTriangulator *pt = mScene->getPolygonTriangulator(); //PolygonTriangulator::getInstance(); + pt->triangulate(&mVisVertices[0], (int32_t)num, &mVisPolyIndices[first]); + const nvidia::Array<int> indices = pt->getIndices(); + + uint32_t numIds = mVisTriIndices.size(); + mVisTriIndices.resize(numIds + indices.size()); + for (uint32_t j = 0; j < indices.size(); j++) + mVisTriIndices[numIds+j] = indices[j]; + } +} + +// -------------------------------------------------------------------------------------------- +void Convex::transformVisualMesh(const PxTransform &trans) +{ + for (uint32_t i = 0; i < mVisVertices.size(); i++) + mVisVertices[i] = trans.transform(mVisVertices[i]); + for (uint32_t i = 0; i < mVisNormals.size(); i++) + mVisNormals[i] = trans.rotate(mVisNormals[i]); + for (uint32_t i = 0; i < mVisTangents.size(); i++) + mVisTangents[i] = trans.rotate(mVisTangents[i]); +} + +// -------------------------------------------------------------------------------------------- +bool Convex::insideVisualMesh(const PxVec3 &pos) const +{ + int num[6] = {0,0,0,0,0,0}; + const uint32_t numAxes = 2; // max 3: the nigher the more robust but slower + + for (uint32_t i = 0; i < mVisTriIndices.size(); i += 3) { + const PxVec3 &p0 = mVisVertices[(uint32_t)mVisTriIndices[i]]; + const PxVec3 &p1 = mVisVertices[(uint32_t)mVisTriIndices[i+1]]; + const PxVec3 &p2 = mVisVertices[(uint32_t)mVisTriIndices[i+2]]; + PxVec3 n = (p1-p0).cross(p2-p0); + float d = n.dot(p0); + float ds = d - pos.dot(n); + + // for all axes, cound the hits of the ray starting from pos with the mesh + for (uint32_t j = 0; j < numAxes; j++) { + if (n[j] == 0.0f) + continue; + + uint32_t j0 = (j+1)%3; + uint32_t j1 = (j+2)%3; + float x0 = p0[j0]; + float y0 = p0[j1]; + float x1 = p1[j0]; + float y1 = p1[j1]; + float x2 = p2[j0]; + float y2 = p2[j1]; + + float px = pos[j0]; + float py = pos[j1]; + + // inside triangle? + float d0 = (x1-x0) * (py-y0) - (y1-y0) * (px-x0); + float d1 = (x2-x1) * (py-y1) - (y2-y1) * (px-x1); + float d2 = (x0-x2) * (py-y2) - (y0-y2) * (px-x2); + bool inside = + (d0 <= 0.0f && d1 <= 0.0f && d2 <= 0.0f) || + (d0 >= 0.0f && d1 >= 0.0f && d2 >= 0.0f); + if (!inside) + continue; + + float s = ds / n[j]; + if (s > 0.0f) + num[2*j] += (n[j] > 0.0f) ? +1 : -1; + else + num[2*j+1] += (n[j] < 0.0f) ? +1 : -1; + } + } + uint32_t numVotes = 0; + for (uint32_t i = 0; i < 6; i++) { + if (num[i] > 0) + numVotes++; + } + return numVotes > numAxes; +} + +// -------------------------------------------------------------------------------------------- +bool Convex::clipVisualMesh(MeshClipper *clipper, const PxTransform &trans, nvidia::Array<Convex*> &newConvexes) +{ + bool empty, completelyInside; + newConvexes.clear(); + + clipper->clip(this, trans, mTexScale, true, empty, completelyInside); + + if (completelyInside) { + mHasExplicitVisMesh = false; + return true; + } + + if (empty) + return false; + + const MeshClipper::Mesh &mesh = clipper->getMesh(0); + + mVisVertices = mesh.vertices; + mVisNormals = mesh.normals; + mVisTangents = mesh.tangents; + mVisTexCoords = mesh.texCoords; + mVisPolyStarts = mesh.polyStarts; + mVisPolyIndices = mesh.polyIndices; + mVisPolyNeighbors = mesh.polyNeighbors; + mHasExplicitVisMesh = true; + + createVisTrisFromPolys(); + + finalize(); + + int numMeshes = clipper->getNumMeshes(); + if (numMeshes > 1) { + newConvexes.resize((uint32_t)numMeshes-1); + for (int i = 1; i < numMeshes; i++) { + const MeshClipper::Mesh &mesh = clipper->getMesh(i); + Convex *c = mScene->createConvex(); + newConvexes[(uint32_t)i-1] = c; + c->createFromConvex(this); + c->mVisVertices = mesh.vertices; + c->mVisNormals = mesh.normals; + c->mVisTangents = mesh.tangents; + c->mVisTexCoords = mesh.texCoords; + c->mVisPolyStarts = mesh.polyStarts; + c->mVisPolyIndices = mesh.polyIndices; + c->mVisPolyNeighbors = mesh.polyNeighbors; + c->mHasExplicitVisMesh = true; + c->createVisTrisFromPolys(); + c->finalize(); + } + } + return true; +} + +// -------------------------------------------------------------------------------------------- +void Convex::fitToVisualMesh(bool &cutEmpty, int numFitDirections) +{ + cutEmpty = false; + if (!mHasExplicitVisMesh) + return; + + static const int numNormals = 3 + 4; + static const float normals[numNormals][3] = { + {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f} + // avoid singular cases + // {1.0f, 1.1f, 1.2f}, {-1.3f, 1.2f, 1.0f}, {1.0f, -1.2f, 1.0f}, {1.2f, 1.3f, -1.0f} + }; + + cutEmpty = false; + const float eps = 1e-3f; + + int num = numFitDirections; + if (num > numNormals) + num = numNormals; + + for (int i = 0; i < num; i++) { + PxVec3 n(normals[i][0], normals[i][1], normals[i][2]); + n.normalize(); + float minVD = PX_MAX_F32; + float maxVD = -PX_MAX_F32; + float minCD = PX_MAX_F32; + float maxCD = -PX_MAX_F32; + for (uint32_t j = 0; j < mVisVertices.size(); j++) { + float d = mVisVertices[j].dot(n); + if (d < minVD) minVD = d; + if (d > maxVD) maxVD = d; + } + for (uint32_t j = 0; j < mVertices.size(); j++) { + float d = mVertices[j].dot(n); + if (d < minCD) minCD = d; + if (d > maxCD) maxCD = d; + } + if (maxVD < maxCD - eps) { + cut(n, maxVD, cutEmpty, false); + if (cutEmpty) + return; + } + if (minVD > minCD + eps) { + cut(-n, -minVD - eps, cutEmpty, false); + if (cutEmpty) + return; + } + } + finalize(); +} + +// -------------------------------------------------------------------------------------------- +float Convex::getVolume() const +{ + if (!mVolumeDirty) + return mVolume; + + mVolume = 0.0f; + for (uint32_t i = 0; i < mFaces.size(); i++) { + const Face &f = mFaces[i]; + if (f.numIndices < 3) + continue; + const int *ids = &mIndices[(uint32_t)f.firstIndex]; + const PxVec3 &p0 = mVertices[(uint32_t)ids[0]]; + for (int j = 1; j < f.numIndices-1; j++) { + const PxVec3 &p1 = mVertices[(uint32_t)ids[(uint32_t)j]]; + const PxVec3 &p2 = mVertices[(uint32_t)ids[(uint32_t)j+1]]; + mVolume += p0.cross(p1).dot(p2); + } + } + mVolume *= (1.0f / 6.0f); + mVolumeDirty = false; + return mVolume; +} + +// -------------------------------------------------------------------------------------------- +void Convex::removeInvisibleFacesFlags() +{ + for (uint32_t i = 0; i < mFaces.size(); i++) + mFaces[i].flags &= ~CompoundGeometry::FF_INVISIBLE; +} + +// -------------------------------------------------------------------------------------------- +void Convex::updateFaceVisibility(const float *faceCoverage) +{ + for (uint32_t i = 0; i < mFaces.size(); i++) { + if (faceCoverage[i] > 0.95f) + mFaces[i].flags |= CompoundGeometry::FF_INVISIBLE; + else + mFaces[i].flags &= ~CompoundGeometry::FF_INVISIBLE; + } +} + +// -------------------------------------------------------------------------------------------- +void Convex::clearFraceFlags(unsigned int flag) +{ + for (uint32_t i = 0; i < mFaces.size(); i++) + mFaces[i].flags &= ~flag; +} + +// -------------------------------------------------------------------------------------------- +bool Convex::insideFattened(const PxVec3 &pos, float r) const +{ + // early out with bounding box + if (pos.x < mBounds.minimum.x - r || pos.x > mBounds.maximum.x + r) + return false; + if (pos.y < mBounds.minimum.y - r || pos.y > mBounds.maximum.y + r) + return false; + if (pos.z < mBounds.minimum.z - r || pos.z > mBounds.maximum.z + r) + return false; + + // planes + for (uint32_t i = 0; i < mPlanes.size(); i++) { + if (mPlanes[i].n.dot(pos) > mPlanes[i].d + r) + return false; + } + return true; +} + +// -------------------------------------------------------------------------------------------- +bool Convex::check() { + PxVec3 center = getCenter(); + + for (uint32_t i = 0; i < mFaces.size(); i++) { + Face &f = mFaces[i]; + if (f.numIndices < 3) + return false; + + PxVec3 &p0 = mVertices[(uint32_t)mIndices[(uint32_t)f.firstIndex]]; + float A = 0.0f; + PxVec3 n(0.0, 0.0, 0.0); + + for (int j = 1; j < f.numIndices-1; j++) { + PxVec3 &p1 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j)]]; + PxVec3 &p2 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j+1)]]; + PxVec3 nj = (p1-p0).cross(p2-p0); + A += nj.magnitude(); + n += nj; + } + if (A < 1e-6) + return false; + + float d = n.dot(p0); + if (n.dot(center) > d) + return false; + } + return true; +} + +bool Convex::isOnConvexSurface(const PxVec3 pts) const { + const float EPSILON = 1e-6f; + uint32_t numF = mFaces.size(); + for (uint32_t i = 0; i < numF; i++) { + + const Face& f = mFaces[i]; + int nv = f.numIndices; + + float areaFan = 0.0f; + // Compute face area + for (int j = 1; j < nv-1; j++) { + const PxVec3& p0 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex)]]; + const PxVec3& p1 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j)]]; + const PxVec3& p2 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+(j+1))]]; + areaFan += 0.5f* (((p1-p0).cross(p2-p0))).magnitude(); + } + float areaP = 0.0f; + + for (int j = 0; j < nv; j++) { + + const PxVec3& p1 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j)]]; + const PxVec3& p2 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+(j+1) % nv)]]; + areaP += 0.5f*(((p1-pts).cross(p2-pts))).magnitude(); + } + if ((areaP - areaFan)/areaFan < EPSILON) { + return true; + } + } + return false; + +} + +} +} +} +#endif diff --git a/APEX_1.4/module/destructible/fracture/Core/ConvexBase.h b/APEX_1.4/module/destructible/fracture/Core/ConvexBase.h new file mode 100644 index 00000000..98b44af2 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/ConvexBase.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef CONVEX_BASE +#define CONVEX_BASE + +#include <PxPhysics.h> +#include <PxCooking.h> +#include <PxVec3.h> +#include <PxPlane.h> +#include <PxBounds3.h> +#include <PxTransform.h> +#include <PsArray.h> +#include <PsUserAllocated.h> + + +namespace nvidia +{ + +namespace fracture +{ +namespace base +{ + +class Compound; +class CompoundGeometry; +class MeshClipper; +class SimScene; + +// ---------------------------------------------------------------------------- +class Convex : public UserAllocated +{ + friend class SimScene; +protected: + Convex(SimScene* scene); +public: + virtual ~Convex(); + + void createFromConvex(const Convex *convex, const PxTransform *trans = NULL); + void createFromGeometry(const CompoundGeometry &geom, int convexNr, const PxMat44 *trans = NULL); + //bool createFromXml(XMLParser *p, float scale, bool ignoreVisualMesh = false); + + void transform(const PxMat44 &trans); + PxVec3 centerAtZero(); + PxVec3 getCenter() const; + void setTexScale(float texScale) { mTexScale = texScale; } + void increaseRefCounter() { mRefCounter++; } + int decreaseRefCounter() { mRefCounter--; return mRefCounter; } + + bool rayCast(const PxVec3 &ray, const PxVec3 &dir, float &dist, PxVec3 &normal) const; + bool collide(const PxVec3 &pos, float r, float &penetration, PxVec3 &surfaceNormal, PxVec3 &surfaceVel) const; + + void intersectWithConvex(const PxPlane *planes, int numPlanes, const PxMat44 &trans, bool &empty); + + virtual void draw(bool /*debug*/ = false) {} + + PxConvexMesh* createPxConvexMesh(Compound *parent, PxPhysics *pxPhysics, PxCooking *pxCooking); + void setPxActor(PxRigidActor *actor); + void setLocalPose(const PxTransform &pose); + + // accessors + Compound *getParent() { return mParent; } + const Compound *getParent() const { return mParent; } + const PxConvexMesh *getPxConvexMesh() const { return mPxConvexMesh; } + PxConvexMesh *getPxConvexMesh() { return mPxConvexMesh; } + + const nvidia::Array<PxPlane> &getPlanes() const { return mPlanes; }; + const PxBounds3 &getBounds() const { return mBounds; } + void getWorldBounds(PxBounds3 &bounds) const; + void getLocalBounds(PxBounds3 &bounds) const; + float getVolume() const; + void removeInvisibleFacesFlags(); + void updateFaceVisibility(const float *faceCoverage); + void clearFraceFlags(unsigned int flag); + + struct Face { + void init() { + firstIndex = 0; numIndices = 0; flags = 0; firstNormal = 0; + } + int firstIndex; + int numIndices; + int flags; + int firstNormal; + + + }; + + const nvidia::Array<Face> &getFaces() const { return mFaces; } + const nvidia::Array<int> &getIndices() const { return mIndices; } + const nvidia::Array<PxVec3> &getVertices() const { return mVertices; } + + const nvidia::Array<PxVec3> &getVisVertices() const { return mVisVertices; } + const nvidia::Array<PxVec3> &getVisNormals() const { return mVisNormals; } + const nvidia::Array<PxVec3> &getVisTangents() const { return mVisTangents; } + const nvidia::Array<float> &getVisTexCoords() const { return mVisTexCoords; } + const nvidia::Array<int> &getVisTriIndices() const { return mVisTriIndices; } + + const nvidia::Array<int> &getVisPolyStarts() const { return mVisPolyStarts; } + const nvidia::Array<int> &getVisPolyIndices() const { return mVisPolyIndices; } + const nvidia::Array<int> &getVisPolyNeighbors() const { return mVisPolyNeighbors; } + + PxVec3 getMaterialOffset() const { return mMaterialOffset; } + void setMaterialOffset(const PxVec3 &offset); + PxTransform getGlobalPose() const; + PxTransform getLocalPose() const; + + bool isGhostConvex() const { return mIsGhostConvex; } + + // explicit visual mesh + bool hasExplicitVisMesh() const { return mHasExplicitVisMesh; } + bool setExplicitVisMeshFromTriangles(int numVertices, const PxVec3 *vertices, const PxVec3 *normals, const PxVec2 *texcoords, + int numIndices, const uint32_t *indices, PxTransform *trans = NULL, const PxVec3* scale = NULL); + bool setExplicitVisMeshFromPolygons(int numVertices, const PxVec3 *vertices, const PxVec3 *normals, + const PxVec3 *tangents, const float *texCoords, + int numPolygons, const int *polyStarts, // numPolygons+1 entries + int numIndices, const int *indices, PxTransform *trans = NULL, const PxVec3* scale = NULL); + void createVisTrisFromPolys(); + void createVisMeshFromConvex(); + void transformVisualMesh(const PxTransform &trans); + bool insideVisualMesh(const PxVec3 &pos) const; + + bool clipVisualMesh(MeshClipper *clipper, const PxTransform &trans, nvidia::Array<Convex*> &newConvexes); + void fitToVisualMesh(bool &cutEmpty, int numFitDirections = 3); + + bool isOnConvexSurface(const PxVec3 pts) const; + bool check(); + + PxActor* getActor(); + bool insideFattened(const PxVec3 &pos, float r) const; + + bool use2dTexture() const { return mUse2dTexture; } + bool isIndestructible() const { return mIndestructible; } + int getMaterialId() const { return mMaterialId; } + int getSurfaceMaterialId() const { return mSurfaceMaterialId; } + void setSurfaceMaterialId(int id) { mSurfaceMaterialId = id; } + + void setModelIslandNr(int nr) { mModelIslandNr = nr; } + int getModelIslandNr() const { return mModelIslandNr; } + + void setConvexRendererInfo(int groupNr, int groupPos) const { mConvexRendererGroupNr = groupNr; mConvexRendererGroupPos = groupPos; } + int getConvexRendererGroupNr() const { return mConvexRendererGroupNr; } + int getConvexRendererGroupPos() const { return mConvexRendererGroupPos; } + + void setIsFarConvex(bool v) { mIsFarConvex = v; } + bool getIsFarConvex() { return mIsFarConvex; } + +protected: + void clear(); + void finalize(); + void updateBounds(); + void updatePlanes(); + + bool computeVisMeshNeighbors(); + void computeVisTangentsFromPoly(); + bool cutVisMesh(const PxVec3 &localPlaneN, float localPlaneD, bool &cutEmpty); + bool cut(const PxVec3 &localPlaneN, float localPlaneD, bool &cutEmpty, bool setNewFaceFlag = true); + + bool rayCastConvex(const PxVec3 &orig, const PxVec3 &dir, float &dist, PxVec3 &normal) const; + bool rayCastVisMesh(const PxVec3 &orig, const PxVec3 &dir, float &dist, PxVec3 &normal) const; + + SimScene* mScene; + + nvidia::Array<Face> mFaces; + nvidia::Array<int> mIndices; + nvidia::Array<PxVec3> mVertices; + nvidia::Array<PxVec3> mNormals; + nvidia::Array<PxPlane> mPlanes; + + nvidia::Array<PxVec3> mVisVertices; + nvidia::Array<PxVec3> mVisNormals; + nvidia::Array<PxVec3> mVisTangents; + nvidia::Array<float> mVisTexCoords; + nvidia::Array<int> mVisTriIndices; + + int mRefCounter; + bool mHasExplicitVisMesh; + bool mIsGhostConvex; + nvidia::Array<int> mVisPolyStarts; // for explicit mesh only + nvidia::Array<int> mVisPolyIndices; + nvidia::Array<int> mVisPolyNeighbors; + + Convex *mNewConvex; // temporary buffer for cut operations + + Compound *mParent; + PxRigidActor *mPxActor; + PxTransform mLocalPose; + PxConvexMesh *mPxConvexMesh; + + PxBounds3 mBounds; + mutable float mVolume; + mutable bool mVolumeDirty; + PxVec3 mMaterialOffset; + float mTexScale; + int mModelIslandNr; + + // material + bool mUse2dTexture; + bool mIndestructible; + int mMaterialId; + int mSurfaceMaterialId; + + bool mIsFarConvex; + + mutable int mConvexRendererGroupNr; + mutable int mConvexRendererGroupPos; +}; + +} +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.cpp b/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.cpp new file mode 100644 index 00000000..a4aa0f1e --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "Delaunay2dBase.h" +#include "PxBounds3.h" +#include <PxMath.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace nvidia; +// ------------------------------------------------------------------------------------- +Delaunay2d::Delaunay2d(SimScene* scene): + mScene(scene) +{ +} + +// ------------------------------------------------------------------------------------- +Delaunay2d::~Delaunay2d() +{ +} + +// ------------------------------------------------------------------------------------- +void Delaunay2d::clear() +{ + mVertices.clear(); + mIndices.clear(); + mTriangles.clear(); + mFirstFarVertex = 0; + + mConvexVerts.clear(); + mConvexes.clear(); + mConvexNeighbors.clear(); +} + +// ------------------------------------------------------------------------------------- +void Delaunay2d::triangulate(const PxVec3 *vertices, int numVerts, int byteStride, bool removeFarVertices) +{ + clear(); + + uint8_t *vp = (uint8_t*)vertices; + mVertices.resize((uint32_t)numVerts); + for (uint32_t i = 0; i < (uint32_t)numVerts; i++) { + mVertices[i] = (*(PxVec3*)vp); + mVertices[i].z = 0.0f; + vp += byteStride; + } + + delaunayTriangulation(); + + for (uint32_t i = 0; i < mTriangles.size(); i++) { + Triangle &t = mTriangles[i]; + if (!removeFarVertices || (t.p0 < mFirstFarVertex && t.p1 < mFirstFarVertex && t.p2 < mFirstFarVertex)) { + mIndices.pushBack(t.p0); + mIndices.pushBack(t.p1); + mIndices.pushBack(t.p2); + } + } + + if (removeFarVertices) + mVertices.resize((uint32_t)mFirstFarVertex); +} + + +// ------------------------------------------------------------------------------------- +void Delaunay2d::delaunayTriangulation() +{ + PxBounds3 bounds; + bounds.setEmpty(); + + for (uint32_t i = 0; i < mVertices.size(); i++) + bounds.include(mVertices[i]); + + bounds.fattenSafe(bounds.getDimensions().magnitude()); + + // start with two triangles + //float scale = 10.0f; + PxVec3 p0(bounds.minimum.x, bounds.minimum.y, 0.0f); + PxVec3 p1(bounds.maximum.x, bounds.minimum.y, 0.0f); + PxVec3 p2(bounds.maximum.x, bounds.maximum.y, 0.0f); + PxVec3 p3(bounds.minimum.x, bounds.maximum.y, 0.0f); + + mFirstFarVertex = (int32_t)mVertices.size(); + mVertices.pushBack(p0); + mVertices.pushBack(p1); + mVertices.pushBack(p2); + mVertices.pushBack(p3); + + mTriangles.clear(); + addTriangle(mFirstFarVertex, mFirstFarVertex+1, mFirstFarVertex+2); + addTriangle(mFirstFarVertex, mFirstFarVertex+2, mFirstFarVertex+3); + + // insert other points + for (uint32_t i = 0; i < (uint32_t)mFirstFarVertex; i++) { + mEdges.clear(); + uint32_t j = 0; + while (j < mTriangles.size()) { + Triangle &t = mTriangles[j]; + if ((t.center - mVertices[i]).magnitudeSquared() > t.circumRadiusSquared) { + j++; + continue; + } + Edge e0(t.p0, t.p1); + Edge e1(t.p1, t.p2); + Edge e2(t.p2, t.p0); + bool found0 = false; + bool found1 = false; + bool found2 = false; + + uint32_t k = 0; + while (k < mEdges.size()) { + Edge &e = mEdges[k]; + bool found = false; + if (e == e0) { found0 = true; found = true; } + if (e == e1) { found1 = true; found = true; } + if (e == e2) { found2 = true; found = true; } + if (found) { + mEdges[k] = mEdges[mEdges.size()-1]; + mEdges.popBack(); + } + else k++; + } + if (!found0) mEdges.pushBack(e0); + if (!found1) mEdges.pushBack(e1); + if (!found2) mEdges.pushBack(e2); + mTriangles[j] = mTriangles[mTriangles.size()-1]; + mTriangles.popBack(); + } + for (j = 0; j < mEdges.size(); j++) { + Edge &e = mEdges[j]; + addTriangle(e.p0, e.p1, (int32_t)i); + } + } +} + +// ------------------------------------------------------------------------------------- +void Delaunay2d::addTriangle(int p0, int p1, int p2) +{ + Triangle triangle; + triangle.p0 = p0; + triangle.p1 = p1; + triangle.p2 = p2; + getCircumSphere(mVertices[(uint32_t)p0], mVertices[(uint32_t)p1], mVertices[(uint32_t)p2], triangle.center, triangle.circumRadiusSquared); + mTriangles.pushBack(triangle); +} + +// ------------------------------------------------------------------------------------- +void Delaunay2d::getCircumSphere(const PxVec3 &p0, const PxVec3 &p1, const PxVec3 &p2, + PxVec3 ¢er, float &radiusSquared) +{ + float x1 = p1.x - p0.x; + float y1 = p1.y - p0.y; + float x2 = p2.x - p0.x; + float y2 = p2.y - p0.y; + + float det = x1 * y2 - x2 * y1; + if (det == 0.0f) { + center = p0; radiusSquared = 0.0f; + return; + } + det = 0.5f / det; + float len1 = x1*x1 + y1*y1; + float len2 = x2*x2 + y2*y2; + float cx = (len1 * y2 - len2 * y1) * det; + float cy = (len2 * x1 - len1 * x2) * det; + center.x = p0.x + cx; + center.y = p0.y + cy; + center.z = 0.0f; + radiusSquared = cx * cx + cy * cy; +} + +// ------------------------------------------------------------------------------------- +void Delaunay2d::computeVoronoiMesh() +{ + mConvexes.clear(); + mConvexVerts.clear(); + mConvexNeighbors.clear(); + + uint32_t numVerts = mVertices.size(); + uint32_t numTris = mIndices.size() / 3; + + // center positions + nvidia::Array<PxVec3> centers(numTris); + for (uint32_t i = 0; i < numTris; i++) { + PxVec3 &p0 = mVertices[(uint32_t)mIndices[3*i]]; + PxVec3 &p1 = mVertices[(uint32_t)mIndices[3*i+1]]; + PxVec3 &p2 = mVertices[(uint32_t)mIndices[3*i+2]]; + float r2; + getCircumSphere(p0,p1,p2, centers[i], r2); + } + + // vertex -> triangles links + nvidia::Array<int> firstVertTri(numVerts+1, 0); + nvidia::Array<int> vertTris; + + for (uint32_t i = 0; i < numTris; i++) { + firstVertTri[(uint32_t)mIndices[3*i]]++; + firstVertTri[(uint32_t)mIndices[3*i+1]]++; + firstVertTri[(uint32_t)mIndices[3*i+2]]++; + } + + int numLinks = 0; + for (uint32_t i = 0; i < numVerts; i++) { + numLinks += firstVertTri[i]; + firstVertTri[i] = numLinks; + } + firstVertTri[numVerts] = numLinks; + vertTris.resize((uint32_t)numLinks); + + for (uint32_t i = 0; i < numTris; i++) { + uint32_t &i0 = (uint32_t&)firstVertTri[(uint32_t)mIndices[3*i]]; + uint32_t &i1 = (uint32_t&)firstVertTri[(uint32_t)mIndices[3*i+1]]; + uint32_t &i2 = (uint32_t&)firstVertTri[(uint32_t)mIndices[3*i+2]]; + i0--; vertTris[i0] = (int32_t)i; + i1--; vertTris[i1] = (int32_t)i; + i2--; vertTris[i2] = (int32_t)i; + } + + // convexes + Convex c; + nvidia::Array<int> nextVert(numVerts, -1); + nvidia::Array<int> vertVisited(numVerts, -1); + nvidia::Array<int> triOfVert(numVerts, -1); + nvidia::Array<int> convexOfVert(numVerts, -1); + + for (uint32_t i = 0; i < numVerts; i++) { + int first = firstVertTri[i]; + int last = firstVertTri[i+1]; + int num = last - first; + if (num < 3) + continue; + + int start = -1; + + for (int j = first; j < last; j++) { + int triNr = vertTris[(uint32_t)j]; + + int k = 0; + while (k < 3 && mIndices[uint32_t(3*triNr+k)] != (int32_t)i) + k++; + + int j0 = mIndices[uint32_t(3*triNr + (k+1)%3)]; + int j1 = mIndices[uint32_t(3*triNr + (k+2)%3)]; + + if (j == first) + start = j0; + + nextVert[(uint32_t)j0] = j1; + vertVisited[(uint32_t)j0] = 2*(int32_t)i; + triOfVert[(uint32_t)j0] = triNr; + } + + c.firstNeighbor = (int32_t)mConvexNeighbors.size(); + c.firstVert = (int32_t)mConvexVerts.size(); + c.numVerts = num; + bool rollback = false; + int id = start; + do { + if (vertVisited[(uint32_t)id] != 2*(int32_t)i) { + rollback = true; + break; + } + vertVisited[(uint32_t)id] = 2*(int32_t)i+1; + + mConvexVerts.pushBack(centers[(uint32_t)triOfVert[(uint32_t)id]]); + mConvexNeighbors.pushBack(id); + id = nextVert[(uint32_t)id]; + } while (id != start); + + if (rollback) { + mConvexVerts.resize((uint32_t)c.firstVert); + mConvexNeighbors.resize((uint32_t)c.firstNeighbor); + continue; + } + + c.numVerts = (int32_t)mConvexVerts.size() - c.firstVert; + c.numNeighbors = (int32_t)mConvexNeighbors.size() - c.firstNeighbor; + convexOfVert[i] = (int32_t)mConvexes.size(); + mConvexes.pushBack(c); + } + + // compute neighbors + uint32_t newPos = 0; + for (uint32_t i = 0; i < mConvexes.size(); i++) { + Convex &c = mConvexes[i]; + uint32_t pos = (uint32_t)c.firstNeighbor; + uint32_t num = (uint32_t)c.numNeighbors; + c.firstNeighbor = (int32_t)newPos; + c.numNeighbors = 0; + for (uint32_t j = 0; j < num; j++) { + int n = convexOfVert[(uint32_t)mConvexNeighbors[pos+j]]; + if (n >= 0) { + mConvexNeighbors[newPos] = n; + newPos++; + c.numNeighbors++; + } + } + } + mConvexNeighbors.resize(newPos); +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.h b/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.h new file mode 100644 index 00000000..2d477c14 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef DELAUNAY_2D_BASE_H +#define DELAUNAY_2D_BASE_H + +#include <PxVec3.h> +#include <PsArray.h> +#include <PsUserAllocated.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +// ------------------------------------------------------------------------------ + +struct Point; +struct Edge; +struct Triangle; +class SimScene; + +// ------------------------------------------------------------------------------ + +class Delaunay2d : public UserAllocated { + friend class SimScene; +public: + // singleton pattern + //static Delaunay2d* getInstance(); + //static void destroyInstance(); + + void triangulate(const PxVec3 *vertices, int numVerts, int byteStride, bool removeFarVertices = true); + const nvidia::Array<int> getIndices() const { return mIndices; } + + // voronoi mesh, needs triangle mesh + void computeVoronoiMesh(); + + struct Convex { + int firstVert; + int numVerts; + int firstNeighbor; + int numNeighbors; + }; + + const nvidia::Array<Convex> getConvexes() const { return mConvexes; } + const nvidia::Array<PxVec3> getConvexVerts() const { return mConvexVerts; } + const nvidia::Array<int> getConvexNeighbors() const { return mConvexNeighbors; } + +protected: + Delaunay2d(SimScene* scene); + virtual ~Delaunay2d(); + + void clear(); + void delaunayTriangulation(); + + struct Edge { + Edge() {} + Edge(int np0, int np1) { p0 = np0; p1 = np1; } + bool operator == (const Edge &e) { + return (p0 == e.p0 && p1 == e.p1) || (p0 == e.p1 && p1 == e.p0); + } + int p0, p1; + }; + + struct Triangle { + int p0, p1, p2; + PxVec3 center; + float circumRadiusSquared; + }; + + void addTriangle(int p0, int p1, int p2); + void getCircumSphere(const PxVec3 &p0, const PxVec3 &p1, const PxVec3 &p2, + PxVec3 ¢er, float &radiusSquared); + + SimScene* mScene; + + nvidia::Array<PxVec3> mVertices; + nvidia::Array<int> mIndices; + + nvidia::Array<Triangle> mTriangles; + nvidia::Array<Edge> mEdges; + + nvidia::Array<Convex> mConvexes; + nvidia::Array<PxVec3> mConvexVerts; + nvidia::Array<int> mConvexNeighbors; + + int mFirstFarVertex; +}; + +} +} +} + +// ------------------------------------------------------------------------------ + + +#endif +#endif diff --git a/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.cpp b/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.cpp new file mode 100644 index 00000000..4af95e65 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.cpp @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "Delaunay3dBase.h" +#include "PsSort.h" +#include <PxAssert.h> + +#include "PxBounds3.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace nvidia; + +// side orientation points outwards +const int Delaunay3d::Tetra::sideIndices[4][3] = {{1,2,3},{2,0,3},{0,1,3},{2,1,0}}; + +// ------ singleton pattern ----------------------------------------------------------- +// +//static Delaunay3d *gDelaunay3d = NULL; +// +//Delaunay3d* Delaunay3d::getInstance() +//{ +// if (gDelaunay3d == NULL) { +// gDelaunay3d = PX_NEW(Delaunay3d)(); +// } +// return gDelaunay3d; +//} +// +//void Delaunay3d::destroyInstance() +//{ +// if (gDelaunay3d != NULL) { +// PX_DELETE(gDelaunay3d); +// } +// gDelaunay3d = NULL; +//} + +// ----------------------------------------------------------------------------- +void Delaunay3d::tetrahedralize(const PxVec3 *vertices, int numVerts, int byteStride, bool removeExtraVerts) +{ + clear(); + + uint8_t *vp = (uint8_t*)vertices; + for (int i = 0; i < numVerts; i++) { + mVertices.pushBack(*(PxVec3*)vp); + vp += byteStride; + } + + delaunayTetrahedralization(); + + compressTetrahedra(removeExtraVerts); + if (removeExtraVerts) { + mVertices.resize((uint32_t)mFirstFarVertex); + } + + for (uint32_t i = 0; i < mTetras.size(); i++) { + Tetra &t = mTetras[i]; + mIndices.pushBack(t.ids[0]); + mIndices.pushBack(t.ids[1]); + mIndices.pushBack(t.ids[2]); + mIndices.pushBack(t.ids[3]); + } +} + +// ----------------------------------------------------------------------------- +void Delaunay3d::clear() +{ + mVertices.clear(); + mIndices.clear(); + mTetras.clear(); + mFirstFarVertex = 0; + mLastFarVertex = 0; + + mGeom.clear(); + + mTetMarked.clear(); + mTetMark = 0; +} + +// ----------------------------------------------------------------------------- +void Delaunay3d::delaunayTetrahedralization() +{ + int i,j; + + nvidia::Array<Edge> edges; + Edge edge; + + PxBounds3 bounds; + bounds.setEmpty(); + for (uint32_t i = 0; i < mVertices.size(); i++) + bounds.include(mVertices[i]); + + // start with large tetrahedron + mTetras.clear(); + float a = 3.0f * bounds.getDimensions().magnitude(); + float x = 0.5f * a; + float y0 = x / sqrtf(3.0f); + float y1 = x * sqrtf(3.0f) - y0; + float z0 = 0.25f * sqrtf(6.0f) * a; + float z1 = a * sqrtf(6.0f) / 3.0f - z0; + + PxVec3 center = bounds.getCenter(); + + mFirstFarVertex = (int32_t)mVertices.size(); + PxVec3 p0(-x,-y0,-z1); mVertices.pushBack(center + p0); + PxVec3 p1( x,-y0,-z1); mVertices.pushBack(center + p1); + PxVec3 p2( 0, y1,-z1); mVertices.pushBack(center + p2); + PxVec3 p3( 0, 0, z0); mVertices.pushBack(center + p3); + mLastFarVertex = (int32_t)mVertices.size()-1; + + Tetra tetra; + tetra.init(mFirstFarVertex, mFirstFarVertex+1, mFirstFarVertex+2, mFirstFarVertex+3); + mTetras.pushBack(tetra); + + // build Delaunay triangulation iteratively + + int lastVertex = (int)mVertices.size()-4; + for (i = 0; i < lastVertex; i++) { + PxVec3 &v = mVertices[(uint32_t)i]; + + int tNr = findSurroundingTetra((int32_t)mTetras.size()-1, v); // fast walk + if (tNr < 0) + continue; + // assert(tNr >= 0); + + int newTetraNr = (int32_t)mTetras.size(); + retriangulate(tNr, i); + edges.clear(); + for (j = newTetraNr; j < (int)mTetras.size(); j++) { + Tetra &newTet = mTetras[(uint32_t)j]; + edge.init(newTet.ids[2], newTet.ids[3], j,1); + edges.pushBack(edge); + edge.init(newTet.ids[3], newTet.ids[1], j,2); + edges.pushBack(edge); + edge.init(newTet.ids[1], newTet.ids[2], j,3); + edges.pushBack(edge); + } + shdfnd::sort(edges.begin(), edges.size()); + for (j = 0; j < (int)edges.size(); j += 2) { + Edge &edge0 = edges[(uint32_t)j]; + Edge &edge1 = edges[(uint32_t)j+1]; + PX_ASSERT(edge0 == edge1); + mTetras[(uint32_t)edge0.tetraNr].neighborNrs[(uint32_t)edge0.neighborNr] = edge1.tetraNr; + mTetras[(uint32_t)edge1.tetraNr].neighborNrs[(uint32_t)edge1.neighborNr] = edge0.tetraNr; + } + } +} + +// ----------------------------------------------------------------------------- +int Delaunay3d::findSurroundingTetra(int startTetra, const PxVec3 &p) const +{ + // find the tetrahedra which contains the vertex + // by walking through mesh O(n ^ (1/3)) + + mTetMark++; + + if (mTetras.size() == 0) return -1; + int tetNr = startTetra; + PX_ASSERT(!mTetras[(uint32_t)startTetra].deleted); + + if (mTetMarked.size() < mTetras.size()) + mTetMarked.resize(mTetras.size(), -1); + + bool loop = false; + + while (tetNr >= 0) { + if (mTetMarked[(uint32_t)tetNr] == mTetMark) { + loop = true; + break; + } + mTetMarked[(uint32_t)tetNr] = mTetMark; + + const Tetra &tetra = mTetras[(uint32_t)tetNr]; + const PxVec3 &p0 = mVertices[(uint32_t)tetra.ids[0]]; + PxVec3 q = p-p0; + PxVec3 q0 = mVertices[(uint32_t)tetra.ids[1]] - p0; + PxVec3 q1 = mVertices[(uint32_t)tetra.ids[2]] - p0; + PxVec3 q2 = mVertices[(uint32_t)tetra.ids[3]] - p0; + PxMat33 m; + m.column0 = q0; + m.column1 = q1; + m.column2 = q2; + float det = m.getDeterminant(); + m.column0 = q; + float x = m.getDeterminant(); + if (x < 0.0f && tetra.neighborNrs[1] >= 0) { + tetNr = tetra.neighborNrs[1]; + continue; + } + m.column0 = q0; m.column1 = q; + float y = m.getDeterminant(); + if (y < 0.0f && tetra.neighborNrs[2] >= 0) { + tetNr = tetra.neighborNrs[2]; + continue; + } + m.column1 = q1; m.column2 = q; + float z = m.getDeterminant(); + if (z < 0.0f && tetra.neighborNrs[3] >= 0) { + tetNr = tetra.neighborNrs[3]; + continue; + } + if (x + y + z > det && tetra.neighborNrs[0] >= 0) { + tetNr = tetra.neighborNrs[0]; + continue; + } + return tetNr; + } + if (loop) { // search failed, brute force: + for (uint32_t i = 0; i < mTetras.size(); i++) { + const Tetra &tetra = mTetras[i]; + if (tetra.deleted) + continue; + + const PxVec3 &p0 = mVertices[(uint32_t)tetra.ids[0]]; + const PxVec3 &p1 = mVertices[(uint32_t)tetra.ids[1]]; + const PxVec3 &p2 = mVertices[(uint32_t)tetra.ids[2]]; + const PxVec3 &p3 = mVertices[(uint32_t)tetra.ids[3]]; + + PxVec3 n; + n = (p1-p0).cross(p2-p0); + if (n.dot(p) < n.dot(p0)) continue; + n = (p2-p0).cross(p3-p0); + if (n.dot(p) < n.dot(p0)) continue; + n = (p3-p0).cross(p1-p0); + if (n.dot(p) < n.dot(p0)) continue; + n = (p3-p1).cross(p2-p1); + if (n.dot(p) < n.dot(p1)) continue; + return (int32_t)i; + } + return -1; + } + else + return -1; +} + +// ----------------------------------------------------------------------------- +void Delaunay3d::updateCircumSphere(Tetra &tetra) +{ + if (!tetra.circumsphereDirty) + return; + PxVec3 p0 = mVertices[(uint32_t)tetra.ids[0]]; + PxVec3 b = mVertices[(uint32_t)tetra.ids[1]] - p0; + PxVec3 c = mVertices[(uint32_t)tetra.ids[2]] - p0; + PxVec3 d = mVertices[(uint32_t)tetra.ids[3]] - p0; + float det = b.x*(c.y*d.z - c.z*d.y) - b.y*(c.x*d.z - c.z*d.x) + b.z*(c.x*d.y-c.y*d.x); + if (det == 0.0f) { + tetra.center = p0; tetra.radiusSquared = 0.0f; + return; // singular case + } + det *= 2.0f; + PxVec3 v = c.cross(d)*b.dot(b) + d.cross(b)*c.dot(c) + b.cross(c)*d.dot(d); + v /= det; + tetra.radiusSquared = v.magnitudeSquared(); + tetra.center = p0 + v; + tetra.circumsphereDirty = false; +} + +// ----------------------------------------------------------------------------- +bool Delaunay3d::pointInCircumSphere(Tetra &tetra, const PxVec3 &p) +{ + updateCircumSphere(tetra); + return (tetra.center - p).magnitudeSquared() < tetra.radiusSquared; +} + +// ----------------------------------------------------------------------------- +void Delaunay3d::retriangulate(int tetraNr, int vertNr) +{ + Tetra &tetra = mTetras[(uint32_t)tetraNr]; + if (tetra.deleted) return; + Tetra tNew; + PxVec3 &v = mVertices[(uint32_t)vertNr]; + tetra.deleted = true; + for (uint32_t i = 0; i < 4; i++) { + int n = mTetras[(uint32_t)tetraNr].neighborNrs[i]; + if (n >= 0 && mTetras[(uint32_t)n].deleted) + continue; + if (n >= 0 && pointInCircumSphere(mTetras[(uint32_t)n],v)) + retriangulate(n, vertNr); + else { + Tetra &t = mTetras[(uint32_t)tetraNr]; + tNew.init(vertNr, + t.ids[(uint32_t)Tetra::sideIndices[i][0]], + t.ids[(uint32_t)Tetra::sideIndices[i][1]], + t.ids[(uint32_t)Tetra::sideIndices[i][2]] + ); + tNew.neighborNrs[0] = n; + if (n >= 0) { + mTetras[(uint32_t)n].neighborOf( + tNew.ids[1], tNew.ids[2], tNew.ids[3]) + = (int32_t)mTetras.size(); + } + mTetras.pushBack(tNew); + } + } +} + +// ---------------------------------------------------------------------- +void Delaunay3d::compressTetrahedra(bool removeExtraVerts) +{ + nvidia::Array<int> oldToNew(mTetras.size(), -1); + + uint32_t num = 0; + for (uint32_t i = 0; i < mTetras.size(); i++) { + Tetra &t = mTetras[i]; + + if (removeExtraVerts) { + if (t.ids[0] >= mFirstFarVertex || + t.ids[1] >= mFirstFarVertex || + t.ids[2] >= mFirstFarVertex || + t.ids[3] >= mFirstFarVertex) + continue; + } + + if (t.deleted) + continue; + + oldToNew[i] = (int32_t)num; + mTetras[num] = t; + num++; + } + mTetras.resize(num); + + for (uint32_t i = 0; i < num; i++) { + Tetra &t = mTetras[i]; + for (uint32_t j = 0; j < 4; j++) { + if (t.neighborNrs[j] >= 0) + t.neighborNrs[j] = oldToNew[(uint32_t)t.neighborNrs[j]]; + } + } +} + +// ---------------------------------------------------------------------- +void Delaunay3d::computeVoronoiMesh() +{ + mGeom.clear(); + + if (mTetras.empty()) + return; + + // vertex -> tetras links + uint32_t numVerts = mVertices.size(); + + nvidia::Array<int> firstVertTet(numVerts+1, 0); + nvidia::Array<int> vertTets; + + nvidia::Array<int> tetMarks(mTetras.size(), -1); + int tetMark = 0; + + for (uint32_t i = 0; i < mTetras.size(); i++) { + Tetra &t = mTetras[i]; + firstVertTet[(uint32_t)t.ids[0]]++; + firstVertTet[(uint32_t)t.ids[1]]++; + firstVertTet[(uint32_t)t.ids[2]]++; + firstVertTet[(uint32_t)t.ids[3]]++; + } + + int numLinks = 0; + for (uint32_t i = 0; i < numVerts; i++) { + numLinks += firstVertTet[i]; + firstVertTet[i] = numLinks; + } + firstVertTet[numVerts] = numLinks; + vertTets.resize((uint32_t)numLinks); + + for (uint32_t i = 0; i < mTetras.size(); i++) { + Tetra &t = mTetras[i]; + uint32_t &i0 = (uint32_t&)firstVertTet[(uint32_t)t.ids[0]]; + uint32_t &i1 = (uint32_t&)firstVertTet[(uint32_t)t.ids[1]]; + uint32_t &i2 = (uint32_t&)firstVertTet[(uint32_t)t.ids[2]]; + uint32_t &i3 = (uint32_t&)firstVertTet[(uint32_t)t.ids[3]]; + i0--; vertTets[i0] = (int32_t)i; + i1--; vertTets[i1] = (int32_t)i; + i2--; vertTets[i2] = (int32_t)i; + i3--; vertTets[i3] = (int32_t)i; + } + + nvidia::Array<int> convexOfFace(numVerts, -1); + nvidia::Array<int> vertOfTet(mTetras.size(), -1); + nvidia::Array<int> convexOfVert(numVerts, -1); + + for (uint32_t i = 0; i < numVerts; i++) { + int i0 = (int32_t)i; + + int firstTet = firstVertTet[i]; + int lastTet = firstVertTet[i+1]; + + // debug + //bool ok = true; + //for (int j = firstTet; j < lastTet; j++) { + // int tetNr = vertTets[j]; + // Tetra &t = mTetras[tetNr]; + // int num = 0; + // for (int k = 0; k < 4; k++) { + // int n = t.neighborNrs[k]; + // bool in = false; + // for (int l = firstTet; l < lastTet; l++) { + // if (vertTets[l] == n) + // in = true; + // } + // if (in) + // num++; + // } + // if (num != 3) + // ok = false; + //} + //if (ok) + // int foo = 0; + + + // new convex + int convexNr = (int32_t)i; + CompoundGeometry::Convex c; + mGeom.initConvex(c); + c.numVerts = lastTet - firstTet; + + bool rollBack = false; + + // create vertices + for (int j = firstTet; j < lastTet; j++) { + int tetNr = vertTets[(uint32_t)j]; + vertOfTet[(uint32_t)tetNr] = j - firstTet; + updateCircumSphere(mTetras[(uint32_t)tetNr]); + mGeom.vertices.pushBack(mTetras[(uint32_t)tetNr].center); + } + + // create indices + for (int j = firstTet; j < lastTet; j++) { + int tetNr = vertTets[(uint32_t)j]; + Tetra &t = mTetras[(uint32_t)tetNr]; + + for (uint32_t k = 0; k < 4; k++) { + int i1 = t.ids[k]; + if (i1 == i0) + continue; + if (convexOfFace[(uint32_t)i1] == convexNr) + continue; + convexOfFace[(uint32_t)i1] = convexNr; + mGeom.neighbors.pushBack(i1); + c.numNeighbors++; + + // new face + c.numFaces++; + int faceStart = (int32_t)mGeom.indices.size(); + mGeom.indices.pushBack(0); + mGeom.indices.pushBack(0); // face attrib + + int faceSize = 0; + int currNr = tetNr; + int prevNr = -1; + tetMark++; + + do { + mGeom.indices.pushBack(vertOfTet[(uint32_t)currNr]); + faceSize++; + + if (tetMarks[(uint32_t)currNr] == tetMark) { // safety + rollBack = true; + break; + } + tetMarks[(uint32_t)currNr] = tetMark; + + // find proper neighbor tet + int nextTet = -1; + for (uint32_t l = 0; l < 4; l++) { + int nr = mTetras[(uint32_t)currNr].neighborNrs[l]; + if (nr < 0) + continue; + if (nr == prevNr) + continue; + + Tetra &tn = mTetras[(uint32_t)nr]; + bool hasEdge = + (tn.ids[0] == i0 || tn.ids[1] == i0 || tn.ids[2] == i0 || tn.ids[3] == i0) && + (tn.ids[0] == i1 || tn.ids[1] == i1 || tn.ids[2] == i1 || tn.ids[3] == i1); + if (!hasEdge) + continue; + + //if (prevNr < 0) { // correct winding + // if ((t.center - faceC).cross(tn.center - faceC).dot(faceN) < 0.0f) + // continue; + //} + nextTet = nr; + break; + } + + if (nextTet < 0) { // not proper convex, roll back + rollBack = true; + break; + } + + prevNr = currNr; + currNr = nextTet; + + } while (currNr != tetNr); + + if (rollBack) + break; + + mGeom.indices[(uint32_t)faceStart] = faceSize; + } + if (rollBack) + break; + } + if (rollBack) { + mGeom.indices.resize((uint32_t)c.firstIndex); + mGeom.vertices.resize((uint32_t)c.firstVert); + } + else { + convexOfVert[(uint32_t)i] = (int32_t)mGeom.convexes.size(); + mGeom.convexes.pushBack(c); + } + } + + // fix face orientations + for (uint32_t i = 0; i < mGeom.convexes.size(); i++) { + CompoundGeometry::Convex &c = mGeom.convexes[i]; + int *ids = &mGeom.indices[(uint32_t)c.firstIndex]; + PxVec3 *vertices = &mGeom.vertices[(uint32_t)c.firstVert]; + PxVec3 cc(0.0f, 0.0f, 0.0f); + for (uint32_t j = 0; j < (uint32_t)c.numVerts; j++) + cc += vertices[j]; + cc /= (float)c.numVerts; + + uint32_t *faceIds = (uint32_t*)ids; + for (int j = 0; j < c.numFaces; j++) { + uint32_t faceSize = *faceIds++; + faceIds++; //int faceAttr = *faceIds++; + PxVec3 fc(0.0f, 0.0f, 0.0f); + for (uint32_t k = 0; k < faceSize; k++) + fc += vertices[faceIds[k]]; + fc /= (float)faceSize; + PxVec3 n = fc - cc; + if ((vertices[faceIds[1]] - vertices[faceIds[0]]).cross(vertices[faceIds[2]] - vertices[faceIds[0]]).dot(n) < 0.0f) { + for (uint32_t k = 0; k < faceSize/2; k++) { + uint32_t d = faceIds[k]; faceIds[k] = faceIds[faceSize-1-k]; faceIds[faceSize-1-k] = d; + } + } + faceIds += faceSize; + } + } + + // fix neighbors + for (uint32_t i = 0; i < mGeom.neighbors.size(); i++) { + if (mGeom.neighbors[i] >= 0) + mGeom.neighbors[i] = convexOfVert[(uint32_t)mGeom.neighbors[i]]; + } +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.h b/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.h new file mode 100644 index 00000000..9ffaaa3a --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef DELAUNAY_3D_BASE_H +#define DELAUNAY_3D_BASE_H + +// Matthias Muller-Fischer + +#include <PxVec3.h> +#include <PsArray.h> +#include <PsUserAllocated.h> + +using namespace nvidia; + +#include "CompoundGeometryBase.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + class SimScene; + +// --------------------------------------------------------------------------------------- +class Delaunay3d : public UserAllocated { + friend class SimScene; +public: + // singleton pattern + //static Delaunay3d* getInstance(); + //static void destroyInstance(); + + // tetra mesh + void tetrahedralize(const PxVec3 *vertices, int numVerts, int byteStride, bool removeExtraVerts = true); + const nvidia::Array<int> getTetras() const { return mIndices; } + + // voronoi mesh, needs tetra mesh + void computeVoronoiMesh(); + + const CompoundGeometry &getGeometry() { return mGeom; } + +protected: + Delaunay3d(SimScene* scene): mScene(scene) {} + virtual ~Delaunay3d() {} + + // ------------------------------------------------------ + struct Edge + { + void init(int i0, int i1, int tetraNr, int neighborNr = -1) { + this->tetraNr = tetraNr; + this->neighborNr = neighborNr; + if (i0 > i1) { this->i0 = i0; this->i1 = i1; } + else { this->i0 = i1; this->i1 = i0; } + } + bool operator <(const Edge &e) const { + if (i0 < e.i0) return true; + if (i0 > e.i0) return false; + if (i1 < e.i1) return true; + if (i1 > e.i1) return false; + return (neighborNr < e.neighborNr); + } + bool operator ==(Edge &e) const { + return i0 == e.i0 && i1 == e.i1; + } + int i0, i1; + int tetraNr; + int neighborNr; + }; + + // ------------------------------------------------------ + struct Tetra + { + void init(int i0, int i1, int i2, int i3) { + ids[0] = i0; ids[1] = i1; ids[2] = i2; ids[3] = i3; + neighborNrs[0] = neighborNrs[1] = neighborNrs[2] = neighborNrs[3] = -1; + circumsphereDirty = true; + center = PxVec3(0.0f, 0.0f, 0.0f); + radiusSquared = 0.0f; + deleted = false; + } + inline int& neighborOf(int i0, int i1, int i2) { + if (ids[0] != i0 && ids[0] != i1 && ids[0] != i2) return neighborNrs[0]; + if (ids[1] != i0 && ids[1] != i1 && ids[1] != i2) return neighborNrs[1]; + if (ids[2] != i0 && ids[2] != i1 && ids[2] != i2) return neighborNrs[2]; + if (ids[3] != i0 && ids[3] != i1 && ids[3] != i2) return neighborNrs[3]; + return neighborNrs[0]; + } + + int ids[4]; + int neighborNrs[4]; + bool circumsphereDirty; + PxVec3 center; + float radiusSquared; + bool deleted; + + static const int sideIndices[4][3]; + }; + + // ------------------------------------------------------ + void clear(); + void delaunayTetrahedralization(); + + int findSurroundingTetra(int startTetra, const PxVec3 &p) const; + void updateCircumSphere(Tetra &tetra); + bool pointInCircumSphere(Tetra &tetra, const PxVec3 &p); + void retriangulate(int tetraNr, int vertNr); + void compressTetrahedra(bool removeExtraVerts); + + SimScene* mScene; + + int mFirstFarVertex; + int mLastFarVertex; + nvidia::Array<PxVec3> mVertices; + nvidia::Array<Tetra> mTetras; + nvidia::Array<int> mIndices; + + CompoundGeometry mGeom; + + mutable nvidia::Array<int> mTetMarked; + mutable int mTetMark; + +}; + +} +} +} + +#endif +#endif diff --git a/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.cpp b/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.cpp new file mode 100644 index 00000000..f4a87b27 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.cpp @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "PxMath.h" +#include "PxMat44.h" +#include "PsMathUtils.h" + +#include "FracturePatternBase.h" +#include "ConvexBase.h" +#include "CompoundBase.h" +#include "MeshClipperBase.h" +#include "IslandDetectorBase.h" +#include "SimSceneBase.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace nvidia; + +#define HIDE_INVISIBLE_FACES 1 + +// -------------------------------------------------------------------------------------------- +FracturePattern::FracturePattern(SimScene* scene): + mScene(scene) +{ +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::clear() +{ + mGeom.clear(); + mFirstConvexOfCell.clear(); +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::finalize() +{ + mFirstPiece.resize(mGeom.convexes.size(), -1); + mSplitPiece.resize(mGeom.convexes.size(), false); + mPieces.clear(); + + // compute volumes of convexes + mConvexVolumes.resize(mGeom.convexes.size(), 0.0f); + Convex* c = mScene->createConvex(); + for (uint32_t i = 0; i < mGeom.convexes.size(); i++) { + c->createFromGeometry(mGeom, (int32_t)i); + mConvexVolumes[i] = c->getVolume(); + } + mGeom.derivePlanes(); + PX_DELETE(c); +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::create3dVoronoi(const PxVec3 &dims, int numCells, float biasExp, float maxDist) +{ + using namespace physx::shdfnd; + clear(); + nvidia::Array<PxVec3> points((uint32_t)numCells); + float r = PxPow(dims.magnitude(), 1.0f/biasExp); + float max2 = maxDist * maxDist; + + mBounds.minimum = -dims; + mBounds.maximum = dims; + + for (int i = 0; i < numCells; i++) { + PxVec3 &p = points[(uint32_t)i]; + do { + p = PxVec3(rand(-r,r), rand(-r,r), rand(-r,r)); + float len = p.normalize(); + p *= PxPow(len, biasExp); + } while (!mBounds.contains(p) || (maxDist < PX_MAX_F32 && p.magnitudeSquared() > max2)); + } + // avoid numerical problems with flat quads! + float eps = 0.001f * mBounds.getDimensions().magnitude(); + points.pushBack(PxVec3(-dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps))); + points.pushBack(PxVec3( dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps))); + points.pushBack(PxVec3( dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps))); + points.pushBack(PxVec3(-dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps))); + points.pushBack(PxVec3(-dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), dims.z + rand(-eps, eps))); + points.pushBack(PxVec3( dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), dims.z + rand(-eps, eps))); + points.pushBack(PxVec3( dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), dims.z + rand(-eps, eps))); + points.pushBack(PxVec3(-dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), dims.z + rand(-eps, eps))); + + Delaunay3d *d = mScene->getDelaunay3d(); + d->tetrahedralize(&points[0], (int32_t)points.size(), sizeof(PxVec3), true); + d->computeVoronoiMesh(); + mGeom = d->getGeometry(); + + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::createLocal3dVoronoi(const PxVec3 &dims, int numCells, float radius) +{ + using namespace physx::shdfnd; + + clear(); + nvidia::Array<PxVec3> points((uint32_t)numCells); + float r = radius; + float r2 = r*r; + + mBounds.minimum = -dims; + mBounds.maximum = dims; + + for (int i = 0; i < numCells; i++) { + PxVec3 &p = points[(uint32_t)i]; + do { + p = PxVec3(rand(-r,r), rand(-r,r), rand(-r,r)); + } while (!mBounds.contains(p) || p.magnitudeSquared() > r2); + } + // avoid numerical problems with flat quads! + float eps = 0.001f * mBounds.getDimensions().magnitude(); + points.pushBack(PxVec3(-dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps))); + points.pushBack(PxVec3( dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps))); + points.pushBack(PxVec3( dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps))); + points.pushBack(PxVec3(-dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps))); + points.pushBack(PxVec3(-dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), dims.z + rand(-eps, eps))); + points.pushBack(PxVec3( dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), dims.z + rand(-eps, eps))); + points.pushBack(PxVec3( dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), dims.z + rand(-eps, eps))); + points.pushBack(PxVec3(-dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), dims.z + rand(-eps, eps))); + + Delaunay3d *d = mScene->getDelaunay3d(); + d->tetrahedralize(&points[0], (int32_t)points.size(), sizeof(PxVec3), true); + d->computeVoronoiMesh(); + mGeom = d->getGeometry(); + + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::createRegular3dVoronoi(const PxVec3 &dims, float pieceSize, float relRandOffset) +{ + clear(); + mBounds.minimum= -dims; + mBounds.maximum= dims; + nvidia::Array<PxVec3> points; + + float rel = relRandOffset; + if (rel < 1e-4f) + rel = 1e-4f; // avoid singular cases + + float off = rel * pieceSize; + + int numX = (int)(2.0f*dims.x / pieceSize) + 1; + int numY = (int)(2.0f*dims.y / pieceSize) + 1; + int numZ = (int)(2.0f*dims.z / pieceSize) + 1; + + for (int xi = 0; xi < numX; xi++) { + for (int yi = 0; yi < numY; yi++) { + for (int zi = 0; zi < numZ; zi++) { + points.pushBack(PxVec3( + mBounds.minimum.x + xi * pieceSize + physx::shdfnd::rand(-off, off), + mBounds.minimum.y + yi * pieceSize + physx::shdfnd::rand(-off, off), + mBounds.minimum.z + zi * pieceSize + physx::shdfnd::rand(-off, off))); + } + } + } + + Delaunay3d *d = mScene->getDelaunay3d(); + d->tetrahedralize(&points[0], (int32_t)points.size(), sizeof(PxVec3), true); + d->computeVoronoiMesh(); + mGeom = d->getGeometry(); + + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::addBox(const PxBounds3 &bounds) +{ + static int boxFaces[6][4] = {{0,1,5,4}, {1,2,6,5}, {2,3,7,6}, {3,0,4,7}, {0,3,2,1}, {4,5,6,7}}; + CompoundGeometry::Convex c; + mGeom.initConvex(c); + + c.numVerts = 8; + mGeom.vertices.pushBack(PxVec3(bounds.minimum.x, bounds.minimum.y, bounds.minimum.z)); + mGeom.vertices.pushBack(PxVec3(bounds.maximum.x, bounds.minimum.y, bounds.minimum.z)); + mGeom.vertices.pushBack(PxVec3(bounds.maximum.x, bounds.maximum.y, bounds.minimum.z)); + mGeom.vertices.pushBack(PxVec3(bounds.minimum.x, bounds.maximum.y, bounds.minimum.z)); + mGeom.vertices.pushBack(PxVec3(bounds.minimum.x, bounds.minimum.y, bounds.maximum.z)); + mGeom.vertices.pushBack(PxVec3(bounds.maximum.x, bounds.minimum.y, bounds.maximum.z)); + mGeom.vertices.pushBack(PxVec3(bounds.maximum.x, bounds.maximum.y, bounds.maximum.z)); + mGeom.vertices.pushBack(PxVec3(bounds.minimum.x, bounds.maximum.y, bounds.maximum.z)); + + c.numFaces = 6; + for (int i = 0; i < 6; i++) { + mGeom.indices.pushBack(4); // size + mGeom.indices.pushBack(0); // flags + for (int j = 0; j < 4; j++) + mGeom.indices.pushBack(boxFaces[i][j]); + } + mGeom.convexes.pushBack(c); +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::createCrack(const PxVec3 &dims, float spacing, float zRand) +{ + clear(); + + float minZ = -1.2f * zRand; + float maxZ = 1.2f * zRand; + + PxBounds3 bounds; + bounds.minimum = PxVec3(-dims.x, -dims.y, -dims.z); + bounds.maximum = PxVec3( dims.x, dims.y, minZ); + addBox(bounds); + + nvidia::Array<PxVec3> points; + + mBounds.minimum = -dims; + mBounds.maximum = dims; + + float area = 4.0f * dims.x * dims.y; + int numCells = (int)(area / (spacing * spacing)); + + for (int i = 0; i < numCells; i++) { + PxVec3 p = PxVec3(physx::shdfnd::rand(-dims.x, dims.x), physx::shdfnd::rand(-dims.y,dims.y), 0.0f); + points.pushBack(p); + } + + Delaunay2d *d = mScene->getDelaunay2d(); + d->triangulate(&points[0], (int32_t)points.size(), sizeof(PxVec3), true); + d->computeVoronoiMesh(); + + // convert to 3d + const nvidia::Array<Delaunay2d::Convex> &convexes = d->getConvexes(); + nvidia::Array<PxVec3> verts = d->getConvexVerts(); + for (uint32_t i = 0; i < verts.size(); i++) + verts[i].z += physx::shdfnd::rand(-zRand, zRand); + + int numConvexes = (int32_t)convexes.size(); + + const nvidia::Array<int> &neighbors = d->getConvexNeighbors(); + + for (int side = 0; side < 2; side++) { + for (uint32_t i = 0; i < convexes.size(); i++) { + const Delaunay2d::Convex &c2 = convexes[i]; + + CompoundGeometry::Convex c3; + mGeom.initConvex(c3); + + // neighbors + c3.numNeighbors = c2.numNeighbors + 2; + for (int j = 0; j < c2.numNeighbors; j++) { + int n = neighbors[uint32_t(c2.firstNeighbor + j)] + 1; + if (side == 0) + mGeom.neighbors.pushBack(n); + else + mGeom.neighbors.pushBack(numConvexes + n); + } + if (side == 0) { + mGeom.neighbors.pushBack(1 + numConvexes + (int32_t)i); + mGeom.neighbors.pushBack(0); + } + else { + mGeom.neighbors.pushBack(1 + (int32_t)i); + mGeom.neighbors.pushBack(1 + 2*numConvexes); + } + + // vertices + c3.numVerts = 2 * c2.numVerts; + for (int j = 0; j < c2.numVerts; j++) { + PxVec3 p = verts[uint32_t(c2.firstVert+j)]; + if (side == 0) { + mGeom.vertices.pushBack(PxVec3(p.x, p.y, minZ)); + mGeom.vertices.pushBack(p); + } + else { + mGeom.vertices.pushBack(p); + mGeom.vertices.pushBack(PxVec3(p.x, p.y, maxZ)); + } + } + + // faces + c3.numFaces = c2.numVerts + 2; + mGeom.indices.pushBack(c2.numVerts); + mGeom.indices.pushBack(0); // flags + for (int j = 0; j < c2.numVerts; j++) + mGeom.indices.pushBack(2*j+1); + mGeom.indices.pushBack(c2.numVerts); + mGeom.indices.pushBack(0); // flags + for (int j = c2.numVerts-1; j >= 0; j--) + mGeom.indices.pushBack(2*j); + for (int j = 0; j < c2.numVerts; j++) { + mGeom.indices.pushBack(4); // size + mGeom.indices.pushBack(0); // flags + int k = (j+1)%c2.numVerts; + mGeom.indices.pushBack(2*j); + mGeom.indices.pushBack(2*k); + mGeom.indices.pushBack(2*k+1); + mGeom.indices.pushBack(2*j+1); + } + + mGeom.convexes.pushBack(c3); + } + } + + bounds.minimum = PxVec3(-dims.x, -dims.y, maxZ); + bounds.maximum = PxVec3( dims.x, dims.y, dims.z); + addBox(bounds); + + // two cells + mFirstConvexOfCell.pushBack(0); + mFirstConvexOfCell.pushBack(1 + numConvexes); + mFirstConvexOfCell.pushBack(1 + 2*numConvexes + 1); + + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::create2dVoronoi(const PxVec3 &dims, int numCells, float biasExp, int numRays) +{ + clear(); + nvidia::Array<PxVec3> points; + float r0 = dims.magnitude(); + float r = physx::shdfnd::pow(r0, 1.0f/biasExp); + + mBounds.minimum= -dims; + mBounds.maximum= dims; + + if (numRays == 0) { + for (int i = 0; i < numCells; i++) { + PxVec3 p; + do { + p = PxVec3(physx::shdfnd::rand(-r,r), physx::shdfnd::rand(-r,r), 0.0f); + float len = p.normalize(); + p *= physx::shdfnd::pow(len, biasExp); + } while (!mBounds.contains(p)); + points.pushBack(p); + } + } + else { + float diag = mBounds.getDimensions().magnitude(); + float eps = 0.0025f * diag; + + int cellsPerRay = numCells / numRays + 1; + float dr = 0.05f * diag / cellsPerRay; + float dphi = PxTwoPi / numRays; + + for (int i = 0; i < numRays; i++) { + float phi = i * dphi; + PxVec3 n(PxCos(phi), PxSin(phi), 0.0f); + + for (int j = 0; j < cellsPerRay; j++) { + float rj = dr * physx::shdfnd::pow((float)(j+1), biasExp); + PxVec3 p = n * rj; + p.x += physx::shdfnd::rand(-rj * eps, rj * eps); + p.y += physx::shdfnd::rand(-rj * eps, rj * eps); + if (!mBounds.contains(p)) + break; + points.pushBack(p); + } + } + } + + float s = 1.2f; + points.pushBack(PxVec3(-s*dims.x, -s*dims.y, 0.0f)); + points.pushBack(PxVec3( s*dims.x, -s*dims.y, 0.0f)); + points.pushBack(PxVec3( s*dims.x, s*dims.y, 0.0f)); + points.pushBack(PxVec3(-s*dims.x, s*dims.y, 0.0f)); + + Delaunay2d *d = mScene->getDelaunay2d(); + d->triangulate(&points[0], (int32_t)points.size(), sizeof(PxVec3), true); + d->computeVoronoiMesh(); + + // convert to 3d + const nvidia::Array<Delaunay2d::Convex> &convexes = d->getConvexes(); + const nvidia::Array<PxVec3> &verts = d->getConvexVerts(); + mGeom.neighbors = d->getConvexNeighbors(); + + mGeom.convexes.resize(convexes.size()); + for (uint32_t i = 0; i < convexes.size(); i++) { + CompoundGeometry::Convex &c3 = mGeom.convexes[i]; + const Delaunay2d::Convex &c2 = convexes[i]; + + c3.firstNeighbor = c2.firstNeighbor; + c3.numNeighbors = c2.numNeighbors; + + c3.firstVert = (int32_t)mGeom.vertices.size(); + c3.numVerts = 2 * c2.numVerts; + for (int j = 0; j < c2.numVerts; j++) { + PxVec3 p = verts[uint32_t(c2.firstVert+j)]; + p.z = mBounds.minimum.z; + mGeom.vertices.pushBack(p); + p.z = mBounds.maximum.z; + mGeom.vertices.pushBack(p); + } + + c3.firstIndex = (int32_t)mGeom.indices.size(); + c3.numFaces = c2.numVerts + 2; + mGeom.indices.pushBack(c2.numVerts); + mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE); + for (int j = 0; j < c2.numVerts; j++) + mGeom.indices.pushBack(2*j+1); + mGeom.indices.pushBack(c2.numVerts); + mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE); + for (int j = c2.numVerts-1; j >= 0; j--) + mGeom.indices.pushBack(2*j); + for (int j = 0; j < c2.numVerts; j++) { + mGeom.indices.pushBack(4); + mGeom.indices.pushBack(0); + int k = (j+1)%c2.numVerts; + mGeom.indices.pushBack(2*j); + mGeom.indices.pushBack(2*k); + mGeom.indices.pushBack(2*k+1); + mGeom.indices.pushBack(2*j+1); + } + } + + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::createGlass(float radius, float thickness, int numSectors, float sectorRand, float firstSegmentSize, float segmentScale, float segmentRand) +{ + clear(); + CompoundGeometry::Convex c; + static int faces[6][4] = {{0,1,5,4}, {1,2,6,5}, {2,3,7,6}, {3,0,4,7}, {3,2,1,0}, {4,5,6,7}}; + + nvidia::Array<float> secAngles((uint32_t)numSectors); + float dSec = PxTwoPi / (float)numSectors; + for (uint32_t i = 0; i < (uint32_t)numSectors; i++) + secAngles[i] = i * dSec + physx::shdfnd::rand(-sectorRand, sectorRand) * dSec; + + // how many segments? + float segSize = firstSegmentSize; + float d = 0.0f; + int numSegs = 0; + while (d < radius) { + numSegs++; + d += segSize; + segSize *= segmentScale; + } + + for (uint32_t i = 0; i < (uint32_t)numSectors; i++) { + float segSize = firstSegmentSize; + float d = 0.0f; + float r0 = 0.0f; + float r1 = 0.0f; + float p0, p1; + + float a0 = secAngles[i]; + float a1 = secAngles[(i + 1) % numSectors]; + + for (int j = 0; j < numSegs; j++) { + d += segSize; + p0 = r0; + p1 = r1; + r0 = d + physx::shdfnd::rand(-segmentRand, segmentRand) * segSize; + r1 = d + physx::shdfnd::rand(-segmentRand, segmentRand) * segSize; + segSize *= segmentScale; + + mGeom.initConvex(c); + c.numFaces = 6; + c.numNeighbors = 6; + c.numVerts = 8; + c.firstPlane = 0; + mGeom.convexes.pushBack(c); + + float sin0 = PxSin(a0); + float sin1 = PxSin(a1); + float cos0 = PxCos(a0); + float cos1 = PxCos(a1); + + mGeom.vertices.pushBack(PxVec3(p0 * cos0, p0 * sin0, -thickness)); + mGeom.vertices.pushBack(PxVec3(r0 * cos0, r0 * sin0, -thickness)); + mGeom.vertices.pushBack(PxVec3(r1 * cos1, r1 * sin1, -thickness)); + mGeom.vertices.pushBack(PxVec3(p1 * cos1, p1 * sin1, -thickness)); + mGeom.vertices.pushBack(PxVec3(p0 * cos0, p0 * sin0, thickness)); + mGeom.vertices.pushBack(PxVec3(r0 * cos0, r0 * sin0, thickness)); + mGeom.vertices.pushBack(PxVec3(r1 * cos1, r1 * sin1, thickness)); + mGeom.vertices.pushBack(PxVec3(p1 * cos1, p1 * sin1, thickness)); + + for (uint32_t k = 0; k < 6; k++) { + mGeom.indices.pushBack(4); // face size + mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE); // flags + mGeom.indices.pushBack(faces[k][0]); + mGeom.indices.pushBack(faces[k][1]); + mGeom.indices.pushBack(faces[k][2]); + mGeom.indices.pushBack(faces[k][3]); + } + mGeom.neighbors.pushBack(i > 0 ? ((int32_t)i-1) * numSegs + j : (numSectors-1) * numSegs + j); + mGeom.neighbors.pushBack(j < numSegs-1 ? (int32_t)i * numSegs + j+1 : -1); + mGeom.neighbors.pushBack((int32_t)i < numSectors-1 ? ((int32_t)i+1) * numSegs + j : j); + mGeom.neighbors.pushBack(j > 0 ? (int32_t)i * numSegs + j-1 : -1); + mGeom.neighbors.pushBack(-1); + mGeom.neighbors.pushBack(-1); + } + } + finalize(); +} +// -------------------------------------------------------------------------------------------- +void FracturePattern::createRegularCubeMesh(const PxVec3 &extents, float cubeSize) +{ + clear(); + int numX = (int)(2.0f*extents.x / cubeSize) + 1; + int numY = (int)(2.0f*extents.y / cubeSize) + 1; + int numZ = (int)(2.0f*extents.z / cubeSize) + 1; + + CompoundGeometry::Convex c; + static int faces[6][4] = {{0,1,5,4}, {1,2,6,5}, {2,3,7,6}, {3,0,4,7}, {3,2,1,0}, {4,5,6,7}}; + + for (int xi = 0; xi < numX; xi++) { + for (int yi = 0; yi < numY; yi++) { + for (int zi = 0; zi < numZ; zi++) { + mGeom.initConvex(c); + c.numFaces = 6; + c.numNeighbors = 6; + c.numVerts = 8; + c.firstPlane = 0; + mGeom.convexes.pushBack(c); + + PxVec3 p0(-extents.x + xi*cubeSize, -extents.y + yi*cubeSize, -extents.z + zi*cubeSize); + PxVec3 p1 = p0 + PxVec3(cubeSize, cubeSize, cubeSize); + mGeom.vertices.pushBack(PxVec3(p0.x, p0.y, p0.z)); + mGeom.vertices.pushBack(PxVec3(p1.x, p0.y, p0.z)); + mGeom.vertices.pushBack(PxVec3(p1.x, p1.y, p0.z)); + mGeom.vertices.pushBack(PxVec3(p0.x, p1.y, p0.z)); + mGeom.vertices.pushBack(PxVec3(p0.x, p0.y, p1.z)); + mGeom.vertices.pushBack(PxVec3(p1.x, p0.y, p1.z)); + mGeom.vertices.pushBack(PxVec3(p1.x, p1.y, p1.z)); + mGeom.vertices.pushBack(PxVec3(p0.x, p1.y, p1.z)); + for (int i = 0; i < 6; i++) { + mGeom.indices.pushBack(4); // face size + mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE); // flags + mGeom.indices.pushBack(faces[i][0]); + mGeom.indices.pushBack(faces[i][1]); + mGeom.indices.pushBack(faces[i][2]); + mGeom.indices.pushBack(faces[i][3]); + } + mGeom.neighbors.pushBack(yi > 0 ? (xi * numY + yi-1) * numZ + zi : -1); + mGeom.neighbors.pushBack(xi < numX-1 ? ((xi+1) * numY + yi) * numZ + zi : -1); + mGeom.neighbors.pushBack(yi < numY-1 ? (xi * numY + yi+1) * numZ + zi : -1); + mGeom.neighbors.pushBack(xi > 0 ? ((xi-1) * numY + yi) * numZ + zi : -1); + mGeom.neighbors.pushBack(zi > 0 ? (xi * numY + yi) * numZ + zi-1 : -1); + mGeom.neighbors.pushBack(zi < numZ-1 ? (xi * numY + yi) * numZ + zi+1 : -1); + } + } + } + + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::createCrosses(const PxVec3 &dims, float spacing) +{ + clear(); + + int numX = (int)floorf(2.0f * dims.x / spacing) + 1; + int numY = (int)floorf(2.0f * dims.y / spacing) + 1; + int numZ = (int)floorf(2.0f * dims.z / spacing) + 1; + + static int offset[5] = {0,3,1,4,2}; + static int cross[5][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}, {0,0}}; + PxBounds3 bounds; + + for (int zi = 0; zi < numZ; zi++) { + for (int yi = 0; yi < numY; yi++) { + for (int xi = 0; xi < numX; xi += 5) { + float z = -dims.z + (zi + xi % 2 + yi % 2) * spacing; + float y = -dims.y + yi * spacing; + float x = -dims.x + (xi + offset[yi % 5]) * spacing; + + mFirstConvexOfCell.pushBack((int32_t)mGeom.convexes.size()); + + for (int i = 0; i < 5; i++) { + bounds.minimum.x = x + cross[i][0] * spacing; + bounds.minimum.y = y + cross[i][1] * spacing; + bounds.minimum.z = z; + bounds.maximum = bounds.minimum + PxVec3(spacing, spacing, spacing); + addBox(bounds); + } + } + } + } + + mFirstConvexOfCell.pushBack((int32_t)mGeom.convexes.size()); + + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::getConvexIntersection(const Convex *convex, const PxMat44 &trans, float minConvexSize, int /*numFitDirections*/) const +{ + PxTransform localPose = convex->getLocalPose(); + const nvidia::Array<PxPlane> convexPlanes = convex->getPlanes(); + + mScene->profileBegin("find pattern candidates"); + + // cull outside convexes + nvidia::Array<int> candidates(mGeom.convexes.size()); + for (uint32_t i = 0; i < candidates.size(); i++) + candidates[i] = (int32_t)i; + + for (uint32_t i = 0; i < convexPlanes.size(); i++) { + PxPlane plane = convexPlanes[i]; + plane.n = localPose.rotate(plane.n); // only valid for rigid transforms! + plane.d = plane.d + localPose.p.dot(plane.n); + + uint32_t num = 0; + for (uint32_t j = 0; j < candidates.size(); j++) { + const CompoundGeometry::Convex &c = mGeom.convexes[(uint32_t)candidates[j]]; + bool inside = false; + for (int k = 0; k < c.numVerts; k++) { + PxVec3 p = trans.transform(mGeom.vertices[uint32_t(c.firstVert + k)]); + if (p.dot(plane.n) < plane.d) { + inside = true; + break; + } + } + if (inside) { + candidates[num] = candidates[j]; + num++; + } + } + candidates.resize(num); + } + + mScene->profileEnd("find pattern candidates"); + + // retreive convexes + Piece piece; + nvidia::Array<Convex*> newConvexes; + + mScene->profileBegin("clip all"); + + mScene->profileBegin("clipper init"); + MeshClipper *clipper = mScene->getMeshClipper(); + clipper->init(convex); + mScene->profileEnd("clipper init"); + + mScene->profileBegin("clipper clip"); + + for (uint32_t i = 0; i < candidates.size(); i++) { + uint32_t convexNr = (uint32_t)candidates[i]; + Convex *c = mScene->createConvex(); + const PxTransform transformTemp = convex->getLocalPose(); + c->createFromConvex(convex, &transformTemp); + const CompoundGeometry::Convex &gc = mGeom.convexes[convexNr]; + + bool empty = true; + c->intersectWithConvex(&mGeom.planes[(uint32_t)gc.firstPlane], gc.numFaces, trans, empty); + + if (empty) { + PX_DELETE(c); + continue; + } + + const PxBounds3 &bounds = c->getBounds(); + PxVec3 dim = bounds.getDimensions(); + if (!c->isGhostConvex() && (dim.x < minConvexSize || dim.y < minConvexSize || dim.z < minConvexSize)) { + PX_DELETE(c); + continue; + } + + empty = false; + newConvexes.clear(); + + if (convex->hasExplicitVisMesh()) { + if (!c->clipVisualMesh(clipper, convex->getLocalPose(), newConvexes)) { + PX_DELETE(c); + continue; + } + if (newConvexes.size() > 0) + mSplitPiece[convexNr] = true; + } + + c->setModelIslandNr(convex->getModelIslandNr()); + c->setSurfaceMaterialId(convex->getSurfaceMaterialId()); + newConvexes.pushBack(c); + + for (uint32_t i = 0; i < newConvexes.size(); i++) { + Convex *c = newConvexes[i]; + const PxBounds3 &bounds = c->getBounds(); + PxVec3 dim = bounds.getDimensions(); + if (!c->isGhostConvex() && (dim.x < minConvexSize || dim.y < minConvexSize || dim.z < minConvexSize)) { + // TODO: Spawn debris? + PX_DELETE(c); + continue; + } + piece.convex = newConvexes[i]; + piece.next = mFirstPiece[convexNr]; + mFirstPiece[convexNr] = (int32_t)mPieces.size(); + mPieces.pushBack(piece); + } + } + mScene->profileBegin("clipper clip"); + + mScene->profileEnd("clip all"); + +} + +// -------------------------------------------------------------------------------------------- +void FracturePattern::getCompoundIntersection(const Compound *compound, const PxMat44 &trans, float radius, float minConvexSize, + nvidia::Array<int> &compoundSizes, nvidia::Array<Convex*> &newConvexes) const +{ + // radius = 0.0f : complete fracture + // radius > 0.0f : partial (local) fracture + + //{ + + // IslandDetector *id = IslandDetector::getInstance(); + // id->detect(&convexes[0], convexes.size(), true); + //} + + const nvidia::Array<Convex*> &convexes = compound->getConvexes(); + //const nvidia::Array<PxBounds3>& attachmentBounds = compound->getAttachmentBounds(); + + PxMat33 m(trans.getBasis(0), trans.getBasis(1), trans.getBasis(2)); + float transScale = m.getDeterminant(); + + newConvexes.clear(); + compoundSizes.clear(); + + PxVec3 fractureCenter = trans.getPosition(); + + for (uint32_t i = 0; i < mGeom.convexes.size(); i++) { + mFirstPiece[i] = -1; + mSplitPiece[i] = false; + } + mPieces.clear(); + + nvidia::Array<Convex*> farConvexes; + nvidia::Array<Convex*> cellConvexes; + + // fracture convexes + int numFitDirections = 7; + + // complete fracture + if (radius == 0.0f) { + for (uint32_t i = 0; i < convexes.size(); i++) { + Convex *c = convexes[i]; + //if (c->isGhostConvex()) + // /*int foo = 0*/; + getConvexIntersection(c, trans, minConvexSize, numFitDirections); + } + } + else { // partial fracture + + // fracture non-ghost convexes and determine furthest fractured vertex + float maxGhostRadius2 = 0.0f; + + for (uint32_t i = 0; i < convexes.size(); i++) { + Convex *c = convexes[i]; + if (c->isGhostConvex()) + continue; + + PxTransform localPose = c->getLocalPose(); + PxVec3 localCenter = localPose.transformInv(fractureCenter); + + // is the convex outside of the fracture sphere? + if (c->insideFattened(localCenter, radius)) { + getConvexIntersection(c, trans, minConvexSize, numFitDirections); + + const nvidia::Array<PxVec3> &verts = c->getVertices(); + for (uint32_t j = 0; j < verts.size(); j++) { + float r2 = (verts[j] - localCenter).magnitudeSquared(); + if (r2 > maxGhostRadius2) + maxGhostRadius2 = r2; + } + } + else { + c->transform(localPose); + c->clearFraceFlags(CompoundGeometry::FF_NEW); + c->setIsFarConvex(true); + farConvexes.pushBack(c); // double use -> that is why we need reference counters for convexes! + } + } + + // added overlap test in island detector, no need for ghost anymore! + +// // fracture ghost convexes using the maxGhostRadius +// float maxGhostRadius = PxSqrt(maxGhostRadius2); +// +// for (int i = 0; i < (int)convexes.size(); i++) { +// Convex *c = convexes[i]; +// if (!c->isGhostConvex()) +// continue; +// PxTransform localPose = c->getLocalPose(); +// PxVec3 localCenter = localPose.transformInv(fractureCenter); +// +// // is the convex outside of the fracture sphere? +// if (c->insideFattened(localCenter, maxGhostRadius)) { +//// if (c->insideFattened(localCenter, radius)) { // foo +// getConvexIntersection(c, trans, minConvexSize, numFitDirections); +// } +// else { +// c->transform(localPose); +// farConvexes.pushBack(c); // double use -> that is why we need reference counters for convexes! +// } +// } + } + + // collect pieces + bool complexCells = !mFirstConvexOfCell.empty(); + uint32_t numCells = complexCells ? mFirstConvexOfCell.size()-1 : mGeom.convexes.size(); + + for (uint32_t i = 0; i < numCells; i++) { + uint32_t numConvexes = uint32_t(complexCells ? mFirstConvexOfCell[i+1] - mFirstConvexOfCell[i] : 1); + + cellConvexes.clear(); + PxVec3 matOff = PxVec3(0.0f, 0.0f, 0.0f); + bool hasGhosts = false; + bool splitCell = false; + + + for (uint32_t k = 0; k < numConvexes; k++) { + uint32_t convexNr = complexCells ? (uint32_t)mFirstConvexOfCell[i] + k : i; + + if (mSplitPiece[convexNr]) + splitCell = true; + + if (mFirstPiece[convexNr] < 0) + continue; + + int nr = mFirstPiece[convexNr]; + while (nr >= 0) { + Convex *c = mPieces[(uint32_t)nr].convex; + if (c->isGhostConvex()) + hasGhosts = true; + else + matOff = c->getMaterialOffset(); + cellConvexes.pushBack(c); + nr = mPieces[(uint32_t)nr].next; + } + } + + // fit to visual mesh, only if there are no ghost convexes, otherwise the faces do to match anymore + if (!hasGhosts) { + uint32_t num = 0; + for (uint32_t j = 0; j < cellConvexes.size(); j++) { + Convex *c = cellConvexes[j]; + if (c->hasExplicitVisMesh()) { + bool empty = false; + c->fitToVisualMesh(empty, numFitDirections); + if (empty) { + PX_DELETE(c); + continue; + } + } + cellConvexes[num] = c; + num++; + } + cellConvexes.resize(num); + } + + if (cellConvexes.size() == 1) { + newConvexes.pushBack(cellConvexes[0]); + compoundSizes.pushBack(1); + continue; + } + + // all volume covered with new pieces? + bool hasExplicitMesh = false; + + float volumeFraction = 0.0f; + for (uint32_t j = 0; j < cellConvexes.size(); j++) { + const Convex *c = cellConvexes[j]; + float vol = c->isGhostConvex() ? -c->getVolume() : c->getVolume(); + volumeFraction += vol; + if (c->hasExplicitVisMesh()) + hasExplicitMesh = true; + } + + float vol = mConvexVolumes[i] * transScale; + float volDiff = fabsf(vol - volumeFraction) / vol; + + if (splitCell) { // each convex piece within the pattern piece becomes a separate compound + for (uint32_t j = 0; j < cellConvexes.size(); j++) { + newConvexes.pushBack(cellConvexes[j]); + compoundSizes.pushBack(1); + } + } + else if (!complexCells && !hasExplicitMesh && volDiff < 0.01f) { // the entire pattern piece becomes a convex + // delete parts + for (uint32_t j = 0; j < cellConvexes.size(); j++) + PX_DELETE(cellConvexes[j]); + + // create single piece + Convex *c = mScene->createConvex(); + c->createFromGeometry(mGeom, (int32_t)i, &trans); + newConvexes.pushBack(c); + c->setMaterialOffset(matOff); + compoundSizes.pushBack(1); + } + else { // all connected convex pieces within the pattern cell become one compound + IslandDetector *id = mScene->getIslandDetector(); + id->detect(cellConvexes, false); + const nvidia::Array<IslandDetector::Island> &islands = id->getIslands(); + const nvidia::Array<int> &islandConvexes = id->getIslandConvexes(); + + for (uint32_t j = 0; j < islands.size(); j++) { + const IslandDetector::Island &is = islands[j]; + for (int k = 0; k < is.size; k++) + newConvexes.pushBack(cellConvexes[(uint32_t)islandConvexes[uint32_t(is.firstNr+k)]]); + compoundSizes.pushBack(is.size); + } + } + } + + // merge far convexes for local fracture + if (radius > 0.0f) { + farConvexes.reserve(farConvexes.size() + newConvexes.size()); + + uint32_t oldConvexNr = 0; + uint32_t newConvexNr = 0; + uint32_t numNewCompounds = 0; + + for (uint32_t i = 0; i < compoundSizes.size(); i++) { + uint32_t oldCompoundSize = (uint32_t)compoundSizes[i]; + uint32_t newCompoundSize = 0; + bool onlyGhosts = true; + for (uint32_t j = 0; j < oldCompoundSize; j++) { + Convex *c = newConvexes[oldConvexNr + j]; + if (!c->insideFattened(fractureCenter, radius)) { + c->clearFraceFlags(CompoundGeometry::FF_NEW); + c->setIsFarConvex(true); + farConvexes.pushBack(c); + } + else { + if (!c->isGhostConvex()) + onlyGhosts = false; + newConvexes[newConvexNr] = c; + newConvexNr++; + newCompoundSize++; + } + } + if (newCompoundSize > 0) { + if (onlyGhosts) { // remove compounds that contain only ghost convexes + for (uint32_t j = 0; j < newCompoundSize; j++) { + newConvexNr--; + PX_DELETE(newConvexes[newConvexNr]); + } + } + else { + compoundSizes[numNewCompounds] = (int32_t)newCompoundSize; + numNewCompounds++; + } + } + oldConvexNr += oldCompoundSize; + } + newConvexes.resize(newConvexNr); + compoundSizes.resize(numNewCompounds); + } + + if (farConvexes.size() > 0) { + IslandDetector *id = mScene->getIslandDetector(); + + mScene->profileBegin("island detection"); + + id->detect(farConvexes, true); + + mScene->profileEnd("island detection"); + + const nvidia::Array<IslandDetector::Island> &islands = id->getIslands(); + const nvidia::Array<int> &islandConvexes = id->getIslandConvexes(); + + for (uint32_t i = 0; i < islands.size(); i++) { + const IslandDetector::Island &island = islands[i]; + compoundSizes.pushBack(island.size); + for (int j = 0; j < island.size; j++) { + int nr = islandConvexes[uint32_t(island.firstNr + j)]; + newConvexes.pushBack(farConvexes[(uint32_t)nr]); + } + } + + //const nvidia::Array<int> &pairs = id->getNeighborEdges(); + //FILE *f = fopen("c:\\test.txt", "a"); + //fprintf(f, "convexes %i, edges %i\n", farConvexes.size(), pairs.size()/2); + //fclose(f); + + //StaticTester::getInstance()->setStretchThreshold(1.0f); // 1 newton / m^2 + //StaticTester::getInstance()->setCompressionThreshold(10.0f); // 10 newton / m^2 + //StaticTester::getInstance()->setTorqueThreshold(2.0f); // 2 newton / m + //StaticTester::getInstance()->analyse(farConvexes, attachmentBounds, id->getNeighborEdges()); + +#if HIDE_INVISIBLE_FACES + if (radius != 0.0f) { + // invisible faces may open up with partial fracturing + const nvidia::Array<float> faceCoverage = mScene->getIslandDetector()->getFaceCoverage(); + uint32_t globalFaceNr = 0; + for (uint32_t i = 0; i < farConvexes.size(); i++) { + Convex *c = farConvexes[i]; + c->updateFaceVisibility(&faceCoverage[globalFaceNr]); + globalFaceNr += c->getFaces().size(); + } + // brute force + //for (int i = 0; i < (int)newConvexes.size(); i++) { + // newConvexes[i]->updateFaceVisibility + // newConvexes[i]->removeInvisibleFacesFlags(); + //} + } +#endif + } + + //if (farConvexes.size() > 0) { + // compoundSizes.pushBack(farConvexes.size()); + // for (int i = 0; i < (int)farConvexes.size(); i++) + // newConvexes.pushBack(farConvexes[i]); + //} + +// printf("%i new convexes, %i new compounds\n", newConvexes.size(), compoundSizes.size()); +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.h b/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.h new file mode 100644 index 00000000..425efd22 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef FRACTURE_PATTERN_BASE +#define FRACTURE_PATTERN_BASE + +#include "Delaunay3dBase.h" +#include "Delaunay2dBase.h" +#include "CompoundGeometryBase.h" +#include "PxTransform.h" +#include "PxBounds3.h" +#include <PsUserAllocated.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +class Convex; +class Compound; +class CompoundGeometry; + +//------------------------------------------------------------------------------------------ +class FracturePattern : public UserAllocated +{ + friend class SimScene; +protected: + FracturePattern(SimScene* scene); +public: + virtual ~FracturePattern() {} + + void create3dVoronoi(const PxVec3 &dims, int numCells, float biasExp = 1.0f, float maxDist = PX_MAX_F32); + void create2dVoronoi(const PxVec3 &dims, int numCells, float biasExp = 1.0f, int numRays = 0); + + void createRegularCubeMesh(const PxVec3 &dims, float cubeSize); + void createRegular3dVoronoi(const PxVec3 &dims, float pieceSize, float relRandOffset = 0.1f); + void createLocal3dVoronoi(const PxVec3 &dims, int numCells, float radius); + void createGlass(float radius, float thickness, int numSectors, float sectorRand, float firstSegmentSize, float segmentScale, float segmentRand); + void createCrack(const PxVec3 &dims, float spacing, float zRand); + void createCrosses(const PxVec3 &dims, float spacing); + + // radius = 0.0f : complete fracture + // radius > 0.0f : partial (local) fracture + void getCompoundIntersection(const Compound *compound, const PxMat44 &trans, float radius, float minConvexSize, + nvidia::Array<int> &compoundSizes, nvidia::Array<Convex*> &newConvexes) const; + + const CompoundGeometry &getGeometry() { return mGeom; } + +protected: + void addBox(const PxBounds3 &bounds); + void clear(); + void finalize(); + + void getConvexIntersection(const Convex *convex, const PxMat44 &trans, float minConvexSize, int numFitDirections = 3) const; + + SimScene* mScene; + + CompoundGeometry mGeom; + + // cells can have multiple connected convexes + // if this array is empty, each convex is a separate cell + // size of array must be num cells + 1 + nvidia::Array<int> mFirstConvexOfCell; + + PxBounds3 mBounds; + nvidia::Array<float> mConvexVolumes; + + // temporary for intersection computation + mutable nvidia::Array<int> mFirstPiece; + mutable nvidia::Array<bool> mSplitPiece; + struct Piece { + Convex* convex; + int next; + }; + mutable nvidia::Array<Piece> mPieces; +}; + +} +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.cpp b/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.cpp new file mode 100644 index 00000000..774d0049 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for box pruning. + * \file IceBoxPruning.cpp + * \author Pierre Terdiman + * \date January, 29, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + You could use a complex sweep-and-prune as implemented in I-Collide. + You could use a complex hashing scheme as implemented in V-Clip or recently in ODE it seems. + You could use a "Recursive Dimensional Clustering" algorithm as implemented in GPG2. + + Or you could use this. + Faster ? I don't know. Probably not. It would be a shame. But who knows ? + Easier ? Definitely. Enjoy the sheer simplicity. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +*/ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "IceBoxPruningBase.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set. + * \param nb0 [in] number of boxes in the first set + * \param bounds0 [in] list of boxes for the first set + * \param nb1 [in] number of boxes in the second set + * \param bounds1 [in] list of boxes for the second set + * \param pairs [out] list of overlapping pairs + * \param axes [in] projection order (0,2,1 is often best) + * \return true if success. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool BoxPruning::bipartiteBoxPruning(const nvidia::Array<PxBounds3> &bounds0, const nvidia::Array<PxBounds3> &bounds1, nvidia::Array<uint32_t>& pairs, const Axes& axes) +{ + uint32_t nb0 = bounds0.size(); + uint32_t nb1 = bounds1.size(); + pairs.clear(); + // Checkings + if(nb0 == 0 || nb1 == 0) return false; + + // Catch axes + uint32_t Axis0 = axes.Axis0; + //uint32_t Axis1 = axes.Axis1; + //uint32_t Axis2 = axes.Axis2; + + // Allocate some temporary data + if (mMinPosBounds0.size() < nb0) + mMinPosBounds0.resize(nb0); + if (mMinPosBounds1.size() < nb1) + mMinPosBounds1.resize(nb1); + + // 1) Build main lists using the primary axis + for(uint32_t i=0;i<nb0;i++) mMinPosBounds0[i] = bounds0[i].minimum[Axis0]; + for(uint32_t i=0;i<nb1;i++) mMinPosBounds1[i] = bounds1[i].minimum[Axis0]; + + // 2) Sort the lists + uint32_t* Sorted0 = mRS0.Sort(&mMinPosBounds0[0], nb0).GetRanks(); + uint32_t* Sorted1 = mRS1.Sort(&mMinPosBounds1[0], nb1).GetRanks(); + + // 3) Prune the lists + uint32_t Index0, Index1; + + const uint32_t* const LastSorted0 = &Sorted0[nb0]; + const uint32_t* const LastSorted1 = &Sorted1[nb1]; + const uint32_t* RunningAddress0 = Sorted0; + const uint32_t* RunningAddress1 = Sorted1; + + while(RunningAddress1<LastSorted1 && Sorted0<LastSorted0) + { + Index0 = *Sorted0++; + + while(RunningAddress1<LastSorted1 && mMinPosBounds1[*RunningAddress1]<mMinPosBounds0[Index0]) RunningAddress1++; + + const uint32_t* RunningAddress2_1 = RunningAddress1; + + while(RunningAddress2_1<LastSorted1 && mMinPosBounds1[Index1 = *RunningAddress2_1++]<=bounds0[Index0].maximum[Axis0]) + { + if(bounds0[Index0].intersects(bounds1[Index1])) + { + pairs.pushBack(Index0); + pairs.pushBack(Index1); + } + } + } + + //// + + while(RunningAddress0<LastSorted0 && Sorted1<LastSorted1) + { + Index0 = *Sorted1++; + + while(RunningAddress0<LastSorted0 && mMinPosBounds0[*RunningAddress0]<=mMinPosBounds1[Index0]) RunningAddress0++; + + const uint32_t* RunningAddress2_0 = RunningAddress0; + + while(RunningAddress2_0<LastSorted0 && mMinPosBounds0[Index1 = *RunningAddress2_0++]<=bounds1[Index0].maximum[Axis0]) + { + if(bounds0[Index1].intersects(bounds1[Index0])) + { + pairs.pushBack(Index1); + pairs.pushBack(Index0); + } + } + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set. + * \param nb [in] number of boxes + * \param list [in] list of boxes + * \param pairs [out] list of overlapping pairs + * \param axes [in] projection order (0,2,1 is often best) + * \return true if success. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool BoxPruning::completeBoxPruning(const nvidia::Array<PxBounds3> &bounds, nvidia::Array<uint32_t> &pairs, const Axes& axes) +{ + uint32_t nb = bounds.size(); + pairs.clear(); + + // Checkings + if(!nb) return false; + + // Catch axes + uint32_t Axis0 = axes.Axis0; + //uint32_t Axis1 = axes.Axis1; + //uint32_t Axis2 = axes.Axis2; + + // Allocate some temporary data + if (mPosList.size() < nb) + mPosList.resize(nb); + + // 1) Build main list using the primary axis + for(uint32_t i=0;i<nb;i++) mPosList[i] = bounds[i].minimum[Axis0]; + + // 2) Sort the list + uint32_t* Sorted = mRS.Sort(&mPosList[0], nb).GetRanks(); + + // 3) Prune the list + const uint32_t* const LastSorted = &Sorted[nb]; + const uint32_t* RunningAddress = Sorted; + uint32_t Index0, Index1; + while(RunningAddress<LastSorted && Sorted<LastSorted) + { + Index0 = *Sorted++; + + while(RunningAddress<LastSorted && mPosList[*RunningAddress++]<mPosList[Index0]); + + const uint32_t* RunningAddress2 = RunningAddress; + + while(RunningAddress2<LastSorted && mPosList[Index1 = *RunningAddress2++]<=bounds[Index0].maximum[Axis0]) + { + if(Index0!=Index1) + { + if(bounds[Index0].intersects(bounds[Index1])) + { + pairs.pushBack(Index0); + pairs.pushBack(Index1); + } + } + } + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Brute-force versions are kept: +// - to check the optimized versions return the correct list of intersections +// - to check the speed of the optimized code against the brute-force one +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Brute-force bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set. + * \param nb0 [in] number of boxes in the first set + * \param bounds0 [in] list of boxes for the first set + * \param nb1 [in] number of boxes in the second set + * \param bounds1 [in] list of boxes for the second set + * \param pairs [out] list of overlapping pairs + * \return true if success. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool BoxPruning::bruteForceBipartiteBoxTest(const nvidia::Array<PxBounds3> &bounds0, const nvidia::Array<PxBounds3> &bounds1, nvidia::Array<uint32_t>& pairs, const Axes& /*axes*/) +{ + uint32_t nb0 = bounds0.size(); + uint32_t nb1 = bounds1.size(); + pairs.clear(); + + // Checkings + if(!nb0 || !nb1) return false; + + // Brute-force nb0*nb1 overlap tests + for(uint32_t i=0;i<nb0;i++) + { + for(uint32_t j=0;j<nb1;j++) + { + if(bounds0[i].intersects(bounds1[j])) { + pairs.pushBack(i); + pairs.pushBack(j); + } + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set. + * \param nb [in] number of boxes + * \param list [in] list of boxes + * \param pairs [out] list of overlapping pairs + * \return true if success. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool BoxPruning::bruteForceCompleteBoxTest(const nvidia::Array<PxBounds3> &bounds, nvidia::Array<uint32_t> &pairs, const Axes& /*axes*/) +{ + uint32_t nb = bounds.size(); + pairs.clear(); + + // Checkings + if(!nb) return false; + + // Brute-force n(n-1)/2 overlap tests + for(uint32_t i=0;i<nb;i++) + { + for(uint32_t j=i+1;j<nb;j++) + { + if(bounds[i].intersects(bounds[j])) + { + pairs.pushBack(i); + pairs.pushBack(j); + } + } + } + return true; +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.h b/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.h new file mode 100644 index 00000000..b7bb9119 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for box pruning. + * \file IceBoxPruning.h + * \author Pierre Terdiman + * \date January, 29, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEBOXPRUNING_BASE_H__ +#define __ICEBOXPRUNING_BASE_H__ + +//#include "vector" +#include <PsArray.h> +#include "IceRevisitedRadixBase.h" +#include "PxVec3.h" +#include "PxBounds3.h" +#include <PsUserAllocated.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + + struct Axes + { + void set(uint32_t a0, uint32_t a1, uint32_t a2) { + Axis0 = a0; Axis1 = a1; Axis2 = a2; + } + uint32_t Axis0; + uint32_t Axis1; + uint32_t Axis2; + }; + + class BoxPruning : public UserAllocated + { + public: + // Optimized versions + bool completeBoxPruning(const nvidia::Array<PxBounds3> &bounds, nvidia::Array<uint32_t> &pairs, const Axes& axes); + bool bipartiteBoxPruning(const nvidia::Array<PxBounds3> &bounds0, const nvidia::Array<PxBounds3> &bounds1, nvidia::Array<uint32_t>& pairs, const Axes& axes); + + // Brute-force versions + bool bruteForceCompleteBoxTest(const nvidia::Array<PxBounds3> &bounds, nvidia::Array<uint32_t> &pairs, const Axes& axes); + bool bruteForceBipartiteBoxTest(const nvidia::Array<PxBounds3> &bounds0, const nvidia::Array<PxBounds3> &bounds1, nvidia::Array<uint32_t>& pairs, const Axes& axes); + + protected: + nvidia::Array<float> mMinPosBounds0; + nvidia::Array<float> mMinPosBounds1; + nvidia::Array<float> mPosList; + RadixSort mRS0, mRS1; + RadixSort mRS; + }; + +} +} +} + +#endif // __ICEBOXPRUNING_H__ +#endif diff --git a/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.cpp b/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.cpp new file mode 100644 index 00000000..116ea2c4 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.cpp @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains source code from the article "Radix Sort Revisited". + * \file IceRevisitedRadix.cpp + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Revisited Radix Sort. + * This is my new radix routine: + * - it uses indices and doesn't recopy the values anymore, hence wasting less ram + * - it creates all the histograms in one run instead of four + * - it sorts words faster than dwords and bytes faster than words + * - it correctly sorts negative floating-point values by patching the offsets + * - it automatically takes advantage of temporal coherence + * - multiple keys support is a side effect of temporal coherence + * - it may be worth recoding in asm... (mainly to use FCOMI, FCMOV, etc) [it's probably memory-bound anyway] + * + * History: + * - 08.15.98: very first version + * - 04.04.00: recoded for the radix article + * - 12.xx.00: code lifting + * - 09.18.01: faster CHECK_PASS_VALIDITY thanks to Mark D. Shattuck (who provided other tips, not included here) + * - 10.11.01: added local ram support + * - 01.20.02: bugfix! In very particular cases the last pass was skipped in the float code-path, leading to incorrect sorting...... + * - 01.02.02: - "mIndices" renamed => "mRanks". That's a rank sorter after all. + * - ranks are not "reset" anymore, but implicit on first calls + * + * \class RadixSort + * \author Pierre Terdiman + * \version 1.4 + * \date August, 15, 1998 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* +To do: + - add an offset parameter between two input values (avoid some data recopy sometimes) + - unroll ? asm ? + - 11 bits trick & 3 passes as Michael did + - prefetch stuff the day I have a P3 +*/ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "IceRevisitedRadixBase.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +#define INVALIDATE_RANKS mCurrentSize|=0x80000000 +#define VALIDATE_RANKS mCurrentSize&=0x7fffffff +#define CURRENT_SIZE (mCurrentSize&0x7fffffff) +#define INVALID_RANKS (mCurrentSize&0x80000000) + +#define CHECK_RESIZE(n) \ + if(n!=mPreviousSize) \ + { \ + if(n>mCurrentSize) Resize(n); \ + else ResetRanks(); \ + mPreviousSize = n; \ + } + +#define CREATE_HISTOGRAMS(type, buffer) \ + /* Clear counters/histograms */ \ + \ + memset(mHistogram, 0, 256*4*sizeof(uint32_t)); \ + \ + /* Prepare to count */ \ + uint8_t* p = (uint8_t*)input; \ + uint8_t* pe = &p[nb*4]; \ + uint32_t* h0= &mHistogram[0]; /* Histogram for first pass (LSB) */ \ + uint32_t* h1= &mHistogram[256]; /* Histogram for second pass */ \ + uint32_t* h2= &mHistogram[512]; /* Histogram for third pass */ \ + uint32_t* h3= &mHistogram[768]; /* Histogram for last pass (MSB) */ \ + \ + bool AlreadySorted = true; /* Optimism... */ \ + \ + if(INVALID_RANKS) \ + { \ + /* Prepare for temporal coherence */ \ + type* Running = (type*)buffer; \ + type PrevVal = *Running; \ + \ + while(p!=pe) \ + { \ + /* Read input buffer in previous sorted order */ \ + type Val = *Running++;; \ + /* Check whether already sorted or not */ \ + if(Val<PrevVal) { AlreadySorted = false; break; } /* Early out */ \ + /* Update for next iteration */ \ + PrevVal = Val; \ + \ + /* Create histograms */ \ + h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \ + } \ + \ + /* If all input values are already sorted, we just have to return and leave the */ \ + /* previous list unchanged. That way the routine may take advantage of temporal */ \ + /* coherence, for example when used to sort transparent faces. */ \ + if(AlreadySorted) \ + { \ + mNbHits++; \ + for(uint32_t i=0;i<nb;i++) mRanks[i] = i; \ + return *this; \ + } \ + } \ + else \ + { \ + /* Prepare for temporal coherence */ \ + uint32_t* Indices = mRanks; \ + type PrevVal = (type)buffer[*Indices]; \ + \ + while(p!=pe) \ + { \ + /* Read input buffer in previous sorted order */ \ + type Val = (type)buffer[*Indices++]; \ + /* Check whether already sorted or not */ \ + if(Val<PrevVal) { AlreadySorted = false; break; } /* Early out */ \ + /* Update for next iteration */ \ + PrevVal = Val; \ + \ + /* Create histograms */ \ + h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \ + } \ + \ + /* If all input values are already sorted, we just have to return and leave the */ \ + /* previous list unchanged. That way the routine may take advantage of temporal */ \ + /* coherence, for example when used to sort transparent faces. */ \ + if(AlreadySorted) { mNbHits++; return *this; } \ + } \ + \ + /* Else there has been an early out and we must finish computing the histograms */ \ + while(p!=pe) \ + { \ + /* Create histograms without the previous overhead */ \ + h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \ + } + +#define CHECK_PASS_VALIDITY(pass) \ + /* Shortcut to current counters */ \ + uint32_t* CurCount = &mHistogram[pass<<8]; \ + \ + /* Reset flag. The sorting pass is supposed to be performed. (default) */ \ + bool PerformPass = true; \ + \ + /* Check pass validity */ \ + \ + /* If all values have the same byte, sorting is useless. */ \ + /* It may happen when sorting bytes or words instead of dwords. */ \ + /* This routine actually sorts words faster than dwords, and bytes */ \ + /* faster than words. Standard running time (O(4*n))is reduced to O(2*n) */ \ + /* for words and O(n) for bytes. Running time for floats depends on actual values... */ \ + \ + /* Get first byte */ \ + uint8_t UniqueVal = *(((uint8_t*)input)+pass); \ + \ + /* Check that byte's counter */ \ + if(CurCount[UniqueVal]==nb) PerformPass=false; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +RadixSort::RadixSort() : mCurrentSize(0), mRanks(NULL), mRanks2(NULL), mTotalCalls(0), mNbHits(0) +{ + // Initialize indices + mRanksSize = 0; + INVALIDATE_RANKS; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +RadixSort::~RadixSort() +{ + // Release everything + PX_FREE(mRanks2); + PX_FREE(mRanks); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Resizes the inner lists. + * \param nb [in] new size (number of dwords) + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool RadixSort::Resize(uint32_t nb) +{ + if (mRanksSize >= nb) + return true; + + // Free previously used ram + PX_FREE(mRanks2); + PX_FREE(mRanks); + + // Get some fresh one + mRanks = (uint32_t*) PX_ALLOC(sizeof(uint32_t)*nb,PX_DEBUG_EXP("RT_FRACTURE")); + mRanks2 = (uint32_t*) PX_ALLOC(sizeof(uint32_t)*nb,PX_DEBUG_EXP("RT_FRACTURE")); + + mRanksSize = nb; + + return true; +} + +inline void RadixSort::CheckResize(uint32_t nb) +{ + uint32_t CurSize = CURRENT_SIZE; + if(nb!=CurSize) + { + if(nb>CurSize) Resize(nb); + mCurrentSize = nb; + INVALIDATE_RANKS; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Main sort routine. + * This one is for integer values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data. + * \param input [in] a list of integer values to sort + * \param nb [in] number of values to sort, must be < 2^31 + * \param signedvalues [in] true to handle negative values, false if you know your input buffer only contains positive values + * \return Self-Reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +RadixSort& RadixSort::Sort(const uint32_t* input, uint32_t nb, bool signedvalues) +{ + // Checkings + if(!input || !nb || nb&0x80000000) return *this; + + // Stats + mTotalCalls++; + + // Resize lists if needed + CheckResize(nb); + + // Create histograms (counters). Counters for all passes are created in one run. + // Pros: read input buffer once instead of four times + // Cons: mHistogram is 4Kb instead of 1Kb + // We must take care of signed/unsigned values for temporal coherence.... I just + // have 2 code paths even if just a single opcode changes. Self-modifying code, someone? + if(!signedvalues) { CREATE_HISTOGRAMS(uint32_t, input); } + else { CREATE_HISTOGRAMS(int32_t, input); } + + // Compute #negative values involved if needed + uint32_t NbNegativeValues = 0; + if(signedvalues) + { + // An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128 + // last values of the last histogram. Last histogram because that's the one for the Most Significant Byte, + // responsible for the sign. 128 last values because the 128 first ones are related to positive numbers. + uint32_t* h3= &mHistogram[768]; + for(uint32_t i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part + } + + // Radix sort, j is the pass number (0=LSB, 3=MSB) + for(uint32_t j=0;j<4;j++) + { + CHECK_PASS_VALIDITY(j); + + // Sometimes the fourth (negative) pass is skipped because all numbers are negative and the MSB is 0xFF (for example). This is + // not a problem, numbers are correctly sorted anyway. + if(PerformPass) + { + // Should we care about negative values? + if(j!=3 || !signedvalues) + { + // Here we deal with positive values only + + // Create offsets + mOffset[0] = 0; + for(uint32_t i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; + } + else + { + // This is a special case to correctly handle negative integers. They're sorted in the right order but at the wrong place. + + // Create biased offsets, in order for negative numbers to be sorted as well + mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones + for(uint32_t i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers + + // Fixing the wrong place for negative values + mOffset[128] = 0; + for(uint32_t i=129;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; + } + + // Perform Radix Sort + uint8_t* InputBytes = (uint8_t*)input; + InputBytes += j; + if(INVALID_RANKS) + { + for(uint32_t i=0;i<nb;i++) mRanks2[mOffset[InputBytes[i<<2]]++] = i; + VALIDATE_RANKS; + } + else + { + uint32_t* Indices = mRanks; + uint32_t* IndicesEnd = &mRanks[nb]; + while(Indices!=IndicesEnd) + { + uint32_t id = *Indices++; + mRanks2[mOffset[InputBytes[id<<2]]++] = id; + } + } + + // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap. + uint32_t* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp; + } + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Main sort routine. + * This one is for floating-point values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data. + * \param input [in] a list of floating-point values to sort + * \param nb [in] number of values to sort, must be < 2^31 + * \return Self-Reference + * \warning only sorts IEEE floating-point values + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +RadixSort& RadixSort::Sort(const float* input2, uint32_t nb) +{ + // Checkings + if(!input2 || !nb || nb&0x80000000) return *this; + + // Stats + mTotalCalls++; + + uint32_t* input = (uint32_t*)input2; + + // Resize lists if needed + CheckResize(nb); + + // Create histograms (counters). Counters for all passes are created in one run. + // Pros: read input buffer once instead of four times + // Cons: mHistogram is 4Kb instead of 1Kb + // Floating-point values are always supposed to be signed values, so there's only one code path there. + // Please note the floating point comparison needed for temporal coherence! Although the resulting asm code + // is dreadful, this is surprisingly not such a performance hit - well, I suppose that's a big one on first + // generation Pentiums....We can't make comparison on integer representations because, as Chris said, it just + // wouldn't work with mixed positive/negative values.... + { CREATE_HISTOGRAMS(float, input2); } + + // Compute #negative values involved if needed + uint32_t NbNegativeValues = 0; + // An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128 + // last values of the last histogram. Last histogram because that's the one for the Most Significant Byte, + // responsible for the sign. 128 last values because the 128 first ones are related to positive numbers. + uint32_t* h3= &mHistogram[768]; + for(uint32_t i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part + + // Radix sort, j is the pass number (0=LSB, 3=MSB) + for(uint32_t j=0;j<4;j++) + { + // Should we care about negative values? + if(j!=3) + { + // Here we deal with positive values only + CHECK_PASS_VALIDITY(j); + + if(PerformPass) + { + // Create offsets + mOffset[0] = 0; + for(uint32_t i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; + + // Perform Radix Sort + uint8_t* InputBytes = (uint8_t*)input; + InputBytes += j; + if(INVALID_RANKS) + { + for(uint32_t i=0;i<nb;i++) mRanks2[mOffset[InputBytes[i<<2]]++] = i; + VALIDATE_RANKS; + } + else + { + uint32_t* Indices = mRanks; + uint32_t* IndicesEnd = &mRanks[nb]; + while(Indices!=IndicesEnd) + { + uint32_t id = *Indices++; + mRanks2[mOffset[InputBytes[id<<2]]++] = id; + } + } + + // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap. + uint32_t* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp; + } + } + else + { + // This is a special case to correctly handle negative values + CHECK_PASS_VALIDITY(j); + + if(PerformPass) + { + // Create biased offsets, in order for negative numbers to be sorted as well + mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones + for(uint32_t i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers + + // We must reverse the sorting order for negative numbers! + mOffset[255] = 0; + for(uint32_t i=0;i<127;i++) mOffset[254-i] = mOffset[255-i] + CurCount[255-i]; // Fixing the wrong order for negative values + for(uint32_t i=128;i<256;i++) mOffset[i] += CurCount[i]; // Fixing the wrong place for negative values + + // Perform Radix Sort + if(INVALID_RANKS) + { + for(uint32_t i=0;i<nb;i++) + { + uint32_t Radix = input[i]>>24; // Radix byte, same as above. AND is useless here (uint32_t). + // ### cmp to be killed. Not good. Later. + if(Radix<128) mRanks2[mOffset[Radix]++] = i; // Number is positive, same as above + else mRanks2[--mOffset[Radix]] = i; // Number is negative, flip the sorting order + } + VALIDATE_RANKS; + } + else + { + for(uint32_t i=0;i<nb;i++) + { + uint32_t Radix = input[mRanks[i]]>>24; // Radix byte, same as above. AND is useless here (uint32_t). + // ### cmp to be killed. Not good. Later. + if(Radix<128) mRanks2[mOffset[Radix]++] = mRanks[i]; // Number is positive, same as above + else mRanks2[--mOffset[Radix]] = mRanks[i]; // Number is negative, flip the sorting order + } + } + // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap. + uint32_t* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp; + } + else + { + // The pass is useless, yet we still have to reverse the order of current list if all values are negative. + if(UniqueVal>=128) + { + if(INVALID_RANKS) + { + // ###Possible? + for(uint32_t i=0;i<nb;i++) mRanks2[i] = nb-i-1; + VALIDATE_RANKS; + } + else + { + for(uint32_t i=0;i<nb;i++) mRanks2[i] = mRanks[nb-i-1]; + } + + // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap. + uint32_t* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp; + } + } + } + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Gets the ram used. + * \return memory used in bytes + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +uint32_t RadixSort::GetUsedRam() const +{ + uint32_t UsedRam = sizeof(RadixSort); + + UsedRam += 2*CURRENT_SIZE*sizeof(uint32_t); // 2 lists of indices + return UsedRam; +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.h b/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.h new file mode 100644 index 00000000..a7e9dede --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains source code from the article "Radix Sort Revisited". + * \file IceRevisitedRadix.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICERADIXSORT_BASE_H__ +#define __ICERADIXSORT_BASE_H__ + +#include "PxSimpleTypes.h" +#include "ApexUsingNamespace.h" +#include <PsUserAllocated.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + + class RadixSort : public UserAllocated + { + public: + // Constructor/Destructor + RadixSort(); + virtual ~RadixSort(); + // Sorting methods + RadixSort& Sort(const uint32_t* input, uint32_t nb, bool signedvalues=true); + RadixSort& Sort(const float* input, uint32_t nb); + + //! Access to results. mRanks is a list of indices in sorted order, i.e. in the order you may further process your data + inline uint32_t* GetRanks() const { return mRanks; } + + //! mIndices2 gets trashed on calling the sort routine, but otherwise you can recycle it the way you want. + inline uint32_t* GetRecyclable() const { return mRanks2; } + + // Stats + uint32_t GetUsedRam() const; + //! Returns the total number of calls to the radix sorter. + inline uint32_t GetNbTotalCalls() const { return mTotalCalls; } + //! Returns the number of premature exits due to temporal coherence. + inline uint32_t GetNbHits() const { return mNbHits; } + + private: + + uint32_t mHistogram[256*4]; //!< Counters for each byte + uint32_t mOffset[256]; //!< Offsets (nearly a cumulative distribution function) + uint32_t mCurrentSize; //!< Current size of the indices list + + uint32_t mRanksSize; + uint32_t* mRanks; //!< Two lists, swapped each pass + uint32_t* mRanks2; + // Stats + uint32_t mTotalCalls; + uint32_t mNbHits; + // Internal methods + void CheckResize(uint32_t nb); + bool Resize(uint32_t nb); + }; + +} +} +} + +#endif // __ICERADIXSORT_H__ +#endif diff --git a/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.cpp b/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.cpp new file mode 100644 index 00000000..387d5734 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.cpp @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "IslandDetectorBase.h" +#include "ConvexBase.h" +#include "CompoundGeometryBase.h" +#include "PsSort.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace nvidia; + +// ----------------------------------------------------------------------------- +IslandDetector::IslandDetector(SimScene* scene): + mScene(scene) +{ + mNeigborPairsDirty = true; +} + +// ----------------------------------------------------------------------------- +void IslandDetector::detect(const nvidia::Array<Convex*> &convexes, bool computeFaceCoverage) +{ + createConnectivity(convexes, computeFaceCoverage); + addOverlapConnectivity(convexes); + createIslands(); + mNeigborPairsDirty = true; +} + +// ----------------------------------------------------------------------------- +bool IslandDetector::touching(const Convex *c0, int faceNr, const Convex *c1, float eps) +{ + const Convex::Face &face = c0->getFaces()[(uint32_t)faceNr]; + const nvidia::Array<int> &indices = c0->getIndices(); + const nvidia::Array<PxVec3> &verts = c0->getVertices(); + const nvidia::Array<PxPlane> &planes = c1->getPlanes(); + + for (int i = 0; i < face.numIndices; i++) { + PxVec3 v = verts[(uint32_t)indices[uint32_t(face.firstIndex + i)]]; + v = v + c0->getMaterialOffset() - c1->getMaterialOffset(); // transform to c1 + bool inside = true; + for (uint32_t j = 0; j < planes.size(); j++) { + const PxPlane &p = planes[j]; + if (p.n.dot(v) - p.d > eps) { + inside = false; + break; + } + } + if (inside) + return true; + } + return false; +} + +// ----------------------------------------------------------------------------- +void IslandDetector::createConnectivity(const nvidia::Array<Convex*> &convexes, bool computeFaceCoverage) +{ + mFaces.clear(); + Face face; + int globalNr = 0; + + for (uint32_t i = 0; i < convexes.size(); i++) { + const Convex *c = convexes[i]; + face.convexNr = (int32_t)i; + const nvidia::Array<PxPlane> &planes = c->getPlanes(); + for (uint32_t j = 0; j < planes.size(); j++) { + globalNr++; + if (c->getFaces()[j].flags & CompoundGeometry::FF_OBJECT_SURFACE) + continue; + face.faceNr = (int32_t)j; + face.globalNr = globalNr-1; + float d = planes[j].d; + d = d + c->getMaterialOffset().dot(planes[j].n); // transform to global + face.orderVal = fabsf(d); + mFaces.pushBack(face); + } + } + mFaceCoverage.clear(); + + if (computeFaceCoverage) { + mFaceCoverage.resize((uint32_t)globalNr, 0.0f); + } + + shdfnd::sort(mFaces.begin(), mFaces.size()); + + float eps = 1e-3f; + mFirstNeighbor.clear(); + mFirstNeighbor.resize(convexes.size(), -1); + mNeighbors.clear(); + Neighbor n; + + for (uint32_t i = 0; i < mFaces.size(); i++) { + Face &fi = mFaces[i]; + uint32_t j = i+1; + while (j < mFaces.size() && mFaces[j].orderVal - fi.orderVal < eps) { + Face &fj = mFaces[j]; + j++; + + if (fi.convexNr == fj.convexNr) + continue; + + PxPlane pi = convexes[(uint32_t)fi.convexNr]->getPlanes()[(uint32_t)fi.faceNr]; + if (convexes[(uint32_t)fi.convexNr]->isGhostConvex()) + pi.n = -pi.n; + + PxPlane pj = convexes[(uint32_t)fj.convexNr]->getPlanes()[(uint32_t)fj.faceNr]; + if (convexes[(uint32_t)fj.convexNr]->isGhostConvex()) + pj.n = -pj.n; + + if (pi.n.dot(pj.n) > -1.0f + eps) + continue; // need to be opposite + + if ( + touching(convexes[(uint32_t)fi.convexNr], fi.faceNr, convexes[(uint32_t)fj.convexNr], eps) || + touching(convexes[(uint32_t)fj.convexNr], fj.faceNr, convexes[(uint32_t)fi.convexNr], eps)) + { + n.area = 0.5f*( fabsf(faceArea(convexes[(uint32_t)fi.convexNr], fi.faceNr)) + fabsf(faceArea(convexes[(uint32_t)fj.convexNr], fj.faceNr))); + if (computeFaceCoverage) { + float area = faceIntersectionArea(convexes[(uint32_t)fi.convexNr], fi.faceNr, convexes[(uint32_t)fj.convexNr], fj.faceNr); + mFaceCoverage[(uint32_t)fi.globalNr] += area; + mFaceCoverage[(uint32_t)fj.globalNr] += area; + } + + n.convexNr = fj.convexNr; + n.next = mFirstNeighbor[(uint32_t)fi.convexNr]; + mFirstNeighbor[(uint32_t)fi.convexNr] = (int32_t)mNeighbors.size(); + mNeighbors.pushBack(n); + + n.convexNr = fi.convexNr; + n.next = mFirstNeighbor[(uint32_t)fj.convexNr]; + mFirstNeighbor[(uint32_t)fj.convexNr] = (int32_t)mNeighbors.size(); + mNeighbors.pushBack(n); + } + } + } + + if (computeFaceCoverage) { + uint32_t globalNr = 0; + + for (uint32_t i = 0; i < convexes.size(); i++) { + const Convex *c = convexes[i]; + int numFaces = (int32_t)c->getPlanes().size(); + for (int j = 0; j < numFaces; j++) { + float total = faceArea(c, j); + if (total != 0.0f) + mFaceCoverage[globalNr] /= total; + globalNr++; + } + } + } + + mNeigborPairsDirty = true; +} + +// ----------------------------------------------------------------------------- +bool IslandDetector::axisOverlap(const Convex* c0, const Convex* c1, PxVec3 &dir) +{ + float off0 = c0->getMaterialOffset().dot(dir); + float off1 = c1->getMaterialOffset().dot(dir); + const nvidia::Array<PxVec3> &verts0 = c0->getVertices(); + const nvidia::Array<PxVec3> &verts1 = c1->getVertices(); + if (verts0.empty() || verts1.empty()) + return false; + + float d0 = dir.dot(verts0[0]) + off0; + float d1 = dir.dot(verts1[0]) + off1; + if (d0 < d1) { + float max0 = d0; + for (uint32_t i = 1; i < verts0.size(); i++) { + float d = verts0[i].dot(dir) + off0; + if (d > max0) max0 = d; + } + for (uint32_t i = 0; i < verts1.size(); i++) { + float d = verts1[i].dot(dir) + off1; + if (d < max0) + return true; + } + } + else { + float max1 = d1; + for (uint32_t i = 1; i < verts1.size(); i++) { + float d = verts1[i].dot(dir) + off1; + if (d > max1) max1 = d; + } + for (uint32_t i = 0; i < verts0.size(); i++) { + float d = verts0[i].dot(dir) + off0; + if (d < max1) + return true; + } + } + return false; +} + +// ----------------------------------------------------------------------------- +bool IslandDetector::overlap(const Convex* c0, const Convex* c1) +{ + PxVec3 off0 = c0->getMaterialOffset(); + PxVec3 off1 = c1->getMaterialOffset(); + PxVec3 center0 = c0->getCenter() + off0; + PxVec3 center1 = c1->getCenter() + off1; + PxVec3 dir = center1 - center0; + + if (!axisOverlap(c0, c1, dir)) + return false; + + // todo: test other axes + + return true; +} + +// ----------------------------------------------------------------------------- +void IslandDetector::addOverlapConnectivity(const nvidia::Array<Convex*> &convexes) +{ + mBounds.resize(convexes.size()); + PxVec3 off; + + for (uint32_t i = 0; i < convexes.size(); i++) { + const Convex *c = convexes[i]; + const PxBounds3 &cb = c->getBounds(); + off = c->getMaterialOffset(); + + PxBounds3 &b = mBounds[i]; + b.minimum = cb.minimum + off; + b.maximum = cb.maximum + off; + } + + // broad phase with AABBs + Axes axes; + axes.set(0,2,1); + mBoxPruning.completeBoxPruning(mBounds, mPairs, axes); + + for (uint32_t i = 0; i < mPairs.size(); i += 2) { + uint32_t i0 = mPairs[i]; + uint32_t i1 = mPairs[i+1]; + + if (convexes[i0]->getModelIslandNr() == convexes[i1]->getModelIslandNr()) + continue; + + // already detected? + bool found = false; + int nr = mFirstNeighbor[i0]; + while (nr >= 0) { + Neighbor &n = mNeighbors[(uint32_t)nr]; + nr = n.next; + if (n.convexNr == (int32_t)i1) { + found = true; + break; + } + } + if (found) + continue; + + if (overlap(convexes[i0], convexes[i1])) { + Neighbor n; + + // add link + n.convexNr = (int32_t)i0; + n.next = mFirstNeighbor[i1]; + mFirstNeighbor[i1] = (int32_t)mNeighbors.size(); + mNeighbors.pushBack(n); + + n.convexNr = (int32_t)i1; + n.next = mFirstNeighbor[i0]; + mFirstNeighbor[i0] = (int32_t)mNeighbors.size(); + mNeighbors.pushBack(n); + } + + } +} + +// ----------------------------------------------------------------------------- +void IslandDetector::createIslands() +{ + uint32_t numConvexes = mFirstNeighbor.size(); + mIslands.clear(); + mIslandConvexes.clear(); + + Island island; + + // color convexes + mColors.clear(); + mColors.resize(numConvexes,-1); + int color = -1; + + for (uint32_t i = 0; i < numConvexes; i++) { + if (mColors[i] >= 0) + continue; + mQueue.clear(); + mQueue.pushBack((int32_t)i); + color++; + island.firstNr = (int32_t)mIslandConvexes.size(); + island.size = 0; + + while (mQueue.size() > 0) { + int convexNr = mQueue[mQueue.size()-1]; + mQueue.popBack(); + if (mColors[(uint32_t)convexNr] >= 0) + continue; + mColors[(uint32_t)convexNr] = color; + mIslandConvexes.pushBack(convexNr); + island.size++; + + int nr = mFirstNeighbor[(uint32_t)convexNr]; + while (nr >= 0) { + int adj = mNeighbors[(uint32_t)nr].convexNr; + nr = mNeighbors[(uint32_t)nr].next; + if (mColors[(uint32_t)adj] < 0) + mQueue.pushBack(adj); + } + } + mIslands.pushBack(island); + } +} + +// ----------------------------------------------------------------------------- +float IslandDetector::faceArea(const Convex *c, int faceNr) +{ + const Convex::Face &face = c->getFaces()[(uint32_t)faceNr]; + const nvidia::Array<PxVec3> &verts = c->getVertices(); + const nvidia::Array<int> &indices = c->getIndices(); + + float area = 0.0f; + PxVec3 p0 = verts[(uint32_t)indices[(uint32_t)face.firstIndex]]; + for (int i = 1; i < face.numIndices-1; i++) { + PxVec3 p1 = verts[(uint32_t)indices[uint32_t(face.firstIndex+i)]]; + PxVec3 p2 = verts[(uint32_t)indices[uint32_t(face.firstIndex+i+1)]]; + area += (p1-p0).cross(p2-p0).magnitude(); + } + return 0.5f * area; +} + +// ----------------------------------------------------------------------------- +float IslandDetector::faceIntersectionArea(const Convex *c0, int faceNr0, const Convex *c1, int faceNr1) +{ + // vertices of the first face + mCutPolys[0].clear(); + mCutPolys[1].clear(); + + const Convex::Face &face0 = c0->getFaces()[(uint32_t)faceNr0]; + const nvidia::Array<PxVec3> &verts0 = c0->getVertices(); + const nvidia::Array<int> &indices0 = c0->getIndices(); + + const Convex::Face &face1 = c1->getFaces()[(uint32_t)faceNr1]; + const nvidia::Array<PxVec3> &verts1 = c1->getVertices(); + const nvidia::Array<int> &indices1 = c1->getIndices(); + + for (int i = 0; i < face0.numIndices; i++) + mCutPolys[0].pushBack(verts0[(uint32_t)indices0[uint32_t(face0.firstIndex + i)]]); + + const PxVec3 &n0 = c0->getPlanes()[(uint32_t)faceNr0].n; + + // cut face 0 polygon with face 1 polygon + for (int i = 0; i < face1.numIndices; i++) { + const PxVec3 &p0 = verts1[(uint32_t)indices1[uint32_t(face1.firstIndex + (i+1)%face1.numIndices)]]; + const PxVec3 &p1 = verts1[(uint32_t)indices1[uint32_t(face1.firstIndex + i)]]; + PxVec3 n = (p1-p0).cross(n0); + float d = n.dot(p0); + + nvidia::Array<PxVec3> &currPoly = mCutPolys[uint32_t(i%2)]; + nvidia::Array<PxVec3> &newPoly = mCutPolys[uint32_t(1 - (i%2))]; + newPoly.clear(); + + uint32_t num = currPoly.size(); + for (uint32_t j = 0; j < num; j++) { + PxVec3 &q0 = currPoly[j]; + PxVec3 &q1 = currPoly[(j+1) % num]; + + bool inside0 = q0.dot(n) < d; + bool inside1 = q1.dot(n) < d; + + if (inside0) + newPoly.pushBack(currPoly[j]); // point inside -> keep + + if (inside0 != inside1) { // intersection + float s = (d - q0.dot(n)) / (q1-q0).dot(n); + PxVec3 ps = q0 + s*(q1-q0); + newPoly.pushBack(ps); + } + } + } + + // measure area + float area = 0.0f; + nvidia::Array<PxVec3> &currPoly = mCutPolys[face1.numIndices%2]; + if (currPoly.size() < 3) + return 0.0f; + + PxVec3 &p0 = currPoly[0]; + for (uint32_t i = 1; i < currPoly.size()-1; i++) { + PxVec3 &p1 = currPoly[i]; + PxVec3 &p2 = currPoly[i+1]; + area += (p1-p0).cross(p2-p0).magnitude(); + } + return 0.5f * area; +} + +// ----------------------------------------------------------------------------- +const nvidia::Array<IslandDetector::Edge> &IslandDetector::getNeighborEdges() +{ + if (mNeigborPairsDirty) { + Edge e; + mNeighborPairs.clear(); + for (uint32_t i = 0; i < mFirstNeighbor.size(); i++) { + int nr = mFirstNeighbor[i]; + e.n0 = (int32_t)i; + while (nr >= 0) { + Neighbor &n = mNeighbors[(uint32_t)nr]; + nr = n.next; + if (n.convexNr > (int32_t)i) { + e.n1 = n.convexNr; + e.area = n.area; + mNeighborPairs.pushBack(e); + //mNeighborPairs.pushBack(i); + //mNeighborPairs.pushBack(n.convexNr); + } + } + } + mNeigborPairsDirty = false; + } + return mNeighborPairs; +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.h b/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.h new file mode 100644 index 00000000..d13ed849 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef ISLAND_DETECTOR_BASE_H +#define ISLAND_DETECTOR_BASE_H + +// Matthias Muller-Fischer + +#include <PxVec3.h> +#include <PsArray.h> +#include "IceBoxPruningBase.h" +#include <PsUserAllocated.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +class SimScene; +class Convex; + +// --------------------------------------------------------------------------------------- +class IslandDetector : public UserAllocated { + friend class SimScene; +public: + // singleton pattern + //static IslandDetector* getInstance(); + //static void destroyInstance(); + + void detect(const nvidia::Array<Convex*> &convexes, bool computeFaceCoverage); + + struct Island { + int size; + int firstNr; + }; + const nvidia::Array<Island> &getIslands() { return mIslands; } + const nvidia::Array<int> &getIslandConvexes() { return mIslandConvexes; } + + const nvidia::Array<float> &getFaceCoverage() { return mFaceCoverage; } + + class Edge{ + public: + int n0, n1; + float area; + }; + const nvidia::Array<Edge> &getNeighborEdges(); + +protected: + IslandDetector(SimScene* scene); + virtual ~IslandDetector(){} + + void createConnectivity(const nvidia::Array<Convex*> &convexes, bool computeFaceCoverage); + static bool touching(const Convex *c0, int faceNr, const Convex *c1, float eps); + void createIslands(); + + float faceArea(const Convex *c, int faceNr); + float faceIntersectionArea(const Convex *c0, int faceNr0, const Convex *c1, int faceNr1); + + bool axisOverlap(const Convex* c0, const Convex* c1, PxVec3 &dir); + bool overlap(const Convex* c0, const Convex* c1); + + void addOverlapConnectivity(const nvidia::Array<Convex*> &convexes); + + SimScene* mScene; + + // auxiliary + nvidia::Array<int> mFirstNeighbor; + struct Neighbor { + int convexNr; + int next; + float area; + }; + nvidia::Array<Neighbor> mNeighbors; + struct Face { + int convexNr; + int faceNr; + float orderVal; + int globalNr; + bool operator < (const Face &f) const { return orderVal < f.orderVal; } + }; + bool mNeigborPairsDirty; + nvidia::Array<Edge> mNeighborPairs; + nvidia::Array<float> mNeighborAreaPairs; + nvidia::Array<Face> mFaces; + nvidia::Array<int> mColors; + nvidia::Array<int> mQueue; + + nvidia::Array<PxVec3> mCutPolys[2]; + + // overlaps + BoxPruning mBoxPruning; + nvidia::Array<PxBounds3> mBounds; + nvidia::Array<uint32_t> mPairs; + + // output + nvidia::Array<Island> mIslands; + nvidia::Array<int> mIslandConvexes; + nvidia::Array<float> mFaceCoverage; +}; + +} +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/MeshBase.cpp b/APEX_1.4/module/destructible/fracture/Core/MeshBase.cpp new file mode 100644 index 00000000..fecbd5d2 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/MeshBase.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include <PxBounds3.h> + +#include "MeshBase.h" +#include <algorithm> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace nvidia; + +// ---------------------------------------------------------------------- +void Mesh::updateNormals() +{ + if (mVertices.empty()) + return; + + PxVec3 zero(0.0f, 0.0f, 0.0f); + + mNormals.resize(mVertices.size()); + for (uint32_t i = 0; i < mNormals.size(); i++) + mNormals[i] = zero; + PxVec3 n; + + uint32_t *idx = &mIndices[0]; + uint32_t numTriangles = mIndices.size() / 3; + for (uint32_t i = 0; i < numTriangles; i++) { + uint32_t i0 = *idx++; + uint32_t i1 = *idx++; + uint32_t i2 = *idx++; + n = (mVertices[i1] - mVertices[i0]).cross(mVertices[i2] - mVertices[i0]); + mNormals[i0] += n; + mNormals[i1] += n; + mNormals[i2] += n; + } + for (uint32_t i = 0; i < mNormals.size(); i++) { + if (!mNormals[i].isZero()) + mNormals[i].normalize(); + } +} + +// ------------------------------------------------------------------------------ +void Mesh::getBounds(PxBounds3 &bounds, int subMeshNr) const +{ + bounds.setEmpty(); + if (subMeshNr < 0 || subMeshNr >= (int)mSubMeshes.size()) { + for (uint32_t i = 0; i < mVertices.size(); i++) + bounds.include(mVertices[i]); + } + else { + const SubMesh &sm = mSubMeshes[(uint32_t)subMeshNr]; + for (int i = 0; i < sm.numIndices; i++) { + bounds.include(mVertices[(uint32_t)mIndices[uint32_t(sm.firstIndex + i)]]); + } + } +} + +// ------------------------------------------------------------------------------ +void Mesh::normalize(const PxVec3 ¢er, float diagonal) +{ + if (mVertices.size() < 3) + return; + + PxBounds3 bounds; + getBounds(bounds); + + float s = diagonal / bounds.getDimensions().magnitude(); + PxVec3 c = 0.5f * (bounds.minimum + bounds.maximum); + + for (uint32_t i = 0; i < mVertices.size(); i++) + mVertices[i] = center + (mVertices[i] - c) * s; +} + +// ------------------------------------------------------------------------------ +void Mesh::scale(float diagonal) +{ + if (mVertices.size() < 3) + return; + + PxBounds3 bounds; + getBounds(bounds); + + float s = diagonal / bounds.getDimensions().magnitude(); + for (uint32_t i = 0; i < mVertices.size(); i++) + mVertices[i] *= s; +} + +// -------------------------------------------------------------------------------------------- +struct IdEdge { + void set(uint32_t &i0, uint32_t &i1, int faceNr, int edgeNr) { + if (i0 < i1) { this->i0 = i0; this->i1 = i1; } + else { this->i0 = i1; this->i1 = i0; } + this->faceNr = faceNr; this->edgeNr = edgeNr; + } + bool operator < (const IdEdge &e) const { + if (i0 < e.i0) return true; + if (i0 == e.i0 && i1 < e.i1) return true; + return false; + } + bool operator == (const IdEdge &e) const { return i0 == e.i0 && i1 == e.i1; } + uint32_t i0,i1; + int faceNr, edgeNr; +}; + +// ------------------------------------------------------------------------------ +bool Mesh::computeNeighbors() +{ + uint32_t numTris = mIndices.size() / 3; + + nvidia::Array<IdEdge> edges(3*numTris); + + for (uint32_t i = 0; i < numTris; i++) { + for (uint32_t j = 0; j < 3; j++) + edges[3*i+j].set(mIndices[3*i+j], mIndices[3*i + (j+1)%3], (int32_t)i, (int32_t)j); + } + std::sort(edges.begin(), edges.end()); + + mNeighbors.clear(); + mNeighbors.resize(mIndices.size(), -1); + bool manifold = true; + uint32_t i = 0; + while (i < edges.size()) { + IdEdge &e0 = edges[i]; + i++; + if (i < edges.size() && edges[i] == e0) { + IdEdge &e1 = edges[i]; + mNeighbors[uint32_t(3* e0.faceNr + e0.edgeNr)] = e1.faceNr; + mNeighbors[uint32_t(3* e1.faceNr + e1.edgeNr)] = e0.faceNr; + i++; + } + while (i < edges.size() && edges[i] == e0) { + manifold = false; + i++; + } + } + return manifold; +} + +// -------------------------------------------------------------------------------------------- +struct PosEdge { + // not using indices for edge match but positions + // so duplicated vertices are handled as one vertex + static bool smaller(const PxVec3 &v0, const PxVec3 &v1) { + if (v0.x < v1.x) return true; + if (v0.x > v1.x) return false; + if (v0.y < v1.y) return true; + if (v0.y > v1.y) return false; + return (v0.z < v1.z); + } + void set(const PxVec3 &v0, const PxVec3 &v1, int faceNr, int edgeNr) { + if (smaller(v0,v1)) { this->v0 = v0; this->v1 = v1; } + else { this->v0 = v1; this->v1 = v0; } + this->faceNr = faceNr; this->edgeNr = edgeNr; + } + bool operator < (const PosEdge &e) const { + if (smaller(v0, e.v0)) return true; + if (v0 == e.v0 && smaller(v1, e.v1)) return true; + return false; + } + bool operator == (const PosEdge &e) const { return v0 == e.v0 && v1 == e.v1; } + PxVec3 v0,v1; + int faceNr, edgeNr; +}; + +// ------------------------------------------------------------------------------ +bool Mesh::computeWeldedNeighbors() +{ + uint32_t numTris = mIndices.size() / 3; + nvidia::Array<PosEdge> edges(3*numTris); + + for (uint32_t i = 0; i < numTris; i++) { + for (uint32_t j = 0; j < 3; j++) + edges[3*i+j].set(mVertices[(uint32_t)mIndices[3*i+j]], mVertices[(uint32_t)mIndices[3*i + (j+1)%3]], (int32_t)i, (int32_t)j); + } + std::sort(edges.begin(), edges.end()); + + mNeighbors.clear(); + mNeighbors.resize(mIndices.size(), -1); + bool manifold = true; + uint32_t i = 0; + while (i < edges.size()) { + PosEdge &e0 = edges[i]; + i++; + if (i < edges.size() && edges[i] == e0) { + PosEdge &e1 = edges[i]; + mNeighbors[uint32_t(3* e0.faceNr + e0.edgeNr)] = e1.faceNr; + mNeighbors[uint32_t(3* e1.faceNr + e1.edgeNr)] = e0.faceNr; + i++; + } + while (i < edges.size() && edges[i] == e0) { + manifold = false; + i++; + } + } + return manifold; +} + +void Mesh::flipV() +{ + for(uint32_t i = 0; i < mTexCoords.size(); i++) + { + mTexCoords[i].y = 1.0f - mTexCoords[i].y; + } +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/MeshBase.h b/APEX_1.4/module/destructible/fracture/Core/MeshBase.h new file mode 100644 index 00000000..db4617c4 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/MeshBase.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef MESH_BASE +#define MESH_BASE + +#include <PxVec3.h> +#include <PxVec2.h> +#include <PsArray.h> +#include <PsUserAllocated.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +// ----------------------------------------------------------------------------------- +class Mesh : public UserAllocated +{ +public: + Mesh() {}; + virtual ~Mesh() {}; + + const nvidia::Array<PxVec3> &getVertices() const { return mVertices; } + const nvidia::Array<PxVec3> &getNormals() const { return mNormals; } + const nvidia::Array<PxVec2> &getTexCoords() const { return mTexCoords; } + const nvidia::Array<uint32_t> &getIndices() const { return mIndices; } + const nvidia::Array<int> &getNeighbors() const { return mNeighbors; } + + struct SubMesh { + void init() { /*name = "";*/ firstIndex = -1; numIndices = 0; } + //std::string name; + int firstIndex; + int numIndices; + }; + + const nvidia::Array<SubMesh> &getSubMeshes() const { return mSubMeshes; } + + void normalize(const PxVec3 ¢er, float diagonal); + void scale(float diagonal); + void getBounds(PxBounds3 &bounds, int subMeshNr = -1) const; + + void flipV(); // flips v values to hand coordinate system change (Assumes normalized coordinates) + + bool computeNeighbors(); + bool computeWeldedNeighbors(); + +protected: + void clear(); + void updateNormals(); + + nvidia::Array<PxVec3> mVertices; + nvidia::Array<PxVec3> mNormals; + nvidia::Array<PxVec2> mTexCoords; + + nvidia::Array<SubMesh> mSubMeshes; + nvidia::Array<uint32_t> mIndices; + nvidia::Array<int> mNeighbors; +}; + +} +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.cpp b/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.cpp new file mode 100644 index 00000000..cccbb023 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.cpp @@ -0,0 +1,1439 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "MeshClipperBase.h" +#include "PsSort.h" +#include "ConvexBase.h" +#include <PxAssert.h> + +#define DEBUG 0 +#if DEBUG +#include <stdio.h> +#else +#define printf(...) +#define fwrite(...) +#define fread(...) +#define fopen(...) +#define fclose(...) +#endif + +#include "SimSceneBase.h" + +#pragma warning(disable:4127) + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace nvidia; + +int vecFloor(float f ) { return (int)::floorf(f); } + +#define DUMP_PATH "c:\\meshClipDump.bin" + +// ----------------------------------------------------------------------------- +MeshClipper::MeshClipper(SimScene* scene) +{ + mScene = scene; + mMeshConvex = NULL; + mClipConvex = NULL; + mDumpOnError = false; +} + +// ----------------------------------------------------------------------------- +void MeshClipper::Mesh::clear() +{ + vertices.clear(); + normals.clear(); + tangents.clear(); + texCoords.clear(); + polyStarts.resize(1, 0); + polyIndices.clear(); + polyNeighbors.clear(); +} + +// ----------------------------------------------------------------------------- +//PxVec3 MeshClipper::conv(const Vec3 &v) +//{ +// return PxVec3((float)v.x, (float)v.y, (float)v.z); +//} +// +//Vec3 MeshClipper::conv(const PxVec3 &v) +//{ +// return Vec3((VecReal)v.x, (VecReal)v.y, (VecReal)v.z); +//} +// +//Plane MeshClipper::conv(const PxPlane &p) +//{ +// return Plane(conv(p.n), VecReal(p.d)); +//} +// +//Transform MeshClipper::conv(const PxTransform &t) +//{ +// return Transform(conv(t.p), Quat(t.q.x, t.q.y, t.q.z, t.q.w)); +//} + +// ----------------------------------------------------------------------------- +int MeshClipper::getNumMeshes() +{ + if (mOutMeshes.size() == 1) // no islands + return 1; + else + return (int32_t)mOutMeshes.size()-1; +} + +// ----------------------------------------------------------------------------- +const MeshClipper::Mesh& MeshClipper::getMesh(int meshNr) +{ + if (mOutMeshes.size() == 1) // no islands + return mOutMeshes[0]; + else + return mOutMeshes[1 + (uint32_t)meshNr]; +} + +// ----------------------------------------------------------------------------- +void MeshClipper::init(const Convex *meshConvex) +{ + if (!meshConvex->hasExplicitVisMesh()) { + mMeshConvex = NULL; + return; + } + + mMeshConvex = meshConvex; + const nvidia::Array<PxVec3> &verts = mMeshConvex->getVisVertices(); + mMeshVertices.resize(verts.size()); + for (uint32_t i = 0; i < verts.size(); i++) + mMeshVertices[i] = verts[i]; + + PxVec3 center(0.0, 0.0, 0.0); + for (uint32_t i = 0; i < mMeshVertices.size(); i++) + center += mMeshVertices[i]; + center /= (float)mMeshVertices.size(); + + for (uint32_t i = 0; i < mMeshVertices.size(); i++) { + mMeshVertices[i] = center + (mMeshVertices[i] - center) * 1.001f; + } + + const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts(); + const nvidia::Array<int> &meshPolyIndices = mMeshConvex->getVisPolyIndices(); + uint32_t numPolys = meshPolyStarts.size()-1; + + mPolyBounds.resize(numPolys); + for (uint32_t i = 0; i < numPolys; i++) { + int first = meshPolyStarts[i]; + int last = meshPolyStarts[i+1]; + mPolyBounds[i].setEmpty(); + for (int k = first; k < last; k++) + mPolyBounds[i].include(mMeshVertices[(uint32_t)meshPolyIndices[(uint32_t)k]]); + } + + createGrid(); +} + +// -------------------------------------------------------------------------------------------- +void MeshClipper::createGrid() +{ + const uint32_t minGridPolys = 1000; + + uint32_t numPolys = mPolyBounds.size(); + mGridFirstPoly.clear(); + + if (numPolys < minGridPolys) + return; + + // determine grid dimensions + PxBounds3 meshBounds; + meshBounds.setEmpty(); + for (uint32_t i = 0; i < mMeshVertices.size(); i++) + meshBounds.include(mMeshVertices[i]); + PxVec3 meshExtent = meshBounds.maximum - meshBounds.minimum; + + // number of cells in the order of num polygons +// int targetNumCells = numPolys; + float targetNumCells = 10000; + float s3 = meshExtent.x * meshExtent.y * meshExtent.z / (float)targetNumCells; + mGridSpacing = PxPow((float)s3, 1.0f/3.0f); + + mGridBounds.minimum = meshBounds.minimum; + mGridNumX = vecFloor(meshExtent.x / mGridSpacing) + 1; + mGridNumY = vecFloor(meshExtent.y / mGridSpacing) + 1; + mGridNumZ = vecFloor(meshExtent.z / mGridSpacing) + 1; + uint32_t numCells = uint32_t(mGridNumX * mGridNumY * mGridNumZ); + mGridBounds.maximum = mGridBounds.minimum + + PxVec3(mGridNumX * mGridSpacing, mGridNumY * mGridSpacing, mGridNumZ * mGridSpacing); + + mGridFirstPoly.resize(numCells+1, -0); + mGridPolys.clear(); + + // histogram + //float h = mGridSpacing; + float h1 = 1.0f / mGridSpacing; + PxBounds3 polyBounds; + for (uint32_t i = 0; i < numPolys; i++) { + PxBounds3 &polyBounds = mPolyBounds[i]; + int x0 = (int)((polyBounds.minimum.x - mGridBounds.minimum.x) * h1); + int y0 = (int)((polyBounds.minimum.y - mGridBounds.minimum.y) * h1); + int z0 = (int)((polyBounds.minimum.z - mGridBounds.minimum.z) * h1); + int x1 = (int)((polyBounds.maximum.x - mGridBounds.minimum.x) * h1); + int y1 = (int)((polyBounds.maximum.y - mGridBounds.minimum.y) * h1); + int z1 = (int)((polyBounds.maximum.z - mGridBounds.minimum.z) * h1); + for (int xi = x0; xi <= x1; xi++) { + for (int yi = y0; yi <= y1; yi++) { + for (int zi = z0; zi <= z1; zi++) { + int nr = (xi * mGridNumY + yi) * mGridNumZ + zi; + mGridFirstPoly[(uint32_t)nr]++; + } + } + } + } + int first = 0; + for (uint32_t i = 0; i < numCells; i++) { + first += mGridFirstPoly[i]; + mGridFirstPoly[i] = first; + } + mGridFirstPoly[numCells] = first; + mGridPolys.resize((uint32_t)first); + + // fill in + for (uint32_t i = 0; i < numPolys; i++) { + PxBounds3 &polyBounds = mPolyBounds[i]; + int x0 = (int)((polyBounds.minimum.x - mGridBounds.minimum.x) * h1); + int y0 = (int)((polyBounds.minimum.y - mGridBounds.minimum.y) * h1); + int z0 = (int)((polyBounds.minimum.z - mGridBounds.minimum.z) * h1); + int x1 = (int)((polyBounds.maximum.x - mGridBounds.minimum.x) * h1); + int y1 = (int)((polyBounds.maximum.y - mGridBounds.minimum.y) * h1); + int z1 = (int)((polyBounds.maximum.z - mGridBounds.minimum.z) * h1); + for (int xi = x0; xi <= x1; xi++) { + for (int yi = y0; yi <= y1; yi++) { + for (int zi = z0; zi <= z1; zi++) { + int nr = (xi * mGridNumY + yi) * mGridNumZ + zi; + mGridFirstPoly[(uint32_t)nr]--; + mGridPolys[(uint32_t)mGridFirstPoly[(uint32_t)nr]] = (int32_t)i; + } + } + } + } + mGridPolyMarks.clear(); + mGridPolyMarks.resize(numPolys, 0); + mGridCurrentMark = 1; +} + +// -------------------------------------------------------------------------------------------- +void MeshClipper::computeClipFaceNeighbors() +{ + const nvidia::Array<int> &indices = mClipConvex->getIndices(); + const nvidia::Array<Convex::Face> &faces = mClipConvex->getFaces(); + + mClipFaceNeighbors.clear(); + mClipFaceNeighbors.resize(indices.size(), -1); + + mEdges.resize(indices.size()); + //int edgeNr = 0; + for (uint32_t i = 0; i < faces.size(); i++) { + const Convex::Face &f = faces[i]; + for (int j = 0; j < f.numIndices; j++) { + int edgeNr = f.firstIndex + j; + mEdges[(uint32_t)edgeNr].init(indices[uint32_t(f.firstIndex + j)], indices[uint32_t(f.firstIndex + (j+1)%f.numIndices)], edgeNr, (int32_t)i); + } + } + shdfnd::sort(mEdges.begin(), mEdges.size()); + uint32_t i = 0; + while (i < mEdges.size()) { + Edge &e0 = mEdges[i]; + i++; + if (i < mEdges.size() && mEdges[i] == e0) { + Edge &e1 = mEdges[i]; + mClipFaceNeighbors[(uint32_t)e0.edgeNr] = e1.faceNr; + mClipFaceNeighbors[(uint32_t)e1.edgeNr] = e0.faceNr; + i++; + } + while (i < mEdges.size() && mEdges[i] == e0) + i++; + } +} + +// -------------------------------------------------------------------------------------------- +bool MeshClipper::getGridCandidates(const PxBounds3 &bounds) +{ + if (mGridFirstPoly.empty()) + return false; // too few mesh polygons, no grid created + + float h1 = 1.0f / mGridSpacing; + mGridCurrentMark++; // make sure we return any poligon only once + + int x0 = vecFloor((bounds.minimum.x - mGridBounds.minimum.x) * h1); + int y0 = vecFloor((bounds.minimum.y - mGridBounds.minimum.y) * h1); + int z0 = vecFloor((bounds.minimum.z - mGridBounds.minimum.z) * h1); + int x1 = vecFloor((bounds.maximum.x - mGridBounds.minimum.x) * h1); + int y1 = vecFloor((bounds.maximum.y - mGridBounds.minimum.y) * h1); + int z1 = vecFloor((bounds.maximum.z - mGridBounds.minimum.z) * h1); + + if (x0 < 0) x0 = 0; + if (y0 < 0) y0 = 0; + if (z0 < 0) z0 = 0; + if (x1 >= mGridNumX) x1 = mGridNumX-1; + if (y1 >= mGridNumY) y1 = mGridNumY-1; + if (z1 >= mGridNumZ) z1 = mGridNumZ-1; + + + mPolyCandidates.clear(); + + for (int xi = x0; xi <= x1; xi++) { + for (int yi = y0; yi <= y1; yi++) { + for (int zi = z0; zi <= z1; zi++) { + int nr = (xi * mGridNumY + yi) * mGridNumZ + zi; + int first = mGridFirstPoly[(uint32_t)nr]; + int last = mGridFirstPoly[(uint32_t)nr+1]; + for (int i = first; i < last; i++) { + int polyNr = mGridPolys[(uint32_t)i]; + if (mGridPolyMarks[(uint32_t)polyNr] != mGridCurrentMark) { + mGridPolyMarks[(uint32_t)polyNr] = mGridCurrentMark; + mPolyCandidates.pushBack(polyNr); + } + } + } + } + } + return true; +} + +// -------------------------------------------------------------------------------------------- +void MeshClipper::generateCandidates(const PxTransform &pxTrans) +{ + // cull polys that are completely outside of at least one convex plane + // determine polys that are completely inside of all convex planes + + const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts(); + const nvidia::Array<int> &meshPolyIndices = mMeshConvex->getVisPolyIndices(); + + const nvidia::Array<PxPlane> &clipPlanes = mClipConvex->getPlanes(); + const nvidia::Array<PxVec3> &clipConvexVertices = mClipConvex->getVertices(); + + PxTransform trans = (pxTrans); + PxTransform invTrans = trans.getInverse(); + + PxBounds3 clipBounds; + clipBounds.setEmpty(); + for (uint32_t i = 0; i < clipConvexVertices.size(); i++) + clipBounds.include(invTrans.transform((clipConvexVertices[i]))); + + uint32_t numPolys = meshPolyStarts.size()-1; + + // use grid for initial culling + if (!getGridCandidates(clipBounds)) { + mPolyCandidates.resize(numPolys); // no grid, start with all polys + for (uint32_t i = 0; i < numPolys; i++) + mPolyCandidates[i] = (int32_t)i; + } + + // use bounding boxes for further culling + PxBounds3 polyBounds; + uint32_t numCandidates = 0; + for (uint32_t i = 0; i < mPolyCandidates.size(); i++) { + int polyNr = mPolyCandidates[i]; + PxBounds3 &polyBounds = mPolyBounds[(uint32_t)polyNr]; + if (polyBounds.intersects(clipBounds)) { + mPolyCandidates[numCandidates] = polyNr; + numCandidates++; + } + } + mPolyCandidates.resize(numCandidates); + + // use clip planes for further culling + mPolyInside.resize(0); + mPolyInside.resize(numPolys, true); + + for (uint32_t i = 0; i < clipPlanes.size(); i++) { + PxPlane plane = (clipPlanes[i]); + plane.n = invTrans.rotate(plane.n); + plane.d = plane.d + invTrans.p.dot(plane.n); + + uint32_t numCandidates = 0; + for (uint32_t j = 0; j < mPolyCandidates.size(); j++) { + uint32_t polyNr = (uint32_t)mPolyCandidates[j]; + int first = meshPolyStarts[polyNr]; + int last = meshPolyStarts[polyNr+1]; + bool outside = true; + for (int k = first; k < last; k++) { + PxVec3 &p = mMeshVertices[(uint32_t)meshPolyIndices[(uint32_t)k]]; + float dot = plane.n.dot(p); + if (dot > plane.d) + mPolyInside[polyNr] = false; + if (dot < plane.d) + outside = false; + if (!mPolyInside[polyNr] && !outside) + break; + } + if (!outside) { + mPolyCandidates[numCandidates] = (int32_t)polyNr; + numCandidates++; + } + } + mPolyCandidates.resize(numCandidates); + } +} + +// -------------------------------------------------------------------------------------------- +bool MeshClipper::createInternalPolygons(const PxTransform &pxTrans) +{ +#if VEC3_DOUBLE + const float eps = 1e-8f; +#else + const float eps = 1e-4f; +#endif + + PxTransform trans = (pxTrans); + + const nvidia::Array<PxVec3> &meshNormals = mMeshConvex->getVisNormals(); + const nvidia::Array<PxVec3> &meshTangents = mMeshConvex->getVisTangents(); + const nvidia::Array<float> &meshTexCoords = mMeshConvex->getVisTexCoords(); + + const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts(); + const nvidia::Array<int> &meshPolyIndices = mMeshConvex->getVisPolyIndices(); + const nvidia::Array<int> &meshPolyNeighbors = mMeshConvex->getVisPolyNeighbors(); + + const nvidia::Array<PxPlane> &clipPlanes = mClipConvex->getPlanes(); + //const nvidia::Array<Convex::Face> &clipConvexFaces = mClipConvex->getFaces(); + + uint32_t current = 0; + Mesh &out = mOutMeshes[0]; + + for (uint32_t i = 0; i < mPolyCandidates.size(); i++) { + uint32_t polyNr = (uint32_t)mPolyCandidates[i]; + + int first = meshPolyStarts[polyNr]; + int last = meshPolyStarts[polyNr+1]; + int polySize = last - first; + PX_ASSERT(polySize >= 3); + + // initialize working poly with original poly + // todo: fast poly for insides + + mClipPolyStarts[current].resize(2, 0); + mClipPolyStarts[current][1] = polySize; + + mClipPolyVerts[current].resize((uint32_t)polySize); + + if (mPolyInside[polyNr]) { // fast path for polygons completely inside convex + + mFirstOutPoly[polyNr] = (int32_t)out.polyStarts.size()-1; + mNumOutPolys[polyNr] = 1; + + for (int j = 0; j < polySize; j++) { + uint32_t id = (uint32_t)meshPolyIndices[uint32_t(first + j)]; + if (mOutVertNr[id] < 0) { + mOutVertNr[id] = (int32_t)out.vertices.size(); + out.vertices.pushBack((trans.transform(mMeshVertices[id]))); + out.normals.pushBack(pxTrans.rotate(meshNormals[id])); + out.tangents.pushBack(pxTrans.rotate(meshTangents[id])); + out.texCoords.pushBack(meshTexCoords[2*id]); + out.texCoords.pushBack(meshTexCoords[2*id+1]); + } + out.polyIndices.pushBack(mOutVertNr[id]); + out.polyNeighbors.pushBack(meshPolyNeighbors[uint32_t(first + j)]); + } + out.polyStarts.pushBack((int32_t)out.polyIndices.size()); + continue; + } + + for (int j = 0; j < polySize; j++) { + PolyVert &pv = mClipPolyVerts[current][(uint32_t)j]; + pv.init(); + pv.id = meshPolyIndices[uint32_t(first + j)]; + pv.pos = trans.transform(mMeshVertices[(uint32_t)pv.id]); + pv.normal = trans.rotate((meshNormals[(uint32_t)pv.id])); + pv.tangent = trans.rotate((meshTangents[(uint32_t)pv.id])); + pv.u = meshTexCoords[2 * (uint32_t)pv.id]; + pv.v = meshTexCoords[2 * (uint32_t)pv.id + 1]; + pv.edgeNeighbor = meshPolyNeighbors[uint32_t(first + j)]; + pv.edgeOnFace = false; + } + + // determine face normal + PxVec3 faceNormal(0.0, 0.0, 0.0); + PxVec3 &p0 = mClipPolyVerts[current][0].pos; + for (int j = 1; j < polySize-1; j++) { + PxVec3 &p1 = mClipPolyVerts[current][(uint32_t)j].pos; + PxVec3 &p2 = mClipPolyVerts[current][(uint32_t)j+1].pos; + faceNormal += (p1-p0).cross(p2-p0); + } + faceNormal.normalize(); + + // clip working poly against all planes + for (uint32_t j = 0; j < clipPlanes.size(); j++) { + + const PxPlane plane = (clipPlanes[j]); + PxVec3 cutNormal = faceNormal.cross(plane.n); + if (cutNormal.magnitudeSquared() < eps * eps) + continue; + + uint32_t prev = current; + current = 1-current; + + mClipPolyStarts[current].clear(); + mClipPolyStarts[current].pushBack(0); + mClipPolyVerts[current].clear(); + + uint32_t numPrevPolys = mClipPolyStarts[prev].size()-1; + if (numPrevPolys == 0) + break; + + for (uint32_t k = 0; k < numPrevPolys; k++) { + int prevFirst = mClipPolyStarts[prev][k]; + int prevLast = mClipPolyStarts[prev][k+1]; + int prevNum = prevLast - prevFirst; + + // determine cuts + mCuts.clear(); + bool anyIn = false; + + for (int l = 0; l < prevNum; l++) { + PolyVert &pv0 = mClipPolyVerts[prev][uint32_t(prevFirst + l)]; + PolyVert &pv1 = mClipPolyVerts[prev][uint32_t(prevFirst + (l+1)%prevNum)]; + pv0.nextVert = -1; + + bool sign0 = plane.n.dot(pv0.pos) > plane.d; + bool sign1 = plane.n.dot(pv1.pos) > plane.d; + + if (!sign0 || !sign1) + anyIn = true; + + if (sign0 == sign1) + continue; + + PxVec3 p0 = pv0.pos; + PxVec3 p1 = pv1.pos; + + // compute in unique order such that cut positions are identical on shared edges + bool smaller = + (p0.x < p1.x) || + (p0.x == p1.x && p0.y < p1.y) || + (p0.x == p1.x && p0.y == p1.y && p0.z < p1.z); + if (smaller) { + p0 = pv1.pos; + p1 = pv0.pos; + } + + float t = (p1 - p0).dot(plane.n); + if (t == 0.0) + continue; + t = (plane.d - p0.dot(plane.n)) / t; + + PolyVert cut; + cut.init(); + cut.pos = p0 + (p1 - p0) * t; + if (smaller) { + cut.normal = pv1.normal + (pv0.normal - pv1.normal) * t; + cut.tangent = pv1.tangent + (pv0.tangent - pv1.tangent) * t; + cut.u = pv1.u + (pv0.u - pv1.u) * t; + cut.v = pv1.v + (pv0.v - pv1.v) * t; + } + else { + cut.normal = pv0.normal + (pv1.normal - pv0.normal) * t; + cut.tangent = pv0.tangent + (pv1.tangent - pv0.tangent) * t; + cut.u = pv0.u + (pv1.u - pv0.u) * t; + cut.v = pv0.v + (pv1.v - pv0.v) * t; + } + cut.normal.normalize(); + cut.tangent.normalize(); + cut.id = -1; + + // vertex following this cut + if (sign1) { + cut.edgeOnFace = true; + cut.edgeNeighbor = (int32_t)j; // planeNr + cut.nextVert = -1; // exit convex + } + else { + cut.edgeOnFace = pv0.edgeOnFace; + cut.edgeNeighbor = pv0.edgeNeighbor; + cut.nextVert = (l+1)%prevNum; // enter convex + } + + pv0.nextVert = (int32_t)mCuts.size(); + mCuts.pushBack(cut); + } + if (!anyIn) + continue; + + // poly not cut, copy 1:1 + if (mCuts.empty()) { + for (int l = 0; l < prevNum; l++) { + PolyVert &pv = mClipPolyVerts[prev][uint32_t(prevFirst + l)]; + mClipPolyVerts[current].pushBack(pv); + } + mClipPolyStarts[current].pushBack((int32_t)mClipPolyVerts[current].size()); + continue; + } + + // construct new polygon(s) + for (uint32_t l = 0; l < mCuts.size(); l++) + { + if (mCuts[l].nextVert < 0) // exit polygon + continue; + + // start a polygon from this cut + int nr = mCuts[l].nextVert; + mCuts[l].nextVert = -1; // visited + mClipPolyVerts[current].pushBack(mCuts[l]); + + int safetyCnt = 0; + + while ( true ) + { + if (!check(safetyCnt < prevNum + (int)mCuts.size(), "construct new polygons infinite loop")) + return false; + safetyCnt++; + + if (!check(nr >= 0, "construct new polygons loop not closed")) + return false; + + if(nr >= (int)mClipPolyVerts[prev].size()) // prevents a crash + return false; + + mClipPolyVerts[current].pushBack(mClipPolyVerts[prev][(uint32_t)nr]); + int cutNr = mClipPolyVerts[prev][(uint32_t)nr].nextVert; + if (cutNr < 0) { + nr = (nr+1) % prevNum; + continue; + } + // we reached the next cut + mClipPolyVerts[current].pushBack(mCuts[(uint32_t)cutNr]); + + // find the closest cut to the left + float s0 = mCuts[(uint32_t)cutNr].pos.dot(cutNormal); + float sMax = -FLT_MAX; + float sMin = FLT_MAX; + int minNr = -1; + int maxNr = -1; + for (int m = 0; m < (int)mCuts.size(); m++) { + float s = mCuts[(uint32_t)m].pos.dot(cutNormal); + if (s > s0 && s < sMin) { + sMin = s; + minNr = m; + } + if (s > sMax) { + sMax = s; + maxNr = m; + } + } + uint32_t nextCutNr = uint32_t((minNr >= 0) ? minNr : maxNr); + + if (nextCutNr == l) + break; // loop closed + + PolyVert &nextCut = mCuts[nextCutNr]; + nr = nextCut.nextVert; + nextCut.nextVert = -1; // visited + mClipPolyVerts[current].pushBack(nextCut); + } + // close poly + mClipPolyStarts[current].pushBack((int32_t)mClipPolyVerts[current].size()); + } + } + } // next plane + + // map from old to new poly numbers + mFirstOutPoly[polyNr] = (int32_t)out.polyStarts.size()-1; + mNumOutPolys[polyNr] = (int32_t)mClipPolyStarts[current].size()-1; + // separate num needed because we do not process the polys with candidate list, not in order + + // clipped poly empty? + if (mNumOutPolys[polyNr] <= 0) + continue; + + // create visual polygon(s) + for (uint32_t j = 0; j < mClipPolyStarts[current].size()-1; j++) { + int first = mClipPolyStarts[current][j]; + int last = mClipPolyStarts[current][j+1]; + int num = last - first; + for (int k = 0; k < num; k++) { + PolyVert &pv0 = mClipPolyVerts[current][uint32_t(first + k)]; + PolyVert &pv1 = mClipPolyVerts[current][uint32_t(first + (k+1)%num)]; + + int id = -1; + int faceId = -1; + + if (!pv0.edgeOnFace && !pv1.edgeOnFace) { // existing vertex, duplicate + if (!check(pv1.id >= 0, "internal vertex with id < 0")) + return false; + + if (mOutVertNr[(uint32_t)pv1.id] < 0) { + mOutVertNr[(uint32_t)pv1.id] = (int32_t)out.vertices.size(); + out.vertices.pushBack((pv1.pos)); + out.normals.pushBack((pv1.normal)); + out.tangents.pushBack((pv1.tangent)); + out.texCoords.pushBack((float)pv1.u); + out.texCoords.pushBack((float)pv1.v); + } + id = mOutVertNr[(uint32_t)pv1.id]; + faceId = -1; + } + else if (pv0.edgeOnFace && pv1.edgeOnFace) { // new, non shared + id = (int32_t)out.vertices.size(); + out.vertices.pushBack((pv1.pos)); + out.normals.pushBack((pv1.normal)); + out.tangents.pushBack((pv1.tangent)); + out.texCoords.pushBack((float)pv1.u); + out.texCoords.pushBack((float)pv1.v); + faceId = id; + } + else { // new, shared + int edgeNeighbor = pv0.edgeOnFace ? pv1.edgeNeighbor : pv0.edgeNeighbor; + int sharedId = -1; + int numPolys = mNumOutPolys[(uint32_t)edgeNeighbor]; + + // new neighbor exists, search shared vertex + if (numPolys > 0) { + int firstPoly = mFirstOutPoly[(uint32_t)edgeNeighbor]; + for (int l = 0; l < numPolys; l++) { + int newPolyNr = firstPoly + l; + int first = out.polyStarts[(uint32_t)newPolyNr]; + int last = out.polyStarts[(uint32_t)newPolyNr+1]; + for (int m = first; m < last; m++) { + int testId = out.polyIndices[(uint32_t)m]; + if (out.vertices[(uint32_t)testId] == (pv1.pos)) { + sharedId = testId; + break; + } + } + if (sharedId >= 0) + break; + } + } + if (sharedId >= 0 && out.normals[(uint32_t)sharedId] == (pv1.normal)) // share it + id = sharedId; + else { + id = (int32_t)out.vertices.size(); // create new + out.vertices.pushBack((pv1.pos)); + out.normals.pushBack((pv1.normal)); + out.tangents.pushBack((pv1.tangent)); + out.texCoords.pushBack((float)pv1.u); + out.texCoords.pushBack((float)pv1.v); + } + if (sharedId >= 0) + faceId = sharedId; // on the convex surface we need the shared id to make the surface poly connected + else + faceId = id; + } + out.polyIndices.pushBack(id); + out.polyNeighbors.pushBack(pv1.edgeOnFace ? -1 : pv1.edgeNeighbor); + pv1.id = faceId; + } + out.polyStarts.pushBack((int32_t)out.polyIndices.size()); // close poly + + // create face vertices + for (int k = 0; k < num; k++) { + PolyVert &pv0 = mClipPolyVerts[current][uint32_t(first + k)]; + PolyVert &pv1 = mClipPolyVerts[current][uint32_t(first + (k+1)%num)]; + if (!pv0.edgeOnFace && !pv1.edgeOnFace) + continue; + + if (pv1.id >= (int)mFaceVertNrs.size()) + mFaceVertNrs.resize((uint32_t)pv1.id + 1, -1); + + int &vertNr = mFaceVertNrs[(uint32_t)pv1.id]; + if (vertNr < 0) { + FaceVert newSv; + newSv.init(); + vertNr = (int32_t)mFaceVerts.size(); + mFaceVerts.pushBack(newSv); + } + FaceVert &sv = mFaceVerts[(uint32_t)vertNr]; + sv.id = pv1.id; + } + + // create face polyline + for (int k = 0; k < num; k++) { + PolyVert &pv0 = mClipPolyVerts[current][uint32_t(first + k)]; + PolyVert &pv1 = mClipPolyVerts[current][uint32_t(first + (k+1)%num)]; + + if (pv1.id < 0) // not on surface + continue; + + FaceVert &sv = mFaceVerts[(uint32_t)mFaceVertNrs[(uint32_t)pv1.id]]; + if (pv0.edgeOnFace) { + sv.nextFaceNr = pv0.edgeNeighbor; + sv.neighborPos = out.polyStarts[out.polyStarts.size()-2] + (k+num-1)%num; + sv.neighborPolyNr = (int32_t)out.polyStarts.size()-2; + sv.nextVert = mFaceVertNrs[(uint32_t)pv0.id]; + } + if (pv1.edgeOnFace) { + sv.prevFaceNr = pv1.edgeNeighbor; + } + } + } + } // next polygon candidate + + // fix neighbors + for (int i = 0; i < (int)out.polyStarts.size()-1; i++) { + int first = out.polyStarts[(uint32_t)i]; + int num = out.polyStarts[(uint32_t)i+1] - first; + for (int j = 0; j < num; j++) { + int oldNr = out.polyNeighbors[uint32_t(first + j)]; + if (oldNr < 0) + continue; + + int numNew = mNumOutPolys[(uint32_t)oldNr]; + if (!check(numNew > 0, "fix internal neighbors, no new polygond created")) + return false; + + if (numNew == 1) { // simple mapping + out.polyNeighbors[uint32_t(first + j)] = mFirstOutPoly[(uint32_t)oldNr]; + } + else { // find correct new poly + PxVec3 v1 = out.vertices[(uint32_t)out.polyIndices[uint32_t(first + (j+1)%num)]]; + float minD2 = PX_MAX_F32; + int minNr = -1; + + for (int k = 0; k < numNew; k++) { + int newNr = mFirstOutPoly[(uint32_t)oldNr] + k; + int firstNew = out.polyStarts[(uint32_t)newNr]; + int lastNew = out.polyStarts[(uint32_t)newNr+1]; + for (int l = firstNew; l < lastNew; l++) { + PxVec3 v0 = out.vertices[(uint32_t)out.polyIndices[(uint32_t)l]]; + float d2 = (v1-v0).magnitudeSquared(); + if (d2 < minD2) { + minD2 = d2; + minNr = newNr; + } + } + } + out.polyNeighbors[uint32_t(first + j)] = minNr; + } + } + } + + return true; +} + +// -------------------------------------------------------------------------------------------- +bool MeshClipper::createFacePolys() +{ + const nvidia::Array<PxPlane> &clipPlanes = mClipConvex->getPlanes(); + const nvidia::Array<Convex::Face> &clipConvexFaces = mClipConvex->getFaces(); + const nvidia::Array<PxVec3> &clipConvexVertices = mClipConvex->getVertices(); + const nvidia::Array<int> &clipConvexIndices = mClipConvex->getIndices(); + + mFaceTypes.clear(); + mFaceTypes.resize(clipConvexFaces.size(), 0); + mFaceOfPoly.clear(); + + Mesh &out = mOutMeshes[0]; + int firstFacePoly = (int32_t)out.polyStarts.size()-1; + + + // create face polys + for (uint32_t i = 0; i < mFaceVerts.size(); i++) { + FaceVert &startSv = mFaceVerts[i]; + if (startSv.visited) + continue; + + int faceNr = startSv.nextFaceNr; + if (!check(faceNr >= 0, "create face polygons, loop interrupted")) + return false; + + mFaceTypes[(uint32_t)faceNr] = 1; // has visual mesh + + PxVec3 faceNormal = clipPlanes[(uint32_t)faceNr].n; + PxVec3 t0,t1; + // tangents + if (fabs(faceNormal.x) < fabs(faceNormal.y) && fabs(faceNormal.x) < fabs(faceNormal.z)) + t0 = PxVec3(1.0f, 0.0f, 0.0f); + else if (fabs(faceNormal.y) < fabs(faceNormal.z)) + t0 = PxVec3(0.0f, 1.0f, 0.0); + else + t0 = PxVec3(0.0f, 0.0f, 1.0f); + t1 = faceNormal.cross(t0); + t1.normalize(); + t0 = t1.cross(faceNormal); + + const Convex::Face &face = clipConvexFaces[(uint32_t)faceNr]; + int thisPolyNr = (int32_t)out.polyStarts.size()-1; + + int vertNr = (int32_t)i; + int safetyCnt = 0; + + while (true) { + if (!check(safetyCnt <= (int)mFaceVerts.size() + (int)clipConvexVertices.size(), "create face polygons infinite loop")) + return false; + safetyCnt++; + + if (!check(vertNr >= 0, "create face polygons loop interrupted")) + return false; + + FaceVert &sv = mFaceVerts[(uint32_t)vertNr]; + + out.polyIndices.pushBack((int32_t)out.vertices.size()); + PxVec3 temp = out.vertices[(uint32_t)sv.id]; + out.vertices.pushBack(temp); + out.normals.pushBack(faceNormal); + out.tangents.pushBack(t0); + out.texCoords.pushBack(out.vertices[(uint32_t)sv.id].dot(t0) * mTexScale); + out.texCoords.pushBack(out.vertices[(uint32_t)sv.id].dot(t1) * mTexScale); + + if (sv.nextFaceNr == faceNr) { // continues on this face + sv.visited = true; + out.polyNeighbors.pushBack(sv.neighborPolyNr); + out.polyNeighbors[(uint32_t)sv.neighborPos] = thisPolyNr; + vertNr = sv.nextVert; + if (vertNr == (int32_t)i) + break; // start reached + else + continue; + } + + // on convex edge, find next entry vert + int edgeNr = 0; + while (edgeNr < face.numIndices && mClipFaceNeighbors[uint32_t(face.firstIndex + edgeNr)] != sv.nextFaceNr) + edgeNr++; + if (!check(edgeNr < face.numIndices, "create face polys, find next entry vert not successfull")) + return false; + + vertNr = -1; + int numCorners = 0; + + for (int j = 0; j <= face.numIndices; j++) { + int adjFaceNr = mClipFaceNeighbors[uint32_t(face.firstIndex + edgeNr)]; + out.polyNeighbors.pushBack(-1-adjFaceNr); + + PxVec3 edgeDir = clipPlanes[(uint32_t)faceNr].n.cross(clipPlanes[(uint32_t)adjFaceNr].n); + float s0 = out.vertices[out.vertices.size()-1].dot(edgeDir); + float minS = PX_MAX_F32; + int minK = -1; + for (uint32_t k = 0; k < mFaceVerts.size(); k++) { // todo: create edge face vert list to speed up + FaceVert &vk = mFaceVerts[k]; +// if (vk.id < 0) continue; + if (vk.nextFaceNr != faceNr || vk.prevFaceNr != adjFaceNr) + continue; + float si = out.vertices[(uint32_t)vk.id].dot(edgeDir); + if (si > s0 && si < minS) { + minS = si; + minK = (int32_t)k; + } + } + + if (minK >= 0) { + vertNr = minK; + break; + } + + // no entry found, add corner of convex + PxVec3 pos = clipConvexVertices[(uint32_t)clipConvexIndices[uint32_t(face.firstIndex + (edgeNr+1)%face.numIndices)]]; + out.vertices.pushBack(pos); + out.normals.pushBack(faceNormal); + out.tangents.pushBack(t0); + out.texCoords.pushBack(pos.dot(t0) * mTexScale); + out.texCoords.pushBack(pos.dot(t1) * mTexScale); + + out.polyIndices.pushBack((int32_t)out.vertices.size()-1); + if (numCorners > 0) { + if (mFaceTypes[(uint32_t)mClipFaceNeighbors[uint32_t(face.firstIndex + edgeNr)]] == 0) + mFaceTypes[(uint32_t)mClipFaceNeighbors[uint32_t(face.firstIndex + edgeNr)]] = 2; // inside visual mesh + } + + numCorners++; + edgeNr = (edgeNr+1) % face.numIndices; + } + if (vertNr == (int32_t)i) + break; // loop closed + } + + mFaceOfPoly.pushBack(faceNr); + out.polyStarts.pushBack((int32_t)out.polyIndices.size()); // close face poly + } + + // determine faces completely inside the visual mesh via flood fill + // start at faces of type 2 and fill all faces of type 0 + // reagion is bounded by faces of type 1 containing the visual mesh + for (uint32_t i = 0; i < mFaceTypes.size(); i++) { + if (mFaceTypes[i] != 2) + continue; + mFaceTypes[i] = 0; + mFaceQueue.resize(1, (int32_t)i); + while (mFaceQueue.size() > 0) { + uint32_t faceNr = (uint32_t)mFaceQueue[mFaceQueue.size()-1]; + mFaceQueue.popBack(); + if (mFaceTypes[faceNr] != 0) + continue; + mFaceTypes[faceNr] = 2; + const Convex::Face &face = clipConvexFaces[faceNr]; + for (int j = 0; j < face.numIndices; j++) { + int adjFaceNr = mClipFaceNeighbors[uint32_t(face.firstIndex + j)]; + if (mFaceTypes[(uint32_t)adjFaceNr] == 0) + mFaceQueue.pushBack(adjFaceNr); + } + } + } + + // create a polygon for each complete face inside the mesh + for (uint32_t i = 0; i < clipConvexFaces.size(); i++) { + if (mFaceTypes[i] != 2) + continue; + const Convex::Face &face = clipConvexFaces[i]; + PxVec3 faceNormal = clipPlanes[i].n; + + // tangents + PxVec3 t0,t1; + if (fabs(faceNormal.x) < fabs(faceNormal.y) && fabs(faceNormal.x) < fabs(faceNormal.z)) + t0 = PxVec3(1.0f, 0.0f, 0.0f); + else if (fabs(faceNormal.y) < fabs(faceNormal.z)) + t0 = PxVec3(0.0f, 1.0f, 0.0); + else + t0 = PxVec3(0.0f, 0.0f, 1.0f); + t1 = faceNormal.cross(t0); + t1.normalize(); + t0 = t1.cross(faceNormal); + + for (int j = 0; j < (int)face.numIndices; j++) { + PxVec3 pos = clipConvexVertices[(uint32_t)clipConvexIndices[uint32_t(face.firstIndex + j)]]; + out.vertices.pushBack(pos); + out.normals.pushBack(faceNormal); + out.tangents.pushBack(t0); + out.texCoords.pushBack(pos.dot(t0) * mTexScale); + out.texCoords.pushBack(pos.dot(t1) * mTexScale); + + out.polyIndices.pushBack((int32_t)out.vertices.size()-1); + out.polyNeighbors.pushBack(-1-mClipFaceNeighbors[uint32_t(face.firstIndex+j)]); + } + mFaceOfPoly.pushBack((int32_t)i); + out.polyStarts.pushBack((int32_t)out.polyIndices.size()); + } + + // fix face polygon neighbors + for (uint32_t i = (uint32_t)firstFacePoly; i < out.polyStarts.size()-1; i++) { + int first = out.polyStarts[i]; + int num = out.polyStarts[i+1] - first; + for (int j = 0; j < num; j++) { + int adjFaceNr = out.polyNeighbors[uint32_t(first + j)]; + if (adjFaceNr >= 0) + continue; + adjFaceNr = -1 - adjFaceNr; + PxVec3 &p0 = out.vertices[(uint32_t)out.polyIndices[uint32_t(first + (j+1)%num)]]; + float minD2 = PX_MAX_F32; + int minAdjPolyNr = -1; + + for (uint32_t k = 0; k < mFaceOfPoly.size(); k++) { + if (mFaceOfPoly[k] != adjFaceNr) + continue; + int adjPolyNr = firstFacePoly + (int32_t)k; + int adjFirst = out.polyStarts[(uint32_t)adjPolyNr]; + int adjLast = out.polyStarts[(uint32_t)adjPolyNr+1]; + for (int l = adjFirst; l < adjLast; l++) { + PxVec3 &p1 = out.vertices[(uint32_t)out.polyIndices[(uint32_t)l]]; + float d2 = (p0 - p1).magnitudeSquared(); + if (d2 < minD2) { + minD2 = d2; + minAdjPolyNr = adjPolyNr; + } + } + } + if (!check(minAdjPolyNr >= 0, "create face polys, fix neighbors")) + return false; + + out.polyNeighbors[uint32_t(first + j)] = minAdjPolyNr; + } + } + return true; +} + +// -------------------------------------------------------------------------------------------- +bool MeshClipper::clip(const Convex *clipConvex, const PxTransform &trans, float texScale, bool splitIslands, + bool &empty, bool &completelyInside) +{ + if (mMeshConvex == NULL) + return false; + + mTexScale = texScale; + + mClipConvex = clipConvex; + computeClipFaceNeighbors(); + + empty = true; + completelyInside = false; + + mOutMeshes.resize(1); + Mesh &out = mOutMeshes[0]; + mOutMeshes[0].clear(); + + mFaceVertNrs.clear(); // necessary? + mFaceVerts.clear(); + + const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts(); + //const nvidia::Array<PxPlane> &clipPlanes = mClipConvex->getPlanes(); + const nvidia::Array<Convex::Face> &clipConvexFaces = mClipConvex->getFaces(); + const nvidia::Array<PxVec3> &clipConvexVertices = mClipConvex->getVertices(); + + int numPolys = (int32_t)meshPolyStarts.size()-1; + + mScene->profileBegin("generate poly candidates"); + generateCandidates(trans); + mScene->profileEnd("generate poly candidates"); + + mFirstOutPoly.clear(); // speed up, use only local mesh part + mFirstOutPoly.resize((uint32_t)numPolys, -1); + mNumOutPolys.clear(); + mNumOutPolys.resize((uint32_t)numPolys, 0); + + mOutVertNr.clear(); + mOutVertNr.resize(mMeshVertices.size(), -1); + mFirstOutFacePoly.clear(); + mFirstOutFacePoly.resize(clipConvexFaces.size(), -1); + mNumOutFacePolys.clear(); + mNumOutFacePolys.resize(clipConvexFaces.size(), 0); + + mScene->profileBegin("create internal polygons"); + if (!createInternalPolygons(trans)) { + empty = true; + mScene->profileEnd("create internal polygons"); + return false; + } + mScene->profileEnd("create internal polygons"); + + if (out.polyStarts.size() <= 1) { // cut empty + + // inside visual mesh? + + PxVec3 center(0.0f, 0.0f, 0.0f); + for (uint32_t i = 0; i < clipConvexVertices.size(); i++) + center += clipConvexVertices[i]; + center /= (float)clipConvexVertices.size(); + if (mMeshConvex->insideVisualMesh(trans.transformInv(center))) { + empty = false; + completelyInside = true; + return true; + } + else { + empty = true; + completelyInside = false; + return true; + } + } + + empty = true; + + mScene->profileBegin("create face polys"); + bool OK = createFacePolys(); + mScene->profileEnd("create face polys"); + if (!OK) + return false; + + //if (!testNeighbors()) + // return false; + + if (splitIslands) + this->splitIslands(); + + empty = false; + return true; +} + + + +// -------------------------------------------------------------------------------------------- +bool MeshClipper::splitIslands() +{ + if (mOutMeshes.size() < 1) + return false; + + uint32_t numPolys = mOutMeshes[0].polyStarts.size()-1; + mColors.clear(); + mColors.resize(numPolys, -1); + mQueue.clear(); + + int numIslands = 0; + + // color islands + for (uint32_t i = 0; i < numPolys; i++) { + if (mColors[i] >= 0) + continue; + numIslands++; + mQueue.clear(); + mQueue.pushBack((int32_t)i); + while (!mQueue.empty()) { + uint32_t polyNr = (uint32_t)mQueue[mQueue.size()-1]; + mQueue.popBack(); + if (mColors[polyNr] >= 0) + continue; + mColors[polyNr] = numIslands-1; + int first = mOutMeshes[0].polyStarts[polyNr]; + int last = mOutMeshes[0].polyStarts[polyNr+1]; + for (int j = first; j < last; j++) { + int neighborNr = mOutMeshes[0].polyNeighbors[(uint32_t)j]; + if (mColors[(uint32_t)neighborNr] >= 0) + continue; + mQueue.pushBack(neighborNr); + } + } + } + + // only one island? + if (numIslands <= 1) + return false; + + // create child meshes + mOutMeshes.resize((uint32_t)numIslands+1); + for (uint32_t i = 0; i < (uint32_t)numIslands; i++) { + mOutMeshes[1+i].clear(); + } + + // distribute visual mesh + mNewVertNr.clear(); + mNewVertNr.resize(mOutMeshes[0].vertices.size(), -1); + mNewPolyNr.clear(); + mNewPolyNr.resize(numPolys, -1); + + for (uint32_t i = 0; i < numPolys; i++) { + int meshNr = mColors[i]; + Mesh &parent = mOutMeshes[0]; + Mesh &child = mOutMeshes[(uint32_t)meshNr+1]; + int first = parent.polyStarts[i]; + int last = parent.polyStarts[i+1]; + for (int j = first; j < last; j++) { + uint32_t id = (uint32_t)parent.polyIndices[(uint32_t)j]; + if (mNewVertNr[id] < 0) { + mNewVertNr[id] = (int32_t)child.vertices.size(); + child.vertices.pushBack(parent.vertices[id]); + child.normals.pushBack(parent.normals[id]); + child.tangents.pushBack(parent.tangents[id]); + child.texCoords.pushBack(parent.texCoords[2*id]); + child.texCoords.pushBack(parent.texCoords[2*id+1]); + } + child.polyIndices.pushBack(mNewVertNr[id]); + child.polyNeighbors.pushBack(parent.polyNeighbors[(uint32_t)j]); // cannot adjust neighbor number yet + } + mNewPolyNr[i] = (int32_t)child.polyStarts.size()-1; + child.polyStarts.pushBack((int32_t)child.polyIndices.size()); + } + + // adjust neighbor numbers + //int num = 0; + for (int i = 0; i < numIslands; i++) { + Mesh &child = mOutMeshes[1+(uint32_t)i]; + for (int j = 0; j < (int)child.polyStarts.size()-1; j++) { + int first = child.polyStarts[(uint32_t)j]; + int last = child.polyStarts[(uint32_t)j+1]; + for (int k = first; k < last; k++) { + child.polyNeighbors[(uint32_t)k] = mNewPolyNr[(uint32_t)child.polyNeighbors[(uint32_t)k]]; + } + } + } + return true; +} + +// -------------------------------------------------------------------------------------------- +bool MeshClipper::insideVisualMesh(const PxVec3 & /*pos*/) const +{ + //if (mMeshConvex == NULL) + // return false; + + //const nvidia::Array<PxVec3> &meshNormals = mMeshConvex->getVisNormals(); + //const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts(); + //const nvidia::Array<int> &meshPolyIndices = mMeshConvex->getVisPolyIndices(); + //const nvidia::Array<int> &meshPolyNeighbors = mMeshConvex->getVisPolyNeighbors(); + + //int num[6] = {0,0,0,0,0,0}; + //const int numAxes = 2; // max 3: the nigher the more robust but slower + + //for (int i = 0; i < (int)mVisTriIndices.size(); i += 3) { + // const PxVec3 &p0 = mVisVertices[mVisTriIndices[i]]; + // const PxVec3 &p1 = mVisVertices[mVisTriIndices[i+1]]; + // const PxVec3 &p2 = mVisVertices[mVisTriIndices[i+2]]; + // PxVec3 n = (p1-p0).cross(p2-p0); + // float d = n.dot(p0); + // float ds = d - pos.dot(n); + + // // for all axes, cound the hits of the ray starting from pos with the mesh + // for (int j = 0; j < numAxes; j++) { + // if (n[j] == 0.0f) + // continue; + + // int j0 = (j+1)%3; + // int j1 = (j+2)%3; + // float x0 = p0[j0]; + // float y0 = p0[j1]; + // float x1 = p1[j0]; + // float y1 = p1[j1]; + // float x2 = p2[j0]; + // float y2 = p2[j1]; + + // float px = pos[j0]; + // float py = pos[j1]; + + // // inside triangle? + // float d0 = (x1-x0) * (py-y0) - (y1-y0) * (px-x0); + // float d1 = (x2-x1) * (py-y1) - (y2-y1) * (px-x1); + // float d2 = (x0-x2) * (py-y2) - (y0-y2) * (px-x2); + // bool inside = + // (d0 <= 0.0f && d1 <= 0.0f && d2 <= 0.0f) || + // (d0 >= 0.0f && d1 >= 0.0f && d2 >= 0.0f); + // if (!inside) + // continue; + + // float s = ds / n[j]; + // if (s > 0.0f) + // num[2*j] += (n[j] > 0.0f) ? +1 : -1; + // else + // num[2*j+1] += (n[j] < 0.0f) ? +1 : -1; + // } + //} + //int numVotes = 0; + //for (int i = 0; i < 6; i++) { + // if (num[i] > 0) + // numVotes++; + //} + //return numVotes > numAxes; + return false; +} + +// -------------------------------------------------------------------------------------------- +bool MeshClipper::testNeighbors(int meshNr) +{ + if (meshNr >= (int)mOutMeshes.size()) + return false; + Mesh &mesh = mOutMeshes[(uint32_t)meshNr]; + + for (int i = 0; i < (int)mesh.polyStarts.size()-1; i++) { + int first = mesh.polyStarts[(uint32_t)i]; + int num = mesh.polyStarts[(uint32_t)i+1] - first; + for (int j = 0; j < num; j++) { + uint32_t i0 = (uint32_t)mesh.polyIndices[uint32_t(first+j)]; + uint32_t i1 = (uint32_t)mesh.polyIndices[uint32_t(first + (j+1)%num)]; + PxVec3 p0 = mesh.vertices[i0]; + PxVec3 p1 = mesh.vertices[i1]; + + int adj = mesh.polyNeighbors[uint32_t(first + j)]; + if (adj < 0) + return false; + + int adjFirst = mesh.polyStarts[(uint32_t)adj]; + int adjNum = mesh.polyStarts[(uint32_t)adj+1] - adjFirst; + bool found = false; + for (int k = 0; k < adjNum; k++) { + if (mesh.polyNeighbors[uint32_t(adjFirst+k)] == i) { + uint32_t j0 = (uint32_t)mesh.polyIndices[uint32_t(adjFirst+k)]; + uint32_t j1 = (uint32_t)mesh.polyIndices[uint32_t(adjFirst + (k+1)%adjNum)]; + PxVec3 q0 = mesh.vertices[j0]; + PxVec3 q1 = mesh.vertices[j1]; + if (p0 == q1 && p1 == q0) + found = true; + } + } + if (!found) + return false; + } + } + return true; +} + +// ----------------------------------------------------------------------------- +bool MeshClipper::check(bool test, const char* /*message*/) +{ +#ifndef _DEBUG + return test; +#else + + if (test) + return true; + + printf("\nerror in MeshClipper.cpp: %s\n", message); + + if (!mDumpOnError) + return test; +#endif + +#if DEBUG + FILE *f = fopen(DUMP_PATH, "wb"); + if (f == NULL) + return test; +#endif + +#ifdef _DEBUG + + printf("dump file saved: %s\n", DUMP_PATH); + + const nvidia::Array<PxVec3> &meshVertices = mMeshConvex->getVisVertices(); + //const nvidia::Array<PxVec3> &meshNormals = mMeshConvex->getVisNormals(); + const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts(); + const nvidia::Array<int> &meshPolyIndices = mMeshConvex->getVisPolyIndices(); + //const nvidia::Array<int> &meshPolyNeighbors = mMeshConvex->getVisPolyNeighbors(); + + int cnt = (int)meshVertices.size(); + fwrite(&cnt, sizeof(int), 1, f); + fwrite(&meshVertices[0], sizeof(PxVec3), meshVertices.size(), f); + fwrite(&meshNormals[0], sizeof(PxVec3), meshNormals.size(), f); + + cnt = (int)meshPolyStarts.size(); + fwrite(&cnt, sizeof(int), 1, f); + fwrite(&meshPolyStarts[0], sizeof(int), meshPolyStarts.size(), f); + + cnt = (int)meshPolyIndices.size(); + fwrite(&cnt, sizeof(int), 1, f); + fwrite(&meshPolyIndices[0], sizeof(int), meshPolyIndices.size(), f); + + fclose(f); + return false; +#endif +} + +// ----------------------------------------------------------------------------- +bool MeshClipper::loadDump() +{ +#if DEBUG + FILE *f = fopen(DUMP_PATH, "rb"); + if (f == NULL) + return false; +#endif + + nvidia::Array<PxVec3> vertices; + nvidia::Array<PxVec3> normals; + nvidia::Array<int> polyStarts; + nvidia::Array<int> polyIndices; + nvidia::Array<int> polyNeighbors; + + uint32_t cnt = 0; + fread(&cnt, sizeof(int), 1, f); + vertices.resize(cnt); + fread(&vertices[0], sizeof(PxVec3), vertices.size(), f); + normals.resize(cnt); + fread(&normals[0], sizeof(PxVec3), normals.size(), f); + + fread(&cnt, sizeof(int), 1, f); + polyStarts.resize(cnt); + fread(&polyStarts[0], sizeof(int), polyStarts.size(), f); + + fread(&cnt, sizeof(int), 1, f); + polyIndices.resize(cnt); + fread(&polyIndices[0], sizeof(int), polyIndices.size(), f); + + fclose(f); + + Convex *c = mScene->createConvex(); + + bool isManifold = c->setExplicitVisMeshFromPolygons( + (int32_t)vertices.size(), &vertices[0], &normals[0], NULL, NULL, // todo, save as well + (int32_t)polyStarts.size()-1, &polyStarts[0], + (int32_t)polyIndices.size(), &polyIndices[0]); + + mMeshConvex = c; + + return isManifold; +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.h b/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.h new file mode 100644 index 00000000..70cd8d03 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef MESH_CLIPPER_BASE_H +#define MESH_CLIPPER_BASE_H + +// Matthias Muller-Fischer + +#include <PxVec3.h> +#include <PsArray.h> +#include <PxTransform.h> +#include <PxBounds3.h> +#include <PsUserAllocated.h> + +//#include "Vec3.h" +//#include "Bounds3.h" +//#include "Transform.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ +//using namespace ::M; +class Convex; +class SimScene; + +// --------------------------------------------------------------------------------------- +class MeshClipper : public UserAllocated { + friend class SimScene; +public: + // singleton pattern + //static MeshClipper* getInstance(); + //static void destroyInstance(); + + void init(const Convex *meshConvex); + bool clip(const Convex *clipConvex, const PxTransform &pxTrans, float texScale, bool splitIslands, + bool &empty, bool &completelyInside); + + struct Mesh { + void clear(); + nvidia::Array<PxVec3> vertices; + nvidia::Array<PxVec3> normals; + nvidia::Array<PxVec3> tangents; + nvidia::Array<float> texCoords; + nvidia::Array<int> polyStarts; + nvidia::Array<int> polyIndices; + nvidia::Array<int> polyNeighbors; + }; + + int getNumMeshes(); + const Mesh &getMesh(int meshNr); + + bool loadDump(); + +protected: + MeshClipper(SimScene* scene); + virtual ~MeshClipper() {} + + //static PxVec3 conv(const Vec3 &v); + //static Vec3 conv(const PxVec3 &v); + //static Transform conv(const PxTransform &t); + //static Plane conv(const PxPlane &p); + + void createGrid(); + bool getGridCandidates(const PxBounds3 &bounds); + + void generateCandidates(const PxTransform &pxTrans); + bool createInternalPolygons(const PxTransform &pxTrans); + bool createFacePolys(); + bool testNeighbors(int meshNr); + + bool splitIslands(); + + bool insideVisualMesh(const PxVec3 &pos) const; + + void computeClipFaceNeighbors(); + + SimScene* mScene; + + // input + const Convex *mMeshConvex; + const Convex *mClipConvex; + nvidia::Array<int> mClipFaceNeighbors; + float mTexScale; + + // output + nvidia::Array<Mesh> mOutMeshes; + + // auxiliaries + struct PolyVert { + void init() { + pos = normal = tangent = PxVec3(0.0, 0.0, 0.0); u = 0.0f; v = 0.0f; + id = -1; edgeNeighbor = -1; edgeOnFace = false; nextVert = -1; + } + PxVec3 pos; + PxVec3 normal; + PxVec3 tangent; + double u, v; + int id; + int edgeNeighbor; + bool edgeOnFace; + int nextVert; + }; + + struct FaceVert { + void init() { + id = -1; prevFaceNr = -1; nextFaceNr = -1; neighborPolyNr = -1; neighborPos = -1; + nextVert = -1; visited = false; + } + int id; + int prevFaceNr, nextFaceNr; + int neighborPolyNr; + int neighborPos; + int nextVert; + bool visited; + }; + + nvidia::Array<PxVec3> mMeshVertices; + nvidia::Array<bool> mPolyInside; + nvidia::Array<int> mPolyCandidates; + + nvidia::Array<PolyVert> mClipPolyVerts[2]; + nvidia::Array<int> mClipPolyStarts[2]; + nvidia::Array<PolyVert> mCuts; + nvidia::Array<int> mFaceVertNrs; + nvidia::Array<FaceVert> mFaceVerts; + nvidia::Array<PxBounds3> mPolyBounds; + + struct Edge { + void init(int i0, int i1, int edgeNr, int faceNr) { + if (i0 < i1) { this->i0 = i0; this->i1 = i1; } + else { this->i0 = i1; this->i1 = i0; } + this->edgeNr = edgeNr; this->faceNr = faceNr; + } + bool operator == (const Edge &e) const { return i0 == e.i0 && i1 == e.i1; } + bool operator < (const Edge &e) const { return i0 < e.i0 || (i0 == e.i0 && i1 < e.i1); } + int i0, i1; + int edgeNr, faceNr; + }; + nvidia::Array<Edge> mEdges; + + // map from int to out mesh + nvidia::Array<int> mFirstOutPoly; + nvidia::Array<int> mNumOutPolys; + nvidia::Array<int> mOutVertNr; + nvidia::Array<int> mFirstOutFacePoly; + nvidia::Array<int> mNumOutFacePolys; + + nvidia::Array<int> mFaceTypes; + nvidia::Array<int> mFaceOfPoly; + nvidia::Array<int> mFaceQueue; + + // split islands + nvidia::Array<int> mColors; + nvidia::Array<int> mQueue; + nvidia::Array<int> mNewVertNr; + nvidia::Array<int> mNewPolyNr; + + // grid + nvidia::Array<int> mGridFirstPoly; + nvidia::Array<int> mGridPolys; + int mGridNumX, mGridNumY, mGridNumZ; + float mGridSpacing; + PxBounds3 mGridBounds; + nvidia::Array<int> mGridPolyMarks; + int mGridCurrentMark; + + // error handling + bool check(bool test, const char *message); + bool mDumpOnError; +}; + +} +} +} + +#endif +#endif diff --git a/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.cpp b/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.cpp new file mode 100644 index 00000000..5a1d892b --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "PolygonTriangulatorBase.h" +#include <PxAssert.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace nvidia; + +// ------ singleton pattern ----------------------------------------------------------- + +//static PolygonTriangulator *gPolygonTriangulator = NULL; +// +//PolygonTriangulator* PolygonTriangulator::getInstance() +//{ +// if (gPolygonTriangulator == NULL) { +// gPolygonTriangulator = PX_NEW(PolygonTriangulator)(); +// } +// return gPolygonTriangulator; +//} +// +//void PolygonTriangulator::destroyInstance() +//{ +// if (gPolygonTriangulator != NULL) { +// PX_DELETE(gPolygonTriangulator); +// } +// gPolygonTriangulator = NULL; +//} + +// ------------------------------------------------------------------------------------- +PolygonTriangulator::PolygonTriangulator(SimScene* scene): + mScene(scene) +{ +} + +// ------------------------------------------------------------------------------------- +PolygonTriangulator::~PolygonTriangulator() +{ +} + +// ------------------------------------------------------------------------------------- +float PolygonTriangulator::cross(const PxVec3 &p0, const PxVec3 &p1) +{ + return p0.x * p1.y - p0.y * p1.x; +} + +// ------------------------------------------------------------------------------------- +bool PolygonTriangulator::inTriangle(const PxVec3 &p, const PxVec3 &p0, const PxVec3 &p1, const PxVec3 &p2) +{ + float d0 = cross(p1 - p0, p - p0); + float d1 = cross(p2 - p1, p - p1); + float d2 = cross(p0 - p2, p - p2); + return (d0 >= 0.0f && d1 >= 0.0f && d2 >= 0.0f) || + (d0 <= 0.0f && d1 <= 0.0f && d2 <= 0.0f); +} + +// ------------------------------------------------------------------------------------- +void PolygonTriangulator::triangulate(const PxVec3 *points, int numPoints, const int *indices, PxVec3 *planeNormal) +{ + mIndices.clear(); + + if (numPoints < 3) + return; + if (numPoints == 3) { + if (indices == NULL) { + mIndices.pushBack(0); + mIndices.pushBack(1); + mIndices.pushBack(2); + } + else { + mIndices.pushBack(indices[0]); + mIndices.pushBack(indices[1]); + mIndices.pushBack(indices[2]); + } + return; + } + + bool isConvex; + importPoints(points, numPoints, indices, planeNormal, isConvex); + + if (isConvex) { // fast path + mIndices.resize(3*((uint32_t)numPoints-2)); + for (int i = 0; i < numPoints-2; i++) { + mIndices[3*(uint32_t)i] = 0; + mIndices[3*(uint32_t)i+1] = i+1; + mIndices[3*(uint32_t)i+2] = i+2; + } + } + else + clipEars(); + + if (indices != NULL) { + for (uint32_t i = 0; i < mIndices.size(); i++) { + mIndices[i] = indices[(uint32_t)mIndices[i]]; + } + } +} + +// ------------------------------------------------------------------------------------- +void PolygonTriangulator::importPoints(const PxVec3 *points, int numPoints, const int *indices, PxVec3 *planeNormal, bool &isConvex) +{ + // find projection 3d -> 2d; + PxVec3 n; + + isConvex = true; + + if (planeNormal) + n = *planeNormal; + else { + PX_ASSERT(numPoints >= 3); + n = PxVec3(0.0f, 0.0f, 0.0f); + + for (int i = 1; i < numPoints-1; i++) { + int i0 = 0; + int i1 = i; + int i2 = i+1; + if (indices) { + i0 = indices[i0]; + i1 = indices[i1]; + i2 = indices[i2]; + } + const PxVec3 &p0 = points[i0]; + const PxVec3 &p1 = points[i1]; + const PxVec3 &p2 = points[i2]; + PxVec3 ni = (p1-p0).cross(p2-p0); + if (i > 1 && ni.dot(n) < 0.0f) + isConvex = false; + n += ni; + } + } + + n.normalize(); + PxVec3 t0,t1; + + if (fabs(n.x) < fabs(n.y) && fabs(n.x) < fabs(n.z)) + t0 = PxVec3(1.0f, 0.0f, 0.0f); + else if (fabs(n.y) < fabs(n.z)) + t0 = PxVec3(0.0f, 1.0f, 0.0f); + else + t0 = PxVec3(0.0f, 0.0f, 1.0f); + t1 = n.cross(t0); + t1.normalize(); + t0 = t1.cross(n); + + mPoints.resize((uint32_t)numPoints); + if (indices == NULL) { + for (uint32_t i = 0; i < (uint32_t)numPoints; i++) + mPoints[i] = PxVec3(points[i].dot(t0), points[i].dot(t1), 0.0f); + } + else { + for (uint32_t i = 0; i < (uint32_t)numPoints; i++) { + const PxVec3 &p = points[(uint32_t)indices[i]]; + mPoints[i] = PxVec3(p.dot(t0), p.dot(t1), 0.0f); + } + } +} + +// ------------------------------------------------------------------------------------- +void PolygonTriangulator::clipEars() +{ + // init + int32_t num = (int32_t)mPoints.size(); + + mCorners.resize((uint32_t)num); + + for (int i = 0; i < num; i++) { + Corner &c = mCorners[(uint32_t)i]; + c.prev = (i > 0) ? i-1 : num-1; + c.next = (i < num-1) ? i + 1 : 0; + c.isEar = false; + c.angle = 0.0f; + PxVec3 &p0 = mPoints[(uint32_t)c.prev]; + PxVec3 &p1 = mPoints[(uint32_t)i]; + PxVec3 &p2 = mPoints[(uint32_t)c.next]; + PxVec3 n1 = p1-p0; + PxVec3 n2 = p2-p1; + if (cross(n1, n2) > 0.0f) { + n1.normalize(); + n2.normalize(); + c.angle = n1.dot(n2); + + c.isEar = true; + int nr = (i+2) % num; + for (int j = 0; j < num-3; j++) { + if (inTriangle(mPoints[(uint32_t)nr], p0,p1,p2)) { + c.isEar = false; + break; + } + nr = (nr+1) % num; + } + } + } + + int firstCorner = 0; + int numCorners = num; + + while (numCorners > 3) { + + // find best ear + float minAng = FLT_MAX; + int minNr = -1; + + int nr = firstCorner; + for (int i = 0; i < numCorners; i++) { + Corner &c = mCorners[(uint32_t)nr]; + if (c.isEar && c.angle < minAng) { + minAng = c.angle; + minNr = nr; + } + nr = c.next; + } + + // cut ear +// assert(minNr >= 0); +if (minNr < 0) +break; + Corner &cmin = mCorners[(uint32_t)minNr]; + mIndices.pushBack(cmin.prev); + mIndices.pushBack(minNr); + mIndices.pushBack(cmin.next); + mCorners[(uint32_t)cmin.prev].next = cmin.next; + mCorners[(uint32_t)cmin.next].prev = cmin.prev; + + if (firstCorner == minNr) + firstCorner = cmin.next; + numCorners--; + if (numCorners == 3) + break; + + // new ears? + for (int i = 0; i < 2; i++) { + uint32_t i1 = uint32_t((i == 0) ? cmin.prev : cmin.next); + uint32_t i0 = (uint32_t)mCorners[i1].prev; + uint32_t i2 = (uint32_t)mCorners[i1].next; + + PxVec3 &p0 = mPoints[i0]; + PxVec3 &p1 = mPoints[i1]; + PxVec3 &p2 = mPoints[i2]; + PxVec3 n1 = p1-p0; + PxVec3 n2 = p2-p1; + if (cross(n1, n2) > 0.0f) { + n1.normalize(); + n2.normalize(); + mCorners[i1].angle = n1.dot(n2); + + mCorners[i1].isEar = true; + int nr = mCorners[i2].next; + for (int j = 0; j < numCorners-3; j++) { + if (inTriangle(mPoints[(uint32_t)nr], p0,p1,p2)) { + mCorners[i1].isEar = false; + break; + } + nr = mCorners[(uint32_t)nr].next; + } + } + } + } + int id = firstCorner; + mIndices.pushBack(id); + id = mCorners[(uint32_t)id].next; + mIndices.pushBack(id); + id = mCorners[(uint32_t)id].next; + mIndices.pushBack(id); +} + +} +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.h b/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.h new file mode 100644 index 00000000..b6441ff2 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef POLYGON_TRIANGULATOR_BASE_H +#define POLYGON_TRIANGULATOR_BASE_H + +#include <PxVec3.h> +#include <PsArray.h> +#include <PsUserAllocated.h> +#include <PxMath.h> + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + class SimScene; + +// ------------------------------------------------------------------------------ + +class PolygonTriangulator : public UserAllocated { + friend class SimScene; +public: + // singleton pattern + //static PolygonTriangulator* getInstance(); + //static void destroyInstance(); + + void triangulate(const PxVec3 *points, int numPoints, const int *indices = NULL, PxVec3 *planeNormal = NULL); + const nvidia::Array<int> &getIndices() const { return mIndices; } + +protected: + void importPoints(const PxVec3 *points, int numPoints, const int *indices, PxVec3 *planeNormal, bool &isConvex); + void clipEars(); + + inline float cross(const PxVec3 &p0, const PxVec3 &p1); + bool inTriangle(const PxVec3 &p, const PxVec3 &p0, const PxVec3 &p1, const PxVec3 &p2); + + PolygonTriangulator(SimScene* scene); + virtual ~PolygonTriangulator(); + + SimScene* mScene; + + nvidia::Array<PxVec3> mPoints; + nvidia::Array<int> mIndices; + + struct Corner { + int prev; + int next; + bool isEar; + float angle; + }; + nvidia::Array<Corner> mCorners; +}; + +} +} +} + +#endif +#endif diff --git a/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.cpp b/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.cpp new file mode 100644 index 00000000..e8b1a7be --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.cpp @@ -0,0 +1,654 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "SimSceneBase.h" +#include <PxMat44.h> +#include "PxRigidBodyExt.h" +#include "PxPhysics.h" +#include "PxCooking.h" +#include "PxShape.h" +#include "PxScene.h" +#include "PxMaterial.h" + +#include "ActorBase.h" +#include "CompoundBase.h" +#include "ConvexBase.h" +#include "CompoundCreatorBase.h" +#include "Delaunay2dBase.h" +#include "Delaunay3dBase.h" +#include "PolygonTriangulatorBase.h" +#include "IslandDetectorBase.h" +#include "MeshClipperBase.h" +#include "FracturePatternBase.h" + +#include "RTdef.h" + +#define USE_CONVEX_RENDERER 1 +#define NUM_NO_SOUND_FRAMES 1 + +//#define REL_VEL_FRACTURE_THRESHOLD 5.0f +#define REL_VEL_FRACTURE_THRESHOLD 0.1f + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +using namespace physx; + +SimScene* SimScene::createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath) +{ + SimScene* s = PX_NEW(SimScene)(pxPhysics,pxCooking,scene,minConvexSize,defaultMat,resourcePath); + s->createSingletons(); + return s; +} + +void SimScene::createSingletons() +{ + mCompoundCreator = PX_NEW(CompoundCreator)(this); + mDelaunay2d = PX_NEW(Delaunay2d)(this); + mDelaunay3d = PX_NEW(Delaunay3d)(this); + mPolygonTriangulator = PX_NEW(PolygonTriangulator)(this); + mIslandDetector = PX_NEW(IslandDetector)(this); + mMeshClipper = PX_NEW(MeshClipper)(this); + addActor(createActor()); // make default actor +} + +Convex* SimScene::createConvex() +{ + return PX_NEW(Convex)(this); +} + +Compound* SimScene::createCompound(const FracturePattern *pattern, const FracturePattern *secondaryPattern, float contactOffset, float restOffset) +{ + return PX_NEW(Compound)(this,pattern,secondaryPattern,contactOffset,restOffset); +} + +FracturePattern* SimScene::createFracturePattern() +{ + return PX_NEW(FracturePattern)(this); +} + +Actor* SimScene::createActor() +{ + return PX_NEW(Actor)(this); +} + +nvidia::Array<Compound*> SimScene::getCompounds() +{ + return mActors[0]->getCompounds(); +} + +///*extern*/ std::vector<Compound*> delCompoundList; + +// -------------------------------------------------------------------------------------------- +SimScene::SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath) +{ + mPxPhysics = pxPhysics; // used for cooking + mPxCooking = pxCooking; + mScene = scene; + mPxDefaultMaterial = defaultMat; + if (mPxDefaultMaterial != NULL) + { + mPxDefaultMaterial->acquireReference(); + } + else + { + mPxDefaultMaterial = pxPhysics->createMaterial(0.5f, 0.5f, 0.1f); + } + mResourcePath = resourcePath; + + clear(); + mRenderBuffers.init(); + mSceneVersion = 1; + mRenderBufferVersion = 0; + mOptixBufferVersion = 0; + + //create3dTexture(); + + mFractureForceThreshold = 500.0f; + mContactImpactRadius = 0.5f; + + mNoFractureFrames = 0; + mNoSoundFrames = 0; + mFrameNr = 0; + mDebugDraw = false; +// mDebugDraw = true; // foo + + mPickDepth = 0.0f; + mPickActor = NULL; + mPickPos = mPickLocalPos = PxVec3(0.0f, 0.0f, 0.0f); + + mMinConvexSize = minConvexSize; + mNumNoFractureFrames = 2; + + bumpTextureUVScale = 0.1f; + roughnessScale = 0.2f; + extraNoiseScale = 2.0f; + + particleBumpTextureUVScale = 0.2f; + particleRoughnessScale = 0.8f; + particleExtraNoiseScale = 2.0f; + + + mPlaySounds = false; + mRenderDebris = true; + + mCompoundCreator = NULL; + mDelaunay2d = NULL; + mDelaunay3d = NULL; + mPolygonTriangulator = NULL; + mIslandDetector = NULL; + + mAppNotify = NULL; + + //SDLWrapper::init(); +} + +// -------------------------------------------------------------------------------------------- +SimScene::~SimScene() +{ + clear(); + + if (mPxDefaultMaterial) + { + mPxDefaultMaterial->release(); + mPxDefaultMaterial = NULL; + } + + // Delete actors if not already deleted + for(int i = ((int)mActors.size() - 1) ; i >= 0; i--) + { + PX_DELETE(mActors[(uint32_t)i]); + } + + PX_DELETE(mCompoundCreator); + PX_DELETE(mDelaunay2d); + PX_DELETE(mDelaunay3d); + PX_DELETE(mPolygonTriangulator); + PX_DELETE(mIslandDetector); + PX_DELETE(mMeshClipper); + + mCompoundCreator = NULL; + mDelaunay2d = NULL; + mDelaunay3d = NULL; + mPolygonTriangulator = NULL; + mIslandDetector = NULL; + mMeshClipper = NULL; + + //SDLWrapper::done(); +} + +// -------------------------------------------------------------------------------------------- +void SimScene::restoreUserCallbacks() +{ + if (mScene != NULL) + { + // restore user callbacks + mScene->lockWrite(); + mScene->setSimulationEventCallback(mAppNotify); + mScene->unlockWrite(); + } +} + +// -------------------------------------------------------------------------------------------- +void SimScene::clear() +{ + for(uint32_t i = 0 ; i < mActors.size(); i++) + { + mActors[i]->clear(); + } + deleteCompounds(); + mPickActor = NULL; + + ++mSceneVersion; +} + +void SimScene::addActor(Actor* a) +{ + mActors.pushBack(a); +} + +void SimScene::removeActor(Actor* a) +{ + for(uint32_t i = 0; i < mActors.size(); i++) + { + if( a == mActors[i] ) + { + mActors[i] = mActors[mActors.size()-1]; + mActors.popBack(); + } + } +} + +// -------------------------------------------------------------------------------------------- +void SimScene::addCompound(Compound *c) +{ + mActors[0]->addCompound(c); +} + +// -------------------------------------------------------------------------------------------- +void SimScene::removeCompound(Compound *c) +{ + mActors[0]->removeCompound(c); +} + +// -------------------------------------------------------------------------------------------- +void SimScene::deleteCompounds() +{ + for (uint32_t i = 0; i < delCompoundList.size(); i++) + { + PX_DELETE(delCompoundList[i]); + } + delCompoundList.clear(); +} + +// -------------------------------------------------------------------------------------------- +void SimScene::preSim(float dt) +{ + const float pickStiffness = 2.0f; + + if (mPickActor != NULL) { + PxVec3 pos = mPickActor->getGlobalPose().transform(mPickLocalPos); + float m = mPickActor->getMass(); + + PxRigidBodyExt::addForceAtPos(*mPickActor, (mPickPos - pos) * pickStiffness * m, pos, PxForceMode::eIMPULSE); + } + + for(uint32_t i = 0 ; i < mActors.size(); i++) + { + mActors[i]->preSim(dt); + } + + mFractureEvents.clear(); + + // make sure we use the apex user notify... if the application + // changes their custom one make sure we map to it. + if (mScene != NULL) + { + mScene->lockWrite(); + PxSimulationEventCallback* userNotify = mScene->getSimulationEventCallback(); + if (userNotify != this) + { + mAppNotify = userNotify; + mScene->setSimulationEventCallback(this); + } + mScene->unlockWrite(); + } +} + +//float4* posVelG = 0; +//int numPosVelG = 0; +// -------------------------------------------------------------------------------------------- +void SimScene::postSim(float dt) +{ +// Profiler *p = Profiler::getInstance(); + + //processFractureEvents(fluidSim); + for(uint32_t i = 0 ; i < mActors.size(); i++) + { + mActors[i]->postSim(dt); + } + //posVelG = &posVel[0]; + //numPosVelG = posVel.size(); +// mFractureEvents.clear(); // foo + + mFrameNr++; + mNoFractureFrames--; + mNoSoundFrames--; +} + +// -------------------------------------------------------------------------------------------- +bool SimScene::rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &actorNr , int &compoundNr, int &convexNr, PxVec3 &normal) const +{ + dist = PX_MAX_F32; + actorNr = -1; + compoundNr = -1; + convexNr = -1; + + for (int i = 0; i < (int)mActors.size(); i++) + { + float d; + int comNr; + int conNr; + PxVec3 n; + if (mActors[(uint32_t)i]->rayCast(orig,dir,d,comNr,conNr,n)) + { + if( d < dist ) + { + dist = d; + actorNr = i; + compoundNr = comNr; + convexNr = conNr; + normal = n; + } + } + } + + return actorNr >= 0; +} + +//----------------------------------------------------------------------------- +bool SimScene::pickStart(const PxVec3 &orig, const PxVec3 &dir) +{ + float dist; + int actorNr, compoundNr, convexNr; + PxVec3 normal; + + if (!rayCast(orig, dir, dist, actorNr, compoundNr, convexNr, normal)) + return false; + + mPickActor = mActors[(uint32_t)actorNr]->mCompounds[(uint32_t)compoundNr]->getPxActor(); + mPickPos = orig + dir * dist; + mPickLocalPos = mPickActor->getGlobalPose().transformInv(mPickPos); + mPickDepth = dist; + return true; +} + +//----------------------------------------------------------------------------- +void SimScene::pickMove(const PxVec3 &orig, const PxVec3 &dir) +{ + if (mPickActor == NULL) + return; + + mPickPos = orig + dir * mPickDepth; +} + +//----------------------------------------------------------------------------- +void SimScene::pickRelease() +{ + mPickActor = NULL; +} + +// -------------------------------------------------------------------------------------------- +bool SimScene::patternFracture(const PxVec3 &orig, const PxVec3 &dir, const PxMat33 patternTransform, float impactRadius, float radialImpulse, float directionalImpulse) +{ + float dist; + //float objectSize = 0.0f; + int actorNr; + int compoundNr; + int convexNr; + PxVec3 normal; + + if (!rayCast(orig, dir, dist, actorNr, compoundNr, convexNr, normal)) + return false; + + return mActors[(uint32_t)actorNr]->patternFracture(orig+dist*dir,normal,compoundNr,patternTransform,impactRadius,radialImpulse,directionalImpulse); +} + +bool SimScene::findCompound(const Compound* c, int& actorNr, int& compoundNr) +{ + actorNr = -1; + compoundNr = -1; + for(uint32_t i = 0; i < mActors.size(); i++) + { + if (mActors[i]->findCompound(c,compoundNr)) + { + actorNr = (int32_t)i; + return true; + } + } + return false; +} + +// -------------------------------------------------------------------------------------------- +void SimScene::processFractureEvents(bool& valid,bool* addFireDustP) +{ + valid = false; + debugPoints.clear(); + int numPieces = 0; + + if (mFractureEvents.size() <= 0) + return; + + nvidia::Array<Compound*> compounds; + ++mSceneVersion; + + float objectSize = 0.0f; + + // here the fracture pattern could be randomized + float scale = 1.0f; + PxMat33 fractureTransform; + fractureTransform = PxMat33(PxIdentity); + fractureTransform *= scale; + + bool addFireDust = false; + + for (uint32_t i = 0; i < mFractureEvents.size(); i++) { + const FractureEvent &e = mFractureEvents[i]; + + if (!e.compound->patternFracture(e.pos, mMinConvexSize, compounds, fractureTransform, debugPoints, mContactImpactRadius, + e.additionalRadialImpulse, -e.normal * e.additionalNormalImpulse)) + continue; + + if (e.additionalNormalImpulse > 0.0f || e.additionalRadialImpulse > 0.0f) { + addFireDust = true; + playSound("explosion", 1); + } + else { +// playSound("explosion", 1); + } + + if (compounds.empty()) + continue; + + PxBounds3 bounds; + e.compound->getWorldBounds(bounds); + float size = bounds.getDimensions().magnitude(); + if (size > objectSize) + objectSize = size; + + for (uint32_t j = 0; j < compounds.size(); j++) { + PxRigidDynamic *a = compounds[j]->getPxActor(); +// a->setContactReportFlags(Px_NOTIFY_ON_TOUCH_FORCE_THRESHOLD); + a->setContactReportThreshold(mFractureForceThreshold); + } + + //int compoundNr = 0; + //while (compoundNr < (int)mCompounds.size() && mCompounds[compoundNr] != e.compound) + // compoundNr++; + + //int first = 0; + //if (compoundNr < (int)mCompounds.size()) { + // mCompounds[compoundNr] = compounds[0]; + // first++; + //} + + int first = 0; + int actorNr = 0; + int compoundNr = 0; + if (findCompound(e.compound,actorNr,compoundNr) ) + { + mActors[(uint32_t)actorNr]->mCompounds[(uint32_t)compoundNr] = compounds[0]; + first++; + } + + if (e.compound->getPxActor() == mPickActor) + mPickActor = NULL; + + e.compound->clear(); + //delCompoundList.push_back(e.compound); + delCompoundList.pushBack(e.compound); + + //delete e.compound; + + for (int j = first; j < (int)compounds.size(); j++) + mActors[(uint32_t)actorNr]->mCompounds.pushBack(compounds[(uint32_t)j]); + + numPieces += compounds.size(); + } + + mFractureEvents.clear(); + + if (objectSize > 0.0f) { + // playShatterSound(objectSize); + mNoFractureFrames = mNumNoFractureFrames; + } + if(addFireDustP) + { + *addFireDustP = addFireDust; + } + valid = true; + return; +} + +void SimScene::onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, uint32_t nbPairs) +{ + // Pass along to application's callback, if defined + if (mAppNotify != NULL) + { + mAppNotify->onContact(pairHeader, pairs, nbPairs); + } + + if (mNoFractureFrames > 0) + return; + + for (int i = 0; i < (int)nbPairs; i++) { + + const PxContactPair &pair = pairs[i]; + uint32_t num = pair.contactCount; + if (num == 0) + continue; + + mContactPoints.resize(num); + pairs[i].extractContacts(&mContactPoints[0], num); + + // pick first point (arbitrary) + Convex* convexes[2]; + convexes[0] = findConvexForShape(*pair.shapes[0]); + convexes[1] = findConvexForShape(*pair.shapes[1]); + + PxVec3 &pos = mContactPoints[0].position; + PxVec3 &normal = mContactPoints[0].normal; + + PxVec3 relVel(0.0f, 0.0f, 0.0f); + + for (int j = 0; j < 2; j++) { + if (convexes[j] == NULL) + continue; + PxRigidDynamic *a = convexes[j]->getParent()->getPxActor(); + PxVec3 v = PxRigidBodyExt::getVelocityAtPos(*a, pos); + relVel += (j == 0) ? v : -v; + } + + float normalImpulse = 0; + float radialImpulse = 0; + for (int j = 0; j < 2; j++) { + if (convexes[j] != NULL) { + normalImpulse = PxMax(normalImpulse, convexes[j]->getParent()->getAdditionalImpactNormalImpulse()); + radialImpulse = PxMax(radialImpulse, convexes[j]->getParent()->getAdditionalImpactRadialImpulse()); + } + } + + for (int j = 0; j < 2; j++) { + Convex *c = convexes[j]; + if (c == NULL) + continue; + if (relVel.magnitude() < REL_VEL_FRACTURE_THRESHOLD) + continue; + + Compound *compound = c->getParent(); + + FractureEvent e; + e.init(); + e.compound = compound; + e.pos = pos; + e.normal = normal; + e.withStatic = (convexes[1-j] == NULL); + e.additionalNormalImpulse = normalImpulse; + e.additionalRadialImpulse = radialImpulse; + + uint32_t k = 0; + while (k < mFractureEvents.size() && mFractureEvents[k].compound != compound) + k++; + + if (k < mFractureEvents.size()) { + if (mFractureEvents[k].withStatic && !e.withStatic) // prioritize dynamic collisions + mFractureEvents[k] = e; + } + else + mFractureEvents.pushBack(e); + } + } +} + +void SimScene::onAdvance(const PxRigidBody*const* bodyBuffer, const PxTransform* poseBuffer, const PxU32 count) +{ + PX_UNUSED(bodyBuffer); + PX_UNUSED(poseBuffer); + PX_UNUSED(count); +} + +void SimScene::onTrigger(PxTriggerPair* pairs, uint32_t count) +{ + // Pass along to application's callback, if defined + if (mAppNotify != NULL) + { + mAppNotify->onTrigger(pairs, count); + } +} + +void SimScene::onWake(PxActor** actors, uint32_t count) +{ + // Pass along to application's callback, if defined + if (mAppNotify != NULL) + { + mAppNotify->onWake(actors, count); + } +} + +void SimScene::onSleep(PxActor** actors, uint32_t count) +{ + // Pass along to application's callback, if defined + if (mAppNotify != NULL) + { + mAppNotify->onSleep(actors, count); + } +} + +void SimScene::onConstraintBreak(physx::PxConstraintInfo* constraints, uint32_t count) +{ + // Pass along to application's callback, if defined + if (mAppNotify != NULL) + { + mAppNotify->onConstraintBreak(constraints, count); + } +} + +nvidia::Array<PxVec3>& SimScene::getDebugPoints() { + return debugPoints; +} + +bool SimScene::mapShapeToConvex(const PxShape& shape, Convex& convex) +{ + return mShapeMap.insert(&shape, &convex); +} + +bool SimScene::unmapShape(const PxShape& shape) +{ + return mShapeMap.erase(&shape); +} + +Convex* SimScene::findConvexForShape(const PxShape& shape) +{ + const shdfnd::HashMap<const PxShape*, Convex*>::Entry* entry = mShapeMap.find(&shape); + return entry != NULL ? entry->second : NULL; // Since we don't expect *entry to be NULL, we shouldn't lose information here +} + +} +} +} + +#endif diff --git a/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.h b/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.h new file mode 100644 index 00000000..2170c19e --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.h @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef SIM_SCENE_BASE +#define SIM_SCENE_BASE + +#include "PxSimulationEventCallback.h" +#include <PsArray.h> +#include <PsUserAllocated.h> +#include <PsHashMap.h> + +#include "RTdef.h" + +namespace nvidia +{ +namespace fracture +{ +namespace base +{ + +class Actor; +class Compound; +class Convex; +class FracturePattern; +class CompoundCreator; +class Delaunay2d; +class Delaunay3d; +class PolygonTriangulator; +class IslandDetector; +class MeshClipper; + +// ----------------------------------------------------------------------------------- +class SimScene : + public PxSimulationEventCallback, public UserAllocated +{ + friend class Actor; +public: + static SimScene* createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath); +protected: + SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath); +public: + // Allow the Destructible module to release things in a proper order + void restoreUserCallbacks(); + virtual ~SimScene(); + + // Creates Scene Level Singletons + virtual void createSingletons(); + // Access singletons + CompoundCreator* getCompoundCreator() {return mCompoundCreator;} + Delaunay2d* getDelaunay2d() {return mDelaunay2d;} + Delaunay3d* getDelaunay3d() {return mDelaunay3d;} + PolygonTriangulator* getPolygonTriangulator() {return mPolygonTriangulator;} + IslandDetector* getIslandDetector() {return mIslandDetector;} + MeshClipper* getMeshClipper() {return mMeshClipper;} + + // Create non-Singletons + virtual Actor* createActor(); + virtual Convex* createConvex(); + virtual Compound* createCompound(const FracturePattern *pattern, const FracturePattern *secondaryPattern = NULL, float contactOffset = 0.005f, float restOffset = -0.001f); + virtual FracturePattern* createFracturePattern(); + virtual void clear(); + void addCompound(Compound *m); + void removeCompound(Compound *m); + // perform deferred deletion + void deleteCompounds(); + // + bool findCompound(const Compound* c, int& actorNr, int& compoundNr); + + void removeActor(Actor* a); + + // Profiler hooks + virtual void profileBegin(const char* /*name*/) {} + virtual void profileEnd(const char* /*name*/) {} + + bool rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &actorNr, int &compoundNr, int &convexNr, PxVec3 &normal) const; + + bool patternFracture(const PxVec3 &orig, const PxVec3 &dir, + const PxMat33 patternTransform, float impactRadius = 0.0f, float radialImpulse = 0.0f, float directionalImpulse = 0.0f); + + virtual void playSound(const char * /*name*/, int /*nr*/ = -1) {} + + // accessors + nvidia::Array<Compound*> getCompounds(); //{ return mCompounds; } + nvidia::Array<Actor*> getActors() { return mActors; } + PxPhysics* getPxPhysics() { return mPxPhysics; } + PxCooking* getPxCooking() { return mPxCooking; } + PxScene* getScene() { return mScene; } + + //ConvexRenderer &getConvexRenderer() { return mConvexRenderer; } + + void preSim(float dt); + void postSim(float dt); //, RegularCell3D* fluidSim); + + void setPlaySounds(bool play) { mPlaySounds = play; } + void setContactImpactRadius(float radius) { mContactImpactRadius = radius; } + void setNumNoFractureFrames(int num) { mNumNoFractureFrames = num; } + + void setCamera(const PxVec3 &pos, const PxVec3 &dir, const PxVec3 &up, float fov ) { + mCameraPos = pos; mCameraDir = dir; mCameraUp = up; mCameraFov = fov; + } + + //void draw(bool useShader, Shader* particleShader = NULL) {} + //void setShaderMaterial(Shader* shader, const ShaderMaterial& mat) {this->mShader = shader; this->mShaderMat = mat;} + //void setFractureForceThreshold(float threshold) { mFractureForceThreshold = threshold; } + + PxMaterial *getPxDefaultMaterial() { return mPxDefaultMaterial; } + + void toggleDebugDrawing() { mDebugDraw = !mDebugDraw; } + + virtual bool pickStart(const PxVec3 &orig, const PxVec3 &dir); + virtual void pickMove(const PxVec3 &orig, const PxVec3 &dir); + virtual void pickRelease(); + PxRigidDynamic* getPickActor() { return mPickActor; } + const PxVec3 &getPickPos() { return mPickPos; } + const PxVec3 &getPickLocalPos() { return mPickLocalPos; } + + // callback interface + + void onContactNotify(unsigned int arraySizes, void ** shape0Array, void ** shape1Array, void ** actor0Array, void ** actor1Array, float * positionArray, float * normalArray); + void onConstraintBreak(physx::PxConstraintInfo* constraints, uint32_t count); + void onWake(PxActor** actors, uint32_t count); + void onSleep(PxActor** actors, uint32_t count); + void onTrigger(physx::PxTriggerPair* pairs, uint32_t count); + void onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, uint32_t nbPairs); + void onAdvance(const PxRigidBody*const* bodyBuffer, const PxTransform* poseBuffer, const PxU32 count); + + void toggleRenderDebris() {mRenderDebris = !mRenderDebris;} + bool getRenderDebrs() {return mRenderDebris;} + //virtual void dumpSceneGeometry() {} + nvidia::Array<PxVec3>& getDebugPoints(); + //virtual void createRenderBuffers() {} + //void loadAndCreateTextureArrays(); + + nvidia::Array<PxVec3>& getCrackNormals() {return crackNormals;} + nvidia::Array<PxVec3>& getTmpPoints() {return tmpPoints;} + + bool mapShapeToConvex(const PxShape& shape, Convex& convex); + bool unmapShape(const PxShape& shape); + Convex* findConvexForShape(const PxShape& shape); + bool owns(const PxShape& shape) {return NULL != findConvexForShape(shape);} + +protected: + //virtual void create3dTexture() {} + //virtual void updateConvexesTex() {} + //void playShatterSound(float objectSize); + + void addActor(Actor* a); // done internally upon creation + + PxPhysics *mPxPhysics; + PxCooking *mPxCooking; + PxScene *mScene; + const char *mResourcePath; + bool mPlaySounds; + + //nvidia::Array<Compound*> mCompounds; + nvidia::Array<Actor*> mActors; + + float mFractureForceThreshold; + float mContactImpactRadius; + + nvidia::Array<physx::PxContactPairPoint> mContactPoints; + struct FractureEvent { + void init() { + compound = NULL; + pos = normal = PxVec3(0.0f, 0.0f, 0.0f); + additionalRadialImpulse = additionalNormalImpulse = 0.0f; + withStatic = false; + } + Compound *compound; + PxVec3 pos; + PxVec3 normal; + float additionalRadialImpulse; + float additionalNormalImpulse; + bool withStatic; + }; + nvidia::Array<FractureEvent> mFractureEvents; + void processFractureEvents(bool& valid,bool* addFireDust = NULL); + + struct RenderBuffers { + void init() { + numVertices = 0; numIndices = 0; + VBO = 0; IBO = 0; matTex = 0; volTex = 0; + texSize = 0; numConvexes = -1; + } + nvidia::Array<float> tmpVertices; + nvidia::Array<unsigned int> tmpIndices; + nvidia::Array<float> tmpTexCoords; + int numVertices, numIndices; + unsigned int VBO; + unsigned int IBO; + unsigned int volTex; + unsigned int matTex; + int texSize; + int numConvexes; + }; + RenderBuffers mRenderBuffers; + unsigned int mSceneVersion; // changed on each update + unsigned int mRenderBufferVersion; // to handle updates + unsigned int mOptixBufferVersion; // to handle updates + + PxMaterial *mPxDefaultMaterial; + + //ConvexRenderer mConvexRenderer; + + int mNoFractureFrames; + int mNoSoundFrames; + int mFrameNr; + bool mDebugDraw; + + float mPickDepth; + PxRigidDynamic *mPickActor; + PxVec3 mPickPos; + PxVec3 mPickLocalPos; + + float mMinConvexSize; + int mNumNoFractureFrames; // > 1 to prevent a slow down by too many fracture events + + PxVec3 mCameraPos, mCameraDir, mCameraUp; + float mCameraFov; + + float bumpTextureUVScale; + float extraNoiseScale; + float roughnessScale; + + float particleBumpTextureUVScale; + float particleRoughnessScale; + float particleExtraNoiseScale; + nvidia::Array<PxVec3> debugPoints; + bool mRenderDebris; + + PxSimulationEventCallback* mAppNotify; + + //GLuint diffuseTexArray, bumpTexArray, specularTexArray, emissiveReflectSpecPowerTexArray; + + //GLuint loadTextureArray(std::vector<std::string>& names); + + //Singletons + CompoundCreator* mCompoundCreator; + Delaunay2d* mDelaunay2d; + Delaunay3d* mDelaunay3d; + PolygonTriangulator* mPolygonTriangulator; + IslandDetector* mIslandDetector; + MeshClipper* mMeshClipper; + + //Array for use by Compound (effectively static) + nvidia::Array<PxVec3> crackNormals; + nvidia::Array<PxVec3> tmpPoints; + + // Deferred Deletion list + nvidia::Array<Compound*> delCompoundList; + + // Map used to determine SimScene ownership of shape + shdfnd::HashMap<const PxShape*,Convex*> mShapeMap; +}; + +} +} +} + +#endif +#endif diff --git a/APEX_1.4/module/destructible/fracture/Delaunay2d.cpp b/APEX_1.4/module/destructible/fracture/Delaunay2d.cpp new file mode 100644 index 00000000..efa26e4d --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Delaunay2d.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "Delaunay2d.h" + +namespace nvidia +{ +namespace fracture +{ + +} +} + +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Delaunay2d.h b/APEX_1.4/module/destructible/fracture/Delaunay2d.h new file mode 100644 index 00000000..7776214e --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Delaunay2d.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef DELAUNAY_2D_H +#define DELAUNAY_2D_H + +#include <PxVec3.h> +#include <PsArray.h> + +#include "Delaunay2dBase.h" + +namespace nvidia +{ +namespace fracture +{ + +class Delaunay2d : public base::Delaunay2d +{ + friend class SimScene; +protected: + Delaunay2d(base::SimScene* scene): base::Delaunay2d((base::SimScene*)scene) {} +}; + +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Delaunay3d.cpp b/APEX_1.4/module/destructible/fracture/Delaunay3d.cpp new file mode 100644 index 00000000..2ab81157 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Delaunay3d.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "Delaunay3d.h" + +namespace nvidia +{ +namespace fracture +{ + +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Delaunay3d.h b/APEX_1.4/module/destructible/fracture/Delaunay3d.h new file mode 100644 index 00000000..628e071d --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Delaunay3d.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef DELAUNAY_3D_H +#define DELAUNAY_3D_H + +#include <PxVec3.h> +#include <PsArray.h> + +#include "CompoundGeometry.h" + +#include "Delaunay3dBase.h" + +namespace nvidia +{ +namespace fracture +{ + +class Delaunay3d : public base::Delaunay3d +{ + friend class SimScene; +protected: + Delaunay3d(base::SimScene* scene): base::Delaunay3d((base::SimScene*)scene) {} +}; + +} +} + +#endif +#endif diff --git a/APEX_1.4/module/destructible/fracture/FracturePattern.cpp b/APEX_1.4/module/destructible/fracture/FracturePattern.cpp new file mode 100644 index 00000000..08133f41 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/FracturePattern.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "FracturePattern.h" + +// Empty until base has code proven to be non-portable +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/FracturePattern.h b/APEX_1.4/module/destructible/fracture/FracturePattern.h new file mode 100644 index 00000000..ddf9911b --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/FracturePattern.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef FRACTURE_PATTERN +#define FRACTURE_PATTERN + +#include "Delaunay3d.h" +#include "Delaunay2d.h" +#include "CompoundGeometry.h" +#include "PxTransform.h" +#include "PxBounds3.h" + +#include "FracturePatternBase.h" + +namespace nvidia +{ +namespace fracture +{ + +class Convex; +class Compound; +class CompoundGeometry; + +class FracturePattern : public base::FracturePattern +{ + friend class SimScene; +protected: + FracturePattern(base::SimScene* scene): base::FracturePattern((base::SimScene*)scene) {} +}; + +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/IceBoxPruning.cpp b/APEX_1.4/module/destructible/fracture/IceBoxPruning.cpp new file mode 100644 index 00000000..65ecc1b6 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/IceBoxPruning.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "IceBoxPruning.h" + +// Empty until base has code proven to be non-portable + +namespace nvidia +{ +namespace fracture +{ + +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/IceBoxPruning.h b/APEX_1.4/module/destructible/fracture/IceBoxPruning.h new file mode 100644 index 00000000..b5d2f0f1 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/IceBoxPruning.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef ICEBOXPRUNING_H +#define ICEBOXPRUNING_H + +#include "IceRevisitedRadix.h" +#include "PxVec3.h" +#include "PxBounds3.h" + +#include "IceBoxPruningBase.h" + +namespace nvidia +{ +namespace fracture +{ + +struct Axes : public base::Axes +{ +}; + +class BoxPruning : public base::BoxPruning +{ + +}; + +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.cpp b/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.cpp new file mode 100644 index 00000000..331c7ee6 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "IceRevisitedRadix.h" + +namespace nvidia +{ +namespace fracture +{ + +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.h b/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.h new file mode 100644 index 00000000..19bc8d25 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef ICERADIXSORT_H +#define ICERADIXSORT_H + +#include "IceRevisitedRadixBase.h" + +namespace nvidia +{ +namespace fracture +{ + +class RadixSort : public nvidia::fracture::base::RadixSort +{ +}; + +} +} + +#endif // __ICERADIXSORT_H__ +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/IslandDetector.cpp b/APEX_1.4/module/destructible/fracture/IslandDetector.cpp new file mode 100644 index 00000000..c09dfa80 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/IslandDetector.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "IslandDetector.h" + +namespace nvidia +{ +namespace fracture +{ + +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/IslandDetector.h b/APEX_1.4/module/destructible/fracture/IslandDetector.h new file mode 100644 index 00000000..889e5050 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/IslandDetector.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef ISLAND_DETECTOR_H +#define ISLAND_DETECTOR_H + +#include <PxVec3.h> +#include <PsArray.h> +#include "IceBoxPruning.h" + +#include "IslandDetectorBase.h" + +namespace nvidia +{ +namespace fracture +{ + +class IslandDetector : public base::IslandDetector +{ + friend class SimScene; +protected: + IslandDetector(base::SimScene* scene): base::IslandDetector((base::SimScene*)scene) {} +}; + +} +} + +#endif +#endif diff --git a/APEX_1.4/module/destructible/fracture/Mesh.cpp b/APEX_1.4/module/destructible/fracture/Mesh.cpp new file mode 100644 index 00000000..04ffbbd8 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Mesh.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include <RenderMeshAsset.h> + +#include "Mesh.h" + +namespace nvidia +{ +namespace fracture +{ + +void Mesh::gatherPartMesh(Array<PxVec3>& vertices, + nvidia::Array<uint32_t>& indices, + nvidia::Array<PxVec3>& normals, + nvidia::Array<PxVec2>& texcoords, + nvidia::Array<SubMesh>& subMeshes, + const RenderMeshAsset& renderMeshAsset, + uint32_t partIndex) + +{ + if (partIndex >= renderMeshAsset.getPartCount()) + { + vertices.resize(0); + indices.resize(0); + normals.resize(0); + texcoords.resize(0); + subMeshes.resize(0); + return; + } + + subMeshes.resize(renderMeshAsset.getSubmeshCount()); + + // Pre-count vertices and indices so we can allocate once + uint32_t vertexCount = 0; + uint32_t indexCount = 0; + for (uint32_t submeshIndex = 0; submeshIndex < renderMeshAsset.getSubmeshCount(); ++submeshIndex) + { + const RenderSubmesh& submesh = renderMeshAsset.getSubmesh(submeshIndex); + vertexCount += submesh.getVertexCount(partIndex); + indexCount += submesh.getIndexCount(partIndex); + } + + vertices.resize(vertexCount); + normals.resize(vertexCount); + texcoords.resize(vertexCount); + indices.resize(indexCount); + + vertexCount = 0; + indexCount = 0; + for (uint32_t submeshIndex = 0; submeshIndex < renderMeshAsset.getSubmeshCount(); ++submeshIndex) + { + const RenderSubmesh& submesh = renderMeshAsset.getSubmesh(submeshIndex); + const uint32_t submeshVertexCount = submesh.getVertexCount(partIndex); + if (submeshVertexCount > 0) + { + const VertexBuffer& vertexBuffer = submesh.getVertexBuffer(); + const VertexFormat& vertexFormat = vertexBuffer.getFormat(); + + enum { MESH_SEMANTIC_COUNT = 3 }; + struct { + RenderVertexSemantic::Enum semantic; + RenderDataFormat::Enum format; + uint32_t sizeInBytes; + void* dstBuffer; + } semanticData[MESH_SEMANTIC_COUNT] = { + { RenderVertexSemantic::POSITION, RenderDataFormat::FLOAT3, sizeof(PxVec3), &vertices[vertexCount] }, + { RenderVertexSemantic::NORMAL, RenderDataFormat::FLOAT3, sizeof(PxVec3), &normals[vertexCount] }, + { RenderVertexSemantic::TEXCOORD0, RenderDataFormat::FLOAT2, sizeof(PxVec2), &texcoords[vertexCount] } + }; + + for (uint32_t i = 0; i < MESH_SEMANTIC_COUNT; ++i) + { + const int32_t bufferIndex = vertexFormat.getBufferIndexFromID(vertexFormat.getSemanticID(semanticData[i].semantic)); + if (bufferIndex >= 0) + vertexBuffer.getBufferData(semanticData[i].dstBuffer, + semanticData[i].format, + semanticData[i].sizeInBytes, + (uint32_t)bufferIndex, + submesh.getFirstVertexIndex(partIndex), + submesh.getVertexCount(partIndex)); + else + memset(semanticData[i].dstBuffer, 0, submesh.getVertexCount(partIndex)*semanticData[i].sizeInBytes); + } + + /* + const uint32_t firstVertexIndex = submesh.getFirstVertexIndex(partIndex); + fillBuffer<PxVec3>(vertexBuffer, vertexFormat, RenderVertexSemantic::POSITION, RenderDataFormat::FLOAT3, + firstVertexIndex, submeshVertexCount, &vertices[vertexCount]); + fillBuffer<PxVec3>(vertexBuffer, vertexFormat, RenderVertexSemantic::NORMAL, RenderDataFormat::FLOAT3, + firstVertexIndex, submeshVertexCount, &normals[vertexCount]); + fillBuffer<PxVec2>(vertexBuffer, vertexFormat, RenderVertexSemantic::TEXCOORD0, RenderDataFormat::FLOAT2, + firstVertexIndex, submeshVertexCount, &texcoords[vertexCount]);*/ + + const uint32_t* partIndexBuffer = submesh.getIndexBuffer(partIndex); + const uint32_t partIndexCount = submesh.getIndexCount(partIndex); + subMeshes[submeshIndex].firstIndex = (int32_t)partIndexCount; + for (uint32_t indexNum = 0; indexNum < partIndexCount; ++indexNum) + { + indices[indexCount++] = partIndexBuffer[indexNum] + vertexCount - submesh.getFirstVertexIndex(partIndex); + } + vertexCount += submeshVertexCount; + } + } +} + + +void Mesh::loadFromRenderMesh(const RenderMeshAsset& mesh, uint32_t partIndex) +{ + gatherPartMesh(mVertices, mIndices, mNormals, mTexCoords, mSubMeshes, mesh, partIndex); +} + +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Mesh.h b/APEX_1.4/module/destructible/fracture/Mesh.h new file mode 100644 index 00000000..59231566 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Mesh.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef MESH +#define MESH + +#include <PxVec3.h> +#include <PsArray.h> +#include <PsAllocator.h> + +#include "MeshBase.h" + +namespace nvidia +{ +namespace apex +{ + class RenderMeshAsset; +} +} + +namespace nvidia +{ +namespace fracture +{ + +using namespace ::nvidia::shdfnd; + +class Mesh : public base::Mesh +{ +public: + void loadFromRenderMesh(const apex::RenderMeshAsset& mesh, uint32_t partIndex); +protected: + static void gatherPartMesh(Array<PxVec3>& vertices, Array<uint32_t>& indices, Array<PxVec3>& normals, + Array<PxVec2>& texcoords, nvidia::Array<SubMesh>& subMeshes, const apex::RenderMeshAsset& renderMeshAsset, uint32_t partIndex); +}; + +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/MeshClipper.cpp b/APEX_1.4/module/destructible/fracture/MeshClipper.cpp new file mode 100644 index 00000000..b5e42b7a --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/MeshClipper.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "MeshClipper.h" + +namespace nvidia +{ +namespace fracture +{ + +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/MeshClipper.h b/APEX_1.4/module/destructible/fracture/MeshClipper.h new file mode 100644 index 00000000..e52d5f3d --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/MeshClipper.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef MESH_CLIPPER_H +#define MESH_CLIPPER_H + +#include <PxVec3.h> +#include <PsArray.h> +#include <PxTransform.h> +#include <PxBounds3.h> + +#include "MeshClipperBase.h" + +namespace nvidia +{ +namespace fracture +{ + +class MeshClipper : public base::MeshClipper +{ + friend class SimScene; +protected: + MeshClipper(base::SimScene* scene): base::MeshClipper((base::SimScene*)scene) {} +}; + +} +} + +#endif +#endif diff --git a/APEX_1.4/module/destructible/fracture/PolygonTriangulator.cpp b/APEX_1.4/module/destructible/fracture/PolygonTriangulator.cpp new file mode 100644 index 00000000..c8012cdd --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/PolygonTriangulator.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "PolygonTriangulator.h" + +namespace nvidia +{ +namespace fracture +{ + +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/PolygonTriangulator.h b/APEX_1.4/module/destructible/fracture/PolygonTriangulator.h new file mode 100644 index 00000000..3d142351 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/PolygonTriangulator.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef POLYGON_TRIANGULATOR_H +#define POLYGON_TRIANGULATOR_H + +#include <PxVec3.h> +#include <PsArray.h> + +#include "PolygonTriangulatorBase.h" + +namespace nvidia +{ +namespace fracture +{ + +class PolygonTriangulator : public base::PolygonTriangulator +{ + friend class SimScene; +protected: + PolygonTriangulator(base::SimScene* scene): base::PolygonTriangulator((base::SimScene*)scene) {} +}; + +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/RTdef.h b/APEX_1.4/module/destructible/fracture/RTdef.h new file mode 100644 index 00000000..0a8b9561 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/RTdef.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +// This file exists primarily for APEX integration + +#ifndef RT_DEF_H +#define RT_DEF_H + +#include "ApexDefs.h" +#include "ModuleDestructible.h" + +#if APEX_RUNTIME_FRACTURE +#define RT_COMPILE 1 +#else +#define RT_COMPILE 0 +#endif + +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Renderable.cpp b/APEX_1.4/module/destructible/fracture/Renderable.cpp new file mode 100644 index 00000000..5e8ba01b --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Renderable.cpp @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include "DestructibleActorImpl.h" + +#include "Actor.h" +#include "Compound.h" +#include "Convex.h" + +#include "../fracture/Renderable.h" + +namespace nvidia +{ +namespace fracture +{ + +Renderable::Renderable(): + mVertexBuffer(NULL), + mIndexBuffer(NULL), + mBoneBuffer(NULL), + mVertexBufferSize(0), + mIndexBufferSize(0), + mBoneBufferSize(0), + mVertexBufferSizeLast(0), + mIndexBufferSizeLast(0), + mBoneBufferSizeLast(0), + mFullBufferDirty(true), + valid(false) +{ + +} + +Renderable::~Renderable() +{ + UserRenderResourceManager* rrm = GetInternalApexSDK()->getUserRenderResourceManager(); + if (mVertexBuffer != NULL ) + { + rrm->releaseVertexBuffer(*mVertexBuffer); + } + if (mIndexBuffer != NULL ) + { + rrm->releaseIndexBuffer(*mIndexBuffer); + } + if (mBoneBuffer != NULL) + { + rrm->releaseBoneBuffer(*mBoneBuffer); + } + for (uint32_t k = 0; k < mConvexGroups.size(); k++) + { + ConvexGroup& g = mConvexGroups[k]; + for (uint32_t j = 0; j < g.mSubMeshes.size(); j++) + { + SubMesh& s = g.mSubMeshes[j]; + if(s.renderResource != NULL) + { + rrm->releaseResource(*s.renderResource); + s.renderResource = NULL; + } + } + } +} + +void Renderable::updateRenderResources(bool rewriteBuffers, void* userRenderData) +{ + UserRenderResourceManager* rrm = GetInternalApexSDK()->getUserRenderResourceManager(); + ResourceProviderIntl* nrp = GetInternalApexSDK()->getInternalResourceProvider(); + + PX_ASSERT(rrm != NULL && nrp != NULL); + if (rrm == NULL || nrp == NULL || mConvexGroups.empty()) + { + valid = false; + return; + } + + if (rewriteBuffers) + { + mFullBufferDirty = true; + } + + // Resize buffers if necessary: TODO: intelligently oversize + // vertex buffer + if (mVertexBufferSize > mVertexBufferSizeLast) + { + if (mVertexBuffer != NULL ) + { + rrm->releaseVertexBuffer(*mVertexBuffer); + } + { + UserRenderVertexBufferDesc desc; + desc.uvOrigin = nvidia::apex::TextureUVOrigin::ORIGIN_BOTTOM_LEFT; + desc.hint = RenderBufferHint::DYNAMIC; + desc.maxVerts = mVertexBufferSize; + desc.buffersRequest[RenderVertexSemantic::POSITION] = RenderDataFormat::FLOAT3; + desc.buffersRequest[RenderVertexSemantic::NORMAL] = RenderDataFormat::FLOAT3; + desc.buffersRequest[RenderVertexSemantic::TEXCOORD0] = RenderDataFormat::FLOAT2; + desc.buffersRequest[RenderVertexSemantic::BONE_INDEX] = RenderDataFormat::USHORT1; + mVertexBuffer = rrm->createVertexBuffer(desc); + PX_ASSERT(mVertexBuffer); + } + mFullBufferDirty = true; + } + // index buffer + if (mIndexBufferSize > mIndexBufferSizeLast) + { + if (mIndexBuffer != NULL ) + { + rrm->releaseIndexBuffer(*mIndexBuffer); + } + UserRenderIndexBufferDesc desc; + desc.hint = RenderBufferHint::DYNAMIC; + desc.maxIndices = mIndexBufferSize; + desc.format = RenderDataFormat::UINT1; + mIndexBuffer = rrm->createIndexBuffer(desc); + PX_ASSERT(mIndexBuffer); + mFullBufferDirty = true; + } + // bone buffer + if (mBoneBufferSize > mBoneBufferSizeLast) + { + if (mBoneBuffer != NULL) + { + rrm->releaseBoneBuffer(*mBoneBuffer); + } + UserRenderBoneBufferDesc desc; + desc.hint = RenderBufferHint::DYNAMIC; + desc.maxBones = mBoneBufferSize; + desc.buffersRequest[RenderBoneSemantic::POSE] = RenderDataFormat::FLOAT3x4; + mBoneBuffer = rrm->createBoneBuffer(desc); + PX_ASSERT(mBoneBuffer); + mFullBufferDirty = true; + } + // Fill buffers + if (mFullBufferDirty) + { + uint32_t vertexIdx = 0; + uint32_t indexIdx = 0; + uint32_t boneIdx = 0; + for (uint32_t k = 0; k < mConvexGroups.size(); k++) + { + ConvexGroup& g = mConvexGroups[k]; + for (uint32_t j = 0; j < g.mSubMeshes.size(); j++) + { + SubMesh& s = g.mSubMeshes[j]; + if(s.renderResource != NULL) + { + rrm->releaseResource(*s.renderResource); + s.renderResource = NULL; + } + UserRenderResourceDesc desc; + desc.primitives = RenderPrimitiveType::TRIANGLES; + // configure vertices + desc.vertexBuffers = &mVertexBuffer; + desc.numVertexBuffers = 1; + desc.numVerts = g.mVertexCache.size(); + desc.firstVertex = vertexIdx; + // configure indices; + desc.indexBuffer = mIndexBuffer; + desc.firstIndex = indexIdx; + desc.numIndices = s.mIndexCache.size(); + // configure bones; + desc.boneBuffer = mBoneBuffer; + desc.numBones = g.mBoneCache.size(); + desc.firstBone = boneIdx; + // configure other info + desc.material = nrp->getResource(mMaterialInfo[j].mMaterialID); + desc.submeshIndex = j; + desc.userRenderData = userRenderData; + // create + s.renderResource = rrm->createResource(desc); + PX_ASSERT(s.renderResource); + // copy indices into buffer + PX_ASSERT(indexIdx+s.mIndexCache.size() <= mIndexBufferSize); + mIndexBuffer->writeBuffer(s.mIndexCache.begin(),sizeof(*s.mIndexCache.begin()),indexIdx,s.mIndexCache.size()); + indexIdx += s.mIndexCache.size(); + } + // copy vertices and bones + { + RenderVertexBufferData data; + data.setSemanticData(RenderVertexSemantic::POSITION, g.mVertexCache.begin(), sizeof(*g.mVertexCache.begin()), RenderDataFormat::FLOAT3); + data.setSemanticData(RenderVertexSemantic::NORMAL, g.mNormalCache.begin(), sizeof(*g.mNormalCache.begin()), RenderDataFormat::FLOAT3); + data.setSemanticData(RenderVertexSemantic::TEXCOORD0, g.mTexcoordCache.begin(), sizeof(*g.mTexcoordCache.begin()), RenderDataFormat::FLOAT2); + data.setSemanticData(RenderVertexSemantic::BONE_INDEX,g.mBoneIndexCache.begin(),sizeof(*g.mBoneIndexCache.begin()),RenderDataFormat::USHORT1); + PX_ASSERT(vertexIdx + g.mVertexCache.size() <= mVertexBufferSize); + mVertexBuffer->writeBuffer(data,vertexIdx,g.mVertexCache.size()); + } + { + RenderBoneBufferData data; + data.setSemanticData(RenderBoneSemantic::POSE,g.mBoneCache.begin(),sizeof(*g.mBoneCache.begin()),RenderDataFormat::FLOAT4x4); + PX_ASSERT(boneIdx + g.mBoneCache.size() <= mBoneBufferSize); + mBoneBuffer->writeBuffer(data,boneIdx,g.mBoneCache.size()); + } + vertexIdx += g.mVertexCache.size(); + boneIdx += g.mBoneCache.size(); + } + mFullBufferDirty = false; + } + else // Bones only + { + uint32_t boneIdx = 0; + for (uint32_t k = 0; k < mConvexGroups.size(); k++) + { + ConvexGroup& g = mConvexGroups[k]; + { + RenderBoneBufferData data; + data.setSemanticData(RenderBoneSemantic::POSE,g.mBoneCache.begin(),sizeof(*g.mBoneCache.begin()),RenderDataFormat::FLOAT4x4); + mBoneBuffer->writeBuffer(data,boneIdx,g.mBoneCache.size()); + } + boneIdx += g.mBoneCache.size(); + } + } + mVertexBufferSizeLast = mVertexBufferSize; + mIndexBufferSizeLast = mIndexBufferSize; + mBoneBufferSizeLast = mBoneBufferSize; + valid = true; +} + +void Renderable::dispatchRenderResources(UserRenderer& api) +{ + if (!valid) + { + return; + } + RenderContext ctx; + ctx.local2world = PxMat44(PxIdentity); + ctx.world2local = PxMat44(PxIdentity); + for (uint32_t k = 0; k < mConvexGroups.size(); k++) + { + ConvexGroup& g = mConvexGroups[k]; + for (uint32_t j = 0; j < g.mSubMeshes.size(); j++) + { + SubMesh& s = g.mSubMeshes[j]; + if(s.renderResource && !s.mIndexCache.empty()) + { + ctx.renderResource = s.renderResource; + api.renderResource(ctx); + } + } + } +} + +// -----------------------Cache Update----------------------------------- +void Renderable::updateRenderCacheFull(Actor* actor) +{ + mVertexBufferSize = 0; + mIndexBufferSize = 0; + mBoneBufferSize = 0; + // Resize SubMeshes if necessary + const uint32_t numSubMeshes = actor->mActor->getRenderSubmeshCount(); + if( numSubMeshes == 0 ) + { + return; + } + if( numSubMeshes != mMaterialInfo.size() ) + { + mMaterialInfo.resize(numSubMeshes); + } + // grab material information + if (ResourceProviderIntl* nrp = GetInternalApexSDK()->getInternalResourceProvider()) + { + if (UserRenderResourceManager* rrm = GetInternalApexSDK()->getUserRenderResourceManager()) + { + ResID materialNS = GetInternalApexSDK()->getMaterialNameSpace(); + for(uint32_t i = 0; i < numSubMeshes; i++) + { + if(mMaterialInfo[i].mMaxBones == 0) + { + mMaterialInfo[i].mMaterialID = nrp->createResource(materialNS,actor->mActor->getDestructibleAsset()->getRenderMeshAsset()->getMaterialName(i),false); + mMaterialInfo[i].mMaxBones = rrm->getMaxBonesForMaterial(nrp->getResource(mMaterialInfo[i].mMaterialID)); + } + } + } + } + // Find bone limit + uint32_t maxBones = mMaterialInfo[0].mMaxBones; + for (uint32_t i = 1; i < mMaterialInfo.size(); i++) + { + if (mMaterialInfo[i].mMaxBones < maxBones) + { + maxBones = mMaterialInfo[i].mMaxBones; + } + } + //maxBones = 1; // TEMPORARY: FIXES TEXTURE MAPPING PROBLEM + //maxBones = rand(1,maxBones-1); + // Count Convexes + uint32_t numConvexes = 0; + const Array<base::Compound*>& compounds = actor->getCompounds(); + for (uint32_t k = 0; k < compounds.size(); k++) + { + const Array<base::Convex*>& convexes = compounds[k]->getConvexes(); + numConvexes += convexes.size(); + } + mBoneBufferSize += numConvexes; + + //maxBones is 0 when VTF rendering method is used for destructible(only) + if(maxBones == 0) + maxBones = mBoneBufferSize; + + // Create more groups if necessary + uint32_t numGroups = numConvexes/maxBones + ((numConvexes%maxBones)?1:0); + if (numGroups != mConvexGroups.size()) + { + mConvexGroups.resize(numGroups); + } + // Resize convex caches and subMeshes if necessary + for (uint32_t k = 0; k < mConvexGroups.size(); k++) + { + ConvexGroup& g = mConvexGroups[k]; + g.mConvexCache.clear(); + if( g.mConvexCache.capacity() <= maxBones ) + { + g.mConvexCache.reserve(maxBones); + } + if( g.mSubMeshes.size() != mMaterialInfo.size()) + { + g.mSubMeshes.resize(mMaterialInfo.size()); + } + } + // Populate convex cache + { + uint32_t idx = 0; + const Array<base::Compound*>& compounds = actor->getCompounds(); + for (uint32_t k = 0; k < compounds.size(); k++) + { + const Array<base::Convex*>& convexes = compounds[k]->getConvexes(); + for (uint32_t j = 0; j < convexes.size(); j++) + { + mConvexGroups[idx/maxBones].mConvexCache.pushBack((Convex*)convexes[j]); + idx++; + } + } + } + // Fill other caches + for (uint32_t k = 0; k < mConvexGroups.size(); k++) + { + ConvexGroup& g = mConvexGroups[k]; + // Calculate number of vertices + uint32_t numVertices = 0; + for (uint32_t j = 0; j < g.mConvexCache.size(); j++) + { + numVertices += g.mConvexCache[j]->getVisVertices().size(); + } + mVertexBufferSize += numVertices; + // Resize if necessary + g.mVertexCache.clear(); + g.mNormalCache.clear(); + g.mTexcoordCache.clear(); + g.mBoneIndexCache.clear(); + if (numVertices >= g.mVertexCache.capacity()) + { + g.mVertexCache.reserve(numVertices); + g.mNormalCache.reserve(numVertices); + g.mBoneIndexCache.reserve(numVertices); + g.mTexcoordCache.reserve(numVertices); + } + g.mBoneCache.clear(); + if (maxBones >= g.mBoneCache.capacity()) + { + g.mBoneCache.reserve(maxBones); + } + // Calculate index buffer sizes + for (uint32_t i = 0; i < g.mSubMeshes.size(); i++) + { + uint32_t numIndices = 0; + for (uint32_t j = 0; j < g.mConvexCache.size(); j++) + { + numIndices += g.mConvexCache[j]->getVisTriIndices().size(); + } + g.mSubMeshes[i].mIndexCache.clear(); + if (numIndices >= g.mSubMeshes[i].mIndexCache.capacity()) + { + g.mSubMeshes[i].mIndexCache.reserve(numIndices); + } + mIndexBufferSize += numIndices; + } + // Fill for each convex + for (uint32_t j = 0; j < g.mConvexCache.size(); j++) + { + Convex* c = g.mConvexCache[j]; + uint32_t off = g.mVertexCache.size(); + // fill vertices + const Array<PxVec3>& verts = c->getVisVertices(); + const Array<PxVec3>& norms = c->getVisNormals(); + const Array<float>& texcs = c->getVisTexCoords(); + PX_ASSERT(verts.size() == norms.size() && verts.size() == (texcs.size()/2)); + for (uint32_t i = 0; i < verts.size(); i++) + { + g.mVertexCache.pushBack(verts[i]); + g.mNormalCache.pushBack(norms[i]); + g.mTexcoordCache.pushBack(PxVec2(texcs[2*i],texcs[2*i+1])); + g.mBoneIndexCache.pushBack((uint16_t)j); + } + // fill indicies for each submesh + for (uint32_t i = 0; i < g.mSubMeshes.size(); i++) + { + const Array<int32_t>& indices = c->getVisTriIndices(); + PX_ASSERT(indices.size()%3 == 0); + for (uint32_t a = 0; a < indices.size()/3; a++) + { + uint32_t subMeshID = 0; // <<<--- TODO: acquire subMeshID for triangle + if (subMeshID == i) + { + g.mSubMeshes[i].mIndexCache.pushBack(indices[3*a+0]+off); + g.mSubMeshes[i].mIndexCache.pushBack(indices[3*a+1]+off); + g.mSubMeshes[i].mIndexCache.pushBack(indices[3*a+2]+off); + } + } + } + g.mBoneCache.pushBack(c->getGlobalPose()); + } + } +} + +void Renderable::updateRenderCache(Actor* actor) +{ + if( actor == NULL ) return; + actor->mScene->getScene()->lockRead(); + //actor->mRenderResourcesDirty = true; + if( actor->mRenderResourcesDirty) + { + updateRenderCacheFull(actor); + mFullBufferDirty = true; + actor->mRenderResourcesDirty = false; + } + // Fill other caches + for (uint32_t k = 0; k < mConvexGroups.size(); k++) + { + ConvexGroup& g = mConvexGroups[k]; + g.mBoneCache.clear(); + // Fill bones for each convex + for (uint32_t j = 0; j < g.mConvexCache.size(); j++) + { + Convex* c = g.mConvexCache[j]; + g.mBoneCache.pushBack(c->getGlobalPose()); + } + } + actor->mScene->getScene()->unlockRead(); +} + +PxBounds3 Renderable::getBounds() const +{ + PxBounds3 bounds; + bounds.setEmpty(); + for (uint32_t k = 0; k < mConvexGroups.size(); k++) + { + const ConvexGroup& g = mConvexGroups[k]; + for (uint32_t j = 0; j < g.mConvexCache.size(); j++) + { + const Convex* c = g.mConvexCache[j]; + bounds.include(c->getBounds()); + } + } + return bounds; +} + +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/Renderable.h b/APEX_1.4/module/destructible/fracture/Renderable.h new file mode 100644 index 00000000..9a2af07c --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/Renderable.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef RT_RENDERABLE_H +#define RT_RENDERABLE_H + +#include "PsArray.h" +#include "PsUserAllocated.h" +#include "PxVec2.h" + +namespace nvidia +{ +namespace apex +{ + class UserRenderer; + class UserRenderVertexBuffer; + class UserRenderIndexBuffer; + class UserRenderBoneBuffer; + class UserRenderResource; +} +using namespace shdfnd; + +namespace fracture +{ + +class Actor; +class Convex; + +class Renderable : public UserAllocated +{ +public: + Renderable(); + ~Renderable(); + + // Called by rendering thread + void updateRenderResources(bool rewriteBuffers, void* userRenderData); + void dispatchRenderResources(UserRenderer& api); + + // Per tick bone update, unless Actor is dirty + void updateRenderCache(Actor* actor); + + // Returns the bounds of all of the convexes + PxBounds3 getBounds() const; + +private: + // Called by actor after a patternFracture (On Game Thread) + void updateRenderCacheFull(Actor* actor); + + // To Handle Multiple Materials + struct SubMesh + { + SubMesh(): renderResource(NULL) {} + + Array<uint32_t> mIndexCache; + UserRenderResource* renderResource; + }; + // To Handle Bone Limit + struct ConvexGroup + { + Array<SubMesh> mSubMeshes; + Array<Convex*> mConvexCache; + Array<PxVec3> mVertexCache; + Array<PxVec3> mNormalCache; + Array<PxVec2> mTexcoordCache; + Array<uint16_t> mBoneIndexCache; + Array<PxMat44> mBoneCache; + }; + // Shared by SubMeshes + struct MaterialInfo + { + MaterialInfo(): mMaxBones(0), mMaterialID(0) {} + + uint32_t mMaxBones; + ResID mMaterialID; + }; + // + Array<ConvexGroup> mConvexGroups; + Array<MaterialInfo> mMaterialInfo; + + UserRenderVertexBuffer* mVertexBuffer; + UserRenderIndexBuffer* mIndexBuffer; + UserRenderBoneBuffer* mBoneBuffer; + uint32_t mVertexBufferSize; + uint32_t mIndexBufferSize; + uint32_t mBoneBufferSize; + uint32_t mVertexBufferSizeLast; + uint32_t mIndexBufferSizeLast; + uint32_t mBoneBufferSizeLast; + bool mFullBufferDirty; + bool valid; +}; + +} +} + +#endif +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/SimScene.cpp b/APEX_1.4/module/destructible/fracture/SimScene.cpp new file mode 100644 index 00000000..9d651093 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/SimScene.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#include <PsUserAllocated.h> + +#include "DestructibleActorImpl.h" + +#include "Actor.h" +#include "Compound.h" +#include "Convex.h" +#include "CompoundCreator.h" +#include "Delaunay2d.h" +#include "Delaunay3d.h" +#include "PolygonTriangulator.h" +#include "IslandDetector.h" +#include "MeshClipper.h" +#include "FracturePattern.h" + +#include "SimScene.h" + +namespace nvidia +{ +namespace fracture +{ + +void SimScene::onWake(PxActor** actors, uint32_t count){ + if(mAppNotify != NULL) + mAppNotify->onWake(actors,count); + + for(uint32_t i = 0; i < count; i++) + { + PxActor* actor = actors[i]; + if(actor != NULL && actor->is<physx::PxRigidDynamic>()) + { + uint32_t shapeCount = actor->is<physx::PxRigidDynamic>()->getNbShapes(); + PxShape** shapes = (PxShape**)PX_ALLOC(sizeof(PxShape*)*shapeCount,"onWake Shapes Temp Buffer"); + actor->is<physx::PxRigidDynamic>()->getShapes(shapes,sizeof(PxShape*)*shapeCount,0); + ::nvidia::destructible::DestructibleActorImpl* prevActor = NULL; + for(uint32_t j = 0; j < shapeCount; j++) + { + nvidia::fracture::base::Convex* convex = findConvexForShape(*shapes[j]); + if(convex == NULL || convex->getParent() == NULL) + continue; + nvidia::fracture::Compound* parent = (nvidia::fracture::Compound*)convex->getParent(); + ::nvidia::destructible::DestructibleActorImpl* curActor = parent->getDestructibleActor(); + if(convex && convex->getParent() && curActor != prevActor && curActor) + { + curActor->incrementWakeCount(); + prevActor = curActor; + } + + } + PX_FREE(shapes); + } + } +} + +void SimScene::onSleep(PxActor** actors, uint32_t count){ + if(mAppNotify != NULL) + mAppNotify->onSleep(actors,count); + + for(uint32_t i = 0; i < count; i++) + { + PxActor* actor = actors[i]; + if(actor != NULL && actor->is<physx::PxRigidDynamic>()) + { + uint32_t shapeCount = actor->is<physx::PxRigidDynamic>()->getNbShapes(); + PxShape** shapes = (PxShape**)PX_ALLOC(sizeof(PxShape*)*shapeCount,"onSleep Shapes Temp Buffer"); + actor->is<physx::PxRigidDynamic>()->getShapes(shapes,sizeof(PxShape*)*shapeCount,0); + ::nvidia::destructible::DestructibleActorImpl* prevActor = NULL; + for(uint32_t j = 0; j < shapeCount; j++) + { + nvidia::fracture::base::Convex* convex = findConvexForShape(*shapes[j]); + if(convex == NULL || convex->getParent() == NULL) + continue; + nvidia::fracture::Compound* parent = (nvidia::fracture::Compound*)convex->getParent(); + ::nvidia::destructible::DestructibleActorImpl* curActor = parent->getDestructibleActor(); + if(convex && convex->getParent() && curActor != prevActor && curActor) + { + curActor->decrementWakeCount();; + prevActor = curActor; + } + + } + PX_FREE(shapes); + } + } +} +SimScene* SimScene::createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath) +{ + SimScene* s = PX_NEW(SimScene)(pxPhysics,pxCooking,scene,minConvexSize,defaultMat,resourcePath); + s->createSingletons(); + return s; +} + +void SimScene::createSingletons() +{ + mCompoundCreator = PX_NEW(CompoundCreator)(this); + mDelaunay2d = PX_NEW(Delaunay2d)(this); + mDelaunay3d = PX_NEW(Delaunay3d)(this); + mPolygonTriangulator = PX_NEW(PolygonTriangulator)(this); + mIslandDetector = PX_NEW(IslandDetector)(this); + mMeshClipper = PX_NEW(MeshClipper)(this); + mDefaultGlass = PX_NEW(FracturePattern)(this); + mDefaultGlass->createGlass(10.0f,0.25f,30,0.3f,0.03f,1.4f,0.3f); + //mDefaultGlass->create3dVoronoi(PxVec3(10.0f, 10.0f, 10.0f), 50, 10.0f); + addActor(createActor(NULL)); +} + +base::Actor* SimScene::createActor(::nvidia::destructible::DestructibleActorImpl* actor) +{ + return (base::Actor*)PX_NEW(Actor)(this,actor); +} + +base::Convex* SimScene::createConvex() +{ + return (base::Convex*)PX_NEW(Convex)(this); +} + +base::Compound* SimScene::createCompound(const base::FracturePattern *pattern, const base::FracturePattern *secondaryPattern, float contactOffset, float restOffset) +{ + return (base::Compound*)PX_NEW(Compound)(this,pattern,secondaryPattern,contactOffset,restOffset); +} + +base::FracturePattern* SimScene::createFracturePattern() +{ + return (base::FracturePattern*)PX_NEW(FracturePattern)(this); +} + +SimScene::SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath): + base::SimScene(pxPhysics,pxCooking,scene,minConvexSize,defaultMat,resourcePath) +{ +} + +// -------------------------------------------------------------------------------------------- +SimScene::~SimScene() +{ + PX_DELETE(mDefaultGlass); + + mDefaultGlass = NULL; +} + +} +} +#endif
\ No newline at end of file diff --git a/APEX_1.4/module/destructible/fracture/SimScene.h b/APEX_1.4/module/destructible/fracture/SimScene.h new file mode 100644 index 00000000..fd0e82e6 --- /dev/null +++ b/APEX_1.4/module/destructible/fracture/SimScene.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "RTdef.h" +#if RT_COMPILE +#ifndef SIM_SCENE +#define SIM_SCENE + +#include "SimSceneBase.h" + +namespace nvidia +{ +namespace destructible +{ + class DestructibleActorImpl; +} + +namespace fracture +{ + +class FracturePattern; +class Actor; + +class SimScene : public base::SimScene +{ +public: + static SimScene* createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath); +protected: + SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath); +public: + virtual ~SimScene(); + + virtual void createSingletons(); + + virtual base::Actor* createActor(nvidia::destructible::DestructibleActorImpl* actor); + virtual base::Convex* createConvex(); + virtual base::Compound* createCompound(const base::FracturePattern *pattern, const base::FracturePattern *secondaryPattern = NULL, float contactOffset = 0.005f, float restOffset = -0.001f); + virtual base::FracturePattern* createFracturePattern(); + virtual void onWake(PxActor** actors, uint32_t count); + virtual void onSleep(PxActor** actors, uint32_t count); + + FracturePattern* getDefaultGlass() {return mDefaultGlass;} + +protected: + FracturePattern* mDefaultGlass; +}; + +} +} + +#endif +#endif
\ No newline at end of file |