【Unity】无限地形搭建基础

步骤创建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();
            
        }
    }
}

 

结果:

posted on 2019-07-09 18:47  青先生 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/Mr-QingZi/p/11159330.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity3D地形源文件是指使用Unity3D引擎创建的地形场景的原始文件,它保存了该地形的所有设置和属性信息。这些文件可以包括地形的高度图、纹理、细节贴图、植被、水体、石块等元素的布局和设置。 地形源文件通常以.unity或.terrain等扩展名保存,可以在Unity编辑器中打开和编辑。通过编辑地形源文件,开发者可以对地形进行修改、优化和定制,以满足不同的需求。 地形源文件的内容通常包括以下几个重要部分: 1. 高度图:地形源文件会保存地形的高度图,它描述地形在X、Z轴上的高度变化,以创建起伏的地形表面。 2. 纹理:地形的纹理用于给地形表面添加颜色,使其具有更加真实的外观。地形源文件会保存纹理贴图的布局和设置,包括每个纹理贴图的混合方式和权重。 3. 细节贴图:地形源文件还可能包含用于添加地形细节的贴图,如草地、土地等。这些细节贴图用于增加地形的真实感和细节。 4. 植被:植被是地形场景中的植物元素,如树木、草丛等。地形源文件会保存植被的布局和设置,包括位置、数量、种类等信息。 5. 水体:如果地形场景中有水体元素,如湖泊、河流等,地形源文件也会保存水体的设置和属性。 通过修改地形源文件,开发者可以对地形进行各种定制和优化,以实现更好的游戏性能和更真实的场景效果。此外,地形源文件也可以与其他开发者共享,方便协作开发和交流经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值