Get the normal of the terrain in Unity

sequence

Previously, a topographic map was generated: (42 messages) From grayscale map to topographic map_averagePerson's Blog-CSDN Blog

So, how to get the normal map of the terrain?

It is roughly divided into two parts, first get the normal data, and then draw it into the texture.

About normals

calculate

Unity - Scripting API: Mesh.RecalculateNormals (unity3d.com)

This link is about the calculation of the normal line. What space is it in? never mind……

There is no geometric transformation of the terrain here, and it is the direction, and the model space and world space are a result.

Obtain

Unity - Scripting API: Mesh.normals (unity3d.com)

Directly an equal sign, and then the normal is to the vertex, not to the triangle face.

Just these two points, gone.

save to texture

structure

Unity - Scripting API: Texture2D (unity3d.com)

This variable seems to often appear in the unity shader

To store normal data in Texture2D, you must first construct the object. What is the constructor?

Unity - Scripting API: Texture2D.Texture2D (unity3d.com)

RGBA32, you are also there when constructing RenderTexture.

How to assign value?

assignment

Unity - Scripting API: Texture2D.SetPixels (unity3d.com)

  1. Pass the array directly

  1. The array needs to be flattened [mesh.normals is actually one-dimensional, so it can be used directly]

  1. Finally need to apply

  1. From left to right, from bottom to top [Terrain vertices happen to be in this order]

Official sample code:

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    void Start()
    {
        Renderer rend = GetComponent<Renderer>();

        // duplicate the original texture and assign to the material
        Texture2D texture = Instantiate(rend.material.mainTexture) as Texture2D;
        rend.material.mainTexture = texture;

        // colors used to tint the first 3 mip levels
        Color[] colors = new Color[3];
        colors[0] = Color.red;
        colors[1] = Color.green;
        colors[2] = Color.blue;
        int mipCount = Mathf.Min(3, texture.mipmapCount);

        // tint each mip level
        for (int mip = 0; mip < mipCount; ++mip)
        {
            Color[] cols = texture.GetPixels(mip);
            for (int i = 0; i < cols.Length; ++i)
            {
                cols[i] = Color.Lerp(cols[i], colors[mip], 0.33f);
            }
            texture.SetPixels(cols, mip);
        }
        // actually apply all SetPixels, don't recalculate mip levels
        texture.Apply(false);
    }
}

try it

According to the documentation, just adjust the api.

the code

Calculate normal

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

public class Terrian : MonoBehaviour
{
    public int N = 10;
    public Texture2D texture2dHeightMap;
    [Range(1,100)]
    public float heightRatio = 30.0f;//一个系数,控制地形总体的高度的

    public Texture2D normalTex;

    MeshRenderer meshRenderer;
    MeshFilter meshFilter;

    // 用来存放顶点数据
    List<Vector3> verts;
    List<int> indices;
    Vector3[] normals;

    private void Awake()
    {
    }

    private void Start()
    {
        verts = new List<Vector3>();
        indices = new List<int>();

        meshRenderer = GetComponent<MeshRenderer>();
        meshFilter = GetComponent<MeshFilter>();

        //normalTex = new Texture2D(texture2dHeightMap.width, texture2dHeightMap.height, TextureFormat.RGB24,-1,false);
        normalTex = new Texture2D(N,N, TextureFormat.RGB24, -1, false);//2.5D的地形,顶点的法线,法线贴图规模不是灰度图规模
    }

    private void Update()
    {
        Generate();

        normals = new Vector3[N * N];
        normals = meshFilter.mesh.normals;
        for(int i = 0; i < 10; ++i)
        {
            print(normals[i]);
        }

        Color[] colors = new Color[N * N];
        for(int i = 0; i < N * N; ++i)
        {
            colors[i] = new Color(normals[i].x, normals[i].y, normals[i].z);
        }

        normalTex.SetPixels(colors);
        normalTex.Apply(false);
    }

    public void Generate()
    {
        ClearMeshData();

        // 把数据填写好
        AddMeshData();

        // 把数据传递给Mesh,生成真正的网格
        Mesh mesh = new Mesh();
        mesh.vertices = verts.ToArray();
        mesh.triangles = indices.ToArray();

        mesh.RecalculateNormals();
        mesh.RecalculateBounds();

        meshFilter.mesh = mesh;
    }

    void ClearMeshData()
    {
        verts.Clear();
        indices.Clear();
    }

    void AddMeshData()
    {

        //01填充顶点数据
        for (int z = 0; z < N; ++z)//按先x后z的顶点排列顺序,所以先循环的是z
        {
            for(int x = 0; x < N; ++x)
            {
                int u = Mathf.FloorToInt(1.0f * x / N * texture2dHeightMap.width);
                int v = Mathf.FloorToInt(1.0f * z / N * texture2dHeightMap.height);
                float grayValue = texture2dHeightMap.GetPixel(u,v).grayscale;

                float height = grayValue*heightRatio;
                Vector3 temp = new Vector3(x, height, z);
                verts.Add(temp);
            }
        }
        //02填充索引数据
        for(int z = 0; z < N - 1; ++z)
        {
            for(int x = 0; x < N - 1; ++x)
            {
                int index_lb = z * N + x;//index of the left bottom vertex. lb = left bottom
                int index_lt = (z + 1) * N + x;
                int index_rt = (z + 1) * N + x + 1;
                int index_rb = z * N + x + 1;

                indices.Add(index_lb);indices.Add(index_lt);indices.Add(index_rt);
                indices.Add(index_rt);indices.Add(index_rb);indices.Add(index_lb);
            }
        }
    }


    
}

Displays the normal map. This one is on camera - screen post-processing!

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

public class ShowTexture2D : MonoBehaviour
{
    public Terrian terrian;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        Graphics.Blit(terrian.normalTex, destination);
    }


}

result

Look at... the trend is about the same. And, green, means up, consistent.

right? In this case, there is no way to see it. I can only continue to do it, and then pull out the radish to bring out the mud.

Pure plane is pure green

The larger the height factor, the darker the color

Guess you like

Origin blog.csdn.net/averagePerson/article/details/129243461