【游戏开发】Unity使用ComputeShader实时压缩RT

2021-03-29
5433
0

compute shader最近突然变得异常火热,原神和UE开发者大会多次被人提到通过computershader对手机平台的优化。一方面得益于最近手机硬件的提升,对compute shader的支持和性能提升。另一方面,新出的游戏对于画面质量的要求越来越高,一些新特性,诸如:SSAO,屏幕空间反射,RVT,甚至GPU pipeline,对于compute shader的需求提高。

前不久,在unity实现了RVT,里边提到需要申请使用两种4k的RT,在手机上测试,发现性能还是有一定的损失。虽然,非RVT在使用四层纹理,总共需要9张地形相关的贴图(4*2 1,mask压缩到diffuse和normal),但是贴图的尺寸最多开到1024,一般就512就够了。而RVT需要两张4k的RT,并且RenderTexture是不能压缩的,也就是全展开的4k*2,在原本手机带宽就不够的情况下,这个算得上非常奢侈,非常影响效率。UE开发者大会,正好提到在4.26版本加入VT的压缩,正好可以拔过来,在Unity里实现了一下,用来支持RVT系统。

Compute Shader

UE4.26提供两种VT的压缩格式,BC3(PC)和ETC2(Android),并且ETC2的压缩算法看了一下,为了提升性能,做了很多精简。

我这里贴一下压缩的主体部分代码,具体压缩算法部分,可以在UE4.26preview的ETCCompressionCommon.ush和BCCompressionCommon.ush中。

#include "ETCCompress.hlsl"#include "BCCompress.hlsl"#pragma multi_compile _COMPRESS_BC3 _COMPRESS_ETC2#pragma kernel CSMain RWTexture2D < uint4 > Result;
Texture2D < float4 > RenderTexture0;
SamplerState samplerRenderTexture0;
uint4 DestRect; [numthreads(8, 8, 1)] void CSMain(uint3 ThreadId: SV_DispatchThreadID) {
    uint2 SamplePos = ThreadId.xy * 4;
    if (any(SamplePos >= DestRect.zw)) return;

    float2 TexelUVSize = 1.f / float2(DestRect.zw);
    float2 SampleUV = (float2(SamplePos) 0.5f) * TexelUVSize;

    float3 BlockBaseColor[16];
    ReadBlockRGB(RenderTexture0, samplerRenderTexture0, SampleUV, TexelUVSize, BlockBaseColor);

    float BlockA[16];
    for (int i = 0; i < 16; i ) {
        BlockA[i] = 1;
    }#ifdef _COMPRESS_ETC2 Result[ThreadId.xy] = CompressBlock_ETC2_RGBA(BlockBaseColor, BlockA);#
    else Result[ThreadId.xy] = CompressBC3Block_SRGB(BlockBaseColor, BlockA);#endif
}

他这里的ETC2直接写死的4x4block,然后分RGB和RGBA两种。

 

C#调用

实例代码中,比如我们想要压缩一张256x256的图片,我们需要申请一张64x64的R32G32B32A32_Uint的RT,在compute shader里填入数据。这个RT肯定不能直接当贴图使用,我们需要把数据拷贝到Texture2D中,Texture2D是可以设置压缩格式的。直接使用Graphics.CopyTexture整体拷贝数据,这里比较坑的地方是

这两句话居然不是同一个意思,一定要使用上面那样,下面这种会报错。

using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.UI;
public class ComputeShaderTest: MonoBehaviour {
    public ComputeShader shader;
    Material _mat;
    public Texture _mask;
    int kernelHandle;
    int[] DestRect;
    public RenderTexture tex;
    public Texture2D copyTex;
    public Text tt;

    GraphicsFormat format;
    void Awake() {
        DestRect = new int[4] {
            0,
            0,
            256,
            256
        };
    }
    void Start() {#
        if UNITY_ANDROID && !UNITY_EDITOR format = GraphicsFormat.RGBA_ETC2_UNorm;
        shader.DisableKeyword("_COMPRESS_BC3");
        shader.EnableKeyword("_COMPRESS_ETC2");#
        else format = GraphicsFormat.RGBA_DXT5_UNorm;
        shader.DisableKeyword("_COMPRESS_ETC2");
        shader.EnableKeyword("_COMPRESS_BC3");#endif kernelHandle = shader.FindKernel("CSMain");
        tex = new RenderTexture(64, 64, 24) {
            graphicsFormat = GraphicsFormat.R32G32B32A32_UInt,
            enableRandomWrite = true,
        };
        tex.Create();
        //tt.text = format.ToString() SystemInfo.IsFormatSupported(format, FormatUsage.Linear).ToString() SystemInfo.supportsComputeShaders SystemInfo.copyTextureSupport;
        shader.SetTexture(kernelHandle, "Result", tex);
        shader.SetTexture(kernelHandle, "RenderTexture0", _mask);
        shader.SetInts("DestRect", DestRect);
        shader.Dispatch(kernelHandle, (256 / 4 7) / 8, (256 / 4 7) / 8, 1);
        copyTex = new Texture2D(256, 256, format, TextureCreationFlags.None);
        Graphics.CopyTexture(tex, 0, 0, 0, 0, 64, 64, copyTex, 0, 0, 0, 0);
        _mat = GetComponent < MeshRenderer > ().sharedMaterial;
        _mat.mainTexture = copyTex;
    }
}

效果展示

在移动和PC都可以,vulkan的GraphicCopyTexture有bug,他做了foramt的判断,一样就直接返回,什么也不干,Unreal是没有这个判断的,Unreal甚至能处理block不一样的情况。有源码License的项目可以考虑修改那个返回地方,或者切换到GLES3,或者等Unity修复这个bug吧。

转载声明:本文来源于网络,不作任何商业用途

免责声明:本文内部分内容来自网络,所涉绘画作品及文字版权与著作权归原作者,若有侵权或异议请联系我们处理。
收藏

全部评论

您还没登录

暂无留言,赶紧抢占沙发
王氏教育是国内专业的CG数字艺术设计线上线下学习平台,在王氏教育,有原画、插画、漫画、影视、3D模型等培训课程,也有学习资源下载、行业社区交流。CG数字艺术学习,来王氏教育。
绘学霸iOS端二维码

IOS下载

绘学霸安卓端二维码

安卓下载

绘学霸微信小程序二维码

小程序

版权声明
本网站所有产品设计、功能及展示形式,均已受版权或产权保护,任何公司及个人不得以任何方式复制部分或全部,违者将依法追究责任,特此声明。
热线电话
18026259035
咨询时间:9:00~21:00
在线客服
联系网站客服
客服微信:18026259035
公司地址
中国·广州
广州市海珠区晓港中马路130号之19
绘学霸客户端(权限暂无,用于CG资源与教程交流分享)
王氏教育 王氏教育