본문으로 바로가기

ColorSuite Keijiro

category Technical Report/Unity Scripts 2016. 8. 29. 00:50
반응형


스크립트 코드

ColorSuite.cs




using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
[ImageEffectTransformsToLDR]
[RequireComponent(typeof(Camera))]
[AddComponentMenu("Image Effects/Color Adjustments/Color Suite")]
public class ColorSuite : MonoBehaviour
{
#region Public Properties

// White balance.
[SerializeField] float _colorTemp = 0.0f;
[SerializeField] float _colorTint = 0.0f;

public float colorTemp {
get { return _colorTemp; }
set { _colorTemp = value; }
}
public float colorTint {
get { return _colorTint; }
set { _colorTint = value; }
}

// Tone mapping.
[SerializeField] bool _toneMapping = false;
[SerializeField] float _exposure = 1.0f;

public bool toneMapping {
get { return _toneMapping; }
set { _toneMapping = value; }
}
public float exposure {
get { return _exposure; }
set { _exposure = value; }
}

// Color saturation.
[SerializeField] float _saturation = 1.0f;

public float saturation {
get { return _saturation; }
set { _saturation = value; }
}

// Curves.
[SerializeField] AnimationCurve _rCurve = AnimationCurve.Linear(0, 0, 1, 1);
[SerializeField] AnimationCurve _gCurve = AnimationCurve.Linear(0, 0, 1, 1);
[SerializeField] AnimationCurve _bCurve = AnimationCurve.Linear(0, 0, 1, 1);
[SerializeField] AnimationCurve _cCurve = AnimationCurve.Linear(0, 0, 1, 1);

public AnimationCurve redCurve {
get { return _rCurve; }
set { _rCurve = value; UpdateLUT(); }
}
public AnimationCurve greenCurve {
get { return _gCurve; }
set { _gCurve = value; UpdateLUT(); }
}
public AnimationCurve blueCurve {
get { return _bCurve; }
set { _bCurve = value; UpdateLUT(); }
}
public AnimationCurve rgbCurve {
get { return _cCurve; }
set { _cCurve = value; UpdateLUT(); }
}

// Dithering.
public enum DitherMode { Off, Ordered, Triangular }
[SerializeField] DitherMode _ditherMode = DitherMode.Off;

public DitherMode ditherMode {
get { return _ditherMode; }
set { _ditherMode = value; }
}

#endregion

#region Internal Properties

// Reference to the shader.
[SerializeField] Shader shader;

// Temporary objects.
Material _material;
Texture2D _lutTexture;

#endregion

#region Local Functions

// RGBM encoding.
static Color EncodeRGBM(float r, float g, float b)
{
var a = Mathf.Max(Mathf.Max(r, g), Mathf.Max(b, 1e-6f));
a = Mathf.Ceil(a * 255) / 255;
return new Color(r / a, g / a, b / a, a);
}

// An analytical model of chromaticity of the standard illuminant, by Judd et al.
// http://en.wikipedia.org/wiki/Standard_illuminant#Illuminant_series_D
// Slightly modifed to adjust it with the D65 white point (x=0.31271, y=0.32902).
static float StandardIlluminantY(float x)
{
return 2.87f * x - 3.0f * x * x - 0.27509507f;
}

// CIE xy chromaticity to CAT02 LMS.
// http://en.wikipedia.org/wiki/LMS_color_space#CAT02
static Vector3 CIExyToLMS(float x, float y)
{
var Y = 1.0f;
var X = Y * x / y;
var Z = Y * (1.0f - x - y) / y;

var L = 0.7328f * X + 0.4296f * Y - 0.1624f * Z;
var M = -0.7036f * X + 1.6975f * Y + 0.0061f * Z;
var S = 0.0030f * X + 0.0136f * Y + 0.9834f * Z;

return new Vector3(L, M, S);
}

#endregion

#region Private Methods

// Set up the temporary assets.
void Setup()
{
if (_material == null)
{
_material = new Material(shader);
_material.hideFlags = HideFlags.DontSave;
}

if (_lutTexture == null)
{
_lutTexture = new Texture2D(512, 1, TextureFormat.ARGB32, false, true);
_lutTexture.hideFlags = HideFlags.DontSave;
_lutTexture.wrapMode = TextureWrapMode.Clamp;
UpdateLUT();
}
}

// Update the LUT texture.
void UpdateLUT()
{
for (var x = 0; x < _lutTexture.width; x++)
{
var u = 1.0f / (_lutTexture.width - 1) * x;
var r = _cCurve.Evaluate(_rCurve.Evaluate(u));
var g = _cCurve.Evaluate(_gCurve.Evaluate(u));
var b = _cCurve.Evaluate(_bCurve.Evaluate(u));
_lutTexture.SetPixel(x, 0, EncodeRGBM(r, g, b));
}
_lutTexture.Apply();
}

// Calculate the color balance coefficients.
Vector3 CalculateColorBalance()
{
// Get the CIE xy chromaticity of the reference white point.
// Note: 0.31271 = x value on the D65 white point
var x = 0.31271f - _colorTemp * (_colorTemp < 0.0f ? 0.1f : 0.05f);
var y = StandardIlluminantY(x) + _colorTint * 0.05f;

// Calculate the coefficients in the LMS space.
var w1 = new Vector3(0.949237f, 1.03542f, 1.08728f); // D65 white point
var w2 = CIExyToLMS(x, y);
return new Vector3(w1.x / w2.x, w1.y / w2.y, w1.z / w2.z);
}

#endregion

#region Monobehaviour Functions

void Start()
{
Setup();
}

void OnValidate()
{
Setup();
UpdateLUT();
}

void Reset()
{
Setup();
UpdateLUT();
}

void OnRenderImage(RenderTexture source, RenderTexture destination)
{
var linear = QualitySettings.activeColorSpace == ColorSpace.Linear;

Setup();

if (linear)
_material.EnableKeyword("COLORSPACE_LINEAR");
else
_material.DisableKeyword("COLORSPACE_LINEAR");

if (_colorTemp != 0.0f || _colorTint != 0.0f)
{
_material.EnableKeyword("BALANCING_ON");
_material.SetVector("_Balance", CalculateColorBalance());
}
else
_material.DisableKeyword("BALANCING_ON");

if (_toneMapping && linear)
{
_material.EnableKeyword("TONEMAPPING_ON");
_material.SetFloat("_Exposure", _exposure);
}
else
_material.DisableKeyword("TONEMAPPING_ON");

_material.SetTexture("_Curves", _lutTexture);
_material.SetFloat("_Saturation", _saturation);

if (_ditherMode == DitherMode.Ordered)
{
_material.EnableKeyword("DITHER_ORDERED");
_material.DisableKeyword("DITHER_TRIANGULAR");
}
else if (_ditherMode == DitherMode.Triangular)
{
_material.DisableKeyword("DITHER_ORDERED");
_material.EnableKeyword("DITHER_TRIANGULAR");
}
else
{
_material.DisableKeyword("DITHER_ORDERED");
_material.DisableKeyword("DITHER_TRIANGULAR");
}

Graphics.Blit(source, destination, _material);
}

#endregion
}







