Unity程序化地形教程 第二期 噪声图的完善和更多细节添加
前言:完整的程序化地形教程在我的主页相关专栏中,目前正在持续更新,可以添加收藏,方便日后查找
零、学完本期能够实现的效果
书接上期,学完之后相比上期能够有更多的细节和优化,话不多说,赶快开始吧!
一、noise脚本的属性值添加
相比上一期noise的属性值,这一期里面新添加了五个属性值,我们在上图中也能看到相关的效果,这五个值分别是
public int octaves; //八度数量 高峰的数量
public float persistance; //持久值 可以理解为平滑还是不平滑
public float lacunarity; //缺陷 可以理解为粗糙度
public int seed; //地图种子 相对于偏移量来说能够更大程度上去改变地图的整体面貌
public Vector2 offset; //偏移量
在这里我们添加上相关属性后的代码,各个函数都有相关的注释
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class Noise
{
public static float[,] GenerateNoiseMap(int mapWidth,int mapHeight,int seed, float scale,int octaves,float persistance,float lacunarity,Vector2 offset) //利用噪声来设置地形的高低
{ //回到相同地图的种子 新增八度音阶数量 持久值 缺陷
float[,] noiseMap = new float[mapWidth, mapHeight]; //两个维度的浮点数类型的数组
//创建一个系统点随机对象 伪随机数生成器
System.Random prng = new System.Random(seed);
Vector2[] octaveOffsets = new Vector2[octaves];
for(int i=0;i<octaves;i++)
{
float offsetX = prng.Next(-100000, 100000) + offset.x;
float offsetY = prng.Next(-100000, 100000) + offset.y;
octaveOffsets[i] = new Vector2(offsetX, offsetY);
}
if(scale<=0)
{
scale = 0.0001f;
}
//返回的归一化处理
float maxNoiseHeight = float.MinValue;
float minNoiseHeight = float.MaxValue;
//将噪声图的缩放设置在中心点上 计算e值是地图宽度的一半
float halfwidth = mapWidth / 2f;
float halfHeight = mapHeight / 2f;
//对传入的函数的长、宽参数进行灰度值赋值 模拟噪声
for (int y =0;y<mapHeight;y++)
{
for(int x=0;x<mapWidth;x++)
{
//频率和振幅
float amplitude = 1;
float frequency = 1;
float noiseHeight = 0;
for(int i =0;i<octaves;i++)
{
//除以scale 让影响scale的同时能够影响到地图缩放的大小
float sampleX = (x-halfwidth) / scale *frequency +octaveOffsets[i].x;
float sampleY = (y-halfHeight)/ scale*frequency+octaveOffsets[i].y;
//柏林值 Mathf.PerlinNoise可以简单理解为随机获得在这个点的灰度值
float perlinValue = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1; //让噪声取值为-1到1的范围 让地形发生更多的变化
//将灰度值返回给这个点
noiseMap[x, y] = perlinValue;
noiseHeight += perlinValue * amplitude;
amplitude *= persistance;
frequency *= lacunarity;
}
//获取噪声值的范围 便于后期归一化处理
if(noiseHeight>maxNoiseHeight)
{
maxNoiseHeight = noiseHeight;
}
else if(noiseHeight<minNoiseHeight)
{
minNoiseHeight = noiseHeight;
}
//将高度应用于我们的噪声图 使坐标XY等于该噪声高度值
noiseMap[x, y] = noiseHeight;
}
}
//将取值限定 归一化处理
for (int y = 0; y < mapHeight; y++)
{
for (int x = 0; x < mapWidth; x++)
{
noiseMap[x, y] = Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, noiseMap[x, y]);
}
}
//返回噪声前对其进行归一化处理,使所有的值都回到0到1的范围内
//跟踪噪声图中的最低值和最高值
return noiseMap;
}
}
二、地图生成器MapGenerator脚本的属性添加
很好理解,地图生成器是根据noise脚本为基础来创造噪声图的,noise脚本中修改的属性也要在这个脚本中进行更改
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapGenerator : MonoBehaviour
{
public int mapWidth;
public int mapHeight;
public float noiseScale;
public int octaves; //八度数量
[Range(0,1)] //以滑块的形式限定范围
public float persistance; //持久值
public float lacunarity; //缺陷
public int seed; //种子
public Vector2 offset; //偏移量
public bool autoUpdate; //是否自动更行
//生成地图
public void GenerateMap()
{
//这里将输入的长、宽、大小代入刚刚定义好的生成噪声的函数中
float[,] noiseMap = Noise.GenerateNoiseMap(mapWidth, mapHeight, seed,noiseScale,octaves,persistance,lacunarity,offset);
//MapDisplay是用来将噪声转化为地形的脚本 在这里将上面处理后的数据转化为地形
//下一个脚本再具体介绍 这里可以直接写
MapDisplay display = FindObjectOfType<MapDisplay>();
display.DrawNoiseMap(noiseMap);
}
private void OnValidate() //脚本中的数据改动时会自动调用
{
//将脚本中的值进行限定 因为超出这个值后没有意义
if(mapWidth<1)
{
mapWidth = 1;
}
if(mapHeight<1)
{
mapHeight = 1;
}
if(lacunarity<1)
{
lacunarity = 1;
}
if(octaves<0)
{
octaves = 0;
}
}
}
三、最终的效果展示
保存脚本、之后我们就可以在Unity中运行查看效果了,对于不理解的新添属性值,我们可以在Unity的调试界面对这些属性值进行更改,看对于噪声图会发生怎样的变化
这样一个基本的用于控制地形生成的噪波图就制作好了,是不是很有趣呢?感兴趣的话点个关注,后面持续更新!
上期教程连接:Unity程序化地形教程 第一期 噪波图的制作