void Controller::move(SweptVolume& volume, const NxVec3& disp, NxU32 activeGroups, NxF32 minDist, NxU32& collisionFlags, NxF32 sharpness, const NxGroupsMask* groupsMask, bool constrainedClimbingMode) { // Dynamic-load the utility library if(!gUtilLib) gUtilLib = NxGetUtilLib(); assert(gUtilLib); if(!gUtilLib) return; SweepTest* ST = &cctModule; // Init CCT with per-controller settings ST->debugData = manager->debugData; ST->mSkinWidth = skinWidth; ST->mStepOffset = stepOffset; ST->mUpDirection = upDirection; ST->mHandleSlope = handleSlope; ST->mSlopeLimit = slopeLimit; ST->mFirstUpdate = true; /////////// Controller** boxUserData = NULL; NxExtendedBounds3* boxes = NULL; NxU32 nbBoxes = 0; Controller** capsuleUserData = NULL; NxExtendedCapsule* capsules = NULL; NxU32 nbCapsules = 0; if(1) { // Experiment - to do better NxU32 nbControllers = manager->getNbControllers(); Controller** controllers = manager->getControllers(); boxes = (NxExtendedBounds3*)NxAlloca(nbControllers*sizeof(NxExtendedBounds3)); capsules = (NxExtendedCapsule*)NxAlloca(nbControllers*sizeof(NxExtendedCapsule)); // It's evil to waste that ram boxUserData = (Controller**)NxAlloca(nbControllers*sizeof(Controller*)); capsuleUserData = (Controller**)NxAlloca(nbControllers*sizeof(Controller*)); while(nbControllers--) { Controller* currentController = *controllers++; if(currentController==this) continue; NxActor* pActor = currentController->getActor(); int nbShapes = pActor->getNbShapes(); NX_ASSERT( nbShapes == 1 ); NxShape* pCurrentShape= pActor->getShapes()[0]; // Depending on user settings the current controller can be: // - discarded // - always kept // - or tested against filtering flags NxCCTInteractionFlag interactionFlag = currentController->getInteraction(); bool keepController = true; if(interactionFlag==NXIF_INTERACTION_EXCLUDE) keepController = false; else if(interactionFlag==NXIF_INTERACTION_USE_FILTER) keepController = (activeGroups & ( 1 << pCurrentShape->getGroup()))!=0; if(keepController) { if(currentController->type==NX_CONTROLLER_BOX) { currentController->getWorldBox(boxes[nbBoxes]); boxUserData[nbBoxes++] = currentController; } else if(currentController->type==NX_CONTROLLER_CAPSULE) { CapsuleController* CC = static_cast<CapsuleController*>(currentController); NxExtendedVec3 p0 = CC->position; NxExtendedVec3 p1 = CC->position; p0[ST->mUpDirection] -= CC->height*0.5f; p1[ST->mUpDirection] += CC->height*0.5f; capsules[nbCapsules].p0 = p0; capsules[nbCapsules].p1 = p1; capsules[nbCapsules].radius = CC->radius; capsuleUserData[nbCapsules++] = currentController; } else ASSERT(0); } } } /////////// ST->mWalkExperiment = false; NxExtendedVec3 Backup = volume.mCenter; ST->MoveCharacter(scene, (Controller*)this, volume, disp, nbBoxes, nbBoxes ? boxes : NULL, nbBoxes ? (const void**)boxUserData : NULL, nbCapsules, nbCapsules ? capsules : NULL, nbCapsules ? (const void**)capsuleUserData : NULL, activeGroups, minDist, collisionFlags, groupsMask, constrainedClimbingMode); if(ST->mHitNonWalkable) { // A bit slow, but everything else I tried was less convincing... ST->mWalkExperiment = true; volume.mCenter = Backup; ST->MoveCharacter(scene, (Controller*)this, volume, disp, nbBoxes, nbBoxes ? boxes : NULL, nbBoxes ? (const void**)boxUserData : NULL, nbCapsules, nbCapsules ? capsules : NULL, nbCapsules ? (const void**)capsuleUserData : NULL, activeGroups, minDist, collisionFlags, groupsMask, constrainedClimbingMode); ST->mWalkExperiment = false; } if(sharpness<0.0f) volume.mCenter = Backup; // Copy results back position = volume.mCenter; NxVec3 Delta = Backup - volume.mCenter; NxF32 deltaM2 = Delta.magnitudeSquared(); if(deltaM2!=0.0f) { // Update kinematic actor if(kineActor) kineActor->moveGlobalPosition(NxVec3((float)position.x, (float)position.y, (float)position.z)); } filteredPosition = position; sharpness = fabsf(sharpness); // Apply feedback filter if needed if(sharpness<1.0f) filteredPosition[upDirection] = feedbackFilter(position[upDirection], memory, sharpness); // if(manager->debugData) // manager->debugData->addAABB(cctModule.mCachedTBV, NX_ARGB_YELLOW); }
int pWorld::overlapSphereShapes(const VxSphere& worldSphere,CK3dEntity*shapeReference,pShapesType shapeType,CKGroup*shapes,int activeGroups/* =0xffffffff */, const pGroupsMask* groupsMask/* =NULL */, bool accurateCollision/* =false */) { int result=0; NxSphere sphere; if (shapeReference) { NxShape *shape = getShapeByEntityID(shapeReference->GetID()); if (shape) { //shape->checkOverlapAABB() NxSphereShape *sphereShape = static_cast<NxSphereShape*>(shape->isSphere()); if (sphereShape) { sphere.radius = sphereShape->getRadius() + worldSphere.Radius(); //ori : VxVector ori = worldSphere.Center(); VxVector oriOut = ori; if (shapeReference) { shapeReference->Transform(&oriOut,&ori); } sphere.center = getFrom(oriOut); } } }else{ sphere.center = getFrom(worldSphere.Center()); sphere.radius = worldSphere.Radius(); } int total = 0; if (shapeType & ST_Dynamic ) { total+=getScene()->getNbDynamicShapes(); } if (shapeType & ST_Static) { total+=getScene()->getNbStaticShapes(); } NxShape** _shapes = (NxShape**)NxAlloca(total*sizeof(NxShape*)); for (NxU32 i = 0; i < total; i++) _shapes[i] = NULL; NxGroupsMask mask; if (groupsMask) { mask.bits0 = groupsMask->bits0; mask.bits1 = groupsMask->bits1; mask.bits2 = groupsMask->bits2; mask.bits3 = groupsMask->bits3; }else{ mask.bits0 = 0; mask.bits1 = 0; mask.bits2 = 0; mask.bits3 = 0; } result = getScene()->overlapSphereShapes(sphere,(NxShapesType)shapeType,total,_shapes,NULL,activeGroups,&mask,accurateCollision); if (_shapes && shapes ) { for (int i = 0 ; i < result ; i++) { NxShape *s = _shapes[i]; if (s) { const char* name =s->getName(); pSubMeshInfo *sInfo = static_cast<pSubMeshInfo*>(s->userData); if (sInfo->entID) { CKObject *obj = (CKObject*)GetPMan()->m_Context->GetObject(sInfo->entID); if (obj) { shapes->AddObject((CKBeObject*)obj); } } } } } int op=2; return result; }
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; } } }
int pWorld::overlapOBBShapes(const VxBbox& worldBounds, CK3dEntity*shapeReference, pShapesType shapeType,CKGroup *shapes,int activeGroups/* =0xffffffff */, const pGroupsMask* groupsMask/* =NULL */, bool accurateCollision/* =false */) { int result=0; NxBox box; if (shapeReference) { NxShape *shape = getShapeByEntityID(shapeReference->GetID()); if (shape) { //shape->checkOverlapAABB() NxBoxShape*boxShape = static_cast<NxBoxShape*>(shape->isBox()); if (boxShape) { boxShape->getWorldOBB(box); } } }else{ box.center = getFrom(worldBounds.GetCenter()); box.extents = getFrom(worldBounds.GetSize()); } int total = 0; if (shapeType & ST_Dynamic ) { total+=getScene()->getNbDynamicShapes(); } if (shapeType & ST_Static) { total+=getScene()->getNbStaticShapes(); } NxShape** _shapes = (NxShape**)NxAlloca(total*sizeof(NxShape*)); for (NxU32 i = 0; i < total; i++) _shapes[i] = NULL; NxGroupsMask mask; if (groupsMask) { mask.bits0 = groupsMask->bits0; mask.bits1 = groupsMask->bits1; mask.bits2 = groupsMask->bits2; mask.bits3 = groupsMask->bits3; }else{ mask.bits0 = 0; mask.bits1 = 0; mask.bits2 = 0; mask.bits3 = 0; } result = getScene()->overlapOBBShapes(box,(NxShapesType)shapeType,total,_shapes,NULL,activeGroups,&mask,accurateCollision); if (_shapes && shapes ) { for (int i = 0 ; i < result ; i++) { NxShape *s = _shapes[i]; if (s) { const char* name =s->getName(); pSubMeshInfo *sInfo = static_cast<pSubMeshInfo*>(s->userData); if (sInfo->entID) { CKObject *obj = (CKObject*)GetPMan()->m_Context->GetObject(sInfo->entID); if (obj) { shapes->AddObject((CKBeObject*)obj); } } } } } int op=2; return result; }
bool FindTouchedGeometry( void* user_data, const NxExtendedBounds3& worldBounds, // ### we should also accept other volumes TriArray& world_triangles, TriArray* world_edge_normals, IntArray& edge_flags, IntArray& geom_stream, NxU32 group_flags, bool static_shapes, bool dynamic_shapes, const NxGroupsMask* groupsMask) { NX_ASSERT(user_data); NxScene* scene = (NxScene*)user_data; NxExtendedVec3 Origin; // Will be TouchedGeom::mOffset worldBounds.getCenter(Origin); // Reserve a stack buffer big enough to hold all shapes in the world. This is a lazy approach that is // acceptable here since the total number of shapes is limited to 64K anyway, which would "only" consume // 256 Kb on the stack (hence, stack overflow is unlikely). // ### TODO: the new callback mechanism would allow us to use less memory here // NxU32 total = scene->getNbStaticShapes() + scene->getNbDynamicShapes(); NxU32 total = scene->getTotalNbShapes(); NxShape** buffer = (NxShape**)NxAlloca(total*sizeof(NxShape*)); // Find touched *boxes* i.e. touched objects' AABBs in the world // We collide against dynamic shapes too, to get back dynamic boxes/etc // TODO: add active groups in interface! NxU32 Flags = 0; if(static_shapes) Flags |= NX_STATIC_SHAPES; if(dynamic_shapes) Flags |= NX_DYNAMIC_SHAPES; // ### this one is dangerous NxBounds3 tmpBounds; // LOSS OF ACCURACY tmpBounds.min.x = (float)worldBounds.min.x; tmpBounds.min.y = (float)worldBounds.min.y; tmpBounds.min.z = (float)worldBounds.min.z; tmpBounds.max.x = (float)worldBounds.max.x; tmpBounds.max.y = (float)worldBounds.max.y; tmpBounds.max.z = (float)worldBounds.max.z; NxU32 nbTouchedBoxes = scene->overlapAABBShapes(tmpBounds, NxShapesType(Flags), total, buffer, NULL, group_flags, groupsMask); // Early exit if no AABBs found if(!nbTouchedBoxes) return false; NX_ASSERT(nbTouchedBoxes<=total); // Else we just trashed some stack memory // Loop through touched world AABBs NxShape** touched = buffer; while(nbTouchedBoxes--) { // Get current shape NxShape* shape = *touched++; // Filtering // Discard all CCT shapes, i.e. kinematic actors we created ourselves. We don't need to collide with them since they're surrounded // by the real CCT volume - and collisions with those are handled elsewhere. We use the userData field for filtering because that's // really our only valid option (filtering groups are already used by clients and we don't have control over them, clients might // create other kinematic actors that we may want to keep here, etc, etc) if(size_t(shape->userData)=='CCTS') continue; // Discard if not collidable // PT: this shouldn't be possible at this point since: // - the SF flag is only used for compounds // - the AF flag is already tested in scene query // - we shouldn't get compound shapes here if(shape->getFlag(NX_SF_DISABLE_COLLISION)) continue; // Ubi (EA) : Discarding Triggers : if ( shape->getFlag(NX_TRIGGER_ENABLE) ) continue; // PT: here you might want to disable kinematic objects. // Output shape to stream NxShapeType type = shape->getType(); if(type==NX_SHAPE_SPHERE) outputSphereToStream((NxSphereShape*)shape, shape, geom_stream, Origin); else if(type==NX_SHAPE_CAPSULE) outputCapsuleToStream((NxCapsuleShape*)shape, shape, geom_stream, Origin); else if(type==NX_SHAPE_BOX) outputBoxToStream((NxBoxShape*)shape, shape, geom_stream, Origin); else if(type==NX_SHAPE_MESH) outputMeshToStream((NxTriangleMeshShape*)shape, shape, geom_stream, world_triangles, world_edge_normals, edge_flags, Origin, tmpBounds); else if(type==NX_SHAPE_HEIGHTFIELD) outputHeightFieldToStream((NxHeightFieldShape*)shape, shape, geom_stream, world_triangles, world_edge_normals, edge_flags, Origin, tmpBounds); else if(type==NX_SHAPE_CONVEX) outputConvexToStream((NxConvexShape*)shape, shape, geom_stream, world_triangles, world_edge_normals, edge_flags, Origin, tmpBounds); } return true; }