0. 前言
之前有在關(guān)注色盲視覺糾正問題,最近在調(diào)整游戲的時(shí)候就打算把這個(gè)用上。
色弱色盲,這其實(shí)算是一種誤稱吧,只是人類中的少數(shù)派,只不過看到的顏色和大部分人不一樣。下文用,視覺少數(shù)者,來稱呼吧。
本質(zhì)上是因?yàn)楦兄伾募?xì)胞發(fā)生突變,感知與大部分人有差異。之前就一直在想能不能有一些方法對顏色做一些調(diào)整作為糾正。比如說紅色感知弱,顯示的時(shí)候把紅強(qiáng)度提高作為彌補(bǔ)。但目前來說好像還沒有確切的方案來執(zhí)行,甚至色盲色弱的標(biāo)準(zhǔn)以及測試都不清楚,何談糾正呢。
主要是色覺其實(shí)是比較復(fù)雜的,人有3種感光細(xì)胞用于感知光線,然后感知之后再由大腦腦補(bǔ)一下出畫面。這其中的過程并不能夠簡單映射得出結(jié)果,比如同種顏色在不通顏色的比較下會感知不同。而且三種感光細(xì)胞還有一定的感光范圍,和RBG這種常用的顏色空間基準(zhǔn)還有偏差。所以這部分是比較難處理的。另外如果從小看到的火就是藍(lán)色的,那后面藍(lán)色這個(gè)顏色的意義也會發(fā)生改變,這個(gè)也難以統(tǒng)一。
1. 顏色矯正
顏色矯正是為了讓顏色更好區(qū)分,并不是開了之后就會讓視覺少數(shù)者感知到其他人一樣的顏色。處理還是有挺多種方法的。
- 顏色映射,紅色映射為某一種顏色,紫色映射為另一種等等,這種方法主要是映射空間難以確定,而且運(yùn)行比較復(fù)雜,一般只有對圖片做處理才會有這種方式。
- 旋轉(zhuǎn)H分量,在HSV空間縮放旋轉(zhuǎn)H分量的方式,這樣在色環(huán)上做的處理就可以讓顏色均勻,只不過旋轉(zhuǎn)角度難以確定、前后顏色差異比較大。
- 線性變換,RGB顏色做一個(gè)線性變換,這樣顏色可以做到均勻計(jì)算量也比較小。至于能否在線性空間內(nèi)找到合適的方法,或者因人而異的指定參數(shù)這個(gè)還是比較難確定。
基本上目前軟件上,基本都是用第三種做的矯正處理,目前window中就是用的這個(gè),所以后續(xù)講的也是如此,參數(shù)也是用window開糾正后的顏色,反向求解出來的,效果應(yīng)該還可以。對于應(yīng)用到游戲中、UnIty中,目前考慮的方法就是用寫一個(gè) 顏色線性變換Shader,確定好不同的顏色糾正參數(shù),然后在攝像機(jī)后處理的時(shí)候做統(tǒng)一的糾正處理。
2. 線性變換Shader
這里就簡單的寫一個(gè)RGB線性變換的shder,主要目的是讓顏色與給定的矩陣做叉乘,如下。
Shader "MyShader/ColorTr" {
Properties {
[PerRendererData] _MainTex ("Texture", 2D) = "white" {}
_UtR ("UtR",Vector)=(0.14,0.86,0,0)
_UtG ("UtG",Vector)=(0.14,0.86,0,0)
_UtB ("UtB",Vector)=(0,0,1,0)
}
SubShader {
Pass {
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
float4 _UtR;
float4 _UtG;
float4 _UtB;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
//float3 color : COLOR0;
};
struct v2f {
float4 pos : SV_POSITION;
float3 texcoord : COLOR0;
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.texcoord = v.texcoord;
return o;
}
fixed4 frag(v2f i) : SV_Target {
float4 color = tex2D(_MainTex, i.texcoord);
color.r = mul(_UtR,color);
color.g = mul(_UtG,color);
color.b = mul(_UtB,color);
return color;
}
ENDCG
}
}
FallBack Off
}
好了,那么后面我們只需要修改_UtR 等3個(gè)矩陣點(diǎn)的值,就可以調(diào)整顏色線性變換的結(jié)果了。
2. 顏色糾正參數(shù)
我們先定義下顏色糾正類型,常規(guī)/紅色/綠色/藍(lán)色,
public enum ColorMappingType
{
Normal,
Red,
Green,
Blue,
}
具體的參數(shù)怎么去確定呢,參考window的顏色變換,我們只要獲取到對應(yīng)的顏色變換對,就可以通通過矩陣求逆的方式來得到和這個(gè)參數(shù)了,如下。color為原顏色,colorF為映射得到的函數(shù)
private double[,] GetTranslateU(double[,] color, double[,] colorF)
{
double[,] colorAthwart = MatrixF.Athwart(color);
return MatrixF.MultiplyMatrix(colorF, colorAthwart);
}
// 矩陣運(yùn)算相關(guān)內(nèi)容是參考的這里
// https://blog.csdn.net/Lynn_whu/article/details/80745634
如果不用矩陣運(yùn)算也可以,假設(shè)原本的顏色為(R1,G1,B1),變換后的顏色為(R2, G2, B2),線性變換矩陣為((a,b,c),(d,e,f),(g,h,i)},那么這個(gè)線性變換其實(shí)就是如下的結(jié)果。3個(gè)方程式,只要找到顏色變換對,代入就可以求出這幾個(gè)參數(shù)了。(不過估計(jì)還挺難算的。)
R2 = a * R1 + b * G1 + c * B1
G2 = d * R1 + e * G1 + f * B1
B2 = g * R1 + h * G1 + i * B1
那么求逆矩然后再求解之后,可得參數(shù)如下:
// 紅色
new double[3,3]{
{1,0,0}, {0.47,0.49,0.04}, {0.59,-0.68,1.09},
},
// 綠色
new double[3,3]{
{1.22,-0.31,0.11}, {0,1,0}, {-0.18,0.17,1},
},
// 藍(lán)色
new double[3,3]{
{0.74,-0.39,0.66}, {0.08,0.59,0.33}, {0,0,1},
}
3. 攝像機(jī)后處理
場景等物體渲染后再做處理,用攝像機(jī)后處理來處理就很方便了。寫個(gè)腳本控制一下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace GDT
{
[RequireComponent(typeof(Camera))]
public class ColorMapping : MonoBehaviour
{
public Material materialMapping;
private double[][,] MappingUt;
private Material curMaterial;
private void Awake()
{
MappingUt = new double[3][,]{
// 紅色
new double[3,3]{
{1,0,0}, {0.47,0.49,0.04}, {0.59,-0.68,1.09},
},
// 綠色
new double[3,3]{
{1.22,-0.31,0.11}, {0,1,0}, {-0.18,0.17,1},
},
// 藍(lán)色
new double[3,3]{
{0.74,-0.39,0.66}, {0.08,0.59,0.33}, {0,0,1},
}
};
}
public void SetMaping(ColorMappingType type)
{
switch (type)
{
case ColorMappingType.Normal:
curMaterial = null;
break;
case ColorMappingType.Red:
ChangeShaderColorTraU(MappingUt[0]);
curMaterial = materialMapping;
break;
case ColorMappingType.Green:
ChangeShaderColorTraU(MappingUt[1]);
curMaterial = materialMapping;
break;
case ColorMappingType.Blue:
ChangeShaderColorTraU(MappingUt[2]);
curMaterial = materialMapping;
break;
}
}
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
//https://blog.csdn.net/qq_31042143/article/details/127186310
if (curMaterial)
{
Graphics.Blit(source, destination, curMaterial);
}
else
{
Graphics.Blit(source, destination);
}
// R2 = a * R1 + b * G1 + c * B1
// G2 = d * R1 + e * G1 + f * B1
// B2 = g * R1 + h * G1 + i * B1
}
private void ChangeShaderColorTraU(double[,] Ut)
{
//Debug.LogError("Ut:" + Ut);
materialMapping.SetVector("_UtR", new Vector4((float)Ut[0, 0], (float)Ut[0, 1], (float)Ut[0, 2], 0));
materialMapping.SetVector("_UtG", new Vector4((float)Ut[1, 0], (float)Ut[1, 1], (float)Ut[1, 2], 0));
materialMapping.SetVector("_UtB", new Vector4((float)Ut[2, 0], (float)Ut[2, 1], (float)Ut[2, 2], 0));
}
}
}
- [RequireComponent(typeof(Camera))]
因?yàn)樾枰M(jìn)行相機(jī)后處理,所以要求了一下組件類型 - SetMaping 設(shè)置顏色糾正方式
- OnRenderImage 進(jìn)行攝像機(jī)后處理
- ChangeShaderColorTraU 設(shè)置shader參數(shù)
然后把腳本掛到攝像機(jī)對象上就完成了。
4. 效果
效果還是比較明顯的,下面是參照顏色條,和window 上的變換一致。
實(shí)現(xiàn)還是挺簡單的,只需要掛在顯示的攝像機(jī)上就可以了,不會影響到其他shader的處理,場景和游戲?qū)ο蠖疾挥昧硗庾鎏幚怼?/p>
5. 結(jié)束咯
到這里就結(jié)束了。線性變換的參數(shù)還是有很大操作空間的,不僅可以用于視覺少數(shù)者糾正顏色,也可以用于做一些視覺特殊效果,比如說畫面變黃等濾鏡效果。只要綁定到特殊的攝像頭上,或者直接用于對應(yīng)物體的材質(zhì)上就可以了。文章來源:http://www.zghlxwxcb.cn/news/detail-605478.html
希望能夠提供參考組作用。文章來源地址http://www.zghlxwxcb.cn/news/detail-605478.html
到了這里,關(guān)于[游戲開發(fā)]Unity顏色矯正無障礙方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!