我可以使用此Unity着色器避免垂直纹理拉伸吗?

时间:2019-01-16 00:59:52

标签: unity3d shader

我正在生成动态世界地图,并使用Unity Texture Array作为纹理基础来执行此操作。但是,着色器我目前在x / z上具有良好的平铺效果,但在y上的拉伸效果很差。有什么办法可以纠正它,使其在所有三个轴上平铺?

Shader "Custom/TerrainTexture" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Terrain Texture", 2DArray) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Standard fullforwardshadows
        #pragma target 3.5

        UNITY_DECLARE_TEX2DARRAY(_MainTex);

        struct Input {
            float4 color : COLOR;
            float3 worldPos;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o) {
            float2 uv = IN.worldPos.xz * 0.20;
            fixed4 c = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(uv, 1));
            o.Albedo = c.rgb * _Color;
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

1 个答案:

答案 0 :(得分:3)

为此,您需要三面映射。原理是,将纹理投影到XZ平面上,就像您所做的一样,但随后还将其投影到ZY和XY平面上。最后,使用表面法线(通常多次平方)将纹理混合在一起(相乘和相加)。

以下是混合功能的外观:

inline float3 TriplanarBlendFactor(half3 normal) {
    float3 bf = pow(abs(normal), 6);
    bf /= dot(bf, (float3)1);
    return bf;
}

然后只需像这样组合纹理样本:

fixed4 cx = tex2D(tex, tx) * blendFactor.x;
fixed4 cy = tex2D(tex, ty) * blendFactor.y;
fixed4 cz = tex2D(tex, tz) * blendFactor.z;
fixed4 finalColor = cx + cy + cz;

如果要控制混合距离,可以将混合功能中的功能作为着色器属性公开。