我目前正在使用XNA 3.1制作3D汽车游戏。这是一个出租车游戏。所以我的主要车辆在比赛期间遇到了交通工具。我在交通车辆和主要车辆之间编码碰撞检测时遇到了问题。我使用边界框方法而不是边界球方法,因为边界球体不能正确覆盖车辆。
下面是我用来实现碰撞的代码。问题是当车辆左转或右转时,边界框没有根据那个变化。
我在更新方法中编写了这段代码。
carWorld = Matrix.CreateScale(1f) * Matrix.CreateTranslation(vehicalClassObs[0].Position);
trafficWorld = Matrix.CreateScale(1f) * Matrix.CreateTranslation(carObject.Position);
BoundingBox b=CalculateBoundingBox(carO);
BoundingBox c=CalculateBoundingBox(car);
Vector3[] obb = new Vector3[8];
b.GetCorners(obb);
Vector3.Transform(obb, ref carWorld, obb);
BoundingBox worldAABB = BoundingBox.CreateFromPoints(obb);
Vector3[] occ=new Vector3[8];
c.GetCorners(occ);
Vector3.Transform(occ, ref trafficWorld, occ);
BoundingBox worldAACC = BoundingBox.CreateFromPoints(occ);
if (worldAABB.Intersects(worldAACC))
col = true;
else col = false;
以下是CalculateBoundingBox方法
public BoundingBox CalculateBoundingBox(Model m_model)
{
// Create variables to hold min and max xyz values for the model. Initialise them to extremes
Vector3 modelMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
Vector3 modelMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
foreach (ModelMesh mesh in m_model.Meshes)
{
Matrix[] m_transforms = new Matrix[m_model.Bones.Count];
m_model.CopyAbsoluteBoneTransformsTo(m_transforms);
//Create variables to hold min and max xyz values for the mesh. Initialise them to extremes
Vector3 meshMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
Vector3 meshMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
// There may be multiple parts in a mesh (different materials etc.) so loop through each
foreach (ModelMeshPart part in mesh.MeshParts)
{
// The stride is how big, in bytes, one vertex is in the vertex buffer
// We have to use this as we do not know the make up of the vertex
int stride = part.VertexDeclaration.GetVertexStrideSize(0);
byte[] vertexData = new byte[stride * part.NumVertices];
mesh.VertexBuffer.GetData(part.BaseVertex * stride, vertexData, 0, part.NumVertices, 1); // fixed 13/4/11
// Find minimum and maximum xyz values for this mesh part
// We know the position will always be the first 3 float values of the vertex data
Vector3 vertPosition=new Vector3();
for (int ndx = 0; ndx < vertexData.Length; ndx += stride)
{
vertPosition.X= BitConverter.ToSingle(vertexData, ndx);
vertPosition.Y = BitConverter.ToSingle(vertexData, ndx + sizeof(float));
vertPosition.Z= BitConverter.ToSingle(vertexData, ndx + sizeof(float)*2);
// update our running values from this vertex
meshMin = Vector3.Min(meshMin, vertPosition);
meshMax = Vector3.Max(meshMax, vertPosition);
}
}
// transform by mesh bone transforms
meshMin = Vector3.Transform(meshMin, m_transforms[mesh.ParentBone.Index]);
meshMax = Vector3.Transform(meshMax, m_transforms[mesh.ParentBone.Index]);
// Expand model extents by the ones from this mesh
modelMin = Vector3.Min(modelMin, meshMin);
modelMax = Vector3.Max(modelMax, meshMax);
}
// Create and return the model bounding box
return new BoundingBox(modelMin, modelMax);
}
如果有人可以帮助我解决这个问题,那将会非常有帮助。如果除了我使用的方式之外还有更好的方法来实现碰撞,请告诉我有关该方法的信息。
答案 0 :(得分:1)
你有几个选择。最简单的方法是根据车辆的世界变换来变换车辆的边界框(这里不需要投影或视图,因为在检查碰撞时你不关心摄像机的位置。)
假设您已经拥有车辆的原始边界框,
/// <summary>
/// Transforms a bounding box for collision detection
/// </summary>
/// <param name="vehicleBounds">Original, object-centered bounding box that contains a car model</param>
/// <param name="vehicleWorldMatrix">Vehicle's world transformation matrix (does not include projection or view)</param>
/// <returns>An axis-aligned bounding box (AABB) that will com </returns>
protected BoundingBox TransformBoundingBox(BoundingBox vehicleBounds, Matrix vehicleWorldMatrix)
{
var vertices = vehicleBounds.GetCorners();
/// get a couple of vertices to hold the outer bounds of the transformed bounding box.
var minVertex = new Vector3(float.MaxValue);
var maxVertex = new Vector3(float.MinValue);
for(int i=0;i<vertices.Length;i++)
{
var transformedVertex = Vector3.Transform(vertices[i],vehicleWorldMatrix);
/// update min and max with the component-wise minimum of each transformed vertex
/// to find the outer limits fo teh transformed bounding box
minVertex = Vector3.Min(minVertex, transformedVertex);
maxVertex = Vector3.Max(maxVertex, transformedVertex);
}
var result = new BoundingBox(minVertex, maxVertex);
return result;
}
对于每辆车,使用该方法创建用于碰撞的临时边界框。只测试相互转换的边界框,并且不会覆盖您的原始边界框,因为您需要在车辆移动时从您的源中重新计算此框。
如果您正在使用多网格模型,请使用BoundingBox.CreateMerged()
将它们组合起来以获取包含整个模型的框,或者为每个子网格边界框执行碰撞(尽管这可能会变得昂贵没有使用某种加速结构)。
答案 1 :(得分:0)
我一直在使用的是一种非常简单的方法,几乎适合任何情况。这是:
//Create one of the matricies
//Vector3 loc = new Vector3(0, 0, 0); //Wherever the model is.
//Matrix world1 = Matrix.CreateTransform(loc);
private bool IsCollision(Model model1, Matrix world1, Model model2, Matrix world2)
{
for (int meshIndex1 = 0; meshIndex1 < model1.Meshes.Count; meshIndex1++)
{
BoundingSphere sphere1 = model1.Meshes[meshIndex1].BoundingSphere;
sphere1 = sphere1.Transform(world1);
for (int meshIndex2 = 0; meshIndex2 < model2.Meshes.Count; meshIndex2++)
{
BoundingSphere sphere2 = model2.Meshes[meshIndex2].BoundingSphere;
sphere2 = sphere2.Transform(world2);
if (sphere1.Intersects(sphere2))
return true;
}
}
return false;
}
您可以将所有球体更改为方框,但这可能有效。另外,我所做的是一次移动一个轴的位置(X轴,然后是Y轴,然后是Z轴)。这会产生更平滑的碰撞。