// 셰이더 코드

Shader "Hidden/ColorSuite"
{
Properties
{
_MainTex ("-", 2D) = ""{}
_Curves ("-", 2D) = ""{}
_Exposure ("-", Float) = 1.0
_Saturation ("-", Float) = 1.0
_Balance ("-", Vector) = (1, 1, 1, 0)
}

CGINCLUDE

// Multi-compilation options.
#pragma multi_compile COLORSPACE_SRGB COLORSPACE_LINEAR
#pragma multi_compile BALANCING_OFF BALANCING_ON
#pragma multi_compile TONEMAPPING_OFF TONEMAPPING_ON
#pragma multi_compile DITHER_OFF DITHER_ORDERED DITHER_TRIANGULAR

#include "UnityCG.cginc"

sampler2D _MainTex;
float2 _MainTex_TexelSize;
sampler2D _Curves;
float _Exposure;
float _Saturation;
float4 _Balance;

#if COLORSPACE_LINEAR

// Color space conversion between sRGB and linear space.
// http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html

float3 srgb_to_linear(float3 c)
{
return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);
}

float3 linear_to_srgb(float3 c)
{
return max(1.055 * pow(c, 0.416666667) - 0.055, 0.0);
}

#endif

#if BALANCING_ON

// Color space conversion between linear RGB and LMS
// based on the CIECAM02 model (CAT02).
// http://en.wikipedia.org/wiki/LMS_color_space#CAT02

float3 lrgb_to_lms(float3 c)
{
float3x3 m = {
3.90405e-1f, 5.49941e-1f, 8.92632e-3f,
7.08416e-2f, 9.63172e-1f, 1.35775e-3f,
2.31082e-2f, 1.28021e-1f, 9.36245e-1f
};
return mul(m, c);
}

