Skip to content

Instantly share code, notes, and snippets.

@partybusiness
Last active August 4, 2020 23:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save partybusiness/65e65deb14e5f5277588a229deaa7234 to your computer and use it in GitHub Desktop.
Save partybusiness/65e65deb14e5f5277588a229deaa7234 to your computer and use it in GitHub Desktop.
Visual contrast testing in Unity
//functions from here:
//http://www.chilliant.com/rgb2hsv.html
float3 HUEtoRGB(in float H)
{
float R = abs(H * 6 - 3) - 1;
float G = 2 - abs(H * 6 - 2);
float B = 2 - abs(H * 6 - 4);
return saturate(float3(R, G, B));
}
float Epsilon = 1e-10;
float3 RGBtoHCV(in float3 RGB)
{
// Based on work by Sam Hocevar and Emil Persson
float4 P = (RGB.g < RGB.b) ? float4(RGB.bg, -1.0, 2.0 / 3.0) : float4(RGB.gb, 0.0, -1.0 / 3.0);
float4 Q = (RGB.r < P.x) ? float4(P.xyw, RGB.r) : float4(RGB.r, P.yzx);
float C = Q.x - min(Q.w, Q.y);
float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z);
return float3(H, C, Q.x);
}
float3 HSVtoRGB(in float3 HSV)
{
float3 RGB = HUEtoRGB(HSV.x);
return ((RGB - 1) * HSV.y + 1) * HSV.z;
}
float3 HSLtoRGB(in float3 HSL)
{
float3 RGB = HUEtoRGB(HSL.x);
float C = (1 - abs(2 * HSL.z - 1)) * HSL.y;
return (RGB - 0.5) * C + HSL.z;
}
float3 RGBtoHSV(in float3 RGB)
{
float3 HCV = RGBtoHCV(RGB);
float S = HCV.y / (HCV.z + Epsilon);
return float3(HCV.x, S, HCV.z);
}
Shader "ContrastTest/ColourNoValue"
{
// used for testing games for visual contrast
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
ZWrite off
ZTest always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "ColourFunctions.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col.rg = RGBtoHSV(col.rgb).rg;
col.b = 0.5;
col.rgb = HSVtoRGB(col.rgb);
return col;
}
ENDCG
}
}
}
Shader "ContrastTest/EdgeDetection"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Threshold("Threshold", Range(0, 1)) = 0.1
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
ZWrite off
ZTest always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Threshold;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col.rgb = fwidth(col.rgb);
return col;
}
ENDCG
}
}
}
Shader "ContrastTest/HueOnly"
{
// used for testing games for visual contrast
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
ZWrite off
ZTest always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "ColourFunctions.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col.r = RGBtoHSV(col.rgb).r;
col.gb = 0.5;
col.rgb = HSVtoRGB(col.rgb);
return col;
}
ENDCG
}
}
}
Shader "ContrastTest/SaturationOnly"
{
// used for testing games for visual contrast
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
ZWrite off
ZTest always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "ColourFunctions.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col.g = RGBtoHSV(col.rgb).g;
col.rb = 0.5;
col.rgb = HSVtoRGB(col.rgb);
return col;
}
ENDCG
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ContrastTesting
{
public class TestContrast : MonoBehaviour
{
public enum TestType
{
normal, hueOnly, saturationOnly, valueOnly, colourNoValue,
}
//settings to change what contrast you're testing
public TestType testType;
public bool useThreshold;
public float threshold = 0.1f;
public bool edgeDetect;
/// materials used for post processing
private Material hueMaterial;
private Material saturationMaterial;
private Material valueMaterial;
private Material colourMaterial;
private Material thresholdMaterial;
private Material edgeMaterial;
// intermediate rendertextures
RenderTexture part2;
RenderTexture part3;
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (hueMaterial == null)
{
hueMaterial = new Material(Shader.Find("ContrastTest/HueOnly"));
saturationMaterial = new Material(Shader.Find("ContrastTest/SaturationOnly"));
valueMaterial = new Material(Shader.Find("ContrastTest/ValueOnly"));
colourMaterial = new Material(Shader.Find("ContrastTest/ColourNoValue"));
thresholdMaterial = new Material(Shader.Find("ContrastTest/Threshold"));
edgeMaterial = new Material(Shader.Find("ContrastTest/EdgeDetection"));
}
if (part2 == null || part2.dimension != source.dimension)
{
part2 = new RenderTexture(source);
part3 = new RenderTexture(source);
}
ColourType(source, part2);
Thresholding(part2, part3);
EdgeDetecting(part3, destination);
}
void Thresholding(RenderTexture source, RenderTexture destination)
{
if (useThreshold)
{
thresholdMaterial.SetFloat("_Threshold", threshold);
Graphics.Blit(source, destination, thresholdMaterial);
}
else
{
Graphics.Blit(source, destination);
}
}
void EdgeDetecting(RenderTexture source, RenderTexture destination)
{
if (edgeDetect)
{
Graphics.Blit(source, destination, edgeMaterial);
}
else
{
Graphics.Blit(source, destination);
}
}
void ColourType(RenderTexture source, RenderTexture destination)
{
switch (testType)
{
case TestType.hueOnly:
Graphics.Blit(source, destination, hueMaterial);
break;
case TestType.saturationOnly:
Graphics.Blit(source, destination, saturationMaterial);
break;
case TestType.valueOnly:
Graphics.Blit(source, destination, valueMaterial);
break;
case TestType.colourNoValue:
Graphics.Blit(source, destination, colourMaterial);
break;
default:
Graphics.Blit(source, destination);
break;
}
}
}
}
Shader "ContrastTest/Threshold"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Threshold("Threshold", Range(0.0, 1.0)) = 0.1
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
ZWrite off
ZTest always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Threshold;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col.rgb = col.rgb > _Threshold;
return col;
}
ENDCG
}
}
}
Shader "ContrastTest/ValueOnly"
{
// used for testing games for visual contrast
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
ZWrite off
ZTest always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "ColourFunctions.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col.b = RGBtoHSV(col.rgb).b;
col.rg = 0.0;
col.rgb = HSVtoRGB(col.rgb);
return col;
}
ENDCG
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment