Unity与Photoshop图片透明度差异:颜色空间原理与解决方案
1. 项目概述:一个困扰无数开发者的“视觉陷阱”
最近在项目里又踩了个坑,一个UI界面上的半透明按钮,在Photoshop里设计的时候,那个淡淡的、柔和的叠加效果堪称完美。结果一导入Unity,好家伙,颜色要么深得像蒙了一层灰,要么浅得几乎看不见,透明度完全对不上。美术同学拿着设计稿过来“对质”,程序这边调试得焦头烂额,最后发现,这根本不是谁做错了,而是Unity和Photoshop这两个“世界”的底层规则——颜色空间——压根就不一样。
这问题太常见了,常见到几乎每个涉及UI和视觉效果的Unity项目都会遇到。它不只是“看起来有点不同”那么简单,它会直接导致最终产品与设计稿严重偏离,影响用户体验,更会在团队协作中引发大量的沟通和返工成本。你可能会尝试去调整材质的Alpha值,或者怀疑是不是图片导出格式出了问题,但往往治标不治本。
今天,我们就来彻底拆解这个“Unity与PS看到的图片透明度不一致”的问题。这不仅仅是一个技术笔记,更是一份从原理到实操的排坑指南。无论你是刚入行的TA(技术美术),还是负责界面整合的前端开发,甚至是需要与程序紧密协作的UI设计师,理解背后的原因并掌握正确的应对方法,都能让你的工作流程顺畅十倍。核心关键词就三个:Unity、PS (Photoshop)、图片透明度。接下来,我们会深入颜色空间这个“幕后黑手”,看看它是如何“扭曲”我们的视觉效果的,并给出在不同工作流下的终极解决方案。
2. 核心元凶解析:线性空间与伽马空间的根本差异
为什么同一张带透明通道的PNG图片,在两个软件里看起来天差地别?一切的根源在于它们处理颜色计算的方式不同,也就是颜色空间(Color Space)的差异。Photoshop(默认情况下)和旧版Unity通常工作在伽马空间(Gamma Space),而现代Unity项目为了获得更真实的物理光照效果,强烈推荐并默认使用线性空间(Linear Space)。这两种空间对颜色的编码、存储和计算逻辑完全不同。
2.1 伽马空间:显示器的“历史包袱”
伽马空间的存在,其实是为了“将错就错”。早期的CRT显示器其亮度响应不是线性的,输入电压增加一倍,亮度增加并不是一倍,而是遵循一个大约为2.2的幂次曲线(即伽马值约为2.2)。为了让图像在这些显示器上看起来“正常”,图像数据在存储时就被预先进行了一个相反的操作(应用了约0.45的伽马校正,即1/2.2),把数据“压暗”一些。这样,当显示器用它的2.2曲线“提亮”后,最终人眼看到的才是线性的、正确的亮度。Photoshop作为图像处理软件,其默认的“颜色设置”和工作流程都是基于这个历史惯例,它显示和处理的颜色值,是已经经过伽马编码的。
举个例子,在伽马空间中,一个RGB值为(0.5, 0.5, 0.5)的中灰色,其物理亮度并不是0.5。因为0.5是经过编码的值,实际的物理亮度大约是0.5 ^ 2.2 ≈ 0.22。所有的颜色混合、透明度计算都是在这种“扭曲”的数值上直接进行的,这并不符合真实世界光线叠加的物理规律。
2.2 线性空间:物理正确的计算方式
线性空间则追求物理准确性。在这个空间里,颜色的数值直接对应物理光线的强度。RGB值0.5就代表0.5的亮度。颜色的混合(比如半透明叠加)也按照真实的物理公式进行:结果颜色 = 背景色 * (1 - Alpha) + 前景色 * Alpha。现代图形API(如OpenGL ES 3.0, Metal, Vulkan)和渲染管线(如Unity URP/HDRP)都在内部使用线性空间进行计算,以确保光照、阴影、反射等效果的物理正确性。
当Unity项目设置为线性空间时,引擎期望你输入的纹理颜色是线性的。但问题来了:我们从Photoshop导出的图片,99%都是伽马编码的。Unity在采样这些纹理时,如果知道它是“非颜色数据”(如法线贴图),或者你在导入设置中正确配置了,它会自动进行一次“去伽马校正”(sRGB to Linear),将颜色值转换到线性空间进行计算。计算完毕后,输出到屏幕前,再做一次“伽马校正”(Linear to sRGB),以适应显示器的特性。
2.3 冲突的根源:混合发生的位置
透明度不一致的症结,就在于颜色混合发生的位置。
- 在Photoshop(伽马空间)中:你看到的是两个已经伽马编码的颜色,在伽马空间直接进行混合后的结果,然后直接显示。
- 在Unity(线性空间)中:流程是:伽马编码的纹理 -> 转换到线性空间 -> 在线性空间进行物理正确的混合 -> 转换回伽马空间用于显示。
关键在于,半透明混合(Alpha Blending)这个操作必须在线性空间做才是正确的。如果你把两个在伽马空间下混合好的颜色,直接拿到线性空间下显示,或者反过来,结果必然错误。这就好比一个数学题,Photoshop用的公式是(a^2 + b^2),而Unity用的公式是(a+b)^2,你把前者的结果直接代入后者的环境,答案肯定对不上。
注意:这里最常见的误解是去调整个别UI元素的Shader或材质球。在没理解颜色空间的前提下,这些调整都是盲目的。你必须首先确定整个项目所处的颜色空间,这是解决问题的第一步。
3. 问题诊断与Unity项目设置核查
在开始动手修复之前,我们必须先明确自己项目的“战场环境”。盲目操作只会让问题更混乱。
3.1 确认Unity项目的颜色空间
打开Unity,进入Edit -> Project Settings -> Player。在Other Settings部分,找到Rendering下的Color Space选项。
- Gamma:如果你的项目选择的是这个,那么理论上,Unity和Photoshop都在伽马空间工作,透明度不一致的问题应该不明显或不存在。但通常不建议新项目使用此选项,因为它无法支持先进的渲染效果。
- Linear:这是现代Unity项目的推荐设置,也是导致与PS视觉差异的“元凶”所在。我们接下来的所有解决方案,都基于项目颜色空间为Linear这一前提。
请务必先确认你的项目设置。这是所有后续操作的基石。
3.2 检查纹理的导入设置
即使项目是线性空间,Unity也提供了机制让纹理正确工作。选中你从PS导出后导入Unity的图片文件(通常是PNG),在Inspector面板查看其导入设置。
关键参数是Texture Type下的sRGB (Color Texture)选项。
- 勾选sRGB:告诉Unity这张纹理是颜色纹理,其颜色值是经过伽马编码的。Unity在采样时会自动将其转换到线性空间进行计算。这对于绝大多数UI贴图、角色贴图、场景贴图都是正确的设置。
- 不勾选sRGB:告诉Unity这张纹理中的数据已经是线性值(如法线贴图、金属度贴图、粗糙度贴图等)。Unity会直接使用,不做转换。
对于UI图片,必须确保 sRGB (Color Texture) 被勾选。如果这里错了,颜色从一开始就乱套了。
3.3 分析具体的视觉差异现象
根据颜色空间不匹配的具体情况,视觉差异通常表现为两种:
- 在Unity中看起来更暗、更脏:这通常是因为一张本应被当作sRGB处理的图片(如UI元素),被错误地在线性空间下直接混合了,导致中间调颜色变暗。
- 在Unity中看起来更亮、更淡:这种情况可能发生在你为了“匹配PS”而盲目提高图片的Alpha值或亮度后,叠加效果过于苍白。
记录下你的具体现象,有助于在后续方案中选择正确的路径。一个简单的测试方法是:在Unity中创建一个纯白色(#FFFFFF)背景,和一个纯黑色(#000000)半透明(Alpha=0.5)的前景UI图片。在线性空间下正确渲染的结果,应该是一个准确的50%灰色(#808080)。如果你看到的不是这个灰色,那就证实了问题的存在。
4. 解决方案一:在Photoshop端修正(设计源头把控)
这是从源头解决问题的方法,理念是“让Photoshop模拟线性空间下的混合效果”,这样导出的图片,在Unity线性空间下查看就能直接匹配。
4.1 使用“视图校样”模拟线性空间
Photoshop自身提供了强大的色彩管理功能。我们可以创建一个模拟线性空间显示的“校样设置”。
- 新建校样配置:在Photoshop中,点击视图 -> 校样设置 -> 自定义。
- 关键配置:
- 要模拟的设备:选择sRGB IEC61966-2.1(这是最常见的标准)。
- 保留RGB颜色:不要勾选。这个选项的意思是“不进行颜色转换”,我们需要的是模拟效果,所以必须让PS进行转换计算。
- 渲染方法:选择相对比色或可感知均可,通常“相对比色”更注重色准。
- 黑场补偿:建议勾选,能更好地保持暗部细节。
- 模拟纸张颜色/模拟黑色油墨:都不要勾选。我们模拟的是屏幕显示,不是打印。
- 保存并应用:给这个配置起个名字,比如“Unity Linear View”。然后勾选视图 -> 校样颜色(快捷键
Ctrl+Y/Cmd+Y)。
当你开启“校样颜色”后,画布显示的颜色就是经过模拟转换后的效果。此时,你在这个视图下设计的半透明叠加、图层混合模式,其视觉效果会非常接近在Unity线性空间中的表现。在这个视图下完成UI设计并截图对比,是最高效的方法。
4.2 为UI元素创建专用的线性工作文档
对于重要的、需要精确颜色匹配的UI项目,可以更进一步,直接在线性色彩空间下工作。
- 新建文档时设置:点击文件 -> 新建,在高级选项中,将颜色配置文件从默认的“工作中的RGB: sRGB IEC61966-2.1”改为“显示器RGB”。注意,“显示器RGB”这个配置因系统而异,它可能并不是线性的。更可靠的方法是:
- 载入线性ICC配置文件:你可以从网上下载或自己创建一个代表线性sRGB的ICC配置文件(一个简单的线性Gamma 1.0的sRGB描述文件)。在新建文档时,在“颜色配置文件”中选择“其他”,然后载入这个线性ICC文件。
- 工作流程改变:在这种线性文档中工作,你使用的所有颜色值(如
#808080)直接对应线性亮度。但需要注意的是,Photoshop的很多滤镜、笔刷和调整工具其算法可能是为伽马空间优化的,在线性空间下使用可能得到意想不到的结果。因此,这种方法更适合最终合成和效果确认,而不是全流程设计。
实操心得:对于大多数团队,我强烈推荐4.1 使用“视图校样”的方法。它非侵入性,设计师可以在熟悉的sRGB空间下创作,只需要在最终检查叠加效果时按一下
Ctrl+Y切换视图即可。这能最大程度减少对现有设计流程的冲击。
5. 解决方案二:在Unity端修正(程序渲染适配)
如果无法要求所有设计师都改变工作习惯,或者需要处理大量遗留资源,那么在Unity渲染层面进行修正就是我们的责任。核心思路是:让UI的混合计算,在正确的空间进行。
5.1 理解Unity UI(uGUI)与Sprite的渲染
Unity的默认UI系统(uGUI)使用Canvas和Graphic组件(如Image)。这些UI元素默认使用的Shader是内置的UI/Default。这个Shader是颜色空间感知的。当项目颜色空间为Linear时,它会自动处理sRGB纹理到线性的转换,并在最终输出前转换回去。理论上,只要你的UI图片导入设置正确(sRGB勾选),使用默认UI Shader,半透明混合就应该是正确的。
那为什么还会出问题?常见陷阱有:
- 自定义Shader:如果你为UI元素使用了自定义Shader,并且没有正确处理颜色空间转换,问题就会出现。
- 混合模式(Blend Mode):在某些自定义Shader中,错误的混合方程(如
Blend SrcAlpha OneMinusSrcAlpha)虽然公式正确,但如果输入的颜色值不在同一空间,结果也是错的。 - Render Texture:如果UI被渲染到一张Render Texture,然后这张Render Texture又被作为纹理使用,你需要确保Render Texture的sRGB设置与你的使用场景匹配。
5.2 编写一个简单的线性混合UI Shader
当你确实需要自定义UI效果,并且发现颜色不对时,最稳妥的方式是重写一个正确处理颜色空间的Shader。下面是一个极其简单的、仅实现透明混合的UI Shader示例,它明确了颜色空间的转换:
Shader "Custom/LinearBlendUI" { Properties { [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} _Color ("Tint", Color) = (1,1,1,1) // 其他属性... } SubShader { Tags { "Queue"="Transparent" "RenderType"="Transparent" } Blend SrcAlpha OneMinusSrcAlpha ZWrite Off Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata_t { float4 vertex : POSITION; float2 texcoord : TEXCOORD0; float4 color : COLOR; }; struct v2f { float4 vertex : SV_POSITION; float2 texcoord : TEXCOORD0; float4 color : COLOR; }; sampler2D _MainTex; float4 _MainTex_ST; fixed4 _Color; v2f vert (appdata_t v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); o.color = v.color; return o; } fixed4 frag (v2f i) : SV_Target { // 1. 采样纹理,并应用顶点颜色tint fixed4 col = tex2D(_MainTex, i.texcoord) * i.color * _Color; // 关键步骤:如果项目是线性空间,且纹理标记为sRGB, // UnityCG.cginc中的 `tex2D` 宏会自动进行 sRGB -> Linear 转换。 // 我们得到的 `col.rgb` 现在在线性空间。 // 2. 所有颜色计算(这里只是简单的纹理采样)在线性空间完成。 // 3. 在输出前,使用 UnityCG.cginc 中的 GammaToLinearSpace 或 LinearToGammaSpace 是错误的。 // 因为UI Shader的输出目标通常是sRGB的后缓冲。 // Unity的渲染管线会在最终写入屏幕前,对整个帧缓冲区进行 Linear -> sRGB 转换(如果平台需要)。 // 对于大多数现代平台(支持sRGB回读),我们需要明确告诉Unity我们的输出是线性值。 // 更简单的做法:依赖Unity的自动转换。确保纹理设置正确,这个简单的Shader通常就能工作。 // 一个更显式的、确保正确的输出处理(针对不支持sRGB自动转换的旧平台或特殊路径): #ifndef UNITY_COLORSPACE_GAMMA // 如果我们在线性空间项目下 col.rgb = LinearToGammaSpace(col.rgb); #endif return col; } ENDCG } } }关键解释:
tex2D宏在Linear项目下会自动转换sRGB纹理到线性空间。这是前提。- 我们在片段着色器末尾,手动将线性颜色转换回伽马空间(
LinearToGammaSpace)。这是因为旧版本的Unity或者某些渲染路径下,对UI层的输出可能不会自动做最后的转换。但请注意,在现代Unity版本和标准UI渲染中,这可能不是必须的,甚至会导致双次转换而变亮。最好的方法是先不加这行代码测试,如果颜色偏暗,再加上这行;如果颜色偏亮,则去掉。 - 更推荐的做法是直接使用Unity内置的
UnityCG.cginc和UnityUI.cginc,它们封装了这些复杂的处理。上述Shader主要用于理解原理。
5.3 使用后处理或Command Buffer进行全局校正(不推荐用于UI)
这是一种比较“重”的方法,通过一个全屏后处理效果,对UI层(或整个屏幕)的颜色进行一个伽马校正。这通常用于处理大量无法修改的遗留资源,但会引入额外的性能开销,并且可能影响非UI元素的颜色。对于纯粹的UI透明度问题,这属于杀鸡用牛刀,不推荐作为首选方案。
6. 解决方案三:工作流与资产管理最佳实践
除了技术上的修正,建立规范的工作流可以从根本上减少问题。
6.1 建立团队资源规范
- 颜色空间统一告知:项目启动时,技术负责人必须明确告知美术和设计团队,本项目Unity端使用的是Linear Color Space。并提供简单的对比图或说明,展示Gamma和Linear下透明效果的差异。
- Photoshop视图校样流程:要求UI设计师在检查图层叠加、半透明效果时,必须开启“校样颜色”(使用我们之前创建的“Unity Linear View”配置)。并将此状态下的截图作为效果确认依据。
- 纹理导出设置:确保从Photoshop导出PNG时,不要勾选“转换为sRGB”(如果选项存在)。导出的图片应保持其原有的色彩数据。在Unity中通过导入设置的
sRGB选项来控制转换。 - Unity导入设置预设:在Unity中为不同类型的图片(UI、图标、特效贴图)创建Import Settings Preset。确保UI类图片的预设中
sRGB (Color Texture)为勾选状态。美术人员导入资源后,直接应用对应的预设即可。
6.2 利用Unity Asset Postprocessor自动化
对于大型项目,可以编写一个简单的AssetPostprocessor脚本,自动为特定目录下的纹理资源配置导入设置。
using UnityEngine; using UnityEditor; public class UITextureImportProcessor : AssetPostprocessor { void OnPreprocessTexture() { // 只处理指定目录下的纹理,例如 "Assets/Art/UI/" if (assetPath.Contains("Assets/Art/UI/")) { TextureImporter importer = (TextureImporter)assetImporter; // 设置为Sprite(2D and UI)类型,并勾选sRGB importer.textureType = TextureImporterType.Sprite; importer.sRGBTexture = true; // 关键:颜色纹理启用sRGB转换 // 其他优化设置,如关闭Mipmaps,设置Max Size等 importer.mipmapEnabled = false; importer.maxTextureSize = 2048; // 设置压缩格式为UI常用的高质量格式 importer.SetPlatformTextureSettings(new TextureImporterPlatformSettings { name = "Standalone", overridden = true, format = TextureImporterFormat.RGBA32, // 对于UI,RGBA32无压缩能保证最佳质量 maxTextureSize = 2048 }); } } }将这个脚本放在项目的Editor文件夹下。这样,任何放入Assets/Art/UI/目录的图片,在导入时都会自动被配置为正确的格式,极大减少了手动配置的遗漏和错误。
6.3 设计-开发核对清单
在UI界面交付集成时,建立一个简单的核对流程:
- 设计端:在Photoshop“校样颜色”视图下,对关键半透明元素(按钮、面板、光效)截图,并标注色值(RGB和Alpha)。
- 开发端:在Unity中,确保项目为Linear空间,纹理导入设置正确。在相同的纯色背景(如#FFFFFF白或#000000黑)下,运行游戏或Scene视图,对同一UI元素截图。
- 对比工具:使用专业的像素对比工具(如Beyond Compare的图片比较模式),或者简单地将两张截图在Photoshop中上下图层叠加,设置差值混合模式来查看差异。允许存在极细微的像素级差异(由于抗锯齿、渲染精度不同),但整体色块和通透感应基本一致。
7. 常见问题排查与实战技巧实录
即使理解了原理,实操中还是会遇到各种古怪问题。下面是我踩过坑后总结的一些典型场景和解决方法。
7.1 问题速查表
| 现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 所有UI颜色都偏暗、发灰 | 1. 项目颜色空间为Linear,但UI Shader未处理颜色空间转换。 2. 纹理导入设置中, sRGB (Color Texture)未勾选。 | 1. 检查Player Settings中的Color Space,确认为Linear。 2. 检查UI纹理的导入设置,确保 sRGB已勾选。3. 如果使用自定义Shader,检查其片段着色器输出前是否进行了正确的Linear->Gamma转换(或依赖了正确的Unity内置宏)。 |
| 半透明叠加区域比PS中更淡、更苍白 | 1. 为了匹配PS效果,在Unity中过度提高了图片Alpha值或颜色亮度。 2. 可能错误地在Shader中进行了两次Linear->Gamma转换。 | 1. 恢复图片原始的Alpha和颜色值。 2. 在Photoshop中开启“校样颜色”视图重新评估设计。 3. 检查自定义Shader,移除可能多余的 LinearToGammaSpace调用。 |
| 只有部分UI元素颜色不对 | 1. 这些元素使用了特殊的自定义Shader或Material。 2. 这些元素是动态生成的(如代码设置颜色),设置的颜色值是在Gamma空间下选取的。 | 1. 检查问题材质的Shader,对比其与标准UI Shader的差异。 2. 在代码中设置颜色时,如果颜色值来自Gamma空间(如从PS取色),可能需要使用 Color.gamma属性(这是一个线性空间下的近似转换,但非精确)或更精确的颜色空间转换函数。更佳实践是:在Unity的Color Picker中取色,因为它会根据项目颜色空间显示正确的颜色。 |
| 在编辑器Scene视图正常,Game视图或打包后不正常 | 1. 不同视图的渲染路径或色彩空间设置可能不同(极少见)。 2. 平台差异(如Android/iOS的sRGB支持)。 3. 使用了Render Texture,其格式未考虑sRGB。 | 1. 检查Game视图的显示设置,确保与Scene视图一致。 2. 检查目标平台的Player Settings,确认Color Space设置正确且平台支持。 3. 如果使用了Render Texture,检查其创建时的 sRGB设置(RenderTexture.sRGB),确保其与使用场景匹配。通常用于UI离屏渲染时,需要设为true。 |
| 带粒子特效的UI透明度不对 | 粒子系统使用的纹理和Shader可能未正确处理颜色空间。 | 1. 检查粒子纹理的导入设置(sRGB)。 2. 检查粒子材质使用的Shader。对于Additive等混合模式,颜色空间错误会导致叠加效果异常。尝试使用Unity内置的 Particles/Standard Unlit等Shader,它们通常已做好适配。 |
7.2 实战调试技巧
- 使用Frame Debugger:Unity的Frame Debugger是神器。在Game视图下打开Window -> Analysis -> Frame Debugger。逐步执行渲染命令,选中绘制你问题UI元素的Draw Call,查看其使用的Shader、材质属性、纹理和渲染状态。可以直观地看到输入的颜色值和最终输出的颜色值。
- 简化测试场景:创建一个最简场景:一个Canvas,一个白色背景Image,一个半透明黑色前景Image。屏蔽所有后处理、灯光、其他UI效果。在这个纯净环境下验证颜色是否正确。如果正确,再逐步添加你项目中的复杂因素(自定义Shader、特效、Post Processing等),定位引入问题的环节。
- 检查平台差异:在Unity编辑器中,通过
Edit -> Project Settings -> Player -> Other Settings -> Color Space,你可以看到不同平台(如PC、Android、iOS)的颜色空间设置是独立的。确保你测试和发布的平台设置一致。特别是移动平台,要确认其Graphics API支持线性空间(如OpenGL ES 3.0及以上,Metal, Vulkan)。 - 留意HDR和Tonemapping:如果你的项目使用了HDR和色调映射(Tonemapping),这会在颜色空间转换之外,进一步改变颜色的表现。UI通常渲染在Tonemapping之后(在URP/HDRP中注意UI Renderer的Render Order),但需要确认UI渲染是否受到了HDR范围的影响。确保UI摄像机的HDR设置与主摄像机协调。
7.3 一个典型的排查案例
场景:一个半透明的蓝色(#0066FF, Alpha=0.6)通知面板,在PS校样视图下覆盖在白色背景上效果柔和。在Unity中,面板看起来浑浊、颜色发暗。
排查步骤:
- 确认基础设置:项目Color Space = Linear。纹理
sRGB已勾选。UI使用默认UI/Default材质。问题依旧。 - 检查父级Canvas:发现该面板在一个有
Canvas Group的父物体下,且Canvas Group的Alpha值被代码动态设置为0.8。陷阱出现:Canvas Group的Alpha会与子物体Image的Alpha进行叠加,并且这种叠加是在颜色计算之后进行的吗?实际上,Canvas Group的Alpha会影响整个组件的顶点颜色Alpha,最终混合计算是综合的。但关键在于,这个叠加计算是否发生在正确的颜色空间?Unity内置UI组件的混合计算是处理正确的。 - 简化测试:移除
Canvas Group,直接设置Image的Color为(#0066FF, Alpha=0.6)。在Unity中观察,颜色仍然偏暗。 - 检查Color值:在Inspector中查看Image的Color属性。发现我手动输入的
#0066FF这个值,是从PS的伽马空间取色得到的。在Unity的Linear空间下,Color Picker显示这个蓝色看起来更亮一些。根本原因:我输入了一个伽马空间下的颜色值,但Unity在线性空间下将其当作线性值使用,导致颜色变暗。 - 解决方案:在Unity的Color Picker中,重新选取颜色。或者,如果必须使用PS的色值,可以尝试在代码中设置颜色时进行一个近似的转换(
color = new Color(Mathf.LinearToGammaSpace(r), Mathf.LinearToGammaSpace(g), Mathf.LinearToGammaSpace(b), a);但注意这个转换是针对将线性值转为伽马显示值,我们的情况需要反函数GammaToLinearSpace)。最稳妥的办法永远是:在Unity的Color Picker里,在线性空间的项目环境下,用你的眼睛选取匹配的颜色。
这个案例告诉我们,问题可能层层嵌套。从项目设置、资源导入、Shader、到运行时代码设置的颜色值,任何一个环节在颜色空间上出错,都会导致最终结果不符。建立系统性的检查和规范,是避免此类问题的唯一途径。