# 讲讲不怎么有用却很有意义的包围体测试

#### 几何阶段简介

1. 模型视图变换：模型空间变换到观察空间
2. 顶点着色：光照处理
3. 投影：将模型变换到一个单位立方体内
4. 裁剪：裁剪不显示的部分
5. 屏幕映射：映射到屏幕坐标系

## 讲原理了

### 半径的获得

class GameObject
{
public float max_radius = 0;//最大半径
public Mesh mesh;//网格
public Vector3 position = Vector3.zero;//坐标
public Vector3 rotation = Vector3.zero;
public Matrix4x4 ObjectToWorldMatrix;//模型-世界矩阵
public GameObject(Mesh mesh,Vector3 position)
{
this.mesh = mesh;
this.position = position;
}
/// <summary>
/// 计算半径
/// </summary>
{
int size = mesh.Vertices.Length;
for (int i = 0; i < size; ++i)
{
//计算物体包围球的最大半径
Vector3.DistanceSquare(position, mesh.Vertices[i].m_vertex.position));
}
}

}


### 判断球体是否在视景体外

#### 远近裁剪面

//远近裁剪面裁剪
if (SphereCenterPos.z - go.max_radius> camera.zf||
SphereCenterPos.z + go.max_radius < camera.zn)
{
return go.mesh.CullFlag = true;
}


#### 左右裁剪面和上下裁剪面

class Camera
{
/// <summary>
/// 观察角，弧度
/// </summary>
public float fov;
/// <summary>
/// 宽纵比
/// </summary>
public float aspect;
/// <summary>
/// 近裁平面
/// </summary>
public float zn;
/// <summary>
/// 远裁平面
/// </summary>
public float zf;

/// <summary>
/// 屏幕宽度
/// </summary>
public int ScreenHeight;

/// <summary>
/// 世界-视图 4x4矩阵
/// </summary>
public Matrix4x4 WorldToViewMatrix;
/// <summary>
/// 视图-投影 4x4矩阵
/// </summary>
public Matrix4x4 ViewToProjectionMatrix;

public Vector3 pos;
public Vector3 lookAt;
public Vector3 up;

/// <summary>
/// 焦距
/// </summary>
public float FocalLength
{
get
{
return (float)(1f/ System.Math.Tan(fov * 0.5f) * ScreenHeight/2);
}
}

}


#### 完整代码

/// <summary>
/// 物体剔除-包围球测试
/// </summary>
private bool CullObject(GameObject go,Vector3 SphereCenterPos)
{
if (go.mesh.CullFlag)
return true;
Camera camera = Rendering_pipeline.MainCamera;

//远近裁剪面裁剪
if (SphereCenterPos.z - go.max_radius> camera.zf||
SphereCenterPos.z + go.max_radius < camera.zn)
{
return go.mesh.CullFlag = true;
}

float FocalLength = camera.FocalLength;//获得焦距

//左右裁剪面剔除
float z_test = 0.5f * camera.aspect * camera.ScreenHeight *
SphereCenterPos.z / FocalLength;
if (SphereCenterPos.x - go.max_radius > z_test ||
SphereCenterPos.x + go.max_radius < -z_test)
{
return go.mesh.CullFlag = true;
}

//上下裁剪面剔除
z_test = 0.5f * camera.ScreenHeight *
SphereCenterPos.z / FocalLength;
if (SphereCenterPos.y - go.max_radius > z_test ||
SphereCenterPos.y + go.max_radius < -z_test)
{
return go.mesh.CullFlag = true;
}

return go.mesh.CullFlag = false;
}


## 包围体测试的局限性

posted @ 2018-11-10 12:23  寂灭万乘  阅读(185)  评论(0编辑  收藏