Unity Shader:三向贴图(Tri-planar mapping)---解决地形拉伸贴图变形以及贴图边缘的缝隙问题

来源:互联网 发布:mac设置自动关机 编辑:程序博客网 时间:2024/05/22 14:05

效果图:

这里写图片描述
效果图1,地形:左边为三向贴图效果,右边为一般贴图效果。

这里写图片描述
效果图2,树干:右边为三向贴图效果,左边为一般贴图效果。

这里写图片描述
效果图3,球体:左边为三向贴图效果,右边为一般贴图效果。

1,世界坐标贴图 World Space UV-mapping
在一般的贴图方法中,在片段着色器内使用tex2D(texture,uv);对2D材质进行采样时,片段着色器将会根据顶点着色器将会传入的顶点UV值插值出当前像素点的uv值。在World Space UV-mapping中,uv值使用当前像素的世界坐标,tex2D(texture,worldPos_xy);。由于uv值只可以取0-1,因此一般面积大于1的2D平面会出现一种repeat的效果,可以将uv值除以一个变量进行缩放,tex2D(texture,worldPos_xy/textureScale);。这种贴图方法的优势是物体向xy平面方向放大时贴图不会出现拉伸,缺点时当物体移动或旋转时,贴图不会随着物体移动,而是根据新的坐标重新进行材质采样。
这里写图片描述
效果图4:平面以worldPos_xz进行tex2D()

2,三向贴图 Triplanar Mapping
以世界坐标贴图方法为基础,将像素的世界坐标(x,y,z)取值为三组UV,xy,xz,yz;根据三组UV值分别对材质进行采样, 然后根据法线方形对采样的颜色进行混合。这样当像素的法线面向y轴时,它会显示由xz采样的颜色,当面向x轴时,将会显示yz采样的颜色,在面向xy轴45度夹角时将会显示由xz,yz采样出的颜色的混合颜色。以此种方式对物体所有非平滑处进行混合过渡。对不规则复杂形状物体,如地形,树木用此方式贴图视觉效果更好。缺点是计算量相对普通贴图要更大。

3,代码
surface shader:

Shader "TriplanarTutorial/Triplanar_Final" {    Properties     {        _DiffuseMap ("Diffuse Map ", 2D)  = "white" {}        _TextureScale ("Texture Scale",float) = 1        _TriplanarBlendSharpness ("Blend Sharpness",float) = 1    }    SubShader     {        Tags { "RenderType"="Opaque" }        LOD 200        CGPROGRAM        #pragma target 3.0        #pragma surface surf Lambert        sampler2D _DiffuseMap;        float _TextureScale;        float _TriplanarBlendSharpness;        struct Input        {            float3 worldPos;            float3 worldNormal;        };         void surf (Input IN, inout SurfaceOutput o)         {            // Find our UVs for each axis based on world position of the fragment.            half2 yUV = IN.worldPos.xz / _TextureScale;            half2 xUV = IN.worldPos.zy / _TextureScale;            half2 zUV = IN.worldPos.xy / _TextureScale;            // Now do texture samples from our diffuse map with each of the 3 UV set's we've just made.            half3 yDiff = tex2D (_DiffuseMap, yUV);            half3 xDiff = tex2D (_DiffuseMap, xUV);            half3 zDiff = tex2D (_DiffuseMap, zUV);            // Get the absolute value of the world normal.            // Put the blend weights to the power of BlendSharpness, the higher the value,             // the sharper the transition between the planar maps will be.            half3 blendWeights = pow (abs(IN.worldNormal), _TriplanarBlendSharpness);            // Divide our blend mask by the sum of it's components, this will make x+y+z=1            blendWeights = blendWeights / (blendWeights.x + blendWeights.y + blendWeights.z);            // Finally, blend together all three samples based on the blend mask.            o.Albedo = xDiff * blendWeights.x + yDiff * blendWeights.y + zDiff * blendWeights.z;        }        ENDCG    }}

vertex shader:

Shader "Unlit/Tri-Planar"{    Properties    {        _DiffuseMap ("Diffuse Map ", 2D)  = "white" {}        _TextureScale ("Texture Scale",float) = 1        _TriplanarBlendSharpness ("Blend Sharpness",float) = 1    }    SubShader    {        Tags { "RenderType"="Opaque" }        LOD 100        Pass        {            CGPROGRAM            #pragma vertex vert            #pragma fragment frag            // make fog work            #pragma multi_compile_fog            #include "UnityCG.cginc"            struct appdata            {                float4 vertex : POSITION;                float2 uv : TEXCOORD0;                float3 normal:NORMAL;            };            struct v2f            {                float2 uv : TEXCOORD0;                UNITY_FOG_COORDS(1)                float4 vertex : SV_POSITION;                float3 normal:NORMAL;                float4 w_Vertex : FLOAT;            };            float _TextureScale;            sampler2D _DiffuseMap;            float4 _MainTex_ST;            float _TriplanarBlendSharpness;            v2f vert (appdata v)            {                v2f o;                o.vertex = UnityObjectToClipPos(v.vertex);                o.uv = TRANSFORM_TEX(v.uv, _MainTex);                UNITY_TRANSFER_FOG(o,o.vertex);                o.normal=mul(unity_ObjectToWorld,v.normal);                o.w_Vertex=mul(unity_ObjectToWorld,v.vertex);                return o;            }            fixed4 frag (v2f i) : SV_Target            {                // sample the texture                float3 blending=abs(i.normal);                blending=normalize(pow(blending,_TriplanarBlendSharpness));                float b=(blending.x+blending.y+blending.z);                blending/=float3(b,b,b);                float4 xaxis=tex2D(_DiffuseMap,i.w_Vertex.yz/_TextureScale);                float4 yaxis=tex2D(_DiffuseMap,i.w_Vertex.xz/_TextureScale);                float4 zaxis=tex2D(_DiffuseMap,i.w_Vertex.xy/_TextureScale);                fixed4 tex=xaxis*blending.x+yaxis*blending.y+zaxis*blending.z;        //      fixed4 col = tex2D(_MainTex, i.uv);                // apply fog                UNITY_APPLY_FOG(i.fogCoord, tex);                return tex;            }            ENDCG        }    }}

参考:
Use Tri-Planar Texture Mapping for Better Terrain –Brent Owens
https://gamedevelopment.tutsplus.com/articles/use-tri-planar-texture-mapping-for-better-terrain–gamedev-13821

Triplanar Mapping –MARTIN PALKO
http://www.martinpalko.com/triplanar-mapping/
———————————————————————————
维护日志:
2017-9-20:将“三平面式”改为“三向式”

原创粉丝点击