Unity程序化地形教程 第一期 噪波图的制作

Unity程序化地形教程 第一期

前言:最近在准备作品集,想吧Blender里面利用shader实现的程序化地形导入Unity中,发现我弄不了,于是转向了直接在Unity中实现程序化地形的新途径,但是网上的教程很少,b站和CSDN好像都没有详细的教程,所以今天我科学上网找了一下,查到了一个16年的程序化视频教学,自带机翻英文的那种,就是按他的翻译根本翻译不对,听也听不太懂,所幸能够理解代码意思,想借这个机会去做一篇程序化地形的教程,先是以博客的形式去记录每次所学,把所学弄懂,再去下一章的学习,最后我会在b站制作一个视频教程,希望大家多多支持,文章是我学习后自己的理解,肯定有些地方不对,不对的地方还请大家多多指教,感兴趣的朋友可以点一波关注,持续更新!

零、学完本期后的效果展示

初步直租出一张噪声图,为后续创作打下基础

一、我对于程序化地形的理解

简单来说程序化地形需要一个高效的伪随机数生成器,随机数包括地形的长、宽、高度、大小,然后利用一个载体把这些数合理的展示出来,大家最常见的其实就是黑白噪声图
Unity程序化地形教程 第一期 噪波图的制作_第1张图片
以这张图为载体,他的长、宽、大小就是程序化地形的大小,那么有人就会问:地形高度和地形间的间隙是如何表现出来的?这里其实是使用到了噪声的波形来做的
Unity程序化地形教程 第一期 噪波图的制作_第2张图片
波形图看起来是不是很像山脉的起伏一样?从而我们可以自己定义一个波形图,通过修改波形图的长宽大小,以及噪声的分布来实现一个地形的设计,这样之后噪声图就相当于一个地形编辑器了,我们通过编辑噪声图间接的编辑出地形,进而我们再加上颜色和其他属性,就能为地形增添上更多的细节,以此来达到一个程序化地形的效果。

二、程序化地形初步实现

1.定义噪声图

首先我们需要像我上面所说的一样,定义一个噪声图,让它成为程序化地形的一个载体,为此我们编写一个噪声脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public static class Noise
{   
    //定义一个函数生成地图 利用噪声来设置地形的长宽大小等属性
    public static  float[,] GenerateNoiseMap(int mapWidth,int mapHeight,float scale) 
    {
        //定义一个两个维度的浮点数类型的数组 用于存储长、宽数据
        float[,] noiseMap = new float[mapWidth, mapHeight];
        //防止地图的大小出现负数
        if(scale<=0)
        {
            scale = 0.0001f;
        }
     
       //对传入的函数的长、宽参数进行灰度值赋值 模拟噪声
        for(int y =0;y<mapHeight;y++)
        {
            for(int x=0;x<mapWidth;x++)
            {
                //除以scale 让影响scale的同时能够影响到地图缩放的大小
                float sampleX = x / scale;
                float sampleY = y / scale;

                //柏林值 Mathf.PerlinNoise可以简单理解为随机获得在这个点的灰度值
                float perlinValue = Mathf.PerlinNoise(sampleX, sampleY);
                //将灰度值返回给这个点
                noiseMap[x, y] = perlinValue;
            }
        }
        return noiseMap;
    }
}

2.定义一个地形生成器

在这里就会用到我们刚刚写好的noise脚本,用这个脚本来实现对噪声参数传入的控制,用这个脚本来控制地形的生成

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MapGenerator : MonoBehaviour
{
    public int mapWidth;
    public int mapHeight;
    public float noiseScale;

    //生成地图
    public void GenerateMap()
    {
        //这里将输入的长、宽、大小代入刚刚定义好的生成噪声的函数中
        float[,] noiseMap = Noise.GenerateNoiseMap(mapWidth, mapHeight, noiseScale);

        //MapDisplay是用来将噪声转化为地形的脚本 在这里将上面处理后的数据转化为地形
        //下一个脚本再具体介绍 这里可以直接写
        MapDisplay display = FindObjectOfType<MapDisplay>();
        display.DrawNoiseMap(noiseMap);
    }
}

3.定义一个地图展示器

将我们所输入的参数得到的噪声图转换为一个地图展现出来

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MapDisplay : MonoBehaviour
{
    //通过控制plan的Renderer来控制地形的显示
    public Renderer textureRender;

    //绘制噪声图
    public void DrawNoiseMap(float[,] noiseMap)
    {
        //用来获取数组指定维数中的元素个数 这里分别是长和宽
        int width = noiseMap.GetLength(0);
        int height = noiseMap.GetLength(1);

        Texture2D texture = new Texture2D(width, height);

        //Color类型是接收的是一个[0,1]的值,需要用R,G,B,A四个值各自除以255
        //这里是定义整张图的取值面积 即要修改颜色点的多少
        Color[] colourMap = new Color[width * height];

        //将每个点赋值色彩
        for(int y=0;y<height;y++)
        {
            for(int x =0;x<width;x++)
            {
                colourMap[y * width + x] = Color.Lerp(Color.black, Color.white, noiseMap[x, y]);
            }
        }

        //将图按原比例绘制下来
        texture.SetPixels(colourMap);
        //将定义的图像纹理进行应用 此前需要进行SetPixels
        texture.Apply();

        //将应用后的图交给Randerer去展现效果
        textureRender.sharedMaterial.mainTexture = texture;
        textureRender.transform.localScale = new Vector3(width, 1, height);
    }
}

四、定义一个地图编辑器

用于实时呈现出更改后的地形的样式

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

//将我们定义好的控件展示出来
[CustomEditor(typeof(MapGenerator))]
public class MapGeneratorEditor : Editor
{
    public bool mapGenChange = true;
    public override void OnInspectorGUI() 
    {
        MapGenerator mapGen = (MapGenerator)target;

        //修改参数不用运行就能看到修改后的效果
        if(DrawDefaultInspector())
        {
            if(mapGenChange)
            {
                mapGen.GenerateMap();
            }
        }
       
        //点击按键就能更新
        if (GUILayout.Button("Generate"))
        {
            mapGen.GenerateMap();
        }
    }
}

5.初步效果展现

首先在3D场景中创建一个Plane,只保留如下两个组件
Unity程序化地形教程 第一期 噪波图的制作_第3张图片
创建一个材质球,将它的类型修改为Unlit/Texture,并赋值给Plane,如上图所示
Unity程序化地形教程 第一期 噪波图的制作_第4张图片
再新建一个空物体用来控制地形的生成,挂载脚本以及赋值如图所示
Unity程序化地形教程 第一期 噪波图的制作_第5张图片
最后我们通过修改Map Genertor脚本中的参数来控制地形的生成

这样一个基本的用于控制地形生成的噪波图就制作好了,是不是很有趣呢?感兴趣的话点个关注,后面持续更新!

你可能感兴趣的:(Unity程序化地形,程序化地形,Unity,地形编辑,场景制作)