float3 lms_to_lrgb(float3 c)
{
float3x3 m = {
2.85847e+0f, -1.62879e+0f, -2.48910e-2f,
-2.10182e-1f, 1.15820e+0f, 3.24281e-4f,
-4.18120e-2f, -1.18169e-1f, 1.06867e+0f
};
return mul(m, c);
}

// Color balance function.
// - The gamma compression/expansion equation used in this function
// differs from the standard sRGB-Linear conversion.

float3 apply_balance(float3 c)
{
#if !COLORSPACE_LINEAR
// Do the gamma expansion before applying the color balance.
c = pow(c, 2.2);
#endif

// Apply the color balance in the LMS color space.
c = lms_to_lrgb(lrgb_to_lms(c) * _Balance);

// It may return a minus value, which should be cropped out.
c = max(c, 0.0);

#if !COLORSPACE_LINEAR
// Gamma compression.
c = pow(c, 1.0 / 2.2);
#endif

return c;
}

#endif

#if TONEMAPPING_ON

// John Hable's filmic tone mapping operator.
// http://filmicgames.com/archives/6

float3 hable_op(float3 c)
{
float A = 0.15;
float B = 0.50;
float C = 0.10;
float D = 0.20;
float E = 0.02;
float F = 0.30;
return ((c * (c * A + B * C) + D * E) / (c * (c * A + B) + D * F)) - E / F;
}

float3 tone_mapping(float3 c)
{
c *= _Exposure * 4;
c = hable_op(c) / hable_op(11.2);
return pow(c, 1 / 2.2);
}

#endif

// Color saturation.

float luma(float3 c)
{
return 0.212 * c.r + 0.701 * c.g + 0.087 * c.b;
}

float3 apply_saturation(float3 c)
{
return lerp((float3)luma(c), c, _Saturation);
}

// RGB curves.

float3 apply_curves(float3 c)
{
float4 r = tex2D(_Curves, float2(c.r, 0));
float4 g = tex2D(_Curves, float2(c.g, 0));
float4 b = tex2D(_Curves, float2(c.b, 0));
return float3(r.r * r.a, g.g * g.a, b.b * b.a);
}

#if DITHER_ORDERED

// Interleaved gradient function from CoD AW.
// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare

float interleaved_gradient(float2 uv)
{
float3 magic = float3(0.06711056, 0.00583715, 52.9829189);
return frac(magic.z * frac(dot(uv, magic.xy)));
}

float3 dither(float2 uv)
{
return (float3)(interleaved_gradient(uv / _MainTex_TexelSize) / 255);
}

#endif

#if DITHER_TRIANGULAR

// Triangular PDF.

float nrand(float2 uv)
{
return frac(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453);
}

float3 dither(float2 uv)
{
float r = nrand(uv) + nrand(uv + (float2)1.1) - 0.5;
return (float3)(r / 255);
}

#endif

float4 frag(v2f_img i) : SV_Target
{
float4 source = tex2D(_MainTex, i.uv);
float3 rgb = source.rgb;

#if BALANCING_ON
rgb = apply_balance(rgb);
#endif

#if COLORSPACE_LINEAR
#if TONEMAPPING_ON
// Apply the tone mapping.
rgb = tone_mapping(rgb);
#else
// Convert the color into the sRGB color space.
rgb = linear_to_srgb(rgb);
#endif
#endif

// Color saturation.
rgb = apply_saturation(rgb);

// RGB curves.
rgb = apply_curves(rgb);

#if !DITHER_OFF
rgb += dither(i.uv);
#endif

#if COLORSPACE_LINEAR
// Take the color back into the linear color space.
rgb = srgb_to_linear(rgb);
#endif

return float4(rgb, source.a);
}

ENDCG

Subshader
{
Pass
{
ZTest Always Cull Off ZWrite Off
Fog { Mode off }
CGPROGRAM
#pragma target 3.0
#pragma glsl
#pragma vertex vert_img
#pragma fragment frag
ENDCG
}
}


반응형

'Technical Report > Unity Scripts' 카테고리의 다른 글

Texture2D.Encode  (0) 2017.08.17
Unity FPSCounter  (0) 2017.07.26
Unity Attribute API  (0) 2017.07.26
Unity Shader Property API  (0) 2017.07.25
Unity Attribetes  (0) 2016.07.18