【问题标题】:Need average and max value of a texture in shader需要着色器中纹理的平均值和最大值
【发布时间】:2016-10-29 07:07:03
【问题描述】:

我有一个 RenderTexture,需要计算它的平均和最大像素值。 RenderTexture 是 RFloat 格式,所以只有一个组件。而且它现在不使用 mipmap。

【问题讨论】:

    标签: unity3d shader


    【解决方案1】:

    经过一番搜索,似乎最好的方法是减少纹理,这意味着运行一个着色器,它的输入是纹理大小,输出是输入大小的一半。我们可以采样 4 个相邻像素并从中计算最大值并将值写入输出。

        sampler2D _MainTex;
        float4 _MainTex_ST;
        float4 _MainTex_TexelSize;
    
        v2f vert(appdata v)
        {
            v2f o;
            o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
            o.uv = TRANSFORM_TEX(v.uv, _MainTex);
            return o;
        }
        float4 frag (v2f i) : SV_Target
        {
            float dx = _MainTex_TexelSize.x*0.5;
            float maximum = tex2D(_MainTex, i.uv + float2(-dx,-dx));
            maximum = max(maximum, tex2D(_MainTex, i.uv + float2(dx,-dx)));
            maximum = max(maximum, tex2D(_MainTex, i.uv + float2(-dx,dx)));
            maximum = max(maximum, tex2D(_MainTex, i.uv + float2(dx,dx)));
            return maximum;
        }
    

    下一次迭代获取上一次迭代的输出并写入一个渲染纹理,该渲染纹理是其输入的一半,意思是原始纹理的四分之一。所以尺寸像 1024,512,256,... 等等,直到 1 x 1 纹理,这给出了最大值。下面是一些显示 CPU 端的代码:

            private RenderTexture Reduce(RenderTexture diff, Material mat)
        {
            int reductions = POT.GetPowerFromNum(diff.width);
            var rtList = new List<RenderTexture>();
            int smallRes = diff.width/2;
            var bigRT = diff;
            for (int i = 0; i < reductions; i++)
            {
                var smallRT = RenderTexture.GetTemporary(smallRes, smallRes, 0, diff.format);
                rtList.Add(smallRT);
                GpuUtils.Blit(bigRT,smallRT,mat);
                bigRT = smallRT;
                smallRes >>= 1;
            }
            for (int i = 0; i < reductions-1; i++)
            {
                RenderTexture.ReleaseTemporary(rtList[i]);
            }
            return rtList[reductions-1];
        }
    

    这里diff是原始渲染纹理,GetPowerFromNum计算1024的2的幂,mat是shader的材质。

    对于平均而言,可以对平均着色器而不是 max 执行相同的操作,或者只是为渲染纹理启用 mipmap 并读取最高的 mipmap 级别。

    【讨论】:

    • 不知道是不是搞错了,还是我的知识不够深入,但是我把shader中的maximum的类型改成了float4...
    猜你喜欢
    • 2023-03-08
    • 2011-09-22
    • 1970-01-01
    • 2020-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    相关资源
    最近更新 更多