Unity 随机 生成地形 (PerlinNoise 柏林噪声)

2023-11-08 06:50

本文主要是介绍Unity 随机 生成地形 (PerlinNoise 柏林噪声),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Unity 随机 生成地形 (PerlinNoise 柏林噪声)

  • 程序化地图生成
    • 地图显示模块
    • 柏林噪声地图模块
      • 柏林噪声效果显示
    • 彩色地图模块
      • 色彩地图效果显示
    • 基础网格生成规则
    • 网格地图模块
      • 网格地图效果显示
    • 程序化地图管理模块
    • 地图管理 菜单编辑
    • 代码搭载
    • 效果展示

程序化地图生成

地图显示模块

三种不同的地图格式数据生成:DrawNoiseMap() 噪声地图DrawTexture() 色彩地图DrawMesh() 网格地图
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 地图显示
/// 将噪声贴图转换为纹理 
/// </summary>
public class MapDisplay_ZH : MonoBehaviour
{[Header("纹理渲染")]public Renderer _TextureRender;[Header("网格数据")]public MeshFilter _MeshFilter;[Header("网格渲染")]public MeshRenderer _MeshRender;/// <summary>/// 噪声地图绘制/// </summary>/// <param 柏林噪声="_NoiseMap"></param>public void DrawNoiseMap(float[,] _NoiseMap){//地图宽度int _Width = _NoiseMap.GetLength(0);//地图高度int _Height = _NoiseMap.GetLength(1);//根据传入值  确定渲染纹理长宽Texture2D _Texture = new Texture2D(_Width, _Height);//获取噪波数组中的所有值Color[] _ColourMap = new Color[_Width * _Height];//设置每个像素点的颜色for (int y = 0; y < _Width; y++){for (int x = 0; x < _Height; x++){//色彩取样// Color 是一维数组 噪声是二维数组//获取当前像素点所在位置 : Y值 乘 地图宽度 再加上 X  就是当前像素在噪声地图中的位置//当前取样点的颜色 //由于只想要 黑白色域  所以使用 Color.black 和 Color.white_ColourMap[y * _Width + x] = Color.Lerp(Color.black, Color.white, _NoiseMap[x, y]);}}//色彩传递//纹理贴图赋值_Texture.SetPixels(_ColourMap);_Texture.Apply();//主纹理贴图赋值_TextureRender.sharedMaterial.mainTexture = _Texture;//地图大小赋值_TextureRender.transform.localScale = new Vector3(_Width, 1, _Height);}/// <summary>/// Texture 地图绘制/// </summary>/// <param 图像="_Texture"></param>public void DrawTexture(Texture2D _Texture){//渲染贴图赋予_TextureRender.sharedMaterial.mainTexture = _Texture;//渲染物体大小设置_TextureRender.transform.localScale = new Vector3(_Texture.width, 1, _Texture.height);}/// <summary>/// 网格地形绘制/// </summary>/// <param 地形网格="_MeshData"></param>/// <param 地形贴图="_Texture2D"></param>internal void DrawMesh(MeshData _MeshData, Texture2D _Texture2D){_MeshFilter.sharedMesh = _MeshData.CreteMesh();_MeshRender.sharedMaterial.mainTexture = _Texture2D;}
}

柏林噪声地图模块

