10.6 射线与地形的碰撞检测

要检测物体是否和地形相交,你需要创建一些碰撞检测方法。一个有用的方法是使用射线和地形间的碰撞检测。例如,一个物体在场景中移动,你可以追踪一条指向物体移动方向的射线并获取它与地形间的距离。 要检测射线和地形的碰撞,你可以在射线和高度图之间进行碰撞检测,用来替代射线和地形网格(很多三角形)间的碰撞检测。碰撞检测分成两个部分,首先,你在射线上执行一个线性搜索知道你找到在地形上和地形之下的两个点。接着,你在这两点间执行一个二分法搜索(binary search)找到地形上的确切碰撞点。图10-13展示了线性搜索过程,找到地形之上和之下的最近点。

图10-13

图10-13:使用线性搜索找到地形之上和之下的点 你可以使用下列代码实现线性搜索:

你可以使用下列代码实现线性搜索:

// A good ray step is half of the blockScale 
Vector3 rayStep = ray.Direction * blockScale * 0.5f;
Vector3 rayStartPosition = ray.Position; 

// Linear search - Loop until find a point inside and outside the terrain Vector3 
lastRayPosition = ray.Position; ray.Position += rayStep; 
float height = GetHeight(ray.Position); 
while (ray.Position.Y > height && height >= 0)
{
    lastRayPosition = ray.Position; 
    ray.Position += rayStep; 
    height = GetHeight(ray.Position); 
} 

线性搜索之后,lastRayPosition变量存储了地形之上的位置而ray变量存储了地形之下的点。你需要在两个点之间执行二分法搜索找到地形上最近的点。你使用固定步数实现这个搜索,32步已能提供足够的精度,代码如下:

Vector3 startPosition = lastRayPosition; 
Vector3 endPosition = ray.Position; 

// Binary search with 32 steps. Try to find the exact collision point 
for (int i= 0; i< 32; i++) 
{ 
    // Binary search pass 
    Vector3 middlePoint = (startPosition + endPosition) * 0.5f;
    if (middlePoint.Y < height) 
        endPosition = middlePoint; 
    else 
        startPosition = middlePoint;
} 
Vector3 collisionPoint = (startPosition + endPosition) * 0.5f; 

然后创建Intersects方法检测射线和地形间的相交。Intersects方法返回射线起始点和地形上碰撞点的距离,如果没有碰撞,这个方法返回null。下列是Terrain类中的Intersects方法的代码:

public float? Intersects(Ray ray)
{
    float? collisionDistance = null;
    Vector3 rayStep = ray.Direction * blockScale * 0.5f; 
    Vector3 rayStartPosition = 	ray.Position; 
    
    // Linear search - Loop until find a point inside and outside the terrain 
    Vector3 lastRayPosition = ray.Position; 
    ray.Position += rayStep;
    float height = GetHeight(ray.Position); 
    while (ray.Position.Y > height && height >= 0) 
    {
        lastRayPosition = ray.Position; 
        ray.Position += rayStep; 
        height = GetHeight(ray.Position); 
    } 
    
    // If the ray collides with the terrain 
    if (height >= 0)
    {
        Vector3 startPosition = lastRayPosition; 
        Vector3 endPosition = ray.Position; 
        
        // Binary search. Find the exact collision point 
        for (int i= 0; i<32; i++) 
        { 
            // Binary search pass 
            Vector3 middlePoint = (startPosition + endPosition) * 0.5f; 
            if (middlePoint.Y < height) 
                endPosition = middlePoint; 
            else 
                startPosition = middlePoint;
        }
        Vector3 collisionPoint = (startPosition +endPosition) * 0.5f; 
        collisionDistance = Vector3.Distance(rayStartPosition,collisionPoint); 
    } 
    return collisionDistance; 
} 

10.7 总结

本章你学习了从高度图创建地形的所有步骤。你首先学习了什么是高度图和如何从高度图生成地形。然后学习了如何创建一个顶点网格表示地形网格和如何使用高度贴图改变顶点的高度,对每个顶点,你还学习了如何计算多纹理、光线和法线贴图必须的各种属性。最后你学习了如何创建一个使用多纹理和法线贴图的effect。除了以上知识,你还学习了查询地形上任意位置高度的辅助方法,并检测射线和地形间的碰撞。


发布时间:2009/4/24 下午12:05:45  阅读次数:6979

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号