Unity 生成DEM地形方法
(下面代码比较完整,如有需要可以下载工程文件)工程文件地址
基本思路
首先创建n × \times ×n个顶点的平面网格,用每一个网点的相对坐标对DEM(数字高程模型)进行采样,取得0~1的灰度值,将灰度值乘上高度系数得到相对高程,最后用高度值修改网格点三维坐标的Y值。
对DEM的理解
DEM是对地形高度的一种灰度图表现,越白的地方越接近1,表示越高,越黑的地方越接近0,表示越低。
n × \times ×n网格建立
为了方便采样,将建立网格的起始点定在左下角,与uv和图片的原点一致。
为了后面做位置变换,网格的原点定在中心。
网格建立完整代码
public static class MeshExtention
{
/// <summary>
/// 创建正方形面
/// </summary>
/// <param name="size">尺寸</param>
/// <param name="num">细分</param>
/// <returns></returns>
public static Mesh CreateSquareArea(this Mesh mesh ,float size,int num)
{
//一共多少行/列
int ranks = 2 * num + 1;
int pointsCount = ranks * ranks;
Vector3[] meshPoints = new Vector3[pointsCount];
int[] triangles = new int[24 * num * num];
Vector2[] uvs = new Vector2[pointsCount];
float halfSize = size * 0.5f;
//左下角角点
Vector3 cornerPoint = new Vector3(-halfSize, 0, -halfSize);
//距离单位偏移
float unitSize = size / (num * 2);
//距离单位偏移X
Vector3 unitVec_x= new Vector3(unitSize, 0, 0);
//距离单位偏移Z
Vector3 unitVec_z = new Vector3(0, 0, unitSize);
//UV单位偏移
float unitUV = 1.00f / (num * 2.00f);
//UV单位偏移X
Vector2 uvVec_x = new Vector2(unitUV, 0);
//UV单位偏移Y
Vector2 uvVec_y = new Vector2(0,unitUV);
int k = 0;
for (int i = 0; i < ranks; i++)
{
for (int j = 0; j < ranks; j++)
{
meshPoints[i* ranks+ j] = cornerPoint + j * unitVec_x + i * unitVec_z;
uvs[i * ranks + j] = j * uvVec_x + i * uvVec_y;
if (i < ranks-1&& j < ranks-1)
{
triangles[k] = (i * ranks) + j+1;
triangles[k + 1] = (i * ranks) + j;
triangles[k + 2] = ((i + 1) * ranks) + j;
triangles[k + 3] = (i * ranks) + j+1;
triangles[k + 4] = ((i + 1) * ranks) + j;
triangles[k + 5] = ((i + 1) * ranks) + j+1;
k += 6;
}
}
}
mesh.vertices = meshPoints;
mesh.triangles = triangles;
mesh.uv = uvs;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
return mesh;
}
}
DEM采样
有网格的uv做为采样坐标,完美的切合了图片的坐标信息。
public Texture texture;
public Texture2D Dem;
[Range(10, 100)]//高度系数范围
public int Range;
public int num=20;//点数量
public float size=100;//地图尺寸
void Start()
{
GameObject game = new GameObject();
MeshFilter filter = game.AddComponent<MeshFilter>();
MeshRenderer renderer = game.AddComponent<MeshRenderer>();
Material material= new Material(Shader.Find("Standard"));
material.mainTexture = texture;
renderer.sharedMaterial = material;
Mesh mesh = new Mesh();
mesh.CreateSquareArea(size, num);
int length = mesh.vertices.Length;
Vector3[] newVector3s = new Vector3[length];
for (int i = 0; i < length; i++)
{
Vector2 uv = mesh.uv[i];
int x =(int)(Dem.width * uv.x);
int y = (int)(Dem.height * uv.y);
float heightVelue = Dem.GetPixel(x, y).grayscale * Range;//采样
Vector3 vector3 = mesh.vertices[i];
newVector3s[i]= new Vector3(vector3.x, heightVelue, vector3.z);
}
mesh.vertices = newVector3s;
filter.mesh = mesh;
}