197 lines
7.8 KiB
HLSL
197 lines
7.8 KiB
HLSL
#ifndef TERRAIN_FUNCTIONS_INCLUDED
|
||
#define TERRAIN_FUNCTIONS_INCLUDED
|
||
|
||
#include "UnityCG.cginc"
|
||
|
||
// 如果需要使用 Texture2DArray 类型,请确保 Shader 目标版本支持(例如 5.0 以上)
|
||
// #pragma target 5.0
|
||
|
||
// 全局变量声明(在 Amplify Shader Editor 中可作为属性绑定使用)
|
||
// 主贴图图集(2DArray)
|
||
UNITY_DECLARE_TEX2DARRAY(_MainTex);
|
||
// 贴图编号贴图(2D)
|
||
sampler2D _TexNo;
|
||
// 遮罩编号贴图(2D)
|
||
sampler2D _MaskNo;
|
||
// 遮罩图集(2DArray)
|
||
UNITY_DECLARE_TEX2DARRAY(_MaskTex);
|
||
|
||
// 地形参数:x 表示宽度,z 表示高度(y/w 可忽略)
|
||
float4 _TerrainSize;
|
||
// 纹理重复系数
|
||
float _Repeat;
|
||
// UV 偏移(防止采样边界问题)
|
||
float _UVOffsetX;
|
||
float _UVOffsetY;
|
||
// 采样时的 texel 尺寸(由 Unity 自动传入)
|
||
float4 _TexNo_TexelSize;
|
||
float4 _MaskNo_TexelSize;
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// 计算全局 UV(根据世界坐标和地形尺寸)
|
||
// worldPos.x 对应宽度方向,worldPos.z 对应高度方向
|
||
float2 ComputeGlobalUV(float3 worldPos)
|
||
{
|
||
return float2(worldPos.x / (_TerrainSize.x + 1.0), worldPos.z / (_TerrainSize.z + 1.0));
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// 将从 _TexNo 中采样到的数值转换为图集层号(0~64 内的整数)
|
||
int GetTexNo(float f)
|
||
{
|
||
return (int)round(f * 64.0);
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// 混合函数:从主图集中采样指定图层,并根据遮罩图集的采样结果进行混合
|
||
// (使用全局变量版本)
|
||
// @param color 当前颜色
|
||
// @param maskTexuv 用于遮罩图集采样的 UV
|
||
// @param mainTexuv 用于主图集采样的局部 UV
|
||
// @param mask 遮罩值(对应 _MaskNo 中的通道)
|
||
// @param layer 主图集的图层号
|
||
float4 Blend(float4 color, float2 maskTexuv, float2 mainTexuv, float mask, int layer)
|
||
{
|
||
float4 col2 = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(mainTexuv, layer));
|
||
int idx = (int)round(mask * 16.0);
|
||
maskTexuv += float2(_UVOffsetX, _UVOffsetY);
|
||
float4 maskTexCol = UNITY_SAMPLE_TEX2DARRAY(_MaskTex, float3(maskTexuv, idx));
|
||
return lerp(color, col2, maskTexCol);
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// 调试用混合测试函数(返回遮罩图集采样结果)
|
||
// @param color 当前颜色(仅用于占位)
|
||
// @param uv 用于遮罩采样的 UV
|
||
// @param mask 遮罩值
|
||
// @param layer 贴图层号
|
||
float4 BlendTest(float4 color, float2 uv, float mask, int layer)
|
||
{
|
||
int idx = (int)round(mask * 16.0);
|
||
uv += float2(_UVOffsetX, _UVOffsetY);
|
||
return UNITY_SAMPLE_TEX2DARRAY(_MaskTex, float3(uv, idx));
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// 主混合函数(使用全局变量):根据 _TexNo 与 _MaskNo 中采样的编号和遮罩值混合出最终颜色
|
||
// @param globalUV 全局 UV(例如由 ComputeGlobalUV 得来,用于 _TexNo 与 _MaskNo 采样)
|
||
// @param localUV 局部 UV(例如每个 tile 内的局部坐标,用于主图集采样)
|
||
// @return 混合后的最终颜色
|
||
float4 TerrainBlend(float2 globalUV, float2 localUV)
|
||
{
|
||
// 调整 UV(增加偏移以保证采样精度)
|
||
float2 uvAdjusted = globalUV + float2(0, _TexNo_TexelSize.y);
|
||
float4 texNo = tex2D(_TexNo, uvAdjusted);
|
||
|
||
int layer1 = GetTexNo(texNo.r);
|
||
int layer2 = GetTexNo(texNo.g);
|
||
int layer3 = GetTexNo(texNo.b);
|
||
int layer4 = GetTexNo(texNo.a);
|
||
|
||
float4 maskNo = tex2D(_MaskNo, uvAdjusted);
|
||
|
||
// 局部 UV:uv2 用于遮罩采样,mainTextureUV2 用于主图集采样
|
||
float2 uv2 = frac(localUV * _Repeat);
|
||
float2 mainTextureUV2 = frac(localUV * (_Repeat / 4.0));
|
||
|
||
// 先采样第一层
|
||
float4 col = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(mainTextureUV2, layer1));
|
||
|
||
if (layer2 > 0)
|
||
{
|
||
col = Blend(col, uv2, mainTextureUV2, maskNo.g, layer2);
|
||
}
|
||
if (layer3 > 0)
|
||
{
|
||
col = Blend(col, uv2, mainTextureUV2, maskNo.b, layer3);
|
||
}
|
||
if (layer4 > 0)
|
||
{
|
||
col = Blend(col, uv2, mainTextureUV2, maskNo.a, layer4);
|
||
}
|
||
return col;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// 新的函数入口:提供所有参数(不依赖全局变量)
|
||
// 2DArray 类型参数采用 HLSL 原生类型 Texture2DArray + SamplerState(需要 Shader Model 5.0 支持)
|
||
// @param globalUV 全局 UV 坐标(例如由世界坐标计算得到)
|
||
// @param localUV 局部 UV 坐标(例如 tile 内坐标)
|
||
// @param _MainTexParam 主贴图图集(2DArray 贴图对象)
|
||
// @param _MainTexSamplerParam 主贴图采样状态
|
||
// @param _TexNoParam 贴图编号贴图(2D 采样器)
|
||
// @param _MaskNoParam 遮罩编号贴图(2D 采样器)
|
||
// @param _MaskTexParam 遮罩图集(2DArray 贴图对象)
|
||
// @param _MaskTexSamplerParam 遮罩图集采样状态
|
||
// @param TerrainSizeParam 地形尺寸(float4,x为宽度,z为高度)
|
||
// @param RepeatParam 纹理重复系数
|
||
// @param UVOffsetXParam UV X轴偏移
|
||
// @param UVOffsetYParam UV Y轴偏移
|
||
// @param TexNo_TexelSizeParam _TexNo 贴图的 texel 尺寸(float4)
|
||
// @param MaskNo_TexelSizeParam _MaskNo 贴图的 texel 尺寸(float4)
|
||
// @return 最终混合后的颜色
|
||
float4 TerrainBlendFull(
|
||
float2 globalUV,
|
||
float2 localUV,
|
||
uniform Texture2DArray _MainTexParam,
|
||
uniform SamplerState _MainTexSamplerParam,
|
||
sampler2D _TexNoParam,
|
||
sampler2D _MaskNoParam,
|
||
uniform Texture2DArray _MaskTexParam,
|
||
uniform SamplerState _MaskTexSamplerParam,
|
||
float4 TerrainSizeParam,
|
||
float RepeatParam,
|
||
float UVOffsetXParam,
|
||
float UVOffsetYParam,
|
||
float4 TexNo_TexelSizeParam,
|
||
float4 MaskNo_TexelSizeParam
|
||
)
|
||
{
|
||
// 调整 UV 用于 _TexNo 与 _MaskNo 的采样
|
||
float2 uvAdjusted = globalUV + float2(0, TexNo_TexelSizeParam.y);
|
||
float4 texNo = tex2D(_TexNoParam, uvAdjusted);
|
||
|
||
int layer1 = (int)round(texNo.r * 64.0);
|
||
int layer2 = (int)round(texNo.g * 64.0);
|
||
int layer3 = (int)round(texNo.b * 64.0);
|
||
int layer4 = (int)round(texNo.a * 64.0);
|
||
|
||
float4 maskNo = tex2D(_MaskNoParam, uvAdjusted);
|
||
|
||
// 计算局部 UV(用于主贴图与遮罩采样)
|
||
float2 uv2 = frac(localUV * RepeatParam);
|
||
float2 mainTextureUV2 = frac(localUV * (RepeatParam / 4.0));
|
||
|
||
// 从主贴图图集中采样第一层
|
||
float4 col = _MainTexParam.Sample(_MainTexSamplerParam, float3(mainTextureUV2, layer1));
|
||
|
||
// 内联 Blend 逻辑(采用 .Sample() 方法)
|
||
if (layer2 > 0)
|
||
{
|
||
int idx = (int)round(maskNo.g * 16.0);
|
||
float2 maskUV = uv2 + float2(UVOffsetXParam, UVOffsetYParam);
|
||
float4 col2 = _MainTexParam.Sample(_MainTexSamplerParam, float3(mainTextureUV2, layer2));
|
||
float4 maskTexCol = _MaskTexParam.Sample(_MaskTexSamplerParam, float3(maskUV, idx));
|
||
col = lerp(col, col2, maskTexCol);
|
||
}
|
||
if (layer3 > 0)
|
||
{
|
||
int idx = (int)round(maskNo.b * 16.0);
|
||
float2 maskUV = uv2 + float2(UVOffsetXParam, UVOffsetYParam);
|
||
float4 col2 = _MainTexParam.Sample(_MainTexSamplerParam, float3(mainTextureUV2, layer3));
|
||
float4 maskTexCol = _MaskTexParam.Sample(_MaskTexSamplerParam, float3(maskUV, idx));
|
||
col = lerp(col, col2, maskTexCol);
|
||
}
|
||
if (layer4 > 0)
|
||
{
|
||
int idx = (int)round(maskNo.a * 16.0);
|
||
float2 maskUV = uv2 + float2(UVOffsetXParam, UVOffsetYParam);
|
||
float4 col2 = _MainTexParam.Sample(_MainTexSamplerParam, float3(mainTextureUV2, layer4));
|
||
float4 maskTexCol = _MaskTexParam.Sample(_MaskTexSamplerParam, float3(maskUV, idx));
|
||
col = lerp(col, col2, maskTexCol);
|
||
}
|
||
return col;
|
||
}
|
||
|
||
#endif // TERRAIN_FUNCTIONS_INCLUDED
|