序
之前,生成了地形图:(42条消息) 从灰度图到地形图_averagePerson的博客-CSDN博客
那末,地形的法线贴图怎么获取?
大概分为两个部分吧,先拿到法线数据,再画到纹理中去。
关于法线
计算
Unity - Scripting API: Mesh.RecalculateNormals (unity3d.com)
这个链接讲的是法线的计算,它是什么空间下的?无所谓了……
这里也不对地形搞什么几何变换,而且它是方向,模型空间世界空间是一个结果。
获取
Unity - Scripting API: Mesh.normals (unity3d.com)
直接一个等于号,然后这个法线是对顶点不是对三角形面片。
就这两点,没了。
存到纹理中
构造
Unity - Scripting API: Texture2D (unity3d.com)
这个变量,好像在unity shader里也经常出现嘞
要把法线数据存到Texture2D里,首先得构造一下对象啊,构造函数是什么?
Unity - Scripting API: Texture2D.Texture2D (unity3d.com)
RGBA32,构造RenderTexture的时候也有你。
怎么赋值?
赋值
Unity - Scripting API: Texture2D.SetPixels (unity3d.com)
直接传数组
数组要展平【mesh.normals其实就是一维的,那就可以直接用了】
最后需要Apply
从左到右从下到上【地形顶点正好也是这个顺序的】
官方示例代码:
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);
}
}
试一试
根据文档,调api就行了。
代码
计算法线的
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);
}
}
}
}
显示法线贴图的。这个是在摄像机上的——屏幕后处理嘛!
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);
}
}
结果
看着……走势差不多吧。而且,绿色的,表示向上,符合的。
对不对?在这种情况下,没法看出来。只能接着往下做,然后拔出萝卜带出泥巴。