#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