void TSStatic::_updatePhysics() { SAFE_DELETE( mPhysicsRep ); if ( !PHYSICSMGR || mCollisionType == None ) return; PhysicsCollision *colShape = NULL; if ( mCollisionType == Bounds ) { MatrixF offset( true ); offset.setPosition( mShape->center ); colShape = PHYSICSMGR->createCollision(); colShape->addBox( getObjBox().getExtents() * 0.5f * mObjScale, offset ); } else colShape = mShape->buildColShape( mCollisionType == VisibleMesh, getScale() ); if ( colShape ) { PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" ); mPhysicsRep = PHYSICSMGR->createBody(); mPhysicsRep->init( colShape, 0, 0, this, world ); mPhysicsRep->setTransform( getTransform() ); } }
PhysicsCollision* CollisionComponent::getCollisionData() { if ((!PHYSICSMGR || mCollisionType == None) || mOwnerRenderInterface == NULL) return NULL; PhysicsCollision *colShape = NULL; if (mCollisionType == Bounds) { MatrixF offset(true); offset.setPosition(mOwnerRenderInterface->getShape()->center); colShape = PHYSICSMGR->createCollision(); colShape->addBox(mOwner->getObjBox().getExtents() * 0.5f * mOwner->getScale(), offset); } else if (mCollisionType == CollisionMesh || (mCollisionType == VisibleMesh/* && !mOwner->getComponent<AnimatedMesh>()*/)) { colShape = buildColShapes(); //colShape = mOwnerShapeInstance->getShape()->buildColShape(mCollisionType == VisibleMesh, mOwner->getScale()); } /*else if (mCollisionType == VisibleMesh && !mOwner->getComponent<AnimatedMesh>()) { //We don't have support for visible mesh collisions with animated meshes currently in the physics abstraction layer //so we don't generate anything if we're set to use a visible mesh but have an animated mesh component. colShape = mOwnerShapeInstance->getShape()->buildColShape(mCollisionType == VisibleMesh, mOwner->getScale()); }*/ else if (mCollisionType == VisibleMesh/* && mOwner->getComponent<AnimatedMesh>()*/) { Con::printf("CollisionComponent::updatePhysics: Cannot use visible mesh collisions with an animated mesh!"); } return colShape; }
bool GroundPlane::onAdd() { if( !Parent::onAdd() ) return false; if( isClientObject() ) _updateMaterial(); if( mSquareSize < sMIN_SQUARE_SIZE ) { Con::errorf( "GroundPlane - squareSize below threshold; re-setting to %.02f", sMIN_SQUARE_SIZE ); mSquareSize = sMIN_SQUARE_SIZE; } Parent::setScale( VectorF( 1.0f, 1.0f, 1.0f ) ); Parent::setTransform( MatrixF::Identity ); setGlobalBounds(); resetWorldBox(); addToScene(); if ( PHYSICSMGR ) { PhysicsCollision *colShape = PHYSICSMGR->createCollision(); colShape->addPlane( PlaneF( Point3F::Zero, Point3F( 0, 0, 1 ) ) ); PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" ); mPhysicsRep = PHYSICSMGR->createBody(); mPhysicsRep->init( colShape, 0, 0, this, world ); } return true; }
//.logicking >> void StaticShape::updatePhysics() { SAFE_DELETE(mPhysicsRep); if ( PHYSICSMGR) { mShapeInstance->animate(); // Get the interior collision geometry. ConcretePolyList polylist; if (buildPolyList(PLC_Collision, &polylist, getWorldBox(), getWorldSphere())) { polylist.triangulate(); PhysicsCollision *colShape = PHYSICSMGR->createCollision(); colShape->addTriangleMesh( polylist.mVertexList.address(), polylist.mVertexList.size(), polylist.mIndexList.address(), polylist.mIndexList.size() / 3, MatrixF::Identity ); PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" ); mPhysicsRep = PHYSICSMGR->createBody(); //.hack - set kinematic flag to prevent crash on deleting static shape in character sweep(deleting Doors) mPhysicsRep->init( colShape, 0, PhysicsBody::BF_KINEMATIC, this, world ); } if (isServerObject()) setMaskBits(PhysicsMask); } }
void Trigger::setTriggerPolyhedron(const Polyhedron& rPolyhedron) { mTriggerPolyhedron = rPolyhedron; if (mTriggerPolyhedron.pointList.size() != 0) { mObjBox.minExtents.set(1e10, 1e10, 1e10); mObjBox.maxExtents.set(-1e10, -1e10, -1e10); for (U32 i = 0; i < mTriggerPolyhedron.pointList.size(); i++) { mObjBox.minExtents.setMin(mTriggerPolyhedron.pointList[i]); mObjBox.maxExtents.setMax(mTriggerPolyhedron.pointList[i]); } } else { mObjBox.minExtents.set(-0.5, -0.5, -0.5); mObjBox.maxExtents.set( 0.5, 0.5, 0.5); } MatrixF xform = getTransform(); setTransform(xform); mClippedList.clear(); mClippedList.mPlaneList = mTriggerPolyhedron.planeList; // for (U32 i = 0; i < mClippedList.mPlaneList.size(); i++) // mClippedList.mPlaneList[i].neg(); MatrixF base(true); base.scale(Point3F(1.0/mObjScale.x, 1.0/mObjScale.y, 1.0/mObjScale.z)); base.mul(mWorldToObj); mClippedList.setBaseTransform(base); SAFE_DELETE( mPhysicsRep ); if ( PHYSICSMGR ) { PhysicsCollision *colShape = PHYSICSMGR->createCollision(); MatrixF colMat( true ); colMat.displace( Point3F( 0, 0, mObjBox.getExtents().z * 0.5f * mObjScale.z ) ); colShape->addBox( mObjBox.getExtents() * 0.5f * mObjScale, colMat ); //MatrixF colMat( true ); //colMat.scale( mObjScale ); //colShape->addConvex( mTriggerPolyhedron.pointList.address(), mTriggerPolyhedron.pointList.size(), colMat ); PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" ); mPhysicsRep = PHYSICSMGR->createBody(); mPhysicsRep->init( colShape, 0, PhysicsBody::BF_TRIGGER | PhysicsBody::BF_KINEMATIC, this, world ); mPhysicsRep->setTransform( getTransform() ); } }
void CollisionComponent::prepCollision() { if (!mOwner) return; // Let the client know that the collision was updated setMaskBits(ColliderMask); mOwner->disableCollision(); if ((!PHYSICSMGR || mCollisionType == None) || (mOwnerRenderInterface == NULL && (mCollisionType == CollisionMesh || mCollisionType == VisibleMesh))) return; PhysicsCollision *colShape = NULL; if (mCollisionType == Bounds) { MatrixF offset(true); if (mOwnerRenderInterface && mOwnerRenderInterface->getShape()) offset.setPosition(mOwnerRenderInterface->getShape()->center); colShape = PHYSICSMGR->createCollision(); colShape->addBox(mOwner->getObjBox().getExtents() * 0.5f * mOwner->getScale(), offset); } else if (mCollisionType == CollisionMesh || (mCollisionType == VisibleMesh /*&& !mOwner->getComponent<AnimatedMesh>()*/)) { colShape = buildColShapes(); } if (colShape) { mPhysicsWorld = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client"); if (mPhysicsRep) { if (mBlockColliding) mPhysicsRep->init(colShape, 0, 0, mOwner, mPhysicsWorld); else mPhysicsRep->init(colShape, 0, PhysicsBody::BF_TRIGGER, mOwner, mPhysicsWorld); mPhysicsRep->setTransform(mOwner->getTransform()); } } mOwner->enableCollision(); onCollisionChanged.trigger(colShape); }
void Item::_updatePhysics() { SAFE_DELETE( mPhysicsRep ); if ( !PHYSICSMGR ) return; if (mDataBlock->simpleServerCollision) { // We only need the trigger on the server. if ( isServerObject() ) { PhysicsCollision *colShape = PHYSICSMGR->createCollision(); colShape->addBox( mObjBox.getExtents() * 0.5f, MatrixF::Identity ); PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" ); mPhysicsRep = PHYSICSMGR->createBody(); mPhysicsRep->init( colShape, 0, PhysicsBody::BF_TRIGGER | PhysicsBody::BF_KINEMATIC, this, world ); mPhysicsRep->setTransform( getTransform() ); } } else { if ( !mShapeInstance ) return; PhysicsCollision* colShape = mShapeInstance->getShape()->buildColShape( false, getScale() ); if ( colShape ) { PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" ); mPhysicsRep = PHYSICSMGR->createBody(); mPhysicsRep->init( colShape, 0, PhysicsBody::BF_KINEMATIC, this, world ); mPhysicsRep->setTransform( getTransform() ); } } }
void ConvexShape::_updateCollision() { SAFE_DELETE( mPhysicsRep ); if ( !PHYSICSMGR ) return; PhysicsCollision *colShape = PHYSICSMGR->createCollision(); // We need the points untransformed! Vector<Point3F> rawPoints; MatrixF xfm( getWorldTransform() ); xfm.setPosition( Point3F::Zero ); for ( U32 i=0; i < mGeometry.points.size(); i++ ) { Point3F p = mGeometry.points[i]; xfm.mulP( p ); rawPoints.push_back( p ); } // The convex generation from a point cloud // can fail at times... give up in that case. if ( !colShape->addConvex( mGeometry.points.address(), mGeometry.points.size(), MatrixF::Identity ) ) { delete colShape; return; } PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" ); mPhysicsRep = PHYSICSMGR->createBody(); mPhysicsRep->init( colShape, 0, 0, this, world ); mPhysicsRep->setTransform( getTransform() ); }
void ForestCell::buildPhysicsRep( Forest *forest ) { AssertFatal( isLeaf(), "ForestCell::buildPhysicsRep() - This shouldn't be called on non-leaf cells!" ); bool isServer = forest->isServerObject(); // Already has a PhysicsBody, if it needed to be rebuilt it would // already be null. if ( mPhysicsRep[ isServer ] ) return; if ( !PHYSICSMGR ) return; PhysicsCollision *colShape = NULL; // If we can steal the collision shape from the server-side cell // then do so as it saves us alot of cpu time and memory. if ( mPhysicsRep[ 1 ] ) { colShape = mPhysicsRep[ 1 ]->getColShape(); } else { // We must pass a sphere to buildPolyList but it is not used. const static SphereF dummySphere( Point3F::Zero, 0 ); // Step thru them and build collision data. ForestItemVector::iterator itemItr = mItems.begin(); ConcretePolyList polyList; for ( ; itemItr != mItems.end(); itemItr++ ) { const ForestItem &item = *itemItr; const ForestItemData *itemData = item.getData(); // If not collidable don't need to build anything. if ( !itemData->mCollidable ) continue; // TODO: When we add breakable tree support this is where // we would need to store their collision data seperately. item.buildPolyList( &polyList, item.getWorldBox(), dummySphere ); // TODO: Need to support multiple collision shapes // for really big forests at some point in the future. } if ( !polyList.isEmpty() ) { colShape = PHYSICSMGR->createCollision(); if ( !colShape->addTriangleMesh( polyList.mVertexList.address(), polyList.mVertexList.size(), polyList.mIndexList.address(), polyList.mIndexList.size() / 3, MatrixF::Identity ) ) { SAFE_DELETE( colShape ); } } } // We might not have any trees. if ( !colShape ) return; PhysicsWorld *world = PHYSICSMGR->getWorld( isServer ? "server" : "client" ); mPhysicsRep[ isServer ] = PHYSICSMGR->createBody(); mPhysicsRep[ isServer ]->init( colShape, 0, 0, forest, world ); }
PhysicsCollision* CollisionComponent::buildColShapes() { PROFILE_SCOPE(CollisionComponent_buildColShapes); PhysicsCollision *colShape = NULL; U32 surfaceKey = 0; TSShape* shape = mOwnerRenderInterface->getShape(); if (mCollisionType == VisibleMesh) { // Here we build triangle collision meshes from the // visible detail levels. // A negative subshape on the detail means we don't have geometry. const TSShape::Detail &detail = shape->details[0]; if (detail.subShapeNum < 0) return NULL; // We don't try to optimize the triangles we're given // and assume the art was created properly for collision. ConcretePolyList polyList; polyList.setTransform(&MatrixF::Identity, mOwner->getScale()); // Create the collision meshes. S32 start = shape->subShapeFirstObject[detail.subShapeNum]; S32 end = start + shape->subShapeNumObjects[detail.subShapeNum]; for (S32 o = start; o < end; o++) { const TSShape::Object &object = shape->objects[o]; if (detail.objectDetailNum >= object.numMeshes) continue; // No mesh or no verts.... nothing to do. TSMesh *mesh = shape->meshes[object.startMeshIndex + detail.objectDetailNum]; if (!mesh || mesh->mNumVerts == 0) continue; // Gather the mesh triangles. polyList.clear(); mesh->buildPolyList(0, &polyList, surfaceKey, NULL); // Create the collision shape if we haven't already. if (!colShape) colShape = PHYSICSMGR->createCollision(); // Get the object space mesh transform. MatrixF localXfm; shape->getNodeWorldTransform(object.nodeIndex, &localXfm); colShape->addTriangleMesh(polyList.mVertexList.address(), polyList.mVertexList.size(), polyList.mIndexList.address(), polyList.mIndexList.size() / 3, localXfm); } // Return what we built... if anything. return colShape; } else if (mCollisionType == CollisionMesh) { // Scan out the collision hulls... // // TODO: We need to support LOS collision for physics. // for (U32 i = 0; i < shape->details.size(); i++) { const TSShape::Detail &detail = shape->details[i]; const String &name = shape->names[detail.nameIndex]; // Is this a valid collision detail. if (!dStrStartsWith(name, colisionMeshPrefix) || detail.subShapeNum < 0) continue; // Now go thru the meshes for this detail. S32 start = shape->subShapeFirstObject[detail.subShapeNum]; S32 end = start + shape->subShapeNumObjects[detail.subShapeNum]; if (start >= end) continue; for (S32 o = start; o < end; o++) { const TSShape::Object &object = shape->objects[o]; const String &meshName = shape->names[object.nameIndex]; if (object.numMeshes <= detail.objectDetailNum) continue; // No mesh, a flat bounds, or no verts.... nothing to do. TSMesh *mesh = shape->meshes[object.startMeshIndex + detail.objectDetailNum]; if (!mesh || mesh->getBounds().isEmpty() || mesh->mNumVerts == 0) continue; // We need the default mesh transform. MatrixF localXfm; shape->getNodeWorldTransform(object.nodeIndex, &localXfm); // We have some sort of collision shape... so allocate it. if (!colShape) colShape = PHYSICSMGR->createCollision(); // Any other mesh name we assume as a generic convex hull. // // Collect the verts using the vertex polylist which will // filter out duplicates. This is importaint as the convex // generators can sometimes fail with duplicate verts. // VertexPolyList polyList; MatrixF meshMat(localXfm); Point3F t = meshMat.getPosition(); t.convolve(mOwner->getScale()); meshMat.setPosition(t); polyList.setTransform(&MatrixF::Identity, mOwner->getScale()); mesh->buildPolyList(0, &polyList, surfaceKey, NULL); colShape->addConvex(polyList.getVertexList().address(), polyList.getVertexList().size(), meshMat); } // objects } // details } return colShape; }