Unity Shader的Color Property存在的精度问题以及修改方案

背景

有时候我们希望将某个color转化为一个texture。这个时候我们会使用Graphic.DrawMesh将颜色转化为RenderTexture
但Unity Shader的Color属性精度非常低,传入0.005这样平平无奇的float数值,最后存储在texture里面的也可能由于精度问题变为0
本篇文章将会对不同的精度设置进行测试,查看并对比返回的像素值。

正文

准备

下面给出渲染texture使用的 C#代码 以及 对应的Shader代码。

private static void RenderCore(RenderTexture targetTexture, Material material)
{
  renderCamera.targetTexture = targetTexture;
  Graphics.DrawMesh(blitQuad, Vector3.zero, Quaternion.identity, material, SF_PreviewWindow.Layer_INT, renderCamera);
  renderCamera.Render();
  renderCamera.targetTexture = null;
}

Shader "Hidden/Shader Forge/FillColor" {
    Properties {
       //[HDR] _Color ("Color", Color) = (1,1,1,1)
        _Color ("Color", Color) = (1,1,1,1)
    }
    SubShader {
        Tags {
            "RenderType"="Opaque"
        }
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #define UNITY_PASS_FORWARDBASE
            #include "UnityCG.cginc"
            #pragma target 3.0
            uniform float4 _Color;

            struct VertexInput {
                float4 vertex : POSITION;
                float2 texcoord0 : TEXCOORD0;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.uv = v.texcoord0;
                o.pos = UnityObjectToClipPos(v.vertex );
                return o;
            }
            float4 frag(VertexOutput i) : COLOR {
                return _Color;
            }
            ENDCG
        }
    }
}

接着我们可以使用下面的代码,将RenderTexture转化为Texture2D,并检验像素的值。

    var texture = PreviewTexture.ToTexture2D();

    var color = texture.GetPixel(0, 0);
    Debug.Log($"RenderPreviewTexture Node={TypeName4UI} pixel={color}");
    Texture2D.DestroyImmediate(texture);

准备工作完成后,我们将对不同的精度设置,测试GetPixel返回的像素的值。

精度测试

Color Property

首先就是上文代码对应的Color(ARGB32)精度,每个channel为8bit,传入0.005,返回的值是0

[HDR] Color Property

接着,我们对Color Property添加 [HDR] 前缀。 传入0.005,返回的值为0.004

Vector Property

我们将 Color Property 改成 Vector Property。 得出的结果和 [HDR] Color Property 相同。

[HDR] Color Property 并且设置相机 allowHDR,texture的format设置为RGBAFloat

RenderTexture rt = new RenderTexture(256, 256, 0 , RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear );
_renderCamera.allowHDR = true;
var texture = PreviewTexture.ToTexture2D(TextureFormat.RGBAFloat);

如果我们基于 [HDR] Color Property, 将用于渲染的camera设置为允许HDR,并将读取像素的Texture2D也设置为一个channel 有32bit的RGBAFloat格式。
基本上 传入什么值,返回的也是那个值。

参考

https://discussions.unity.com/t/get-high-precision-output-from-shader/679345

posted @ 2025-07-16 01:05  dewxin  阅读(46)  评论(0)    收藏  举报