diff options
Diffstat (limited to 'KaplaDemo/samples/sampleViewer3/Fracture/Core')
16 files changed, 4690 insertions, 0 deletions
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.cpp new file mode 100644 index 00000000..4504add8 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.cpp @@ -0,0 +1,139 @@ +#include "RTdef.h" +#if RT_COMPILE +#include "ActorBase.h" + +#include <foundation/PxMat44.h> +#include "PxRigidBodyExt.h" + +#include "PxScene.h" +#include "SimSceneBase.h" +#include "CompoundBase.h" + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +Actor::Actor(SimScene* scene): + mScene(scene), + mMinConvexSize(scene->mMinConvexSize), + mDepthLimit(100), + mDestroyIfAtDepthLimit(false) +{ + +} + +Actor::~Actor() +{ + mScene->getScene()->lockWrite(); + clear(); + mScene->getScene()->unlockWrite(); + mScene->removeActor(this); +} + +void Actor::clear() +{ + for (int i = 0; i < (int)mCompounds.size(); i++) { + PX_DELETE(mCompounds[i]); + } + mCompounds.clear(); +} + +void Actor::addCompound(Compound *c) +{ + mCompounds.pushBack(c); + PxRigidDynamic *a = c->getPxActor(); +#if 1 + if (a) { +// a->setContactReportFlags(Px_NOTIFY_ON_TOUCH_FORCE_THRESHOLD | Px_NOTIFY_ON_START_TOUCH_FORCE_THRESHOLD); + a->setContactReportThreshold(mScene->mFractureForceThreshold); + } +#endif + c->mActor = this; + ++(mScene->mSceneVersion); +} + +void Actor::removeCompound(Compound *c) +{ + int num = 0; + for (int i = 0; i < (int)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) +{ + int num = 0; + for (int i = 0; i < (int)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 (int i = 0; i < (int)mCompounds.size(); i++) { + float d; + int cNr; + PxVec3 n; + if (mCompounds[i]->rayCast(orig, dir, d, cNr, n)) { + if (d < dist) { + dist = d; + compoundNr = i; + convexNr = cNr; + normal = n; + } + } + } + return compoundNr >= 0; +} + +bool Actor::findCompound(const Compound* c, int& compoundNr) +{ + for(int i = 0; i < (int)mCompounds.size(); i++) + { + if(mCompounds[i] == c) + { + compoundNr = i; + return true; + } + } + return false; +} + +} +} +} +#endif
\ No newline at end of file diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.h new file mode 100644 index 00000000..b268b5f9 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.h @@ -0,0 +1,54 @@ +#include "RTdef.h" +#if RT_COMPILE +#ifndef ACTOR_BASE_H +#define ACTOR_BASE_H + +#include <PsArray.h> +#include <PsUserAllocated.h> + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +class Compound; + +class Actor : public ::physx::shdfnd::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; + + shdfnd::Array<Compound*> getCompounds() { return mCompounds; } + +protected: + SimScene* mScene; + shdfnd::Array<Compound*> mCompounds; + + PxF32 mMinConvexSize; + PxU32 mDepthLimit; + bool mDestroyIfAtDepthLimit; +}; + +} +} +} + +#endif +#endif
\ No newline at end of file diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.cpp new file mode 100644 index 00000000..ac2c4f15 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.cpp @@ -0,0 +1,536 @@ +#include "RTdef.h" +#if RT_COMPILE +#include "MeshBase.h" +#include "CompoundGeometryBase.h" +#include "CompoundCreatorBase.h" +#include "PxConvexMeshGeometry.h" +#include "PxRigidBodyExt.h" +#include "foundation/PxMat44.h" +#include "PxScene.h" +#include "PxShape.h" + +#include "SimSceneBase.h" +#include "CompoundBase.h" +#include "ActorBase.h" +#include "ConvexBase.h" +#include "foundation/PxMathUtils.h" + +#include <stdio.h> + +#include "MathUtils.h" + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +//vector<PxVec3> tmpPoints; +void Compound::appendUniformSamplesOfConvexPolygon(PxVec3* vertices, int numV, float area, shdfnd::Array<PxVec3>& samples, shdfnd::Array<PxVec3>* normals) { + 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)floor(aa); + + if (randRange(0.0f,1.0f) <= aa-np) np++; + + for (int j = 0; j < np; j++) { + float r1 = randRange(0.0f,1.0f); + float sr1 = physx::PxSqrt(r1); + float r2 = randRange(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, PxReal contactOffset, PxReal restOffset) +{ + mScene = scene; + mActor = NULL; + mPxActor = NULL; + 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 physx::PxU32 shapeCount = mPxActor->getNbShapes(); + physx::PxShape* shapeBuffer[SHAPE_BUFFER_SIZE]; + for (physx::PxU32 shapeStartIndex = 0; shapeStartIndex < shapeCount; shapeStartIndex += SHAPE_BUFFER_SIZE) + { + physx::PxU32 shapesRead = mPxActor->getShapes(shapeBuffer, SHAPE_BUFFER_SIZE, shapeStartIndex); + for (physx::PxU32 shapeBufferIndex = 0; shapeBufferIndex < shapesRead; ++shapeBufferIndex) + { + mScene->unmapShape(*shapeBuffer[shapeBufferIndex]); + } + } + // release the actor + mPxActor->release(); + mPxActor = NULL; + } + for (int i = 0; i < (int)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, int matID, int surfMatID) +{ + return createFromConvexes(&convex, 1, pose, vel, omega, copyConvexes, matID, surfMatID); +} + +// -------------------------------------------------------------------------------------------- +bool Compound::createFromConvexes(Convex** convexes, int numConvexes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes, int matID, int surfMatID) +{ + 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; + + shdfnd::Array<PxShape*> shapes; + + for (int i = 0; i < numConvexes; i++) { + Convex *c; + if (copyConvexes) { + c = mScene->createConvex(); + c->createFromConvex(convexes[i], 0, matID, surfMatID); + } + 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); + + PxShape *shape = mScene->getPxPhysics()->createShape( + PxConvexMeshGeometry(mesh), + *mScene->getPxDefaultMaterial(), + true + ); + shape->setLocalPose(c->getLocalPose()); + + //shape->setContactOffset(mContactOffset); + //shape->setRestOffset(mRestOffset); + + if (mContactOffset < mRestOffset || mContactOffset < 0.0f) + { + printf("WRONG\n"); + } + + mScene->mapShapeToConvex(*shape, *c); + + shapes.pushBack(shape); + } + + if (shapes.empty()) + { + return false; + } + + createPxActor(shapes, pose, vel, omega); + + + return true; +} + +// -------------------------------------------------------------------------------------------- + +bool Compound::createFromGeometry(const CompoundGeometry &geom, PxRigidDynamic* body, Shader* myShader, int matID, int surfMatID) +{ + clear(); + + shdfnd::Array<PxShape*> shapes(body->getNbShapes()); + + body->getShapes(shapes.begin(), body->getNbShapes()); + + PX_ASSERT(geom.convexes.size() == body->getNbShapes()); + + for (int i = 0; i < (int)geom.convexes.size(); i++) { + Convex *c = mScene->createConvex(); + c->createFromGeometry(geom, i, 0, matID, surfMatID); + 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; + + if (!reused) + convexAdded(c, myShader); //mScene->getConvexRenderer().add(c); + + mScene->mapShapeToConvex(*shapes[i], *c); + + } + + if (shapes.empty()) + return false; + + mPxActor = body; + for (int i = 0; i < (int)mConvexes.size(); i++) + mConvexes[i]->setPxActor(mPxActor); + + //createPxActor(shapes, pose, vel, omega); + return true; + +} +bool Compound::createFromGeometry(const CompoundGeometry &geom, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, Shader* myShader, int matID, int surfMatID) +{ + clear(); + + shdfnd::Array<PxShape*> shapes; + + for (int i = 0; i < (int)geom.convexes.size(); i++) { + Convex *c = mScene->createConvex(); + c->createFromGeometry(geom, i, 0, matID, surfMatID); + 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, myShader); //mScene->getConvexRenderer().add(c); + + PxShape *shape; + if (geom.convexes[i].isSphere) + { + shape = mScene->getPxPhysics()->createShape( + PxSphereGeometry(geom.convexes[i].radius), + *mScene->getPxDefaultMaterial(), + true + ); + } + else + { + shape = mScene->getPxPhysics()->createShape( + PxConvexMeshGeometry(mesh), + *mScene->getPxDefaultMaterial(), + true + ); + } + shape->setLocalPose(c->getLocalPose()); + + //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, int matID, int surfMatID) +{ + const shdfnd::Array<PxVec3> &verts = mesh->getVertices(); + const shdfnd::Array<PxVec3> &normals = mesh->getNormals(); + const shdfnd::Array<PxVec2> &texcoords = mesh->getTexCoords(); + const shdfnd::Array<PxU32> &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, NULL, matID, surfMatID); + PxTransform trans(-center); + + if (submeshNr < 0) + mConvexes[0]->setExplicitVisMeshFromTriangles(verts.size(), &verts[0], &normals[0], &texcoords[0], indices.size(), &indices[0], &trans, &scale); + else { + const Mesh::SubMesh &sm = mesh->getSubMeshes()[submeshNr]; + mConvexes[0]->setExplicitVisMeshFromTriangles(verts.size(), &verts[0], &normals[0], &texcoords[0], sm.numIndices, &indices[sm.firstIndex], &trans, &scale); + } +} + +// -------------------------------------------------------------------------------------------- +bool Compound::createPxActor(shdfnd::Array<PxShape*> &shapes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega) +{ + if (shapes.empty()) + return false; + + for(int i = 0; i < (int)shapes.size(); i++) + { + applyShapeTemplate(shapes[i]); + } + + PxRigidDynamic* body = mScene->getPxPhysics()->createRigidDynamic(pose); + if (body == NULL) + return false; + + //body->setSleepThreshold(getSleepingThresholdRB()); +#if 0 + body->setWakeCounter(100000000000.f); +#endif + + mScene->getScene()->addActor(*body); + + for (int i = 0; i < (int)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, 1.0f); + + /*const PxReal maxMass = 50.f; + const PxReal minMass = 1.f; + + PxReal mass = PxMax(PxMin(maxMass, body->getMass()), minMass); + PxRigidBodyExt::setMassAndUpdateInertia(*body, mass);*/ + + + + body->setLinearVelocity(vel); + body->setAngularVelocity(omega); + + /*if (vel.isZero() && omega.isZero()) + { + body->putToSleep(); + }*/ + + mPxActor = body; + for (int i = 0; i < (int)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 (int i = 0; i < (int)mConvexes.size(); i++) { + float d; + PxVec3 n; + if (mConvexes[i]->rayCast(orig, dir, d, n)) { + if (d < dist) { + dist = d; + convexNr = i; + normal = n; + } + } + } + return convexNr >= 0; +} + +// -------------------------------------------------------------------------------------------- +void Compound::getRestBounds(PxBounds3 &bounds) const +{ + bounds.setEmpty(); + PxBounds3 bi; + for (int i = 0; i < (int)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 (int i = 0; i < (int)mConvexes.size(); i++) { + mConvexes[i]->getWorldBounds(bi); + bounds.include(bi); + } +} + +// -------------------------------------------------------------------------------------------- +void Compound::getLocalBounds(PxBounds3 &bounds) const +{ + bounds.setEmpty(); + PxBounds3 bi; + for (int i = 0; i < (int)mConvexes.size(); i++) { + mConvexes[i]->getLocalBounds(bi); + bounds.include(bi); + } +} + +// -------------------------------------------------------------------------------------------- +bool Compound::isAttached() +{ + if (mAttachmentBounds.empty()) + return false; + + PxBounds3 b; + for (int i = 0; i < (int)mConvexes.size(); i++) { + Convex *c = mConvexes[i]; + b = c->getBounds(); + b.minimum += c->getMaterialOffset(); + b.maximum += c->getMaterialOffset(); + for (int j = 0; j < (int)mAttachmentBounds.size(); j++) { + if (b.intersects(mAttachmentBounds[j])) + return true; + } + } + return false; +} + +// -------------------------------------------------------------------------------------------- +void Compound::attach(const shdfnd::Array<PxBounds3> &bounds) +{ + mAttachmentBounds.resize(bounds.size()); + + PxTransform t = getPxActor()->getGlobalPose().getInverse(); + for (int i = 0; i < (int)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 shdfnd::Array<PxBounds3> &bounds) +{ + mAttachmentBounds.resize(bounds.size()); + + for (int i = 0; i < (int)bounds.size(); i++) { + mAttachmentBounds[i] = bounds[i]; + } + + if (isAttached()) + mPxActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true); +} +} +} +} +#endif
\ No newline at end of file diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.h new file mode 100644 index 00000000..3ab093a5 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.h @@ -0,0 +1,136 @@ +#include "RTdef.h" +#if RT_COMPILE +#ifndef COMPOUNDBASE +#define COMPOUNDBASE + +#define TECHNICAL_MODE 1 + +#include <foundation/PxVec3.h> +#include <foundation/PxPlane.h> +#include <foundation/PxBounds3.h> +#include <foundation/PxTransform.h> +#include <PsArray.h> +#include <PxRigidDynamic.h> +#include <PsUserAllocated.h> + + +class Shader; + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +class Convex; +class Mesh; +class SimScene; +class CompoundGeometry; + +// ----------------------------------------------------------------------------------- +class Compound : public ::physx::shdfnd::UserAllocated +{ + friend class SimScene; + friend class Actor; +protected: + Compound(SimScene* scene, PxReal contactOffset = 0.005f, PxReal 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, int matID = 0, int surfMatID = 0); + bool createFromConvex(Convex* convex, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes = true, int matID = 0, int surfMatID = 0); + bool createFromGeometry(const CompoundGeometry &geom, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, Shader* myShader, int matID = 0, int surfMatID = 0); + bool createFromGeometry(const CompoundGeometry &geom, PxRigidDynamic* body, Shader* myShader, int matID = 0, int surfMatID = 0); + void createFromMesh(const Mesh *mesh, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, int submeshNr = -1, const PxVec3& scale = PxVec3(1.f), int matID = 0, int surfMatID = 0); + //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; } + + + virtual void convexAdded(Convex* /*c*/, Shader* shader = NULL) {} + virtual void convexRemoved(Convex* /*c*/) {} + + void attach(const shdfnd::Array<PxBounds3> &bounds); + void attachLocal(const shdfnd::Array<PxBounds3> &bounds); + + const shdfnd::Array<Convex*>& getConvexes() const { return mConvexes; } + const shdfnd::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: + + bool isAttached(); + + bool createPxActor(shdfnd::Array<PxShape*> &shapes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega); + + static void appendUniformSamplesOfConvexPolygon(PxVec3* vertices, int numV, float area, shdfnd::Array<PxVec3>& samples, shdfnd::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; + }; + + shdfnd::Array<Convex*> mConvexes; + shdfnd::Array<Edge> mEdges; + + SimScene *mScene; + Actor *mActor; + PxRigidDynamic *mPxActor; + PxVec3 mKinematicVel; + shdfnd::Array<PxBounds3> mAttachmentBounds; + + //Shader *mShader; + //ShaderMaterial mShaderMat; + + PxReal mContactOffset; + PxReal mRestOffset; + + int mLifeFrames; + + float mAdditionalImpactNormalImpulse; + float mAdditionalImpactRadialImpulse; + + PxU32 mDepth; // fracture depth + PxVec3 mNormal; // normal use with mSheetFracture +}; + +}}} + +#endif +#endif
\ No newline at end of file diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.cpp new file mode 100644 index 00000000..f01d0701 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.cpp @@ -0,0 +1,844 @@ +#include "RTdef.h" +#if RT_COMPILE +#include "CompoundCreatorBase.h" +#include <algorithm> +#include <foundation/PxAssert.h> + +#include "PhysXMacros.h" +#include "PxConvexMeshGeometry.h" +#include "PxConvexMesh.h" + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +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 = PX_TRANSFORM_ID; + if (trans) + t = *trans; + + shdfnd::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[i0]); + mGeom.normals.pushBack(normals[i1]); + mGeom.normals.pushBack(normals[i2]); + mGeom.normals.pushBack(normals[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 = PX_TRANSFORM_ID; + if (trans) + t = *trans; + + mGeom.clear(); + CompoundGeometry::Convex c; + mGeom.initConvex(c); + + float dphi = PxTwoPi / (float)numSegs; + c.numVerts = 2*numSegs; + mGeom.vertices.resize(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*i] = t.transform(p0); + mGeom.vertices[2*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, bool clear) +{ + PxTransform t = PX_TRANSFORM_ID; + if (trans) + t = *trans; + + if (clear) + mGeom.clear(); + CompoundGeometry::Convex c; + mGeom.initConvex(c); + + c.numVerts = 8; + 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::createFromConvexMesh(const PxConvexMeshGeometry& convexGeom, PxTransform offset, bool clear) +{ + + if (clear) + { + mGeom.clear(); + } + CompoundGeometry::Convex c; + mGeom.initConvex(c); + + PxConvexMesh* convexMesh = convexGeom.convexMesh; + c.numVerts = convexMesh->getNbVertices(); + c.numFaces = convexMesh->getNbPolygons(); + + const PxVec3* verts = convexMesh->getVertices(); + const PxU8* indexBuff = convexMesh->getIndexBuffer(); + + + for (PxU32 a = 0; a < c.numVerts; ++a) + { + mGeom.vertices.pushBack(offset.transform(verts[a])); + } + + + for (PxU32 a = 0; a < c.numFaces; ++a) + { + PxHullPolygon data; + convexMesh->getPolygonData(a, data); + + mGeom.indices.pushBack(data.mNbVerts); + mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE); + const PxU32 indexBase = data.mIndexBase; + for (PxU32 b = 0; b < data.mNbVerts; ++b) + { + PxU32 ind = indexBuff[indexBase + b]; + mGeom.indices.pushBack(ind); + } + } + + mGeom.convexes.pushBack(c); +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::createSphere(const PxVec3 &dims, int resolution, const PxTransform *trans) +{ + PxTransform t = PX_TRANSFORM_ID; + 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); + + if (rx == ry && rx == rz) + { + c.isSphere = true; + c.radius = rx; + } + + 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 = mGeom.vertices.size(); + mGeom.vertices.pushBack(PxVec3(0.0f, 0.0f, -rz)); + int topNr = mGeom.vertices.size(); + mGeom.vertices.pushBack(PxVec3(0.0f, 0.0f, +rz)); + + c.numVerts = 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[i0]; n.normalize(); mGeom.normals.pushBack(n); + n = mGeom.vertices[i1]; n.normalize(); mGeom.normals.pushBack(n); + n = mGeom.vertices[i2]; n.normalize(); mGeom.normals.pushBack(n); + n = mGeom.vertices[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[i0]; n.normalize(); mGeom.normals.pushBack(n); + n = mGeom.vertices[i1]; n.normalize(); mGeom.normals.pushBack(n); + n = mGeom.vertices[i2]; n.normalize(); mGeom.normals.pushBack(n); + c.numFaces++; + } + } + mGeom.convexes.pushBack(c); +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::fromTetraMesh(const shdfnd::Array<PxVec3> &tetVerts, const shdfnd::Array<int> &tetIndices) +{ + mTetVertices = tetVerts; + mTetIndices = tetIndices; + deleteColors(); + + computeTetNeighbors(); + computeTetEdges(); + colorTets(); + colorsToConvexes(); +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::computeTetNeighbors() +{ + int 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; + }; + shdfnd::Array<TetFace> faces(numTets * 4); + + for (int 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 (int j = 0; j < 4; j++) { + int i0 = ids[tetFaceIds[j][0]]; + int i1 = ids[tetFaceIds[j][1]]; + int i2 = ids[tetFaceIds[j][2]]; + faces[4*i+j].init(i0,i1,i2, j, i); + } + } + std::sort(faces.begin(), faces.end()); + + mTetNeighbors.clear(); + mTetNeighbors.resize(numTets * 4, -1); + int i = 0; + while (i < (int)faces.size()) { + TetFace &f0 = faces[i]; + i++; + if (i < (int)faces.size() && faces[i] == f0) { + TetFace &f1 = faces[i]; + mTetNeighbors[4*f0.tetNr + f0.faceNr] = f1.tetNr; + mTetNeighbors[4*f1.tetNr + f1.faceNr] = f0.tetNr; + while (i < (int)faces.size() && faces[i] == f0) + i++; + } + } +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::computeTetEdges() +{ + int 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; + }; + shdfnd::Array<SortEdge> edges(numTets * 6); + + for (int 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 (int j = 0; j < 6; j++) { + int i0 = ids[tetEdgeVerts[j][0]]; + int i1 = ids[tetEdgeVerts[j][1]]; + edges[6*i + j].init(i0,i1, j, 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; + shdfnd::Array<ChainVert> chainVerts(mTetVertices.size(), cv); + shdfnd::Array<int> chainVertNrs; + + int mark = 1; + + int i = 0; + while (i < (int)edges.size()) { + SortEdge &e0 = edges[i]; + int edgeNr = mTetEdges.size(); + te.init(e0.i0, e0.i1); + te.firstTet = mEdgeTetNrs.size(); + te.numTets = 0; + mark++; + chainVertNrs.clear(); + do { + SortEdge &e = edges[i]; + mTetEdgeNrs[6 * e.tetNr + e.edgeNr] = edgeNr; + int i2 = -1; + int i3 = -1; + for (int j = 0; j < 4; j++) { + int id = mTetIndices[4 * 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[e0.i0]; + PxVec3 &p1 = mTetVertices[e0.i1]; + PxVec3 &p2 = mTetVertices[i2]; + PxVec3 &p3 = mTetVertices[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[i2]; + ChainVert &cv3 = chainVerts[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 < (int)edges.size() && edges[i] == e0); + + te.numTets = chainVertNrs.size() / 2; + // find chain start; + int startVertNr = -1; + for (int j = 0; j < (int)chainVertNrs.size(); j++) { + ChainVert &cv = chainVerts[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[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[tetNr]; + while (nr >= 0) { + if (mTetColors[nr].color == color) + return true; + nr = mTetColors[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[tetNr]; + + if (mTetColorsFirstEmpty <= 0) { // new entry + mTetFirstColor[tetNr] = mTetColors.size(); + mTetColors.pushBack(c); + } + else { // take from empty list + int newNr = mTetColorsFirstEmpty; + mTetFirstColor[tetNr] = newNr; + mTetColorsFirstEmpty = mTetColors[newNr].next; + mTetColors[newNr] = c; + } + return true; +} + +// ----------------------------------------------------------------------------- +bool CompoundCreator::tetRemoveColor(int tetNr, int color) +{ + int nr = mTetFirstColor[tetNr]; + int prev = -1; + while (nr >= 0) { + if (mTetColors[nr].color == color) { + if (prev < 0) + mTetFirstColor[tetNr] = mTetColors[nr].next; + else + mTetColors[prev].next = mTetColors[nr].next; + + // add to empty list + mTetColors[nr].next = mTetColorsFirstEmpty; + mTetColorsFirstEmpty = nr; + return true; + } + prev = nr; + nr = mTetColors[nr].next; + } + return false; +} + +// ----------------------------------------------------------------------------- +int CompoundCreator::tetNumColors(int tetNr) +{ + int num = 0; + int nr = mTetFirstColor[tetNr]; + while (nr >= 0) { + num++; + nr = mTetColors[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[6*tetNr+i]); + + bool failed = false; + + while (mTestEdges.size() > 0) { + int edgeNr = mTestEdges[mTestEdges.size()-1]; + mTestEdges.popBack(); + + TetEdge &e = mTetEdges[edgeNr]; + bool anyOtherCol = false; + float sumAng = 0.0f; + for (int i = 0; i < e.numTets; i++) { + int edgeTetNr = mEdgeTetNrs[e.firstTet + i]; + if (tetHasColor(edgeTetNr, color)) + sumAng += mEdgeTetAngles[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[e.firstTet + i]; + if (!tetHasColor(edgeTetNr, color)) { + tetAddColor(edgeTetNr, color); + mAddedTets.pushBack(edgeTetNr); + for (int j = 0; j < 6; j++) + mTestEdges.pushBack(mTetEdgeNrs[6*edgeTetNr+j]); + } + } + } + if (failed) { + for (int i = 0; i < (int)mAddedTets.size(); i++) + tetRemoveColor(mAddedTets[i], color); + mAddedTets.clear(); + return false; + } + + return true; +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::colorTets() +{ + int numTets = mTetIndices.size() / 4; + deleteColors(); + + int color = 0; + shdfnd::Array<int> edges; + shdfnd::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[faceNr]; + + if (adjTetNr < 0) + continue; + + //if (tetNumColors(adjTetNr) > 0) + // continue; + + if (!tryTet(adjTetNr, color)) + continue; + + for (int j = 0; j < (int)mAddedTets.size(); j++) { + int addedTet = mAddedTets[j]; + for (int k = 0; k < 4; k++) { + int adj = mTetNeighbors[4*addedTet+k]; + if (adj >= 0 && !tetHasColor(adj, color)) + faces.pushBack(4*addedTet+k); + } + } + } + color++; + } +} + +// ----------------------------------------------------------------------------- +void CompoundCreator::colorsToConvexes() +{ + mGeom.clear(); + + int numTets = mTetIndices.size() / 4; + int numColors = 0; + for (int i = 0; i < (int)mTetColors.size(); i++) { + int color = mTetColors[i].color; + if (color >= numColors) + numColors = color+1; + } + + shdfnd::Array<bool> colorVisited(numColors, false); + shdfnd::Array<int> queue; + shdfnd::Array<int> globalToLocal(mTetVertices.size(), -1); + + shdfnd::Array<int> tetMarks(numTets, 0); + shdfnd::Array<int> vertMarks(mTetVertices.size(), 0); + int mark = 1; + + shdfnd::Array<int> colorToConvexNr; + + CompoundGeometry::Convex c; + + for (int i = 0; i < numTets; i++) { + int nr = mTetFirstColor[i]; + while (nr >= 0) { + int color = mTetColors[nr].color; + nr = mTetColors[nr].next; + + if (colorVisited[color]) + continue; + colorVisited[color] = true; + + if ((int)colorToConvexNr.size() <= color) + colorToConvexNr.resize(color+1, -1); + colorToConvexNr[color] = mGeom.convexes.size(); + + queue.clear(); + queue.pushBack(i); + + mGeom.initConvex(c); + mark++; + c.numVerts = 0; + + // flood fill + while (!queue.empty()) { + int tetNr = queue[queue.size()-1]; + queue.popBack(); + if (tetMarks[tetNr] == mark) + continue; + tetMarks[tetNr] = mark; + + for (int j = 0; j < 4; j++) { + int adjNr = mTetNeighbors[4*tetNr + j]; + if (adjNr < 0 || !tetHasColor(adjNr, 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 (int k = 0; k < 3; k++) { + int id = 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[adjNr]; + while (colNr >= 0) { + int adjColor = mTetColors[colNr].color; + colNr = mTetColors[colNr].next; + if (adjColor != color) { + bool isNew = true; + for (int k = 0; k < c.numNeighbors; k++) { + if (mGeom.neighbors[c.firstNeighbor+k] == adjColor) { + isNew = false; + break; + } + } + if (isNew) { + mGeom.neighbors.pushBack(adjColor); + c.numNeighbors++; + } + } + } + } + if (adjNr < 0 || !tetHasColor(adjNr, color) || tetMarks[adjNr] == mark) + continue; + queue.pushBack(adjNr); + } + } + mGeom.convexes.pushBack(c); + } + } + + for (int i = 0; i < (int)mGeom.neighbors.size(); i++) { + if (mGeom.neighbors[i] >= 0) + mGeom.neighbors[i] = colorToConvexNr[mGeom.neighbors[i]]; + } +} + +} +} +} +#endif
\ No newline at end of file diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.h new file mode 100644 index 00000000..cc614672 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.h @@ -0,0 +1,103 @@ +#include "RTdef.h" +#if RT_COMPILE +#ifndef COMPOUND_CREATOR_BASE_H +#define COMPOUND_CREATOR_BASE_H + +// Matthias M�ller-Fischer + +#include <foundation/PxVec3.h> +#include <foundation/PxTransform.h> +#include <PsArray.h> +#include <PsUserAllocated.h> + +#include "CompoundGeometryBase.h" + +namespace physx +{ + class PxConvexMeshGeometry; +namespace fracture +{ +namespace base +{ + + class SimScene; +// --------------------------------------------------------------------------------------- +class CompoundCreator : public ::physx::shdfnd::UserAllocated { + friend class 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, bool clearShape = true); + void createSphere(const PxVec3 &dims, int resolution = 5, const PxTransform *trans = NULL); + void fromTetraMesh(const shdfnd::Array<PxVec3> &tetVerts, const shdfnd::Array<int> &tetIndices); + + void createFromConvexMesh(const PxConvexMeshGeometry& convexGeom, PxTransform offset = PxTransform(PxIdentity), bool clear = true); + + + 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 + shdfnd::Array<PxVec3> mTetVertices; + shdfnd::Array<int> mTetIndices; + shdfnd::Array<int> mTetNeighbors; + + shdfnd::Array<int> mTetFirstColor; + struct Color { + int color; + int next; + }; + int mTetColorsFirstEmpty; + shdfnd::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; + }; + shdfnd::Array<TetEdge> mTetEdges; + shdfnd::Array<int> mTetEdgeNrs; + shdfnd::Array<int> mEdgeTetNrs; + shdfnd::Array<float> mEdgeTetAngles; + + shdfnd::Array<int> mAddedTets; + shdfnd::Array<int> mTestEdges; + + // input + shdfnd::Array<PxVec3> mVertices; + shdfnd::Array<int> mIndices; + + // output + CompoundGeometry mGeom; +}; + +}}} + +#endif +#endif diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.cpp new file mode 100644 index 00000000..7051b72a --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.cpp @@ -0,0 +1,86 @@ +#include "RTdef.h" +#if RT_COMPILE +#include "CompoundGeometryBase.h" + +namespace physx +{ +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 = vertices.size(); + c.numVerts = 0; + c.firstNormal = normals.size(); + c.firstIndex = indices.size(); + c.numFaces = 0; + c.firstPlane = 0; + c.firstNeighbor = neighbors.size(); + c.numNeighbors = 0; + c.radius = 0.f; + c.isSphere = false; +} + +// ------------------------------------------------------------------------------- +void CompoundGeometry::derivePlanes() +{ + planes.clear(); + PxPlane p; + + for (int i = 0; i < (int)convexes.size(); i++) { + Convex &c = convexes[i]; + c.firstPlane = planes.size(); + int *ids = &indices[c.firstIndex]; + PxVec3 *verts = &vertices[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/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.h new file mode 100644 index 00000000..e5de3787 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.h @@ -0,0 +1,68 @@ +#include "RTdef.h" +#if RT_COMPILE +#ifndef COMPOUND_GEOMETRY_BASE +#define COMPOUND_GEOMETRY_BASE + +#include <foundation/PxVec3.h> +#include <foundation/PxPlane.h> +#include <PsArray.h> +#include <PsUserAllocated.h> + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +// ----------------------------------------------------------------------------------- +class CompoundGeometry : public ::physx::shdfnd::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; + float radius; + bool isSphere; + }; + + void initConvex(Convex &c); + + shdfnd::Array<Convex> convexes; + shdfnd::Array<PxVec3> vertices; + shdfnd::Array<PxVec3> normals; // one per face and vertex! + // face size, face flags, id, id, .., face size, face flags, id .. + shdfnd::Array<int> indices; + shdfnd::Array<int> neighbors; + + shdfnd::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/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.cpp new file mode 100644 index 00000000..7a6358b6 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.cpp @@ -0,0 +1,1316 @@ +#include "RTdef.h" +#if RT_COMPILE +#include "PxPhysics.h" +#include "PxCooking.h" +#include "PxDefaultStreams.h" +#include "PxShape.h" +#include "foundation/PxMath.h" +#include "PxRigidDynamic.h" +#include "PxConvexMesh.h" +#include "foundation/PxMat44.h" +#include "foundation/PxMathUtils.h" +#include "foundation/PxVec2.h" + +#include "CompoundGeometryBase.h" +#include "SimSceneBase.h" +#include "PolygonTriangulatorBase.h" + +#include "ConvexBase.h" + +#include "PhysXMacros.h" + +class physx::PxPhysics; +class physx::PxCooking; +class physx::PxActor; +class physx::PxScene; +class physx::PxConvexMesh; + +#define COOK_TRIANGLES 1 + +#include <algorithm> + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +// -------------------------------------------------------------------------------------------- +Convex::Convex(SimScene* scene) +{ + mScene = scene; + mPxConvexMesh = NULL; + mPxActor = NULL; + mLocalPose = PX_TRANSFORM_ID; + 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 = PX_TRANSFORM_ID; + + 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, int matID, int surfMatID) +{ + 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; + mMaterialId = matID; + mSurfaceMaterialId = surfMatID; + + if (trans != NULL) { + for (int i = 0; i < (int)mVertices.size(); i++) + mVertices[i] = trans->transform(mVertices[i]); + for (int i = 0; i < (int)mNormals.size(); i++) + mNormals[i] = trans->rotate(mNormals[i]); + mMaterialOffset -= trans->p; + } + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void Convex::transform(const PxMat44 &trans) +{ + for (int i = 0; i < (int)mVertices.size(); i++) + mVertices[i] = trans.transform(mVertices[i]); + for (int i = 0; i < (int)mNormals.size(); i++) + mNormals[i] = trans.rotate(mNormals[i]); + mMaterialOffset -= trans.getPosition(); + + if (mHasExplicitVisMesh) { + for (int i = 0; i < (int)mVisVertices.size(); i++) + mVisVertices[i] = trans.transform(mVisVertices[i]); + for (int i = 0; i < (int)mVisNormals.size(); i++) + mVisNormals[i] = trans.rotate(mVisNormals[i]); + } + finalize(); +} + +// -------------------------------------------------------------------------------------------- +void Convex::createFromGeometry(const CompoundGeometry &geom, int convexNr, const PxMat44 *trans, int matID, int surfMatID) +{ + clear(); + const CompoundGeometry::Convex &c = geom.convexes[convexNr]; + + PxMat44 t = PX_MAT44_ID; + + if (trans) + t = *trans; + + mVertices.resize(c.numVerts); + for (int i = 0; i < c.numVerts; i++) + mVertices[i] = t.transform(geom.vertices[c.firstVert + i]); + + mFaces.resize(c.numFaces); + int num = 0; + const int *id = &geom.indices[c.firstIndex]; + const PxVec3 *normals = (geom.normals.size() > 0) ? &geom.normals[c.firstNormal] : NULL; + mMaterialId = matID; + mSurfaceMaterialId = surfMatID; + + for (int i = 0; i < 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 = 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; + + int numVerts = mVertices.size(); + for (int i = 0; i < numVerts; i++) + center += mVertices[i]; + center /= (float)numVerts; + + return center; +} + +// -------------------------------------------------------------------------------------------- +PxVec3 Convex::centerAtZero() +{ + PxVec3 center = getCenter(); + for (int i = 0; i < (int)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 (int i = 0; i < (int)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 (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 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 = 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 (int i = 0; i < (int)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 = i; + } + } + + if (minPlane < 0) + return false; + else { + PxPlane plane = mPlanes[minPlane]; + surfaceNormal = plane.n; + penetration = minDist; + surfaceVel = PxVec3(0.0f, 0.0f, 0.0f); + + if (mPxActor != NULL) + { + PxRigidDynamic *actor = mPxActor->is<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 (int i = 0; i < (int)mVertices.size(); i++) + mBounds.include(mVertices[i]); +} + +// -------------------------------------------------------------------------------------------- +void Convex::updatePlanes() +{ + int numFaces = mFaces.size(); + mPlanes.resize(numFaces); + + for (int 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[mIndices[f.firstIndex]]; + for (int j = 1; j < f.numIndices-1; j++) { + PxVec3 &p1 = mVertices[mIndices[f.firstIndex+j]]; + PxVec3 &p2 = mVertices[mIndices[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 (int i = 0; i < (int)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 (int i = 0; i < (int)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 + int numFaces = mFaces.size(); + shdfnd::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; + }; + shdfnd::Array<Cut> cuts; + + for (int i = 0; i < numFaces; i++) { + Face &f = mFaces[i]; + int *ids = &mIndices[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 = mNewConvex->mIndices.size(); + bool hasNormals = (f.flags & CompoundGeometry::FF_HAS_NORMALS) != 0; + if (hasNormals) + newFace.firstNormal = mNewConvex->mNormals.size(); + + int cutNrs[2]; + int 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[i0]; + PxVec3 &p1 = mVertices[i1]; + PxVec3 n0,n1; + if (hasNormals) { + n0 = mNormals[f.firstNormal+j]; + n1 = mNormals[f.firstNormal+j1]; + } + bool sign0 = p0.dot(pn) >= pd; + bool sign1 = p1.dot(pn) >= pd; + if (!sign0) { + if (newNr[i0] < 0) { + newNr[i0] = mNewConvex->mVertices.size(); + mNewConvex->mVertices.pushBack(p0); + } + mNewConvex->mIndices.pushBack(newNr[i0]); + if (hasNormals) + mNewConvex->mNormals.pushBack(n0); + if (numCuts == 1) + winding = true; + } + + // cut? + if (sign0 != sign1) { + // do we have the cut vertex already? + int totalCuts = cuts.size(); + int 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, 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] = k; + numCuts++; + } + } + + if (numCuts == 1) { // numerical problems! + cutEmpty = true; + return false; + } + + if (numCuts == 2) { + Cut &cut0 = cuts[cutNrs[0]]; + Cut &cut1 = cuts[cutNrs[1]]; + if (winding) { + cut0.next = cutNrs[1]; + } + else { + cut1.next = cutNrs[0]; + } + } + + // check whether the new convex got a new face + + newFace.numIndices = 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 = mNewConvex->mIndices.size(); + + int nr = 0; + for (int i = 0; i < (int)cuts.size(); i++) { + mNewConvex->mIndices.pushBack(cuts[nr].newId); + closingFace.numIndices++; + nr = cuts[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 + shdfnd::Array<PxU32> 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]); + } + } + + PxConvexMeshDesc meshDesc; + meshDesc.setToDefault(); + meshDesc.points.count = mVertices.size(); + meshDesc.points.stride = sizeof(PxVec3); + meshDesc.points.data = &mVertices[0]; + + meshDesc.flags |= PxConvexFlag::eCOMPUTE_CONVEX; +#else + shdfnd::Array<PxHullPolygon> polygons; + polygons.reserve(mFaces.size()); + if (mPlanes.size() != mFaces.size()) + updatePlanes(); + + for (int i = 0; i < (int)mFaces.size(); i++) { + Face &f = mFaces[i]; + if (f.numIndices < 3) + continue; + PxHullPolygon p; + p.mIndexBase = (physx::PxU16)f.firstIndex; + p.mNbVerts = (physx::PxU16)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); + } + + PxConvexMeshDesc meshDesc; + meshDesc.setToDefault(); + meshDesc.flags |= PxConvexFlag::eDISABLE_MESH_VALIDATION; + 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(PxU32); + meshDesc.polygons.count = mFaces.size(); + meshDesc.polygons.data = &polygons[0]; + meshDesc.polygons.stride = sizeof(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 (int i = 0; i < (int)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 (int i = 0; i < (int)mFaces.size(); i++) { + Face &f = mFaces[i]; + if (f.flags & CompoundGeometry::FF_INVISIBLE) + continue; + if (f.numIndices < 3) + continue; + // normal + int *ids = &mIndices[f.firstIndex]; + if (!(f.flags & CompoundGeometry::FF_HAS_NORMALS)) { + n = (mVertices[ids[1]] - mVertices[ids[0]]).cross(mVertices[ids[2]] - mVertices[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 = mVisVertices.size(); + for (int j = 0; j < f.numIndices; j++) { + PxVec3 p = mVertices[ids[j]]; + mVisVertices.pushBack(p); + if (f.flags & CompoundGeometry::FF_HAS_NORMALS) { + mVisNormals.pushBack(mNormals[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() +{ + int numIndices = mVisPolyIndices.size(); + int numPolygons = mVisPolyStarts.size()-1; + + shdfnd::Array<Edge> edges(numIndices); + + for (int i = 0; i < numPolygons; i++) { + int first = mVisPolyStarts[i]; + int num = mVisPolyStarts[i+1] - first; + for (int j = 0; j < num; j++) { + edges[first + j].set( + mVisVertices[mVisPolyIndices[first + j]], + mVisVertices[mVisPolyIndices[first + (j+1)%num]], i, first + j); + } + } + std::sort(edges.begin(), edges.end()); + + mVisPolyNeighbors.resize(numIndices); + bool manifold = true; + int i = 0; + while (i < (int)edges.size()) { + Edge &e0 = edges[i]; + i++; + if (i < (int)edges.size() && edges[i] == e0) { + Edge &e1 = edges[i]; + mVisPolyNeighbors[e0.edgeNr] = e1.faceNr; + mVisPolyNeighbors[e1.edgeNr] = e0.faceNr; + i++; + } + while (i < (int)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 PxU32 *indices, PxTransform *trans, const PxVec3* scale) +{ + mHasExplicitVisMesh = true; + + // reduce to vertices referenced by indices + // needed if submesh is provided + shdfnd::Array<int> oldToNew(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++) { + int id = indices[i]; + if (oldToNew[id] < 0) { + oldToNew[id] = 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); + } + } + + int numTris = numIndices / 3; + mVisPolyStarts.resize(numTris+1); + for (int i = 0; i < numTris+1; i++) + mVisPolyStarts[i] = 3*i; + + mVisPolyIndices.resize(numIndices); + for (int i = 0; i < numIndices; i++) + mVisPolyIndices[i] = oldToNew[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(numVertices); + mVisNormals.resize(numVertices); + mVisTangents.resize(numVertices); + mVisTexCoords.resize(2*numVertices); + + const float scaleMagn = scale ? scale->magnitude() : 1.f; + + for (int i = 0; i < 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(numPolygons+1); + for (int i = 0; i < numPolygons+1; i++) + mVisPolyStarts[i] = polyStarts[i]; + + mVisPolyIndices.resize(numIndices); + for (int i = 0; i < 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 + + int numTris = mVisTriIndices.size() / 3; + int* tris = &mVisTriIndices[0]; + int numV = mVisVertices.size(); + + for (int i = 0; i < numTris; i++) + { + int i0 = tris[0]; + int i1 = tris[1]; + int i2 = 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); + //NxVec3 b = idet*NxVec3(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 (int 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 (int i = 0; i < (int)mVisPolyStarts.size()-1; i++) { + int first = mVisPolyStarts[i]; + int num = 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], num, &mVisPolyIndices[first]); + const shdfnd::Array<int> indices = pt->getIndices(); + + int numIds = mVisTriIndices.size(); + mVisTriIndices.resize(numIds + indices.size()); + for (int j = 0; j < (int)indices.size(); j++) + mVisTriIndices[numIds+j] = indices[j]; + } +} + +// -------------------------------------------------------------------------------------------- +void Convex::transformVisualMesh(const PxTransform &trans) +{ + for (int i = 0; i < (int)mVisVertices.size(); i++) + mVisVertices[i] = trans.transform(mVisVertices[i]); + for (int i = 0; i < (int)mVisNormals.size(); i++) + mVisNormals[i] = trans.rotate(mVisNormals[i]); + for (int i = 0; i < (int)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 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; +} + +// -------------------------------------------------------------------------------------------- +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 (int j = 0; j < (int)mVisVertices.size(); j++) { + float d = mVisVertices[j].dot(n); + if (d < minVD) minVD = d; + if (d > maxVD) maxVD = d; + } + for (int j = 0; j < (int)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 (int i = 0; i < (int)mFaces.size(); i++) { + const Face &f = mFaces[i]; + if (f.numIndices < 3) + continue; + const int *ids = &mIndices[f.firstIndex]; + const PxVec3 &p0 = mVertices[ids[0]]; + for (int j = 1; j < f.numIndices-1; j++) { + const PxVec3 &p1 = mVertices[ids[j]]; + const PxVec3 &p2 = mVertices[ids[j+1]]; + mVolume += p0.cross(p1).dot(p2); + } + } + mVolume *= (1.0f / 6.0f); + mVolumeDirty = false; + return mVolume; +} + +// -------------------------------------------------------------------------------------------- +void Convex::removeInvisibleFacesFlags() +{ + for (int i = 0; i < (int)mFaces.size(); i++) + mFaces[i].flags &= ~CompoundGeometry::FF_INVISIBLE; +} + +// -------------------------------------------------------------------------------------------- +void Convex::updateFaceVisibility(const float *faceCoverage) +{ + for (int i = 0; i < (int)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 (int i = 0; i < (int)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 (int i = 0; i < (int)mPlanes.size(); i++) { + if (mPlanes[i].n.dot(pos) > mPlanes[i].d + r) + return false; + } + return true; +} + +// -------------------------------------------------------------------------------------------- +bool Convex::check() { + PxVec3 center = getCenter(); + + for (int i = 0; i < (int)mFaces.size(); i++) { + Face &f = mFaces[i]; + if (f.numIndices < 3) + return false; + + PxVec3 &p0 = mVertices[mIndices[f.firstIndex]]; + PxReal A = 0.0f; + PxVec3 n(0.0, 0.0, 0.0); + + for (int j = 1; j < f.numIndices-1; j++) { + PxVec3 &p1 = mVertices[mIndices[f.firstIndex+j]]; + PxVec3 &p2 = mVertices[mIndices[f.firstIndex+j+1]]; + PxVec3 nj = (p1-p0).cross(p2-p0); + A += nj.magnitude(); + n += nj; + } + if (A < 1e-6) + return false; + + PxReal 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; + int numF = mFaces.size(); + for (int 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[mIndices[f.firstIndex]]; + const PxVec3& p1 = mVertices[mIndices[f.firstIndex+j]]; + const PxVec3& p2 = mVertices[mIndices[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[mIndices[f.firstIndex+j]]; + const PxVec3& p2 = mVertices[mIndices[f.firstIndex+(j+1) % nv]]; + areaP += 0.5f*(((p1-pts).cross(p2-pts))).magnitude(); + } + if ((areaP - areaFan)/areaFan < EPSILON) { + return true; + } + } + return false; + +} + +} +} +} +#endif
\ No newline at end of file diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.h new file mode 100644 index 00000000..ad544867 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.h @@ -0,0 +1,213 @@ +#include "RTdef.h" +#if RT_COMPILE +#ifndef CONVEX_BASE +#define CONVEX_BASE + +#include <PxPhysics.h> +#include <PxCooking.h> +#include <foundation/PxVec3.h> +#include <foundation/PxPlane.h> +#include <foundation/PxBounds3.h> +#include <foundation/PxTransform.h> +#include <PsArray.h> +#include <PsUserAllocated.h> + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +class physx::PxShape; +class physx::PxActor; +class physx::PxScene; +class physx::PxConvexMesh; + +class Compound; +class CompoundGeometry; +class SimScene; + +// ---------------------------------------------------------------------------- +class Convex : public ::physx::shdfnd::UserAllocated +{ + friend class SimScene; +protected: + Convex(SimScene* scene); +public: + virtual ~Convex(); + + void createFromConvex(const Convex *convex, const PxTransform *trans = NULL, int matID = 0, int surfMatID = 0); + void createFromGeometry(const CompoundGeometry &geom, int convexNr, const PxMat44 *trans = NULL, int matID = 0, int surfMatID = 0); + //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 shdfnd::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 shdfnd::Array<Face> &getFaces() const { return mFaces; } + const shdfnd::Array<int> &getIndices() const { return mIndices; } + const shdfnd::Array<PxVec3> &getVertices() const { return mVertices; } + + const shdfnd::Array<PxVec3> &getVisVertices() const { return mVisVertices; } + const shdfnd::Array<PxVec3> &getVisNormals() const { return mVisNormals; } + const shdfnd::Array<PxVec3> &getVisTangents() const { return mVisTangents; } + const shdfnd::Array<float> &getVisTexCoords() const { return mVisTexCoords; } + const shdfnd::Array<int> &getVisTriIndices() const { return mVisTriIndices; } + + const shdfnd::Array<int> &getVisPolyStarts() const { return mVisPolyStarts; } + const shdfnd::Array<int> &getVisPolyIndices() const { return mVisPolyIndices; } + const shdfnd::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 PxU32 *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; + + 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; + + shdfnd::Array<Face> mFaces; + shdfnd::Array<int> mIndices; + shdfnd::Array<PxVec3> mVertices; + shdfnd::Array<PxVec3> mNormals; + shdfnd::Array<PxPlane> mPlanes; + + shdfnd::Array<PxVec3> mVisVertices; + shdfnd::Array<PxVec3> mVisNormals; + shdfnd::Array<PxVec3> mVisTangents; + shdfnd::Array<float> mVisTexCoords; + shdfnd::Array<int> mVisTriIndices; + + int mRefCounter; + bool mHasExplicitVisMesh; + bool mIsGhostConvex; + shdfnd::Array<int> mVisPolyStarts; // for explicit mesh only + shdfnd::Array<int> mVisPolyIndices; + shdfnd::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/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.cpp new file mode 100644 index 00000000..303a2d65 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.cpp @@ -0,0 +1,212 @@ +#include "RTdef.h" +#if RT_COMPILE +#include <foundation/PxBounds3.h> + +#include "MeshBase.h" +#include <algorithm> + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +// ---------------------------------------------------------------------- +void Mesh::updateNormals() +{ + if (mVertices.empty()) + return; + + PxVec3 zero(0.0f, 0.0f, 0.0f); + + mNormals.resize(mVertices.size()); + for (int i = 0; i < (int)mNormals.size(); i++) + mNormals[i] = zero; + PxVec3 n; + + PxU32 *idx = &mIndices[0]; + int numTriangles = mIndices.size() / 3; + for (int i = 0; i < numTriangles; i++) { + PxU32 i0 = *idx++; + PxU32 i1 = *idx++; + PxU32 i2 = *idx++; + n = (mVertices[i1] - mVertices[i0]).cross(mVertices[i2] - mVertices[i0]); + mNormals[i0] += n; + mNormals[i1] += n; + mNormals[i2] += n; + } + for (int i = 0; i < (int)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 (int i = 0; i < (int)mVertices.size(); i++) + bounds.include(mVertices[i]); + } + else { + const SubMesh &sm = mSubMeshes[subMeshNr]; + for (int i = 0; i < sm.numIndices; i++) { + bounds.include(mVertices[mIndices[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 (int i = 0; i < (int)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 (int i = 0; i < (int)mVertices.size(); i++) + mVertices[i] *= s; +} + +// -------------------------------------------------------------------------------------------- +struct IdEdge { + void set(PxU32 &i0, PxU32 &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; } + PxU32 i0,i1; + int faceNr, edgeNr; +}; + +// ------------------------------------------------------------------------------ +bool Mesh::computeNeighbors() +{ + int numTris = mIndices.size() / 3; + + shdfnd::Array<IdEdge> edges(3*numTris); + + for (int i = 0; i < numTris; i++) { + for (int j = 0; j < 3; j++) + edges[3*i+j].set(mIndices[3*i+j], mIndices[3*i + (j+1)%3], i, j); + } + std::sort(edges.begin(), edges.end()); + + mNeighbors.clear(); + mNeighbors.resize(mIndices.size(), -1); + bool manifold = true; + int i = 0; + while (i < (int)edges.size()) { + IdEdge &e0 = edges[i]; + i++; + if (i < (int)edges.size() && edges[i] == e0) { + IdEdge &e1 = edges[i]; + mNeighbors[3* e0.faceNr + e0.edgeNr] = e1.faceNr; + mNeighbors[3* e1.faceNr + e1.edgeNr] = e0.faceNr; + i++; + } + while (i < (int)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() +{ + int numTris = mIndices.size() / 3; + shdfnd::Array<PosEdge> edges(3*numTris); + + for (int i = 0; i < numTris; i++) { + for (int j = 0; j < 3; j++) + edges[3*i+j].set(mVertices[mIndices[3*i+j]], mVertices[mIndices[3*i + (j+1)%3]], i, j); + } + std::sort(edges.begin(), edges.end()); + + mNeighbors.clear(); + mNeighbors.resize(mIndices.size(), -1); + bool manifold = true; + int i = 0; + while (i < (int)edges.size()) { + PosEdge &e0 = edges[i]; + i++; + if (i < (int)edges.size() && edges[i] == e0) { + PosEdge &e1 = edges[i]; + mNeighbors[3* e0.faceNr + e0.edgeNr] = e1.faceNr; + mNeighbors[3* e1.faceNr + e1.edgeNr] = e0.faceNr; + i++; + } + while (i < (int)edges.size() && edges[i] == e0) { + manifold = false; + i++; + } + } + return manifold; +} + +void Mesh::flipV() +{ + for(PxU32 i = 0; i < mTexCoords.size(); i++) + { + mTexCoords[i].y = 1.0f - mTexCoords[i].y; + } +} + +} +} +} +#endif
\ No newline at end of file diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.h new file mode 100644 index 00000000..5cde7f17 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.h @@ -0,0 +1,67 @@ +#include "RTdef.h" +#if RT_COMPILE +#ifndef MESH_BASE +#define MESH_BASE + +#include <foundation/PxVec3.h> +#include <foundation/PxVec2.h> +#include <PsArray.h> +#include <PsUserAllocated.h> + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +// ----------------------------------------------------------------------------------- +class Mesh : public ::physx::shdfnd::UserAllocated +{ +public: + Mesh() {}; + virtual ~Mesh() {}; + + const shdfnd::Array<PxVec3> &getVertices() const { return mVertices; } + const shdfnd::Array<PxVec3> &getNormals() const { return mNormals; } + const shdfnd::Array<PxVec2> &getTexCoords() const { return mTexCoords; } + const shdfnd::Array<PxU32> &getIndices() const { return mIndices; } + const shdfnd::Array<int> &getNeighbors() const { return mNeighbors; } + + struct SubMesh { + void init() { /*name = "";*/ firstIndex = -1; numIndices = 0; } + //std::string name; + int firstIndex; + int numIndices; + }; + + const shdfnd::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(); + + shdfnd::Array<PxVec3> mVertices; + shdfnd::Array<PxVec3> mNormals; + shdfnd::Array<PxVec2> mTexCoords; + + shdfnd::Array<SubMesh> mSubMeshes; + shdfnd::Array<PxU32> mIndices; + shdfnd::Array<int> mNeighbors; +}; + +} +} +} + +#endif +#endif
\ No newline at end of file diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.cpp new file mode 100644 index 00000000..9b7f82b3 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.cpp @@ -0,0 +1,272 @@ +#include "RTdef.h" +#if RT_COMPILE +#include "PolygonTriangulatorBase.h" +#include <foundation/PxAssert.h> + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +// ------ 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*(numPoints-2)); + for (int i = 0; i < numPoints-2; i++) { + mIndices[3*i] = 0; + mIndices[3*i+1] = i+1; + mIndices[3*i+2] = i+2; + } + } + else + clipEars(); + + if (indices != NULL) { + for (int i = 0; i < (int)mIndices.size(); i++) { + mIndices[i] = indices[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(numPoints); + if (indices == NULL) { + for (int i = 0; i < numPoints; i++) + mPoints[i] = PxVec3(points[i].dot(t0), points[i].dot(t1), 0.0f); + } + else { + for (int i = 0; i < numPoints; i++) { + const PxVec3 &p = points[indices[i]]; + mPoints[i] = PxVec3(p.dot(t0), p.dot(t1), 0.0f); + } + } +} + +// ------------------------------------------------------------------------------------- +void PolygonTriangulator::clipEars() +{ + // init + int num = mPoints.size(); + + mCorners.resize(num); + + for (int i = 0; i < num; i++) { + Corner &c = mCorners[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[c.prev]; + PxVec3 &p1 = mPoints[i]; + PxVec3 &p2 = mPoints[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[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[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[minNr]; + mIndices.pushBack(cmin.prev); + mIndices.pushBack(minNr); + mIndices.pushBack(cmin.next); + mCorners[cmin.prev].next = cmin.next; + mCorners[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++) { + int i1 = (i == 0) ? cmin.prev : cmin.next; + int i0 = mCorners[i1].prev; + int i2 = 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[nr], p0,p1,p2)) { + mCorners[i1].isEar = false; + break; + } + nr = mCorners[nr].next; + } + } + } + } + int id = firstCorner; + mIndices.pushBack(id); + id = mCorners[id].next; + mIndices.pushBack(id); + id = mCorners[id].next; + mIndices.pushBack(id); +} + +} +} +} +#endif
\ No newline at end of file diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.h new file mode 100644 index 00000000..3b1c08be --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.h @@ -0,0 +1,59 @@ +#include "RTdef.h" +#if RT_COMPILE +#ifndef POLYGON_TRIANGULATOR_BASE_H +#define POLYGON_TRIANGULATOR_BASE_H + +#include <foundation/PxVec3.h> +#include <foundation/PxMath.h> +#include <PsArray.h> +#include <PsUserAllocated.h> + +namespace physx +{ +namespace fracture +{ +namespace base +{ + +// ------------------------------------------------------------------------------ + +class PolygonTriangulator : public ::physx::shdfnd::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 shdfnd::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; + + shdfnd::Array<PxVec3> mPoints; + shdfnd::Array<int> mIndices; + + struct Corner { + int prev; + int next; + bool isEar; + float angle; + }; + shdfnd::Array<Corner> mCorners; +}; + +} +} +} + +#endif +#endif diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.cpp new file mode 100644 index 00000000..6a1d2931 --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.cpp @@ -0,0 +1,337 @@ +#include "RTdef.h" +#if RT_COMPILE +#include "PsHashMap.h" +#include "SimSceneBase.h" +#include <foundation/PxMat44.h> +#include "PxRigidBodyExt.h" +#include "PxPhysics.h" +#include "PxCooking.h" +#include "PxShape.h" + +#include "ActorBase.h" +#include "CompoundBase.h" +#include "ConvexBase.h" +#include "CompoundCreatorBase.h" +#include "PolygonTriangulatorBase.h" + +#include "RTdef.h" + +#include "PhysXMacros.h" +#include "PxScene.h" +#include "PxD6Joint.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 physx +{ +namespace fracture +{ +namespace base +{ + +SimScene* SimScene::createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, bool isGrbScene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath) +{ + SimScene* s = PX_NEW(SimScene)(pxPhysics,pxCooking, isGrbScene,minConvexSize,defaultMat,resourcePath); + s->createSingletons(); + return s; +} + +void SimScene::createSingletons() +{ + mCompoundCreator = PX_NEW(CompoundCreator)(this); + mPolygonTriangulator = PX_NEW(PolygonTriangulator)(this); + addActor(createActor()); // make default actor +} + +Convex* SimScene::createConvex() +{ + return PX_NEW(Convex)(this); +} + +Compound* SimScene::createCompound(const FracturePattern *pattern, const FracturePattern *secondaryPattern, PxReal contactOffset, PxReal restOffset) +{ + return PX_NEW(Compound)(this,contactOffset,restOffset); +} + +Actor* SimScene::createActor() +{ + return PX_NEW(Actor)(this); +} + +shdfnd::Array<Compound*> SimScene::getCompounds() +{ + return mActors[0]->getCompounds(); +} + +///*extern*/ std::vector<Compound*> delCompoundList; + +// -------------------------------------------------------------------------------------------- +SimScene::SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, bool isGrbScene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath) +{ + mPxPhysics = pxPhysics; // used for cooking + mPxCooking = pxCooking; + mPxDefaultMaterial = defaultMat; + 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; + mPickJoint = 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; + mPolygonTriangulator = NULL; + + mAppNotify = NULL; +} + +// -------------------------------------------------------------------------------------------- +SimScene::~SimScene() +{ + clear(); + + // Delete actors if not already deleted + for(int i = ((int)mActors.size() - 1) ; i >= 0; i--) + { + PX_DELETE(mActors[i]); + } + + PX_DELETE(mCompoundCreator); + PX_DELETE(mPolygonTriangulator); + + mCompoundCreator = NULL; + mPolygonTriangulator = NULL; +} + +// -------------------------------------------------------------------------------------------- +void SimScene::clear() +{ + for(int i = 0 ; i < (int)mActors.size(); i++) + { + mActors[i]->clear(); + } + deleteCompounds(); + mPickActor = NULL; + + ++mSceneVersion; +} + +void SimScene::addActor(Actor* a) +{ + mActors.pushBack(a); +} + +void SimScene::removeActor(Actor* a) +{ + for(int i = 0; i < (int)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 (int i = 0; i < (int)delCompoundList.size(); i++) + { + PX_DELETE(delCompoundList[i]); + } + delCompoundList.clear(); +} + +// -------------------------------------------------------------------------------------------- +void SimScene::preSim(float dt) +{ + for(int i = 0 ; i < (int)mActors.size(); i++) + { + mActors[i]->preSim(dt); + } + + + // make sure we use the apex user notify... if the application + // changes their custom one make sure we map to it. + 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) +{ + for(int i = 0 ; i < (int)mActors.size(); i++) + { + mActors[i]->postSim(dt); + } + + mFrameNr++; + mNoFractureFrames--; + mNoSoundFrames--; +} + + +//----------------------------------------------------------------------------- +bool SimScene::pickStart(const PxVec3 &orig, const PxVec3 &dir) +{ + PX_ASSERT(mPickActor == NULL); + + float dist = 1000.f; + + PxRaycastBuffer buffer; + if (!getScene()->raycast(orig, dir, dist, buffer, PxHitFlag::eDEFAULT, PxQueryFilterData(PxQueryFlag::eDYNAMIC))) + return false; + + PxRigidDynamic* pickedActor = buffer.getAnyHit(0).actor->is<PxRigidDynamic>(); + + dist = buffer.getAnyHit(0).distance; + + + + //mPickActor = mActors[actorNr]->mCompounds[compoundNr]->getPxActor(); + mPickPos = orig + dir * dist; + + mPickActor = PxGetPhysics().createRigidDynamic(PxTransform(mPickPos)); + mPickActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true); + + getScene()->addActor(*mPickActor); + + mPickLocalPos = PxVec3(0.f); + + mPickJoint = PxD6JointCreate(PxGetPhysics(), mPickActor, PxTransform(PxIdentity), pickedActor, PxTransform(pickedActor->getGlobalPose().transformInv(mPickPos))); + mPickJoint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eFREE); + mPickJoint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE); + mPickJoint->setMotion(PxD6Axis::eTWIST, PxD6Motion::eFREE); + + mPickDepth = dist; + return true; +} + +//----------------------------------------------------------------------------- +void SimScene::pickMove(const PxVec3 &orig, const PxVec3 &dir) +{ + if (mPickActor == NULL) + return; + + mPickPos = orig + dir * mPickDepth; + mPickActor->setKinematicTarget(PxTransform(mPickPos)); +} + +//----------------------------------------------------------------------------- +void SimScene::pickRelease() +{ + if (mPickJoint) + mPickJoint->release(); + mPickJoint = NULL; + if (mPickActor) + mPickActor->release(); + mPickActor = NULL; +} + +bool SimScene::findCompound(const Compound* c, int& actorNr, int& compoundNr) +{ + actorNr = -1; + compoundNr = -1; + for(int i = 0; i < (int)mActors.size(); i++) + { + if (mActors[i]->findCompound(c,compoundNr)) + { + actorNr = i; + return true; + } + } + return false; +} + +// -------------------------------------------------------------------------------------------- +// CPU +void SimScene::onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, PxU32 nbPairs) +{ + // Pass along to application's callback, if defined + if (mAppNotify != NULL) + { + mAppNotify->onContact(pairHeader, pairs, nbPairs); + } +} + +shdfnd::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 physx::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/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.h new file mode 100644 index 00000000..60bd732d --- /dev/null +++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.h @@ -0,0 +1,248 @@ +#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 physx +{ +class PxPhysics; +class PxCooking; +class PxScene; +class PxRigidDynamic; +class PxD6Joint; +namespace fracture +{ +namespace base +{ + +class Actor; +class Compound; +class Convex; +class FracturePattern; +class CompoundCreator; +class Delaunay2d; +class Delaunay3d; +class PolygonTriangulator; + +// ----------------------------------------------------------------------------------- +class SimScene : + public PxSimulationEventCallback, public ::physx::shdfnd::UserAllocated +{ + friend class Actor; +public: + static SimScene* createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, bool isGrbScene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath); +protected: + SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, bool isGrbScene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath); +public: + virtual ~SimScene(); + + // Creates Scene Level Singletons + virtual void createSingletons(); + // Access singletons + CompoundCreator* getCompoundCreator() {return mCompoundCreator;} + PolygonTriangulator* getPolygonTriangulator() {return mPolygonTriangulator;} + + // Create non-Singletons + virtual Actor* createActor(); + virtual Convex* createConvex(); + virtual Compound* createCompound(const FracturePattern *pattern, const FracturePattern *secondaryPattern = NULL, PxReal contactOffset = 0.005f, PxReal restOffset = -0.001f); + virtual void clear(); + void addCompound(Compound *m); + void removeCompound(Compound *m); + // perform deferred deletion + void deleteCompounds(); + + void setScene(PxScene* scene) { mScene = scene; } + // + 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*/) {} + + virtual void playSound(const char * /*name*/, int /*nr*/ = -1) {} + + // accessors + shdfnd::Array<Compound*> getCompounds(); //{ return mCompounds; } + shdfnd::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(PxConstraintInfo* constraints, PxU32 count) { PX_UNUSED((constraints, count)); } + void onWake(PxActor** actors, PxU32 count) { PX_UNUSED((actors, count)); } + void onSleep(PxActor** actors, PxU32 count) { PX_UNUSED((actors, count)); } + void onTrigger(PxTriggerPair* pairs, PxU32 count) { PX_UNUSED((pairs, count)); } + void onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, PxU32 nbPairs); + void onAdvance(const PxRigidBody*const* bodyBuffer, const PxTransform* poseBuffer, const PxU32 count) { PX_UNUSED(bodyBuffer); PX_UNUSED(poseBuffer); PX_UNUSED(count); } + + void toggleRenderDebris() {mRenderDebris = !mRenderDebris;} + bool getRenderDebrs() {return mRenderDebris;} + //virtual void dumpSceneGeometry() {} + shdfnd::Array<PxVec3>& getDebugPoints(); + //virtual void createRenderBuffers() {} + //void loadAndCreateTextureArrays(); + + shdfnd::Array<PxVec3>& getCrackNormals() {return crackNormals;} + shdfnd::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; + + //shdfnd::Array<Compound*> mCompounds; + shdfnd::Array<Actor*> mActors; + + float mFractureForceThreshold; + float mContactImpactRadius; + + shdfnd::Array<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; + }; + + struct RenderBuffers { + void init() { + numVertices = 0; numIndices = 0; + VBO = 0; IBO = 0; matTex = 0; volTex = 0; + texSize = 0; numConvexes = -1; + } + shdfnd::Array<float> tmpVertices; + shdfnd::Array<unsigned int> tmpIndices; + shdfnd::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; + PxD6Joint* mPickJoint; + 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; + shdfnd::Array<PxVec3> debugPoints; + bool mRenderDebris; + + PxSimulationEventCallback* mAppNotify; + + //GLuint diffuseTexArray, bumpTexArray, specularTexArray, emissiveReflectSpecPowerTexArray; + + //GLuint loadTextureArray(std::vector<std::string>& names); + + //Singletons + CompoundCreator* mCompoundCreator; + PolygonTriangulator* mPolygonTriangulator; + + //Array for use by Compound (effectively static) + shdfnd::Array<PxVec3> crackNormals; + shdfnd::Array<PxVec3> tmpPoints; + + // Deferred Deletion list + shdfnd::Array<Compound*> delCompoundList; + + // Map used to determine SimScene ownership of shape + shdfnd::HashMap<const PxShape*,Convex*> mShapeMap; +}; + +} +} +} + +#endif +#endif |