KopMap/Assets/TerrainUVBlendShader.shader
2025-04-03 02:30:16 +08:00

198 lines
7.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Shader "Unlit/TerrainShader"
{
Properties
{
_MainTex ("Texture Atlas", 2DArray) = "white" {} // 主贴图图集
_TexNo ("TexNo", 2D) = "white" {} // 贴图编号(各通道分别代表不同层)
_MaskNo ("MaskNo", 2D) = "black" {} // 遮罩数据
_MaskTex ("Mask Atlas", 2DArray) = "black" {} // 遮罩图集
_TerrainSize ("Terrain Size", Vector) = (256,0,256,0) // x宽度z高度
_BorderColor ("Border Color", Color) = (1,1,1,1)
_BorderWidth ("Border Width", Range(0,0.1)) = 0.05
_Repeat ("Repeat", float) = 0
_DebugMask ("DebugMask", Range(0,4)) = 0
_DebugShowMaskNoOrNo ("DebugShowMaskNoOrNo", Range(0,2)) = 0
_DebugUV ("DebugUV", Range(0,2)) = 2
_UVOffsetX ("UV Offset", float) = 0
_UVOffsetY ("UV Offset", float) = 0
}
SubShader
{
Tags
{
"RenderType"="Opaque"
}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 输入:由于 Terrain 无法自定义 UV我们只传入顶点位置
struct appdata
{
float2 uv : TEXCOORD1;
float4 vertex : POSITION;
};
// 输出:计算出的全局 uv0用于 _TexNo 采样)会传递到片元,同时用于采样烘培 UV2
struct v2f
{
float2 uv : TEXCOORD0;
float2 uv2 : TEXCOORD1;
float4 vertex : SV_POSITION;
};
// 声明贴图变量
UNITY_DECLARE_TEX2DARRAY(_MainTex);
sampler2D _TexNo; // 贴图编号贴图
sampler2D _MaskNo; // 遮罩贴图
UNITY_DECLARE_TEX2DARRAY(_MaskTex);
int _DebugShowMaskNoOrNo;
float _Repeat;
float4 _TexNo_TexelSize;
float4 _MaskNo_TexelSize;
float4 _BorderColor;
float _BorderWidth;
float4 _TerrainSize; // x宽度z高度y/w分量可忽略
int _DebugMask;
int _DebugUV;
float _UVOffsetX;
float _UVOffsetY;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
// 根据 Terrain 的世界坐标计算全局 uv0
o.uv2 = v.uv;
o.uv = float2(v.vertex.x / (_TerrainSize.x + 1), v.vertex.z / (_TerrainSize.z + 1));
return o;
}
// 依然采用原来的混合函数(利用遮罩混合不同 2DArray 层的贴图)
float4 Blend(float4 color, float2 maskTexuv, float2 mainTexuv, float mask, int layer)
{
float4 col2 = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(mainTexuv, layer));
int idx = round(mask * 16);
float4 maskTexCol = UNITY_SAMPLE_TEX2DARRAY(_MaskTex, float3(maskTexuv, idx));
return lerp(color, col2, maskTexCol);
}
// 将从 _TexNo 采样到的数值转换为图集层号064 内的整数)
int GetTexNo(float f)
{
float idx = f * 64.0;
return round(idx);
}
float4 BlendTest(float4 color, float2 uv, float mask, int layer)
{
int idx = round(mask * 16);
uv += float2(_UVOffsetX, _UVOffsetY);
float4 maskTexCol = UNITY_SAMPLE_TEX2DARRAY(_MaskTex, float3(uv, idx));
return maskTexCol;
}
fixed4 frag(v2f i) : SV_Target
{
// 整个大uv往下偏移
float2 uv = i.uv + float2(0, _TexNo_TexelSize.y);
// 贴图编号
float4 texNo = tex2D(_TexNo, uv);
int layer1 = GetTexNo(texNo.r);
int layer2 = GetTexNo(texNo.g);
int layer3 = GetTexNo(texNo.b);
int layer4 = GetTexNo(texNo.a);
// 取出遮罩值
float4 maskNo = tex2D(_MaskNo, uv);
float2 uv2 = frac(i.uv2 * _Repeat);
float2 mainTextureUV2 = frac(i.uv2 * (_Repeat / 4));
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);
}
// // uv0全局坐标用于 _TexNo、_MaskNo 采样)
// float2 uv = i.uv;
// // 采样烘培贴图恢复原本为每4个顶点设置的局部 uv2例如每个 tile 内从 (0,0) 到 (1,1)
// float2 uv2 = frac(i.uv2 * _Repeat);
// float2 uv3 = frac(i.uv2 * _Repeat + 1);
// // 为了保证采样 texNo 与 maskNo 的准确性,可对 uv0 进行微调(这里延用原来加偏移的思路)
// uv = uv + float2(0, _TexNo_TexelSize.y);
// // 从 _TexNo 中读取各层编号(不同通道对应不同层)
// float4 texNo = tex2D(_TexNo, i.uv);
// int layer1 = GetTexNo(texNo.r);
// int layer2 = GetTexNo(texNo.g);
// int layer3 = GetTexNo(texNo.b);
// int layer4 = GetTexNo(texNo.a);
//
//
// // 先从主贴图图集中采样第一层(使用 uv2 作为局部采样坐标)
// float4 maskNo = tex2D(_MaskNo, i.uv2);
// float4 col = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(uv3, layer1));
// if (layer2 > 0)
// col = Blend(col, uv3, maskNo.g, layer2);
// if (layer3 > 0)
// col = Blend(col, uv3, maskNo.b, layer3);
// if (layer4 > 0)
// col = Blend(col, uv3, maskNo.a, layer4);
if (_DebugShowMaskNoOrNo == 1)
{
return texNo;
}
if (_DebugShowMaskNoOrNo == 2)
{
return maskNo;
}
if (_DebugMask == 1)
{
return BlendTest(col, uv2, maskNo.r, layer1);
}
if (_DebugMask == 2)
{
return BlendTest(col, uv2, maskNo.g, layer2);
}
if (_DebugMask == 3)
{
return BlendTest(col, uv2, maskNo.b, layer3);
}
if (_DebugMask == 4)
{
return BlendTest(col, uv2, maskNo.a, layer4);
}
if (_DebugUV == 1)
{
return float4(i.uv, 0, 1);
}
if (_DebugUV == 2)
{
return float4(uv2, 0, 1);
}
return col;
}
ENDCG
}
}
}