//---------------------------------------------------------------------------- bool Bound::TestIntersection (const Bound& bound, float tmax, const AVector& velocity0, const AVector& velocity1) const { if (bound.GetRadius() == 0.0f || GetRadius() == 0.0f) { return false; } AVector relVelocity = velocity1 - velocity0; // 相对速度 AVector cenDiff = bound.mCenter - mCenter; // 相对位移 float a = relVelocity.SquaredLength(); float c = cenDiff.SquaredLength(); float rSum = bound.mRadius + mRadius; float rSumSqr = rSum*rSum; if (a > 0.0f) { float b = cenDiff.Dot(relVelocity); if (b <= 0.0f) { if (-tmax*a <= b) { return a*c - b*b <= a*rSumSqr; } else { return tmax*(tmax*a + 2.0f*b) + c <= rSumSqr; } } } return c <= rSumSqr; }
//---------------------------------------------------------------------------- bool Bound::TestIntersection (const Bound& bound) const { if (bound.GetRadius() == 0.0f || GetRadius() == 0.0f) { return false; } // 静态相交检测 AVector diff = mCenter - bound.mCenter; float rSum = mRadius + bound.mRadius; return diff.SquaredLength() <= rSum*rSum; }
//---------------------------------------------------------------------------- void Bound::GrowToContain (const Bound& bound) { if (bound.GetRadius() == 0.0f) { // The node is a dummy node and cannot affect growth. return; } if (GetRadius() == 0.0f) { mCenter = bound.GetCenter(); mRadius = bound.GetRadius(); return; } AVector centerDiff = bound.mCenter - mCenter; float lengthSqr = centerDiff.SquaredLength(); float radiusDiff = bound.mRadius - mRadius; float radiusDiffSqr = radiusDiff*radiusDiff; if (radiusDiffSqr >= lengthSqr) { if (radiusDiff >= 0.0f) { mCenter = bound.mCenter; mRadius = bound.mRadius; } return; } float length = Mathf::Sqrt(lengthSqr); if (length > Mathf::ZERO_TOLERANCE) { float coeff = (length + radiusDiff)/(2.0f*length); mCenter += coeff*centerDiff; } mRadius = 0.5f*(length + mRadius + bound.mRadius); }
//---------------------------------------------------------------------------- void Selection::_UpdateSelect() { mCenter = APoint::ORIGIN; mBoundRadius = 0.0f; APoint pos; Bound bound; int firstBound = true; int numObjects = (int)mObjects.size(); for (int i = 0; i < numObjects; i++) { Object *obj = mObjects[i]; Movable *mov = DynamicCast<Movable>(obj); if (mov) { pos += mov->WorldTransform.GetTranslate(); if (0.0f != mov->WorldBound.GetRadius()) { if (firstBound) { bound = mov->WorldBound; firstBound = false; } else { bound.GrowToContain(mov->WorldBound); } } } } if (numObjects > 0) { mCenter = pos / (float)numObjects; mBoundRadius = bound.GetRadius(); } }
//---------------------------------------------------------------------------- bool Culler::IsVisible (const Bound& bound) { if (bound.GetRadius() == 0.0f) { // The node is a dummy node and cannot be visible. return false; } // Start with the last pushed plane, which is potentially the most // restrictive plane. int index = mPlaneQuantity - 1; unsigned int mask = (1 << index); for (int i = 0; i < mPlaneQuantity; ++i, --index, mask >>= 1) { if (mPlaneState & mask) { int side = bound.WhichSide(mPlane[index]); if (side < 0) { // The object is on the negative side of the plane, so // cull it. return false; } if (side > 0) { // The object is on the positive side of plane. There is // no need to compare subobjects against this plane, so // mark it as inactive. mPlaneState &= ~mask; } } } return true; }
bool OutStream::WriteAggregate (const Bound& datum) { APoint center = datum.GetCenter(); float radius = datum.GetRadius(); return WriteAggregate(center) && Write(radius); }
//---------------------------------------------------------------------------- void BoundCtrl::UpdateCtrl() { mCtrlsGroup->SetActiveChild(1); int numObjscts = PX2_SELECTION.GetNumObjects(); if (numObjscts > 0) { Bound bound; int firstBound = true; APoint pos; for (int i = 0; i < numObjscts; i++) { Object *obj = PX2_SELECTION.GetObjectAt(i); Actor *actor = DynamicCast<Actor>(obj); Movable *movable = DynamicCast<Movable>(obj); if (movable) { mCtrlsGroup->SetActiveChild(0); pos += movable->WorldTransform.GetTranslate(); if (0.0f != movable->WorldBound.GetRadius()) { if (firstBound) { bound = movable->WorldBound; firstBound = false; } else { bound.GrowToContain(movable->WorldBound); } } } } pos = pos / (float)numObjscts; float radius = bound.GetRadius(); if (0.0f == radius) { radius = 1.0f; mCtrlsGroup->WorldTransform.SetUniformScale(radius); mCtrlsGroup->WorldTransform.SetTranslate(pos); } else { mCtrlsGroup->WorldTransform.SetUniformScale(radius); mCtrlsGroup->WorldTransform.SetTranslate(bound.GetCenter()); } } else { mCtrlsGroup->SetActiveChild(1); } mCtrlsGroup->Update(Time::GetTimeInSeconds(), false); }