消除贴图重复感

作者: 万里_aa3f | 来源:发表于2019-01-01 00:48 被阅读5次

搬砖----解决贴图重复

参考自巨佬iq的文章,文章用两种方法消除了贴图重复问题。
本文在unity里实现了第一种。第二种实现依靠Voronoi分布,以后在说
先看效果----右边是处理后的效果,消除了重复感


基本的原理是:对每块地砖位置的uv进行随机的翻转和平移,让每块纹理出现不同的采样,然后在地砖边界处进行混合,消除接缝问题。

1.写在前面:随机函数、ddx/ddy()、uv处理
2.最简Shader
(请先扫一遍shader部分,我前面写的有点跳)

1.Hash函数,求伪随机值
float4 hash4( float2 p ) { return frac(sin  ( float4( 1.0+dot(p,float2(37.0,17.0)), 
                                                      2.0+dot(p,float2(11.0,47.0)),
                                                      3.0+dot(p,float2(41.0,29.0)),
                                                      4.0+dot(p,float2(23.0,31.0))))*103.0); }

先看frac(sin(x))与frac(sin(x)*103.0)的函数图




后者通过乘上103,加大了频率形成伪随机数【伪随机数很重要,意味着输入相同的值,输出相同的值(不会有time等因素做干扰);如不是随机数将无法在每块砖之间做准确的融合】。还要注意一点我们的随机值落在【0,1】之间,方便我们用sign随机+-号;图中的x部分也就是Hash里的(a+dot(uv,float(37.,17.)),目的是将uv做降维。【Hash函数还有很多,有时间总结一波】

2.ddx() 和 ddy(),分别对应 x, y 轴上,在屏幕空间中,像素块中各种变量的变化率。
                float2 dx = ddx( uv );
                float2 dy = ddy( uv );

dx与dy将用在tex2D(_Tex,uv,dx,dy)上,通过对传入的uv的偏导数(很好理解,见下图),决定到底选择哪个mipmap的level;dx、dy的缺省值为ddx(uv)/ddy(uv),所以当我们改变贴图的采样方向时,应同时改变dx、dy的±

3.为什么是 float2(0.0,0.0) (1.0,0.0) (1.0,1.0) (0.0,1.0)
          float4 ofa = hash4( iuv + float2(0.0,0.0) );
          float4 ofb = hash4( iuv + float2(1.0,0.0) );
          float4 ofc = hash4( iuv + float2(0.0,1.0) );
          float4 ofd = hash4( iuv + float2(1.0,1.0) );
//请先看return
float2 b = smoothstep(_BlendScale,1-_BlendScale,fuv);
return lerp( lerp( tex2D( samp, uva, ddxa, ddya ), 
                                tex2D( samp, uvb, ddxb, ddyb ), b.x ), 
                            lerp( tex2D( samp, uvc, ddxc, ddyc ),
                                tex2D( samp, uvd, ddxd, ddyd ), b.x), b.y );

从return中可看到我们是先通过 fuv的x分量 将 ↙↘和↖↗分别融合,再通过y分量将上下两部分融合。所以ofb、ofc、ofd应分别对应该砖块位置的x+1、y+1、(x+1,y+1)

完整Shader

Shader "LZ/NoTile"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _BlendScale("BlendScale",Range(0,0.5))=0.25
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _BlendScale;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

             //制造随机
            float4 hash4( float2 p ) { return frac(sin  ( float4( 1.0+dot(p,float2(37.0,17.0)), 
                                                                 2.0+dot(p,float2(11.0,47.0)),
                                                                  3.0+dot(p,float2(41.0,29.0)),
                                                                  4.0+dot(p,float2(23.0,31.0))))*103.0); }

            float4 textureNoTile( sampler2D samp,  float2 uv )
            {
                //iuv得到该片元所在的砖块坐标 fuv该片元在此砖上的位置(常用)
                float2 iuv = floor( uv );   
                float2 fuv = frac( uv );

                // 制造随机4个随机因子,xy分量用来做位移、zw分量用来做横向、纵向的贴图翻转(固值区0-1之间)
                float4 ofa = hash4( iuv + float2(0.0,0.0) );
                float4 ofb = hash4( iuv + float2(1.0,0.0) );
                float4 ofc = hash4( iuv + float2(0.0,1.0) );
                float4 ofd = hash4( iuv + float2(1.0,1.0) );

                //ddx 和 ddy,分别对应 x, y 轴上,在屏幕空间中,像素块中各种变量的变化率。
                float2 dx = ddx( uv );
                float2 dy = ddy( uv );

                // 上面说zw分量为0-1之间的随机数,-0.5后用sign求随机的±
                ofa.zw = sign(ofa.zw-0.5);
                ofb.zw = sign(ofb.zw-0.5);
                ofc.zw = sign(ofc.zw-0.5);
                ofd.zw = sign(ofd.zw-0.5);
                
                //对uv改变+-再加偏移  对uv偏导数区±
                float2 uva = uv*ofa.zw + ofa.xy;     float2 ddxa = dx*ofa.zw;   float2 ddya = dy*ofa.zw;
                float2 uvb = uv*ofb.zw + ofb.xy;    float2 ddxb = dx*ofb.zw;    float2 ddyb = dy*ofb.zw;
                float2 uvc = uv*ofc.zw + ofc.xy;    float2 ddxc = dx*ofc.zw;   float2 ddyc = dy*ofc.zw;
                float2 uvd = uv*ofd.zw + ofd.xy;     float2 ddxd = dx*ofd.zw;   float2 ddyd = dy*ofd.zw;
                    
                // 设置手动调节的融合
                float2 b = smoothstep(_BlendScale,1-_BlendScale,fuv);
                //先通过 fuv的x分量 将 ↙↘和↖↗分别融合,再通过y分量将上下两部分融合。
                return lerp( lerp( tex2D( samp, uva, ddxa, ddya ), 
                                tex2D( samp, uvb, ddxb, ddyb ), b.x ), 
                            lerp( tex2D( samp, uvc, ddxc, ddyc ),
                                tex2D( samp, uvd, ddxd, ddyd ), b.x), b.y );
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = textureNoTile(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }
}

相关文章

  • 消除贴图重复感

    搬砖----解决贴图重复 参考自巨佬iq的文章,文章用两种方法消除了贴图重复问题。本文在unity里实现了第一种。...

  • 消除重复项

    题目:给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额...

  • 【MYSQL】统计分组中不重复的字段数量

    从结果集中消除重复记录 使用DISTINCT关键字即可从结果集中消除重复记录。 查询结果

  • C4D-REDSHIFT学习笔记(四十三)避免贴图重复

    本文介绍了如何避免克隆模型、大面积(地面)贴图重复的问题。

  • 如何优雅消除重复代码

    如何优雅消除重复代码 在消除重复代码之前,我们首先要考虑重复代码的特性是什么。有的同学会说,重复代码不就是一模一样...

  • 消除重复数字

    [华为编程题]消除重复数字 时间限制:3s 空间限制:32768K 题目描述:给定一个正整数,给出消除重复数字以后...

  • 消除重复元素

    问题描述 小易有一个长度为n序列,小易想移除掉里面的重复元素,但是小易想是对于每种元素保留最后出现的那个。小易遇到...

  • list消除重复数据

    面试官:有一个list,有很多重复数据,现在你手写一段代码,重复的数据只留一份。 我:(仔细想了几分钟)双重循环l...

  • 三、效果实现:4、基础效果之法线贴图

    使用法线贴图使得模型表面有一定的粗糙感,层次感。 效果图:

  • 平面设计师必备的800GB样机贴图模板!快来领取吧!

    800GB智能贴图模板包含以下文件 标志贴图模板 企业VI贴图模板 场景贴图模板 户外广告贴图模板 包装贴图模板 ...

网友评论

    本文标题:消除贴图重复感

    本文链接:https://www.haomeiwen.com/subject/yimglqtx.html