我们今天学习Unity的地形渲染

我们可以看这个shader脚本的前五个属性


创建地形分层shader
首先创建一个有光照lit的shadergraph
然后添加如下节点
由于这些材质会默然在inspector暴露参数,我们需要取消勾选每一个“Exposed”不再暴露在inspector (注意: 如果你是unity 6 用户,取消勾选 show in inspector) ,然后勾选每一个sprite的 Use Tilling and offset(平铺与偏移),并将Fragment里的smoothness平滑值设为0(这个我们之前说过,当这个不为0时材质表面上会出现一层像陶瓷轴一样的反光,这里我们不需要这个效果)

Use Tiling and Offset 用于控制纹理是否自动应用材质面板中的 Tiling(平铺) 和 Offset(偏移) 参数。启用后,Shader 会自动对 UV 执行
UV × Tiling + Offset计算,使开发者和美术能够直接在材质球中调整纹理的重复次数和偏移位置,而无需修改 Shader Graph。对于普通贴图材质通常建议开启,对于已经手动处理 UV 的效果(如流动纹理、Triplanar、世界空间映射等)则通常关闭以避免重复计算。
我们们首先实现模型的材质的分层,添加一个control层和四个sprite层,这个是对应代码里的Control和四个图层
[HideInInspector] _Control("Control (RGBA)", 2D) = "red" {}
[HideInInspector] _Splat3("Layer 3 (A)", 2D) = "grey" {}
[HideInInspector] _Splat2("Layer 2 (B)", 2D) = "grey" {}
[HideInInspector] _Splat1("Layer 1 (G)", 2D) = "grey" {}
[HideInInspector] _Splat0("Layer 0 (R)", 2D) = "grey" {}
标准unity地形系统支持四个纹理层,地形系统通过名为Control的首个纹理将数据传输至着色器,也就是我们添加的control纹理,纹理的每个色彩通道都记录了地形对应位置某个图层的强度值,
所以红色通道对应的是第一层,也就是Sprite0
绿色通道对应的是第二层,也就是Sprite1
蓝色通道对应的是第三层,也就是Sprite2
alpha通道对应的是第四层,也就是Sprite3
而这里为了实现这个效果,可以直接用各个sprite层直接乘以control层的各个颜色的通道值,然后依此相加,最后将效果叠加到基础色上

目前已经可以实现分层了,但是为了让山体地形更真实,我们需要特殊处理一下
需要获取地形表面的法向量,检测y轴分量,若接近1或者-1就是近乎水平的地面,若接近0表示检测到的是斜坡地形

我们添加两个浮点参数:
normal start 用于控制y分量阈值用于判定岩石面的起始位置,设置为默认值为0.5取值范围0-1的slider
normal end 用于控制岩石面的终止边界,默认值设为0.6取值范围0-1的slider
然后使用normal vector法向量节点用split分离出y向量(也就是G通道),并使用smoothstep平滑过渡节点在normal start和normal end之间
这里复习一下这个节点: 当输入值小于第一个边界值时,节点输出0,当数值大于edge2时,节点输出1,当输入值介于两者之间的时候,输出值会呈现为从0-1的平滑过渡曲线
可以看到球体垂直面显示的是黑色,而顶部平坦区域显示为白色,这里不会出现全黑的情况,因为在unity实际地形环境中发现向量的y分量不会出现负值
然后我们把第一层和第二层使用smoothstep传入的参数来线性插值,并和control节点的R通道相乘

我们从模型网站下载一个山体的obj免费模型,然后添加合适的材质图通过调整参数来修改山体的效果,这样就可以实现了山体的材质(不过如字面意思,这就是贴图,和无人深空,荒野大镖客,黑神话悟空这些可交互地形这些没法比)




扫描地形效果
我们做一个扫描地形的效果 
添加一个颜色节点并设置为HDR

由于手动控制地形扫描效果过于麻烦,我们可以使用C#脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WorldScanner : MonoBehaviour
{
public float scanSpeed;
public Terrain terrain;
private Material terrainMaterial;
private float scanDistance;
void Start()
{
terrainMaterial = terrain.materialTemplate;
scanDistance = 1000f;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Input.mousePosition;
if (Physics.Raycast(Camera.main.ScreenPointToRay(mousePos), out RaycastHit hitInfo))
{
terrainMaterial.SetVector("_ScanOrigin", hitInfo.point);
scanDistance = 0.0f;
}
}
scanDistance += scanSpeed * Time.deltaTime;
terrainMaterial.SetFloat("_ScanDistance", scanDistance);
}
}
但是之前我们为了节省时间直接从素材网站上下载的山的模型
unity其实自带了地形系统
其实我们可以自己刷一个,首先创建一个terrain

然后切换为set height并选择合适的笔刷来绘制地形

画好地图后来给地图上材质,首先切换为PaintTexture模式

我们点击添加图层,添加纹理并绘制,当然没有的话也可以用现有的texture来create一个

然后我们的一坨山脉就做好了


评论区