본문으로 바로가기

ColorSuite.cs by Keijiro

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

출처 : https://github.com/keijiro/ColorSuite 


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
}

 

 

  • EncodeRGBM():
    → 큰 범위의 색을 RGBM 포맷으로 인코딩 (HDR 값을 LDR로 저장할 때 사용).
  • StandardIlluminantY():
    → 색온도에 따른 Y좌표를 계산 (표준 조명 모델 기반).
  • CIExyToLMS():
    → CIE xy 색공간을 LMS 색공간으로 변환 (화이트 밸런스 조정용 수학).

 

  • 시작 시 Setup() 호출.
  • OnValidate(), Reset() : Inspector 값이 수정되거나 리셋될 때 LUT 업데이트.
  • OnRenderImage(RenderTexture source, RenderTexture destination) : 카메라 렌더링 결과인 source를 가져와서 Shader를 적용하고 destination으로 넘기고, 각 기능별로 Shader 키워드를 설정하여 조건별로 다른 효과를 켜거나 끔.

 

반응형

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

Unity 5.5 texture option  (0) 2016.12.18
Unity Graphics hardware capabilities and emulation  (0) 2016.09.05
Unity sprite texture shader  (0) 2016.08.09
Unity Attribetes  (0) 2016.07.18
UE4 25 tips for Unreal Engine 4(2)  (0) 2016.07.10