如何在HLSL中实现UV块接缝融合?
解决分块旋转UV的边缘融合问题
你的Shader已经实现了UV分块随机旋转,但块边缘出现明显接缝,核心原因是每个块的UV完全独立计算,没有和相邻块做过渡处理。下面是修改后的代码,加入了边缘平滑融合逻辑:
Shader "Custom/Blend_4_test" { Properties { _MainTex ("Texture", 2D) = "white" {} _TileCount("Tile Count", Range(2.0, 100.0)) = 4 _TileCountInside("Tile Count Inside", Range(1.0, 10.0)) = 1 _RotateAngle("Rotate Angle", Float) = 45.0 _RotateNoise("Rotate Noise", Float) = 20.0 _BlendWidth("Edge Blend Width", Range(0.001, 0.1)) = 0.02 [Enum(Texture,0,Checker,1)] _ViewMode("View Mode", Int) = 1 } SubShader { Pass { CGPROGRAM #pragma vertex vert_img #pragma fragment frag #include "UnityCG.cginc" #include "../Libraries/Helper.cginc" sampler2D _MainTex; half _TileCount; half _TileCountInside; half _RotateAngle; half _RotateNoise; half _BlendWidth; int _ViewMode; half Hash21(half2 p) { p = frac(p*half2(123.34, 456.21)); p += dot(p, p+45.32); return frac(p.x*p.y); } half2 getNoise(half2 p) { return rand2(p, _RotateNoise); } int getChecker(half2 uv) { half2 ipos = sin(uv * _TileCountInside * 6.2831); return ipos.x * ipos.y > 0.; } // 封装单个块的旋转与颜色采样逻辑 half4 GetTileColor(half2 tilePos, half2 uvInTile) { half rotAngle = radians(_RotateAngle * Hash21(getNoise(tilePos))); half2 pivot = half2(0.5); half2 rotatedUV = mul(rot(rotAngle), uvInTile - pivot) + pivot; if (_ViewMode == 1) { return getChecker(rotatedUV) ? half4(1,1,1,1) : half4(0,0,0,1); } else { return tex2D(_MainTex, rotatedUV * _TileCountInside); } } half4 frag(v2f_img i) : SV_Target { half2 uv = i.uv * _TileCount; half2 tilePos = floor(uv); half2 uvInTile = frac(uv); // 采样当前块及上下左右四个相邻块的颜色 half4 colCenter = GetTileColor(tilePos, uvInTile); half4 colRight = GetTileColor(tilePos + half2(1,0), uvInTile - half2(1,0)); half4 colLeft = GetTileColor(tilePos - half2(1,0), uvInTile + half2(1,0)); half4 colUp = GetTileColor(tilePos + half2(0,1), uvInTile - half2(0,1)); half4 colDown = GetTileColor(tilePos - half2(0,1), uvInTile + half2(0,1)); // 计算边缘过渡权重,用smoothstep实现平滑的0-1过渡 half2 blend = smoothstep(0.5 - _BlendWidth, 0.5 + _BlendWidth, uvInTile) * smoothstep(0.5 + _BlendWidth, 0.5 - _BlendWidth, uvInTile - 1.0); // 先做水平方向的边缘融合 half4 colHoriz = lerp(colLeft, colCenter, blend.x); colHoriz = lerp(colHoriz, colRight, 1.0 - blend.x); // 再做垂直方向的边缘融合 half4 colVert = lerp(colDown, colCenter, blend.y); colVert = lerp(colVert, colUp, 1.0 - blend.y); // 最终合并两个方向的融合结果 return lerp(colHoriz, colVert, blend.y * blend.x); } ENDCG } } }
关键修改说明:
- 新增
_BlendWidth参数,可手动调节边缘融合的过渡宽度,数值越大接缝过渡越平滑 - 封装
GetTileColor函数,统一处理单块UV旋转和颜色采样,减少重复代码 - 片元着色器中同时采样当前块与相邻块的颜色,通过
smoothstep生成过渡权重,对相邻颜色做平滑插值,彻底消除块边缘接缝
内容的提问来源于stack exchange,提问作者Akeyn
相关产品推荐
相关产品推荐

