UnityMol  0.9.6-875
UnityMol viewer / In developement
ContrastStretch.cs
Go to the documentation of this file.
1 using System;
2 using UnityEngine;
3 
4 namespace UnityStandardAssets.ImageEffects
5 {
6  [ExecuteInEditMode]
7  [AddComponentMenu("Image Effects/Color Adjustments/Contrast Stretch")]
8  public class ContrastStretch : MonoBehaviour
9  {
12  [Range(0.0001f, 1.0f)]
13  public float adaptationSpeed = 0.02f;
14 
19 
21  [Range(0.0f,1.0f)]
22  public float limitMinimum = 0.2f;
23 
25  [Range(0.0f, 1.0f)]
26  public float limitMaximum = 0.6f;
27 
28 
29  // To maintain adaptation levels over time, we need two 1x1 render textures
30  // and ping-pong between them.
31  private RenderTexture[] adaptRenderTex = new RenderTexture[2];
32  private int curAdaptIndex = 0;
33 
34 
35  // Computes scene luminance (grayscale) image
36  public Shader shaderLum;
37  private Material m_materialLum;
38  protected Material materialLum {
39  get {
40  if ( m_materialLum == null ) {
41  m_materialLum = new Material(shaderLum);
42  m_materialLum.hideFlags = HideFlags.HideAndDontSave;
43  }
44  return m_materialLum;
45  }
46  }
47 
48  // Reduces size of the image by 2x2, while computing maximum/minimum values.
49  // By repeatedly applying this shader, we reduce the initial luminance image
50  // to 1x1 image with minimum/maximum luminances found.
51  public Shader shaderReduce;
52  private Material m_materialReduce;
53  protected Material materialReduce {
54  get {
55  if ( m_materialReduce == null ) {
56  m_materialReduce = new Material(shaderReduce);
57  m_materialReduce.hideFlags = HideFlags.HideAndDontSave;
58  }
59  return m_materialReduce;
60  }
61  }
62 
63  // Adaptation shader - gradually "adapts" minimum/maximum luminances,
64  // based on currently adapted 1x1 image and the actual 1x1 image of the current scene.
65  public Shader shaderAdapt;
66  private Material m_materialAdapt;
67  protected Material materialAdapt {
68  get {
69  if ( m_materialAdapt == null ) {
70  m_materialAdapt = new Material(shaderAdapt);
71  m_materialAdapt.hideFlags = HideFlags.HideAndDontSave;
72  }
73  return m_materialAdapt;
74  }
75  }
76 
77  // Final pass - stretches the color values of the original scene, based on currently
78  // adpated minimum/maximum values.
79  public Shader shaderApply;
80  private Material m_materialApply;
81  protected Material materialApply {
82  get {
83  if ( m_materialApply == null ) {
84  m_materialApply = new Material(shaderApply);
85  m_materialApply.hideFlags = HideFlags.HideAndDontSave;
86  }
87  return m_materialApply;
88  }
89  }
90 
91  void Start()
92  {
93  // Disable if we don't support image effects
94  if (!SystemInfo.supportsImageEffects) {
95  enabled = false;
96  return;
97  }
98 
99  if (!shaderAdapt.isSupported || !shaderApply.isSupported || !shaderLum.isSupported || !shaderReduce.isSupported) {
100  enabled = false;
101  return;
102  }
103  }
104 
105  void OnEnable()
106  {
107  for( int i = 0; i < 2; ++i )
108  {
109  if ( !adaptRenderTex[i] ) {
110  adaptRenderTex[i] = new RenderTexture(1, 1, 0);
111  adaptRenderTex[i].hideFlags = HideFlags.HideAndDontSave;
112  }
113  }
114  }
115 
116  void OnDisable()
117  {
118  for( int i = 0; i < 2; ++i )
119  {
120  DestroyImmediate( adaptRenderTex[i] );
121  adaptRenderTex[i] = null;
122  }
123  if ( m_materialLum )
124  DestroyImmediate( m_materialLum );
125  if ( m_materialReduce )
126  DestroyImmediate( m_materialReduce );
127  if ( m_materialAdapt )
128  DestroyImmediate( m_materialAdapt );
129  if ( m_materialApply )
130  DestroyImmediate( m_materialApply );
131  }
132 
133 
135  void OnRenderImage (RenderTexture source, RenderTexture destination)
136  {
137  // Blit to smaller RT and convert to luminance on the way
138  const int TEMP_RATIO = 1; // 4x4 smaller
139  RenderTexture rtTempSrc = RenderTexture.GetTemporary(source.width/TEMP_RATIO, source.height/TEMP_RATIO);
140  Graphics.Blit (source, rtTempSrc, materialLum);
141 
142  // Repeatedly reduce this image in size, computing min/max luminance values
143  // In the end we'll have 1x1 image with min/max luminances found.
144  const int FINAL_SIZE = 1;
145  //const int FINAL_SIZE = 1;
146  while( rtTempSrc.width > FINAL_SIZE || rtTempSrc.height > FINAL_SIZE )
147  {
148  const int REDUCE_RATIO = 2; // our shader does 2x2 reduction
149  int destW = rtTempSrc.width / REDUCE_RATIO;
150  if ( destW < FINAL_SIZE ) destW = FINAL_SIZE;
151  int destH = rtTempSrc.height / REDUCE_RATIO;
152  if ( destH < FINAL_SIZE ) destH = FINAL_SIZE;
153  RenderTexture rtTempDst = RenderTexture.GetTemporary(destW,destH);
154  Graphics.Blit (rtTempSrc, rtTempDst, materialReduce);
155 
156  // Release old src temporary, and make new temporary the source
157  RenderTexture.ReleaseTemporary( rtTempSrc );
158  rtTempSrc = rtTempDst;
159  }
160 
161  // Update viewer's adaptation level
162  CalculateAdaptation( rtTempSrc );
163 
164  // Apply contrast strech to the original scene, using currently adapted parameters
165  materialApply.SetTexture("_AdaptTex", adaptRenderTex[curAdaptIndex] );
166  Graphics.Blit (source, destination, materialApply);
167 
168  RenderTexture.ReleaseTemporary( rtTempSrc );
169  }
170 
171 
173  private void CalculateAdaptation( Texture curTexture )
174  {
175  int prevAdaptIndex = curAdaptIndex;
176  curAdaptIndex = (curAdaptIndex+1) % 2;
177 
178  // Adaptation speed is expressed in percents/frame, based on 30FPS.
179  // Calculate the adaptation lerp, based on current FPS.
180  float adaptLerp = 1.0f - Mathf.Pow( 1.0f - adaptationSpeed, 30.0f * Time.deltaTime );
181  const float kMinAdaptLerp = 0.01f;
182  adaptLerp = Mathf.Clamp( adaptLerp, kMinAdaptLerp, 1 );
183 
184  materialAdapt.SetTexture("_CurTex", curTexture );
185  materialAdapt.SetVector("_AdaptParams", new Vector4(
186  adaptLerp,
187  limitMinimum,
188  limitMaximum,
189  0.0f
190  ));
191  // clear destination RT so its contents don't need to be restored
192  Graphics.SetRenderTarget(adaptRenderTex[curAdaptIndex]);
193  GL.Clear(false, true, Color.black);
194  Graphics.Blit (
195  adaptRenderTex[prevAdaptIndex],
196  adaptRenderTex[curAdaptIndex],
197  materialAdapt);
198  }
199  }
200 }
void CalculateAdaptation(Texture curTexture)
Helper function to do gradual adaptation to min/max luminances.
void OnRenderImage(RenderTexture source, RenderTexture destination)
Apply the filter.