步骤创建GameObject(命名Mesh Genrate网格生成器),为其添加两个组件Mesh Filter和Mesh Renderer.,创建脚本Mesh Genrate。
【1】解析顶点和三角面原理,绘制mesh
【2】绘制mesh网格平面,增加随机高度
【3】基于柏林噪音生成灰度图
【1】解析顶点和三角面原理,绘制mesh
(Unity三角形绘制渲染,正反都是顺时针方向:012;132)
绘制mesh的顶点和三角形。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
//RequireComponent:需要的组件将会自动被添加到game object(游戏物体),有效的避免组装错误,避免GetComponent的空引用错误。
public class MeshGerrate : MonoBehaviour
{
private Vector3[] vertices;//记录顶点坐标信息/坐标值的矢量数组。
private int[] triangLes;//记录顶点数值的数组。
private Mesh mesh;
void Start()
{
mesh = new Mesh();//创建一个空的网格。
GetComponent<MeshFilter>().mesh = mesh;
//将包含mesh的信息赋值给组件
CreatShape();
//该方法表示:mesh网格需要需要存储哪些顶点和三角形信息
UpdateMesh();//加载网格
mesh.RecalculateNormals();//重新计算法线的方向
}
void CreatShape()
{
vertices = new[]
{
new Vector3(0,0,0),
new Vector3(0,0,1),
new Vector3(1,0,0),
new Vector3(1,0,1), //XZ平面的三角形(正面/背面)
};
triangLes = new[]
{
0, 1, 2,
1, 3, 2
};//顺时针三个点的位置数值,与vertices绑定,一一对应三个顶点
}
void UpdateMesh()
{
mesh.Clear();//清空所有顶点数据和所有三角形索引/每次绘制前把之前的信息清理一下,避免造成干扰。
mesh.vertices = vertices;//将顶点坐标信息赋给网格
//vertices:返回一个顶点位置的数组值,或者为一组新的顶点位置数组赋值。
mesh.triangles = triangLes;//将顶点数值赋给网格
//triangles:在网格里,一个包含所有三角形的数组。
}
}
【2】绘制mesh网格平面,增加随机高度
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
//RequireComponent:需要的组件将会自动被添加到game object(游戏物体),有效的避免组装错误,避免GetComponent的空引用错误。
public class MeshGerrate : MonoBehaviour
{
private Vector3[] vertices;//记录顶点坐标信息/坐标值的矢量数组。
private int[] triangLes;//记录顶点数值的数组。
private Mesh mesh;
public int xSize = 20;
public int zSize = 20;
void Start()
{
mesh = new Mesh();//创建一个空的网格。
GetComponent<MeshFilter>().mesh = mesh;
//将包含mesh的信息赋值给组件
CreatShape();
//StartCoroutine(CreatShape());
//该方法表示:mesh网格需要需要存储哪些顶点和三角形信息
//UpdateMesh();//加载网格
}
void CreatShape()
//IEnumerator CreatShape()观察绘制情况可以开一个携程,配合WaitForSeconds来看一步步绘制结果
{
int n = 0;
vertices = new Vector3[(xSize + 1) * (zSize + 1)];
for (int z = 0; z <= zSize; z++)
{
for (int i = 0; i <= xSize; i++)
{
float y = Mathf.PerlinNoise(i*0.3f, z*0.2f) * 2f;//柏林噪音
vertices[n] = new Vector3(i, y, z);
n++;
}
}
triangLes =new int[xSize*zSize*2*3];
int ver = 0;
int count = 0;
for (int z = 0; z < zSize; z++)
{
for (int i = 0; i < xSize; i++)
{
triangLes[count + 0] = ver + 0;
triangLes[count + 1] = ver + xSize + 1;
triangLes[count + 2] = ver + 1;
triangLes[count + 3] = ver + xSize + 1;
triangLes[count + 4] = ver + xSize + 2;
triangLes[count + 5] = ver + 1;
count += 6;
ver++;
//yield return new WaitForSeconds(0.1f);
}
ver++;//直接跳过最后一行最后一个顶点,否则最后一个顶点会连线第二行第一个点,造成黑边。
}
}
void Update()
{
UpdateMesh();//加载网格
}
void UpdateMesh()
{
mesh.Clear();//清空所有顶点数据和所有三角形索引/每次绘制前把之前的信息清理一下,避免造成干扰。
mesh.vertices = vertices;//将顶点坐标信息赋给网格
//vertices:返回一个顶点位置的数组值,或者为一组新的顶点位置数组赋值。
mesh.triangles = triangLes;//将顶点数值赋给网格
//triangles:在网格里,一个包含所有三角形的数组。
mesh.RecalculateNormals();
}
private void OnDrawGizmos()
{//编辑器函数,自动调用。
//绘制可被点选的gizmos,执行这个函数。这允许你在场景中快速选择重要的物体。
if (vertices == null) return;
for (int i = 0; i < vertices.Length; i++)
{
Gizmos.DrawSphere(vertices[i], 0.1f);//使用center和radius参数,绘制一个实心球体。
}
}
}
【3】基于柏林噪音生成灰度图
octave倍频叠加
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.WSA.WebCam;
public class MapGenrator : MonoBehaviour
{
public int widthX;
public int heightY;
public float scale;
public int octave;
[Range(0,1)]//设定范围
public float persistance;
public float lacunrity;
public int seed;
public Vector2 offset;
public void MapGenrate()
{
float[,] noiseMap = PerlinNosie.GenrateNoiseMap(widthX, heightY, scale,seed,offset, persistance,lacunrity,octave);
MapDisplay display = FindObjectOfType<MapDisplay>();
//FindObjectOfType:按类型查找游戏对象
display.DrawNoiseMap(noiseMap);
}
private void OnValidate()//启动的时候执行两次,Stop的时候执行一次,组件数值改变的时候执行一次
{
if (widthX<1) {
widthX = 1;
}
if (heightY<1) {
heightY = 1;
}
if (lacunrity<1) {
lacunrity = 1;
}
if (octave < 0) {
octave = 0;
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = System.Random;
public static class PerlinNosie
//: MonoBehaviour不需要挂在物体上,所以不继承MonoBehaviour
{
public static float[,] GenrateNoiseMap(int mapWidth, int mapHeight, float scale,int seed,Vector2 offset, float persistance, float lacunarity, int octave)
//创建柏林噪声
{
float[,] perlinNoise = new float[mapWidth, mapHeight];
if (scale <= 0)
{
scale = 0.0001f;
}
Random prng = new Random(seed);//随机种子,每个种子代表一个固定的数据,读取。
Vector2[] sctaveOffSet = new Vector2[octave];
for (int i = 0; i < octave; i++)
{
float offsetX = prng.Next(-10000,10000)+offset.x;//随机数+偏移量
float offsetY = prng.Next(-10000, 10000)+offset.y;
sctaveOffSet[i]=new Vector2(offsetX,offsetY);
}
float minNoiseHeight = float.MaxValue;
float maxNoiseHeight = float.MinValue;//这里大小输入时相反的,方便对比时接入值。
float halfWidth = mapWidth / 2;
float halfHeight = mapHeight / 2;
for (int z = 0; z < mapHeight; z++)
{
for (int i = 0; i < mapWidth; i++)
{
float height = 0;
float amplitude = 1f;
float frequence = 1f;
for (int j = 0; j < octave; j++)
{
float sampleX = (i+halfWidth) / scale * frequence+sctaveOffSet[j].x;//scale越大,地图比例缩小(包含的越多)
float sampleY = (z+halfHeight) / scale * frequence+ sctaveOffSet[j].y;
float perlinValue = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1;//*2-1:生成正负值,对应地图水平线上下的点。
//Mathf.PerlinNoise:值介于0.0和1.0之间,XY代表样本点的坐标值。
height += perlinValue * amplitude;//柏林值乘以振幅,在三次倍频叠加。
amplitude *= persistance;//振幅改变
frequence *= lacunarity;//频率改变
}
if (height > maxNoiseHeight) {
maxNoiseHeight = height;//存储大小值
}else if (height < minNoiseHeight) {
minNoiseHeight = height;
}
perlinNoise[i, z] = height;
}
}
for (int z = 0; z < mapHeight; z++)
{
for (int i = 0; i < mapWidth; i++)
{
perlinNoise[i, z] = Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, perlinNoise[i, z]);
//按照A-B之间的比例值计算,将数组取值重新归到0-1之间。
}
}
return perlinNoise;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapDisplay : MonoBehaviour
{
public Renderer mapPerlinTexture;
public void DrawNoiseMap(float[,] noiseMap)//将柏林通过色彩在纹理上表现出来
{
int widthX = noiseMap.GetLength(0);
int heightY = noiseMap.GetLength(1);
Texture2D textures = new Texture2D(widthX, heightY);
Color[] color_Map=new Color[widthX * heightY];
for (int y = 0; y < heightY; y++)
{
for (int x = 0; x < widthX; x++)
{
color_Map[widthX * y + x] = Color.Lerp(Color.black, Color.white, noiseMap[x, y]);//通过float在颜色a和b之间插值,返回不同的元素。
}
}
textures.SetPixels(color_Map);//设置一块像素的颜色
textures.Apply();//实际应用前面的SetPixel和Setpixels的更改
mapPerlinTexture.sharedMaterial.mainTexture = textures;//将改变所有物体使用这个材质的外观,并且也改变储存在工程里的材质设置。
mapPerlinTexture.transform.localScale=new Vector3(widthX,1,heightY); //相对于父级物体变换的缩放。Y不变,XZ做变化。
//前面只富裕了材质的外观,但没赋予对应的大小。
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(MapGenrator))]
//描述了用于编辑器实时运行类型的一个编辑器类。
public class MapGenerateEditor : Editor
{
public override void OnInspectorGUI()//在Unity组件面板里添加一个按钮来操控柏林噪声的生成
{
MapGenrator mapgen = (MapGenrator)target;//受检查的对象。
DrawDefaultInspector();
//绘制内置检视面板。
if (GUILayout.Button("Generate"))//EditorGUI的自动布局版本。
{
mapgen.MapGenrate();
}
}
}
结果: