KopMap/Assets/MindPowerSdk/Shaders/TerrainFunctions.hlsl

197 lines
7.8 KiB
HLSL
Raw Permalink Normal View History

2025-04-03 02:30:16 +08:00
#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 中采样到的数值转换为图集层号064 内的整数)
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);
// 局部 UVuv2 用于遮罩采样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 地形尺寸float4x为宽度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