这个模块为基础模块:返回值在0.01.0之间。(返回值可能略低于0.0或超过1.0)关键性代码: Mathf.PerlinNoise()
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 柏林噪声地图生成
/// </summary>
public static class Noise_ZH
{/// <summary>/// 柏林噪声地图生成方法/// </summary>/// <param 地图宽度="_MapWidth"></param>/// <param 地图高度="_MapHeight"></param>/// <param 地图大小="_Scale"></param>/// <param 种子="_Seed"></param>/// <param 抵消="_Octaves"></param>/// <param 持续="_Persistance"></param>/// <param 空隙="_Lacunarity"></param>/// <param 偏移抵消="_Offset"></param>/// /// <returns></returns>public static float[,] GenerateNoiseMap(int _MapWidth, int _MapHeight, float _Scale, int _Seed, 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(-10000, 10000) + _Offset.x;float _OffsetY = _Prng.Next(-10000, 10000) + _Offset.y;_OctaveOffsets[i] = new Vector2(_OffsetX, _OffsetY);}//避免地图  不存在if (_Scale <= 0){_Scale = 0.0001f;}//地图放大响应float _HalfWidth = _MapWidth / 2;float _HalfHeight = _MapHeight / 2;//最大噪声高度float _MaxNoiseHeight = float.MinValue;//最小噪声高度float _MinNoiseHeight = float.MaxValue;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++){//地图单元取整float _SampleX = (x - _HalfWidth) / _Scale * _Frequency + _OctaveOffsets[i].x;float _SampleY = (y - _HalfHeight) / _Scale * _Frequency + _OctaveOffsets[i].y;//根据传入参数 生成2D柏林噪声float _PerlinValue = Mathf.PerlinNoise(_SampleX, _SampleY) * 2 - 1;//噪波高度等于 柏林噪声 乘于 振幅_NoiseHeight += _PerlinValue * _Amplitude;//振幅变更_Amplitude *= _Persistance;//频率变更_Frequency *= _Lacunarity;}//限值操作if (_NoiseHeight > _MaxNoiseHeight){_MaxNoiseHeight = _NoiseHeight;}else if (_NoiseHeight < _MinNoiseHeight){_MinNoiseHeight = _NoiseHeight;}//传入地图数据_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]);}}//返回地图数据return _NoiseMap;}}

柏林噪声效果显示

请添加图片描述

彩色地图模块

色彩地图模块:
TextureFromColourMap() 纹理生成模块
TextureFromHeightMap() 高度生成模块
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 纹理生成器
/// </summary>
public static class TextureGenerator_ZH
{/// <summary>/// 颜色地图的纹理/// </summary>/// <param 色彩地图="_ColourMap"></param>/// <param 宽度="_Width"></param>/// <param 高度="_Height"></param>/// <returns></returns>public static Texture2D TextureFromColourMap(Color[] _ColourMap, int _Width, int _Height){Texture2D _Texture = new Texture2D(_Width, _Height);//绘制模式 变更//点过滤-纹理像素变得块状近距离//边缘块状显示//_Texture.filterMode = FilterMode.Point;_Texture.filterMode = FilterMode.Point;//纹理坐标缠绕模式//将纹理夹紧到边缘的最后一个像素_Texture.wrapMode = TextureWrapMode.Clamp;//色彩传递//纹理贴图赋值_Texture.SetPixels(_ColourMap);//必须要应用一下不然不响应_Texture.Apply();return _Texture;}/// <summary>/// 高度贴图纹理/// </summary>/// <param 高度贴图="_HeightMap"></param>/// <returns></returns>public static Texture2D TextureFromHeightMap(float[,] _HeightMap){//地图宽度int _Width = _HeightMap.GetLength(0);//地图高度int _Height = _HeightMap.GetLength(1);根据传入值  确定渲染纹理长宽//Texture2D _Texture = new Texture2D(_Width, _Height);//获取噪波数组中的所有值Color[] _ColourMap = new Color[_Width * _Height];//设置每个像素点的颜色for (int y = 0; y < _Width; y++){for (int x = 0; x < _Height; x++){//色彩取样// Color 是一维数组 噪声是二维数组//获取当前像素点所在位置 : Y值 乘 地图宽度 再加上 X  就是当前像素在噪声地图中的位置//当前取样点的颜色 //由于只想要 黑白色域  所以使用 Color.black 和 Color.white_ColourMap[y * _Width + x] = Color.Lerp(Color.black, Color.white, _HeightMap[x, y]);}}色彩传递纹理贴图赋值//_Texture.SetPixels(_ColourMap);//_Texture.Apply();return TextureFromColourMap(_ColourMap, _Width, _Height);}
}

色彩地图效果显示

请添加图片描述

基础网格生成规则

当三角网格数据绘制顺序为逆时针时:
123134  法线方向为朝上。
当三角网格数据绘制顺序为顺时针时:
143132  法线方向为朝下

请添加图片描述

法线方向:法线(normal line),是指始终垂直于某平面的直线。在几何学中,法线指平面上垂直于曲线在某点的切线的一条线。法线也应用于光学的平面镜反射上。
如果法线方向背对视角方向,那么该网格三角面将不可视。

请添加图片描述

网格地图模块

网格地图模块:MeshData 网格类AddTrianle()为关键性方法进行三角形网格绘制逻辑CreteMesh() 网格数据填充方法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 网格生成器
/// </summary>
public static class MeshGenerator_ZH
{/// <summary>/// 地形网格生成/// </summary>/// <param 高度地图="_HeightMap"></param>public static MeshData GenerateTerrainMesh(float[,] _HeightMap){//宽度int _Width = _HeightMap.GetLength(0);//高度int _Height = _HeightMap.GetLength(1);//网格划分float _TopLeftX = (_Width - 1) / -2f;float _TopLeftZ = (_Height - 1) / -2f;//网格数据MeshData _MeshData = new MeshData(_Width, _Height);//三角形 绘制序号int _VertexIndex = 0;//网格数据填充for (int y = 0; y < _Height; y++){for (int x = 0; x < _Width; x++){//顶点数据填充_MeshData._Vertices[_VertexIndex] = new Vector3(_TopLeftX + x, _HeightMap[x, y], _TopLeftZ + y);//UV 数据填充_MeshData._UVs[_VertexIndex] = new Vector2(x / (float)_Width, y / (float)_Height);//剔除 行 列 最边缘 的顶点  不计入网格渲染计算if (x < _Width - 1 && y < _Height - 1){_MeshData.AddTrianle(_VertexIndex, _VertexIndex + _Width + 1, _VertexIndex + _Width);_MeshData.AddTrianle(_VertexIndex + _Width + 1, _VertexIndex, _VertexIndex + 1);}//序号增加_VertexIndex++;}}return _MeshData;}
}/// <summary>
/// 网格数据
/// </summary>
public class MeshData
{//顶点数据public Vector3[] _Vertices;//绘制序列public int[] _Triangles;//UV 数据public Vector2[] _UVs;//三角 序号int _TriangleIndex;public MeshData(int _MeshWidth,int _MeshHeight){//网格顶点数据_Vertices = new Vector3[_MeshWidth * _MeshHeight];//UV 数据_UVs = new Vector2[_MeshWidth * _MeshHeight];//三角形绘制序列_Triangles = new int[(_MeshWidth - 1) * (_MeshHeight - 1) * 6];}/// <summary>/// 网格三角形绘制/// </summary>/// <param 顶点A="_A"></param>/// <param 顶点B="_B"></param>/// <param 顶点C="_C"></param>public void AddTrianle(int _A,int _B,int _C){//例如:// 1 2 3// 4 5 6// 7 8 9// 绘制 逻辑为  124 245 235 356 457 578 568 689  右手定则  逆时针 法线方向朝上//注意 绘制的的方向要统一   统一顺时针绘制  或者逆时针绘制_Triangles[_TriangleIndex] = _C;_Triangles[_TriangleIndex+1] = _B;_Triangles[_TriangleIndex+2] = _A;_TriangleIndex += 3;}/// <summary>/// 新建网格/// </summary>/// <returns></returns>public Mesh CreteMesh(){//网格数据Mesh _Mesh = new Mesh();//顶点数据赋予_Mesh.vertices = _Vertices;//三角形序列赋予_Mesh.triangles = _Triangles;//UV 数据 赋予_Mesh.uv = _UVs;//使用默认法线_Mesh.RecalculateNormals();//数据返回return _Mesh;}
}

网格地图效果显示

请添加图片描述

请添加图片描述

程序化地图管理模块

用作管理地图模块化生成
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
///  地图管理
/// </summary>
public class MapGenertor_ZH : MonoBehaviour
{/// <summary>/// 地图显示类型枚举/// </summary>public enum DrawMap { NoiseMap, ColourMap, MeshMap }[Header("地图绘制类型")]public DrawMap _DrawMap = DrawMap.NoiseMap;[Header("地图宽度")]public int _MapWidth;[Header("地图高度")]public int _MapHeight;[Header("地图大小")]public float _NoiseScale;[Header("八度")]public int _Octaves;[Header("持续")][Range(0, 1)]public float _Persistance;[Header("空隙")]public float _Lacunarity;[Header("地图种子")]public int _Seed;[Header("偏移")]public Vector2 _Offset;[Header("地形区域")]public TerrainType[] _Regions;[Header("自动更新布尔")]public bool _AutoUpdate;/// <summary>/// 地图生成 调用/// </summary>public void GenerateMap(){//参数传递 float[,] _NoiseMap = Noise_ZH.GenerateNoiseMap(_MapWidth, _MapHeight, _NoiseScale, _Seed, _Octaves, _Persistance, _Lacunarity, _Offset);//色彩地图Color[] _ColourMap = new Color[_MapWidth * _MapHeight];//根据地形高度进行色彩赋予for (int y = 0; y < _MapHeight; y++){for (int x = 0; x < _MapWidth; x++){//获取当前地图高度值float _CurrentHeight = _NoiseMap[x, y];//进行地形区域判定for (int i = 0; i < _Regions.Length; i++){if (_CurrentHeight <= _Regions[i]._Height){//色彩赋值_ColourMap[y * _MapWidth + x] = _Regions[i]._Colour;break;}}}}//查找 MapDisplay_ZH 搭载物体MapDisplay_ZH _Display = FindObjectOfType<MapDisplay_ZH>();//根据不同类型进行不同地图绘制if (_DrawMap == DrawMap.NoiseMap){//进行柏林噪声地形绘制_Display.DrawTexture(TextureGenerator_ZH.TextureFromHeightMap(_NoiseMap));}else if (_DrawMap == DrawMap.ColourMap){//进行色彩贴图地形绘制_Display.DrawTexture(TextureGenerator_ZH.TextureFromColourMap(_ColourMap, _MapWidth, _MapHeight));}else if (_DrawMap == DrawMap.MeshMap){//进行网格地形绘制_Display.DrawMesh(MeshGenerator_ZH.GenerateTerrainMesh(_NoiseMap), TextureGenerator_ZH.TextureFromColourMap(_ColourMap, _MapWidth, _MapHeight));}}/// <summary>/// 当脚本被加载或检查器在值被修改时调用此函数时(仅在编辑器调用中)/// </summary>private void OnValidate(){//保证初始化显示if (_MapWidth < 1){_MapWidth = 1;}if (_MapHeight < 1){_MapHeight = 1;}if (_Lacunarity < 1){_Lacunarity = 1;}if (_Octaves < 0){_Octaves = 0;}}
}//序列化
[System.Serializable]
/// <summary>
/// 地形类型
/// </summary>
public struct TerrainType
{//名称public string _Name;//高度public float _Height;//颜色public Color _Colour;
}

地图管理 菜单编辑

需要在 根目录创建一个 Editor 文件夹并把代码文件放进去才能执行
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
/// <summary>
/// 菜单编辑
/// </summary>
[CustomEditor(typeof(MapGenertor_ZH))]
public class MapGeneratorEditor_ZH : Editor
{public override void OnInspectorGUI(){MapGenertor_ZH _MapGen = (MapGenertor_ZH)target;//绘制内置检查器//如果发现变更if (DrawDefaultInspector()){//如果更新布尔为 Ture  就持续更新地图if (_MapGen._AutoUpdate){_MapGen.GenerateMap();}}//在 MapGenertor_ZH 上创建更新按钮if (GUILayout.Button("Generate")){_MapGen.GenerateMap();}}
}

代码搭载

请添加图片描述
请添加图片描述

请添加图片描述

效果展示

根据地图种子的值来进行地图随机变换

请添加图片描述

请添加图片描述
请添加图片描述
请添加图片描述

暂时先这样吧,如果有时间的话就会更新,实在看不明白就留言,看到我会回复的。
路漫漫其修远兮,与君共勉。

这篇关于Unity 随机 生成地形 (PerlinNoise 柏林噪声)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/368441

相关文章

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

java中使用POI生成Excel并导出过程

《java中使用POI生成Excel并导出过程》:本文主要介绍java中使用POI生成Excel并导出过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求说明及实现方式需求完成通用代码版本1版本2结果展示type参数为atype参数为b总结注:本文章中代码均为

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

C/C++随机数生成的五种方法

《C/C++随机数生成的五种方法》C++作为一种古老的编程语言,其随机数生成的方法已经经历了多次的变革,早期的C++版本使用的是rand()函数和RAND_MAX常量,这种方法虽然简单,但并不总是提供... 目录C/C++ 随机数生成方法1. 使用 rand() 和 srand()2. 使用 <random

Flask 验证码自动生成的实现示例

《Flask验证码自动生成的实现示例》本文主要介绍了Flask验证码自动生成的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 目录生成图片以及结果处理验证码蓝图html页面展示想必验证码大家都有所了解,但是可以自己定义图片验证码

Python如何在Word中生成多种不同类型的图表

《Python如何在Word中生成多种不同类型的图表》Word文档中插入图表不仅能直观呈现数据,还能提升文档的可读性和专业性,本文将介绍如何使用Python在Word文档中创建和自定义各种图表,需要的... 目录在Word中创建柱形图在Word中创建条形图在Word中创建折线图在Word中创建饼图在Word

nginx生成自签名SSL证书配置HTTPS的实现

《nginx生成自签名SSL证书配置HTTPS的实现》本文主要介绍在Nginx中生成自签名SSL证书并配置HTTPS,包括安装Nginx、创建证书、配置证书以及测试访问,具有一定的参考价值,感兴趣的可... 目录一、安装nginx二、创建证书三、配置证书并验证四、测试一、安装nginxnginx必须有"-

Java实战之利用POI生成Excel图表

《Java实战之利用POI生成Excel图表》ApachePOI是Java生态中处理Office文档的核心工具,这篇文章主要为大家详细介绍了如何在Excel中创建折线图,柱状图,饼图等常见图表,需要的... 目录一、环境配置与依赖管理二、数据源准备与工作表构建三、图表生成核心步骤1. 折线图(Line Ch