You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 04:55:29