//------------------------------------------------------------------------------------------------- bool sdPhysicsSystem::CreateEmptyScene(uint uiSize) { NIASSERT(!m_pkScene); NIASSERT(!m_pkControllerManager); float fSize = (float)uiSize; float fWalkHeight = 4000.f; NxBounds3 nxBound; nxBound.setCenterExtents(NxVec3(fSize * 0.5f, fSize * 0.5f, 0.f), NxVec3(fSize * 0.5f, fSize * 0.5f, fWalkHeight *0.5f)); NxSceneDesc nxSceneDesc; nxSceneDesc.gravity = NxVec3(0.f, 0.f, -9.8f); nxSceneDesc.simType = NX_SIMULATION_SW; nxSceneDesc.maxBounds = &nxBound; nxSceneDesc.upAxis = 2; ///< Z up nxSceneDesc.bpType = NX_BP_TYPE_SAP_MULTI; nxSceneDesc.nbGridCellsX = 8u; nxSceneDesc.nbGridCellsY = 8u; nxSceneDesc.subdivisionLevel = 5; m_pkScene = m_pkPhysicsSDK->createScene(nxSceneDesc); NIASSERT(m_pkScene); m_pkControllerManager = NxCreateControllerManager(m_pkAllocator); NIASSERT(m_pkControllerManager); return true; }
// ---------------------------------------------------------------------- void ObjMesh::getTriangleBounds(int i, NxBounds3 &bounds) const { const ObjMeshTriangle &mt = mTriangles[i]; bounds.setEmpty(); bounds.include(mVertices[mt.vertexNr[0]]); bounds.include(mVertices[mt.vertexNr[1]]); bounds.include(mVertices[mt.vertexNr[2]]); }
void CCTDebugData::addAABB(const NxBounds3& bounds, NxU32 color, bool renderFrame) { // Reuse OBB code... NxVec3 center; bounds.getCenter(center); NxVec3 extents; bounds.getExtents(extents); NxMat33 id; id.id(); addOBB(NxBox(center, extents, id), color, renderFrame); }
void CCTDebugData::addAABB(const NxExtendedBounds3& bounds, NxU32 color) { NxExtendedVec3 center; NxVec3 extents; bounds.getCenter(center); bounds.getExtents(extents); NxBounds3 tmp; tmp.setCenterExtents(NxVec3((float)center.x, (float)center.y, (float)center.z), extents); addAABB(tmp, color, false); }
static void CreateCube(const NxVec3& pos, const NxVec3 * vel = 0) { // Avoid creating one compound within another NxBounds3 bounds; bounds.setCenterExtents(pos, NxVec3(10.0f, 10.0f, 10.0f)); if(gScene->checkOverlapAABB(bounds)) return; // Create cube made up of 6 individual boxes as its faces, with each box having a different material NxActorDesc actorDesc; NxBodyDesc bodyDesc; bodyDesc.linearVelocity.set(0,5,0); if (vel) bodyDesc.linearVelocity += *vel; bodyDesc.angularVelocity.set(NxMath::rand(0.0f,10.0f),NxMath::rand(0.0f,10.0f),NxMath::rand(0.0f,10.0f)); //throw up the ball with a random initial angular vel as if to roll dice. NxBoxShapeDesc boxDesc[6]; boxDesc[0].dimensions.set(4,4,1); boxDesc[0].localPose.t.set(0,0,4); boxDesc[0].materialIndex = defaultMaterialIndex; actorDesc.shapes.pushBack(&boxDesc[0]); boxDesc[1].dimensions.set(4,4,1); boxDesc[1].localPose.t.set(0,0,-4); boxDesc[1].materialIndex = somewhatBouncyMaterialIndex; actorDesc.shapes.pushBack(&boxDesc[1]); boxDesc[2].dimensions.set(4,1,4); boxDesc[2].localPose.t.set(0,4,0); boxDesc[3].materialIndex = veryBouncyMaterialIndex; actorDesc.shapes.pushBack(&boxDesc[2]); boxDesc[3].dimensions.set(4,1,4); boxDesc[3].localPose.t.set(0,-4,0); boxDesc[3].materialIndex = defaultMaterialIndex; actorDesc.shapes.pushBack(&boxDesc[3]); boxDesc[4].dimensions.set(1,4,4); boxDesc[4].localPose.t.set(4,0,0); boxDesc[4].materialIndex = frictionlessMaterialIndex; actorDesc.shapes.pushBack(&boxDesc[4]); boxDesc[5].dimensions.set(1,4,4); boxDesc[5].localPose.t.set(-4,0,0); boxDesc[5].materialIndex = highFrictionMaterialIndex; actorDesc.shapes.pushBack(&boxDesc[5]); actorDesc.body = &bodyDesc; actorDesc.density = 10.0f; actorDesc.globalPose.t = pos; gScene->createActor(actorDesc); }
//----------------------------------------------------------------------------- // GetWorldBounds //----------------------------------------------------------------------------- NxBounds3 CPhysicObj::GetWorldBounds (void) const { assert( m_bActivated ); int nNumParts = GetNumParts(); // NOTA: Siempre tendremos que tener al menos 1 parte. NxBounds3 result = GetWorldBounds (0); // El resto de bounds los combinamos con el resultado for (int i = 1; i < nNumParts; i++) { result.combine (GetWorldBounds(i)); } return result; }
static bool SweepBoxMesh(const SweepTest* sweep_test, const SweptVolume* volume, const TouchedGeom* geom, const NxExtendedVec3& center, const NxVec3& dir, SweptContact& impact) { ASSERT(volume->GetType()==SWEPT_BOX); ASSERT(geom->mType==TOUCHED_MESH); const SweptBox* SB = static_cast<const SweptBox*>(volume); const TouchedMesh* TM = static_cast<const TouchedMesh*>(geom); NxU32 NbTris = TM->mNbTris; if(!NbTris) return false; // Fetch triangle data for current mesh (the stream may contain triangles from multiple meshes) const NxTriangle* T = &sweep_test->mWorldTriangles[TM->mIndexWorldTriangles]; const NxTriangle* ET = &sweep_test->mWorldEdgeNormals[TM->mIndexWorldEdgeNormals]; const NxU32* EdgeFlags = &sweep_test->mEdgeFlags[TM->mIndexEdgeFlags]; NxBounds3 Box; Box.setCenterExtents(NxVec3(float(center.x - TM->mOffset.x), float(center.y - TM->mOffset.y), float(center.z - TM->mOffset.z)), SB->mExtents); // Precompute // PT: this only really works when the CCT collides with a single mesh, but that's the most common case. When it doesn't, there's just no speedup but it still works. NxU32 CachedIndex = sweep_test->mCachedTriIndex[sweep_test->mCachedTriIndexIndex]; if(CachedIndex>=NbTris) CachedIndex=0; NxVec3 Hit, Normal; float t; NxU32 Index; if(gUtilLib->NxSweepBoxTriangles(NbTris, T, ET, EdgeFlags, Box, dir, impact.mDistance, Hit, Normal, t, Index, &CachedIndex)) { if(t>=impact.mDistance) return false; impact.mDistance = t; impact.mWorldNormal = Normal; impact.mWorldPos.x = Hit.x + TM->mOffset.x; impact.mWorldPos.y = Hit.y + TM->mOffset.y; impact.mWorldPos.z = Hit.z + TM->mOffset.z; // Returned index is only between 0 and NbTris, i.e. it indexes the array of cached triangles, not the original mesh. assert(Index<NbTris); sweep_test->mCachedTriIndex[sweep_test->mCachedTriIndexIndex] = Index; // The CCT loop will use the index from the start of the cache... impact.mIndex = Index + TM->mIndexWorldTriangles; return true; } return false; }
Box3F PxBody::getWorldBounds() { AssertFatal( mActor, "PxBody::getTransform - The actor is null!" ); NxBounds3 bounds; bounds.setEmpty(); NxBounds3 shapeBounds; NxShape *const* pShapeArray = mActor->getShapes(); U32 shapeCount = mActor->getNbShapes(); for ( U32 i = 0; i < shapeCount; i++ ) { // Get the shape's bounds. pShapeArray[i]->getWorldBounds( shapeBounds ); // Combine them into the total bounds. bounds.combine( shapeBounds ); } return pxCast<Box3F>( bounds ); }
//----------------------------------------------------------------------------- // GetWorldBounds //----------------------------------------------------------------------------- NxBounds3 CPhysicObj::GetWorldBounds (int nPartIdx) const { assert( m_bActivated && (nPartIdx < GetNumParts()) ); const NxActor* pActor = GetActor(nPartIdx); // Combinamos los bounds de todas las shapes NxBounds3 result; NxBounds3 shapeBounds; uint nNumShapes = pActor->getNbShapes(); assert( nNumShapes > 0 ); NxShape* const* pShapes = pActor->getShapes(); pShapes[0]->getWorldBounds(result); for (uint i = 1; i < nNumShapes; i++) { pShapes[0]->getWorldBounds (shapeBounds); result.combine (shapeBounds); } return result; }
//----------------------------------------------------------------------------- // CalcBBox //----------------------------------------------------------------------------- NxBox CPhysicModelSimple::CalcBBox (void) const { NxBounds3 bounds; for (int i = 0; i < (int)m_ActorDesc.shapes.size(); i++) { NxShapeDesc* pShapeDesc = m_ActorDesc.shapes[i]; switch (pShapeDesc->getType()) { case NX_SHAPE_BOX: { NxBoxShapeDesc* pBoxShape = (NxBoxShapeDesc*) pShapeDesc; NxBox shapeBBox (pBoxShape->localPose.t, pBoxShape->dimensions, pBoxShape->localPose.M); NxBounds3 shapeBounds; shapeBounds.boundsOfOBB( shapeBBox.rot, shapeBBox.center, shapeBBox.extents ); bounds.combine (shapeBounds); } break; case NX_SHAPE_SPHERE: { NxSphereShapeDesc* pSphereShape = (NxSphereShapeDesc*) pShapeDesc; NxBox shapeBBox (pSphereShape->localPose.t, NxVec3(pSphereShape->radius), pSphereShape->localPose.M); NxBounds3 shapeBounds; shapeBounds.boundsOfOBB( shapeBBox.rot, shapeBBox.center, shapeBBox.extents ); bounds.combine (shapeBounds); } break; default: // Caso no soportado assert(0); break; } } NxBox result; bounds.getCenter (result.center); bounds.getExtents (result.extents); return result; }
// ----------------------------------------------------------------------- // compute the links between the surface mesh and tetrahedras void ObjMesh::buildTetraLinks(const NxVec3 *vertices, const NxU32 *indices, const NxU32 numTets) { if(!mTetraLinks.empty()) return; mTetraLinks.clear(); MeshHash* hash = new MeshHash(); // hash tetrahedra for faster search hash->setGridSpacing(mBounds.min.distance(mBounds.max) * 0.1f); for (NxU32 i = 0; i < numTets; i++) { const NxU32 *ix = &indices[4*i]; NxBounds3 tetraBounds; tetraBounds.setEmpty(); tetraBounds.include(vertices[*ix++]); tetraBounds.include(vertices[*ix++]); tetraBounds.include(vertices[*ix++]); tetraBounds.include(vertices[*ix++]); hash->add(tetraBounds, i); } for (NxU32 i = 0; i < mVertices.size(); i++) { // prepare datastructure for drained tetras mDrainedTriVertices.push_back(false); ObjMeshTetraLink tmpLink; NxVec3 triVert = mVertices[i]; std::vector<int> itemIndices; hash->queryUnique(triVert, itemIndices); NxReal minDist = 0.0f; NxVec3 b; int num, isize; num = isize = itemIndices.size(); if (num == 0) num = numTets; for (int i = 0; i < num; i++) { int j = i; if (isize > 0) j = itemIndices[i]; const NxU32 *ix = &indices[j*4]; const NxVec3 &p0 = vertices[*ix++]; const NxVec3 &p1 = vertices[*ix++]; const NxVec3 &p2 = vertices[*ix++]; const NxVec3 &p3 = vertices[*ix++]; NxVec3 b = computeBaryCoords(triVert, p0, p1, p2, p3); // is the vertex inside the tetrahedron? If yes we take it if (b.x >= 0.0f && b.y >= 0.0f && b.z >= 0.0f && (b.x + b.y + b.z) <= 1.0f) { tmpLink.barycentricCoords = b; tmpLink.tetraNr = j; break; } // otherwise, if we are not in any tetrahedron we take the closest one NxReal dist = 0.0f; if (b.x + b.y + b.z > 1.0f) dist = b.x + b.y + b.z - 1.0f; if (b.x < 0.0f) dist = (-b.x < dist) ? dist : -b.x; if (b.y < 0.0f) dist = (-b.y < dist) ? dist : -b.y; if (b.z < 0.0f) dist = (-b.z < dist) ? dist : -b.z; if (i == 0 || dist < minDist) { minDist = dist; tmpLink.barycentricCoords = b; tmpLink.tetraNr = j; } } mTetraLinks.push_back(tmpLink); } delete hash; }
void Update() { NxMat34 mat34; NxMat33 mat; NxQuat quat(0.0f,NxVec3(0,1,0)); mat.fromQuat(quat); NxBox worldBox; worldBox.extents = NxVec3(2, 2, 2); worldBox.rot = mat; NxSphere worldSphere; NxBounds3 worldBounds; NxCapsule worldCapsule; worldCapsule.radius = 2.0f; NxU32 nbPlanes = 2; NxPlane worldPlanes[2]; worldPlanes[0].set(NxVec3(-2,0,2), NxVec3(0,0,1)); worldPlanes[1].set(NxVec3(-2,0,2), NxVec3(1,0,0)); NxU32 nbDynamicShapes = gScene->getNbDynamicShapes(); NxU32 nbStaticShapes = gScene->getNbStaticShapes(); NxU32 nbShapes = 0; NxShapesType type; int i = 0; for (i = 0; i < 3; ++ i) { if (i == 0) { nbShapes = nbDynamicShapes; type = NX_DYNAMIC_SHAPES; switch(gOverlapType) { case OVERLAP_AABB: case OVERLAP_CHECK_AABB: worldBounds.set(gMIN, gMAX); break; case OVERLAP_OBB: case OVERLAP_CHECK_OBB: worldBox.center = gBoxCenter; break; case OVERLAP_CAPSULE: case OVERLAP_CHECK_CAPSULE: worldCapsule = NxCapsule(gCapsuleSegment, gCapsuleRadius); break; case OVERLAP_SPHERE: case OVERLAP_CHECK_SPHERE: worldSphere = NxSphere(gSphereCenter, gSphereRadius); break; } } else if (i == 1) { nbShapes = nbStaticShapes; type = NX_STATIC_SHAPES; switch(gOverlapType) { case OVERLAP_AABB: case OVERLAP_CHECK_AABB: worldBounds.set(gMIN+NxVec3(-6.0f,0,0),gMAX+NxVec3(-6.0f,0,0)); break; case OVERLAP_OBB: case OVERLAP_CHECK_OBB: worldBox.center = gBoxCenter+NxVec3(-6,0,0); break; case OVERLAP_CAPSULE: case OVERLAP_CHECK_CAPSULE: worldCapsule.p0.x = gCapsuleSegment.p0.x - 6.0f; worldCapsule.p1.x = gCapsuleSegment.p1.x - 6.0f; break; case OVERLAP_SPHERE: case OVERLAP_CHECK_SPHERE: worldSphere = NxSphere(gSphereCenter + NxVec3(-6,0,0), gSphereRadius); break; } } else if (i == 2) { nbShapes = nbStaticShapes + nbDynamicShapes; type = NX_ALL_SHAPES; switch(gOverlapType) { case OVERLAP_AABB: case OVERLAP_CHECK_AABB: worldBounds.set(gMIN+NxVec3(6.0f,0,0),gMAX+NxVec3(6.0f,0,0)); break; case OVERLAP_OBB: case OVERLAP_CHECK_OBB: worldBox.center = gBoxCenter+NxVec3(6,0,0); break; case OVERLAP_CAPSULE: case OVERLAP_CHECK_CAPSULE: worldCapsule.p0.x = gCapsuleSegment.p0.x + 6.0f; worldCapsule.p1.x = gCapsuleSegment.p1.x + 6.0f; break; case OVERLAP_SPHERE: case OVERLAP_CHECK_SPHERE: worldSphere = NxSphere(gSphereCenter + NxVec3(6,0,0), gSphereRadius); break; } } NxShape** shapes = (NxShape**)NxAlloca(nbShapes*sizeof(NxShape*)); for (NxU32 j = 0; j < nbShapes; j++) shapes[j] = NULL; NxU32 activeGroups = 0xffffffff; NxGroupsMask* groupsMask = NULL; bool bResult = true; float linewidth = 1.0f; switch(gOverlapType) { case OVERLAP_AABB: gScene->overlapAABBShapes(worldBounds, type, nbShapes, shapes, &gShapeReport, activeGroups, groupsMask, true); NxCreateBox(worldBox, worldBounds, mat34); DrawWireBox(worldBox, NxVec3(1,0,0), linewidth); break; case OVERLAP_CHECK_AABB: bResult = gScene->checkOverlapAABB(worldBounds, type, activeGroups, groupsMask); NxCreateBox(worldBox, worldBounds, mat34); if (bResult == true) DrawWireBox(worldBox, NxVec3(1,0,0), linewidth); else DrawWireBox(worldBox, NxVec3(0,1,0), linewidth); break; case OVERLAP_OBB: gScene->overlapOBBShapes(worldBox, type, nbShapes, shapes, &gShapeReport, activeGroups, groupsMask); DrawWireBox(worldBox, NxVec3(1,0,0), linewidth); break; case OVERLAP_CHECK_OBB: if (gScene->checkOverlapOBB(worldBox, type, activeGroups, groupsMask) == true) DrawWireBox(worldBox, NxVec3(1,0,0), linewidth); else DrawWireBox(worldBox, NxVec3(0,1,0), linewidth); break; case OVERLAP_CAPSULE: gScene->overlapCapsuleShapes(worldCapsule, type, nbShapes, shapes, &gShapeReport, activeGroups, groupsMask); DrawWireCapsule(worldCapsule, NxVec3(1,0,0)); break; case OVERLAP_CHECK_CAPSULE: if (gScene->checkOverlapCapsule(worldCapsule, type,activeGroups, groupsMask) == true) DrawWireCapsule(worldCapsule, NxVec3(1,0,0)); else DrawWireCapsule(worldCapsule, NxVec3(0,1,0)); break; case OVERLAP_SPHERE: gScene->overlapSphereShapes(worldSphere, type, nbShapes, shapes, &gShapeReport, activeGroups, groupsMask); DrawWireSphere(&worldSphere, NxVec3(1,0,0)); break; case OVERLAP_CHECK_SPHERE: if (gScene->checkOverlapSphere(worldSphere, type,activeGroups, groupsMask) == true) DrawWireSphere(&worldSphere, NxVec3(1,0,0)); else DrawWireSphere(&worldSphere, NxVec3(0,1,0)); break; case OVERLAP_CULL: gScene->cullShapes(nbPlanes, worldPlanes, type, nbShapes, shapes, &gShapeReport, activeGroups, groupsMask); DrawLine(NxVec3(-20,0,2), NxVec3(-2,0,2),NxVec3(1,0,0), linewidth); DrawLine(NxVec3(-2,0,-20), NxVec3(-2,0,2),NxVec3(1,0,0), linewidth); break; } } }
// ----------------------------------------------------------------------- void MyCloth::draw(bool shadows) { static NxU32 numVertices = mNumVertices; NxU32 numElements = mNumIndices; numVertices = mNumVertices; // Disable pressure if tearing occurs if (mTeared && (mCloth->getFlags() & NX_CLF_PRESSURE)) { // Disable Pressure mCloth->setFlags(mCloth->getFlags() & ~NX_CLF_PRESSURE); mCloth->setPressure(0); // Reduce tearing factor NxReal oldTearing = mCloth->getTearFactor(); oldTearing = (oldTearing - 1) / 3 + 1; mCloth->setTearFactor(oldTearing); // Reduce bending stiffness if (mCloth->getBendingStiffness() > 0.9f) mCloth->setBendingStiffness(0.2f); // Apply explosion in the middle of the cloth NxBounds3 bounds; mCloth->getWorldBounds(bounds); NxVec3 center; bounds.getCenter(center); NxReal radius = bounds.min.distance(bounds.max); mCloth->addForceAtPos(center, 7 * NxMath::pow(radius,3), radius, NX_IMPULSE); printf("Pressure disabled\n"); } if (mTexId > 0) { updateTextureCoordinates(); } glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(RenderBufferVertexElement), numVertices, &(mVertexRenderBuffer[0].position.x)); glNormalPointer(GL_FLOAT, sizeof(RenderBufferVertexElement), numVertices, &(mVertexRenderBuffer[0].normal.x)); if (mTexId) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(RenderBufferVertexElement), numVertices, &(mVertexRenderBuffer[0].texCoord[0])); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, mTexId); glColor4f(1.0f, 1.0f, 1.0f,1.0f); } #ifdef __CELLOS_LV2__ glDrawRangeElements(GL_TRIANGLES, 0, numVertices-1, numElements, GL_UNSIGNED_INT, mIndexRenderBuffer); #else glDrawElements(GL_TRIANGLES, numElements, GL_UNSIGNED_INT, mIndexRenderBuffer); #endif if (mTexId) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); } if (shadows) { const static float ShadowMat[]={ 1,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,1 }; glPushMatrix(); glMultMatrixf(ShadowMat); glDisable(GL_LIGHTING); glColor4f(0.05f, 0.1f, 0.15f,1.0f); #ifdef __CELLOS_LV2__ glDrawRangeElements(GL_TRIANGLES, 0, numVertices-1, numElements, GL_UNSIGNED_INT, mIndexRenderBuffer); #else glDrawElements(GL_TRIANGLES, numElements, GL_UNSIGNED_INT, mIndexRenderBuffer); #endif glColor4f(1.0f, 1.0f, 1.0f,1.0f); glEnable(GL_LIGHTING); glPopMatrix(); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); }
void SampleCollision::setup() { SetTitleString(getName()); #ifdef __PPCGEKKO__ SetHelpString(" a: create rigid bodies"); #else SetHelpString(" b: create rigid bodies"); #endif gShadows = false; // Create objects in the scene if (!InitCooking(gAllocator, &gErrorStream)) { printf("\nError: Unable to initialize the cooking library, exiting the sample.\n\n"); return; } // Load ASE file CookASE("fluidSample.ase", gScene, NxVec3(1,10,0)); CookASE("coolFlow.ase", gScene, NxVec3(1,6,-0), NxVec3(1,0.2,1)); CloseCooking(); // Add a box shaped drain. NxActorDesc boxDrainActor; NxBoxShapeDesc boxDrainShape; boxDrainActor.shapes.pushBack(&boxDrainShape); boxDrainShape.dimensions.set(40,1,40); boxDrainShape.shapeFlags |= NX_SF_FLUID_DRAIN; boxDrainActor.globalPose.t.set(0, 0, 0); gScene->createActor(boxDrainActor); //Pre cook hotspots NxBounds3 precookAABB; precookAABB.set(NxVec3(-20,-20,-20), NxVec3(20,20,20)); // gScene->cookFluidMeshHotspot(precookAABB, PACKET_SIZE_MULTIPLIER, REST_PARTICLES_PER_METER, KERNEL_RADIUS_MULTIPLIER, MOTION_LIMIT_MULTIPLIER, COLLISION_DISTANCE_MULTIPLIER ); //Create a set of initial particles ParticleSDK* initParticles = new ParticleSDK[MAX_PARTICLES]; unsigned initParticlesNum = 0; NxVec3 fluidPos(0, 11.6, 0); float distance = 0.1f; unsigned sideNum = 16; float rad = sideNum*distance*0.5f; for (unsigned i=0; i<sideNum; i++) for (unsigned j=0; j<sideNum; j++) for (unsigned k=0; k<sideNum; k++) { NxVec3 p = NxVec3(i*distance,j*distance,k*distance); if (p.distance(NxVec3(rad,rad,rad)) < rad) { p += fluidPos; ParticleSDK& newParticle = initParticles[initParticlesNum++]; newParticle.position = p; newParticle.velocity = NxVec3(0,0,0); } } //Setup structure to pass initial particles. NxParticleData initParticleData; initParticleData.numParticlesPtr = &initParticlesNum; initParticleData.bufferPos = &initParticles[0].position.x; initParticleData.bufferPosByteStride = sizeof(ParticleSDK); initParticleData.bufferVel = &initParticles[0].velocity.x; initParticleData.bufferVelByteStride = sizeof(ParticleSDK); //Setup fluid descriptor NxFluidDesc fluidDesc; fluidDesc.maxParticles = initParticlesNum; fluidDesc.kernelRadiusMultiplier = KERNEL_RADIUS_MULTIPLIER; fluidDesc.restParticlesPerMeter = REST_PARTICLES_PER_METER; fluidDesc.collisionDistanceMultiplier = COLLISION_DISTANCE_MULTIPLIER; fluidDesc.stiffness = 50.0f; fluidDesc.viscosity = 22.0f; fluidDesc.damping = 0.0f; fluidDesc.restitutionForStaticShapes = 0.4f; fluidDesc.dynamicFrictionForStaticShapes = 0.03f; fluidDesc.simulationMethod = NX_F_SPH; //NX_F_NO_PARTICLE_INTERACTION; if (!gHardwareSimulation) fluidDesc.flags &= ~NX_FF_HARDWARE; fluidDesc.initialParticleData = initParticleData; //Create user fluid. //- create NxFluid in NxScene //- setup the buffers to read from data from the SDK //- set NxFluid::userData field to MyFluid instance bool trackUserData = false; bool provideCollisionNormals = false; MyFluid* fluid = new MyFluid(gScene, fluidDesc, trackUserData, provideCollisionNormals, NxVec3(0.2f,0.3f,0.7f), 0.03f); assert(fluid); gMyFluids.pushBack(fluid); delete[] initParticles; gCameraPos.set(23, 14, 23); gCameraForward = fluidPos - NxVec3(0, 3, 0) - gCameraPos; gCameraForward.normalize(); }
// to attach to tetra mesh void TetraMeshHelper::buildTetraLinks(const NxSoftBodyMeshDesc& desc) { const NxVec3 *vertices = (const NxVec3 *) desc.vertices; const void *tetIndices = desc.tetrahedra; bool is32Bits = !(desc.flags & NX_SOFTBODY_MESH_16_BIT_INDICES); const NxU32 numTets = desc.numTetrahedra; mTetraLinks.clear(); MeshHash* hash = new MeshHash(); // hash tetrahedra for faster search hash->setGridSpacing(mBounds.min.distance(mBounds.max) * 0.1f); NxU8* startIndex = (NxU8*) tetIndices; if(is32Bits) { for (NxU32 i = 0; i < numTets; i++) { const NxU32 *ix = ((NxU32*) startIndex) + 4*i; NxBounds3 tetraBounds; tetraBounds.setEmpty(); tetraBounds.include(vertices[*ix++]); tetraBounds.include(vertices[*ix++]); tetraBounds.include(vertices[*ix++]); tetraBounds.include(vertices[*ix++]); hash->add(tetraBounds, i); } for (NxU32 i = 0; i < maxMesh.numVerts; i++) { MeshTetraLink tmpLink; NxVec3 triVert(maxMesh.verts[i].x, maxMesh.verts[i].y, maxMesh.verts[i].z); std::vector<int> itemIndices; hash->queryUnique(triVert, itemIndices); NxReal minDist = 0.0f; NxVec3 b; int num, isize; num = isize = itemIndices.size(); if (num == 0) num = numTets; for (int i = 0; i < num; i++) { int j = i; if (isize > 0) j = itemIndices[i]; const NxU32 *ix = ((NxU32*) startIndex) + 4*j; const NxVec3 &p0 = vertices[*ix++]; const NxVec3 &p1 = vertices[*ix++]; const NxVec3 &p2 = vertices[*ix++]; const NxVec3 &p3 = vertices[*ix++]; NxVec3 b = computeBaryCoords(triVert, p0, p1, p2, p3); // is the vertex inside the tetrahedron? If yes we take it if (b.x >= 0.0f && b.y >= 0.0f && b.z >= 0.0f && (b.x + b.y + b.z) <= 1.0f) { tmpLink.barycentricCoords = b; tmpLink.tetraNr = j; break; } // otherwise, if we are not in any tetrahedron we take the closest one NxReal dist = 0.0f; if (b.x + b.y + b.z > 1.0f) dist = b.x + b.y + b.z - 1.0f; if (b.x < 0.0f) dist = (-b.x < dist) ? dist : -b.x; if (b.y < 0.0f) dist = (-b.y < dist) ? dist : -b.y; if (b.z < 0.0f) dist = (-b.z < dist) ? dist : -b.z; if (i == 0 || dist < minDist) { minDist = dist; tmpLink.barycentricCoords = b; tmpLink.tetraNr = j; } } mTetraLinks.push_back(tmpLink); } } else { for (NxU32 i = 0; i < numTets; i++) { const NxU16 *ix = ((NxU16*) startIndex) + 4*i; NxBounds3 tetraBounds; tetraBounds.setEmpty(); tetraBounds.include(vertices[*ix++]); tetraBounds.include(vertices[*ix++]); tetraBounds.include(vertices[*ix++]); tetraBounds.include(vertices[*ix++]); hash->add(tetraBounds, i); } for (NxU32 i = 0; i < maxMesh.numVerts; i++) { MeshTetraLink tmpLink; NxVec3 triVert(maxMesh.verts[i].x, maxMesh.verts[i].y, maxMesh.verts[i].z); std::vector<int> itemIndices; hash->queryUnique(triVert, itemIndices); NxReal minDist = 0.0f; NxVec3 b; int num, isize; num = isize = itemIndices.size(); if (num == 0) num = numTets; for (int i = 0; i < num; i++) { int j = i; if (isize > 0) j = itemIndices[i]; const NxU16 *ix = ((NxU16*) startIndex) + 4*j; const NxVec3 &p0 = vertices[*ix++]; const NxVec3 &p1 = vertices[*ix++]; const NxVec3 &p2 = vertices[*ix++]; const NxVec3 &p3 = vertices[*ix++]; NxVec3 b = computeBaryCoords(triVert, p0, p1, p2, p3); // is the vertex inside the tetrahedron? If yes we take it if (b.x >= 0.0f && b.y >= 0.0f && b.z >= 0.0f && (b.x + b.y + b.z) <= 1.0f) { tmpLink.barycentricCoords = b; tmpLink.tetraNr = j; break; } // otherwise, if we are not in any tetrahedron we take the closest one NxReal dist = 0.0f; if (b.x + b.y + b.z > 1.0f) dist = b.x + b.y + b.z - 1.0f; if (b.x < 0.0f) dist = (-b.x < dist) ? dist : -b.x; if (b.y < 0.0f) dist = (-b.y < dist) ? dist : -b.y; if (b.z < 0.0f) dist = (-b.z < dist) ? dist : -b.z; if (i == 0 || dist < minDist) { minDist = dist; tmpLink.barycentricCoords = b; tmpLink.tetraNr = j; } } mTetraLinks.push_back(tmpLink); } } delete hash; }
bool UpdateCharacterExtents(NxU32 index, bool& increase) { if(index&1) { NxBoxController* c = static_cast<NxBoxController*>(gManager->getController(index)); NxVec3 extents = c->getExtents(); NxF32 inc = 1.0f; NxExtendedVec3 pos = GetCharacterPos(index); if (increase) { extents.y += inc; pos.y += inc; } else { extents.y -= inc; pos.y -= inc; } if(1) { NxBounds3 worldBounds; worldBounds.setCenterExtents(NxVec3(pos.x, pos.y, pos.z), extents); c->setCollision(false); // Avoid checking overlap with ourself bool Status = gScene->checkOverlapAABB(worldBounds); c->setCollision(true); if(Status) { printf("Can not resize box!\n"); return false; } } increase = !increase; // Increase or decrease height each time we're called // WARNING: the SDK currently doesn't check for collisions when changing extents, so if you're close // to a wall you might end up penetrating it. In some cases you might also fall through the level. // A more advanced implementation will take care of that later. c->setPosition(pos); return c->setExtents(extents); } else { NxCapsuleController* c = static_cast<NxCapsuleController*>(gManager->getController(index)); NxF32 height = c->getHeight(); NxF32 radius = c->getRadius(); NxF32 inc = 1.0f; NxExtendedVec3 pos = GetCharacterPos(index); if (increase) { height += inc; pos.y += inc*0.5f; } else { height -= inc; pos.y -= inc*0.5f; } if(1) { NxCapsule worldCapsule; worldCapsule.p0.x = worldCapsule.p1.x = pos.x; worldCapsule.p0.y = worldCapsule.p1.y = pos.y; worldCapsule.p0.z = worldCapsule.p1.z = pos.z; worldCapsule.p0.y -= height*0.5f; worldCapsule.p1.y += height*0.5f; worldCapsule.radius = radius; c->setCollision(false); // Avoid checking overlap with ourself bool Status = gScene->checkOverlapCapsule(worldCapsule); c->setCollision(true); if(Status) { printf("Can not resize capsule!\n"); return false; } } increase = !increase; // Increase or decrease height each time we're called // WARNING: the SDK currently doesn't check for collisions when changing height, so if you're close // to a wall you might end up penetrating it. In some cases you might also fall through the level. // A more advanced implementation will take care of that later. c->setPosition(NxExtendedVec3(pos.x, pos.y, pos.z)); return c->setHeight(height); } }