Unity截屏或Render Texture渲染后的图片透明物体出错的问题及解决方法

本文探讨了Unity中透明物体截图出现错误的问题,分析了不同RenderingMode(Opaque, Transparent, Fade)下的混合模式差异。作者发现Fade模式由于其A通道的计算方式导致截图透明异常,并提供了Shader修改建议,以确保截图正确处理透明度。解决方案包括在Shader编写时针对Fade模式调整A通道的混合方式,或者在不透明材质中强制A通道为1。
摘要由CSDN通过智能技术生成

发现问题

  刚刚接触一个需要截屏分享的项目,但Unity那边一直反馈透明物体截图会错误,有透明物体的地方不管该物体后面有没有其他物体,截屏出来的图片都会变透明掉了。

寻找原因

  我使用的截屏方法如下:

    private IEnumerator ScreenShot()
    {
        yield return new WaitForEndOfFrame();
        Rect rect = new Rect(0, 0, (int)Screen.width, (int)Screen.height);
        Texture2D screenShot = new Texture2D((int)Screen.width, (int)Screen.height, TextureFormat.ARGB32, false);
        screenShot.ReadPixels(rect, 0, 0);
        screenShot.Apply();
        byte[] bytes = screenShot.EncodeToTGA();
        string filename = Application.dataPath + "/Screenshot.tga";
        System.IO.File.WriteAllBytes(filename, bytes);
        Debug.Log("截图成功了");
    }

  刚开始我以为是我的截屏方法出了问题,我百度了很多的截屏方法也是出现这个问题,也尝试了使用Unity的PackageManager自带的Recorder截屏也是出现这样的问题,那说明问题不是出在于截屏的方法,极有可能是shader的问题。
  最后尝试使用Unity默认的StandardShader,通过多次测试发现并不是所有的透明物体都会出现这个问题,Transparent显示是正常的,Fade显示是有问题的,自定义的shader一般都会出现问题。
  下面的这张图就是在Unity测试的,左边是在Unity的Game视图,右边是截屏保存下来的图

请添加图片描述
  通过对比发现,这三种RenderingMode的区别在于:
    Opaque是不透明混合(Blend One Zero)
    Transparent是预乘透明度混合(Blend One OneMinusSrcAlpha)
    Fade是传统透明度混合(Blend SrcAlpha OneMinusDstAlpha)

  这三种RenderingMode的意思见下表(可以参考我另一篇文章"【Unity Shader入门】6、Blend-混合",里面有详细的介绍)

  假设该材质的颜色为RmGmBmAm 屏幕颜色为RsGsBsAs

RenderingModeBlend最终输出
OpaqueBlend One ZerooutColor = RmGmBmAm
TransparentBlend One OneMinusSrcAlphaoutColor = RmGmBmAm + RsGsBsAs * (1 - Am)
FadeBlend SrcAlpha OneMinusDstAlphaoutColor = RmGmBmAm * Am + RsGsBsAs * (1 - Am)

  那为什么Transparent显示是正常的,Fade显示是有问题的呢?
  原来,通过上面的公式可以算出:
    Transparent的模式下,输出的A通道值 outColor_A = Am + As * (1 - Am),假如原来屏幕的颜色A值是1的话,那 outColor_A = 1;其实不难发现,这个就是PS的不透明度叠加的A通道的算法,所以就会显示正常了
    Fade的模式下,输出的A通道值 outColor_A = Am * Am + As * (1 - Am),假如原来屏幕的颜色A值是1的话,那 outColor_A = Am * Am + (1 - Am) ;很明显,如果材质的A通道小于1,则outColor_A也会小于1,所以就会导致出现A通道错误的效果。

其实Transparent模式就是PS的不透明度叠加的A通道的算法;Fade模式就是PS的不透明度叠加的RGB通道的算法

如果知道是这个问题就容易解决了

解决问题

  在写shader的时候就得注意一下,如果是直接使用Transparent模式的话截图是没问题的;如果使用Fade模式的话A通道的不透明度混合需要单独区分开来

Shader "Unlit/BlendTest"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Pass
        {
            //这是Fade模式的,Blend SrcAlpha OneMinusDstAlpha
            Blend SrcAlpha OneMinusDstAlpha,One OneMinusSrcAlpha
            //这是Transparent模式的,是没问题的,Blend One OneMinusSrcAlpha
            //Blend One OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
            };
            struct v2f
            {
                float4 vertex : SV_POSITION;
            };
            uniform float4 _Color;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = _Color;
                return col;
            }
            ENDCG
        }
    }
}

  那问题来了,如果是不透明材质(关闭混合),材质的A通道又被调了不是1呢?
  这样的话屏幕的A通道值就会被该材质的A通道值直接替换,所以截出来的图片还是会变透明的,但是Unity默认的shader没有这个问题,看一下Unity内置的shader的源码就不难发现:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
  如果不开启_ALPHABLEND_ON和_ALPHAPREMULTIPLY_ON,则输出的A通道强制为1,这样截屏就不会出现问题了。
  所以我们在写shader的时候也可以这样实现,如果是不透明shader,则强制A通道输出为1。

Unity是一款非常流行的游戏开发引擎,它可以用来制作各种类型的游戏和应用程序。在Unity中,截图更新是指在游戏运行时动态更新游戏画面的截图,并且能够在截图上添加一些信息或者签名。 在Unity中,我们可以使用RenderTexture来实现截图的功能。RenderTexture是一个可以将场景渲染到纹理的组件。我们可以创建一个新的RenderTexture,并将其绑定到一个相机上,然后在游戏运行时,通过调用相机的Render方法,将相机的视角渲染RenderTexture中。接着,我们可以使用Texture2D的ReadPixels方法,将RenderTexture中的像素数据读取出来,并保存为一张图片。 要截取透明图片并签字,我们可以在RenderTexture渲染之前,将相机的背景色设置为透明色,这样在截图时场景中的透明部分就会被保存下来。然后,我们可以通过调用Texture2D的SetPixel方法,在截图的指定位置上绘制我们想要的签字或者其他信息。最后,调用Texture2D的Apply方法,将修改后的纹理数据应用到截图上。 通过这种方法,我们就可以实现在Unity中截图更新和截取透明图片并签字的功能了。这种功能在游戏开发中常常用于制作截图分享功能,让玩家可以将游戏中的画面分享到社交媒体或者朋友圈。同时,也可以用于一些需要对图片进行加工处理,并添加个人标识的应用场景。总的来说,Unity提供的截图更新和截取透明图片签字的功能非常强大和灵活,可以满足各种图形处理需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值