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     {

10         ///
Adaptation speed - percents per frame, if playing at 30FPS.
11         ///
Default is 0.02 (2% each 1/30s).
12         
public float adaptationSpeed = 0.02f;
13
14         ///
If our scene is really dark (or really bright), we might not want to
15         ///
stretch its contrast to the full range.
16         ///
limitMinimum=0, limitMaximum=1 is the same as not applying the effect at all.
17         ///
limitMinimum=1, limitMaximum=0 is always stretching colors to full range.
18
19         ///
The limit on the minimum luminance (0...1) - we won't go above this.
20         
public float limitMinimum = 0.2f;
21
22         ///
The limit on the maximum luminance (0...1) - we won't go below this.
23         
public float limitMaximum = 0.6f;
24
25
26         
// To maintain adaptation levels over time, we need two 1x1 render textures
27         
// and ping-pong between them.
28         
private RenderTexture[] adaptRenderTex = new RenderTexture[2];
29         
private int curAdaptIndex = 0;
30
31
32         
// Computes scene luminance (grayscale) image
33         
public Shader shaderLum;
34         
private Material m_materialLum;
35         
protected Material materialLum {
36             
get {
37                 
if ( m_materialLum == null ) {
38                     m_materialLum =
new Material(shaderLum);
39                     m_materialLum.hideFlags = HideFlags.HideAndDontSave;
40                 }
41                 
return m_materialLum;
42             }
43         }
44
45         
// Reduces size of the image by 2x2, while computing maximum/minimum values.
46         
// By repeatedly applying this shader, we reduce the initial luminance image
47         
// to 1x1 image with minimum/maximum luminances found.
48         
public Shader shaderReduce;
49         
private Material m_materialReduce;
50         
protected Material materialReduce {
51             
get {
52                 
if ( m_materialReduce == null ) {
53                     m_materialReduce =
new Material(shaderReduce);
54                     m_materialReduce.hideFlags = HideFlags.HideAndDontSave;
55                 }
56                 
return m_materialReduce;
57             }
58         }
59
60         
// Adaptation shader - gradually "adapts" minimum/maximum luminances,
61         
// based on currently adapted 1x1 image and the actual 1x1 image of the current scene.
62         
public Shader shaderAdapt;
63         
private Material m_materialAdapt;
64         
protected Material materialAdapt {
65             
get {
66                 
if ( m_materialAdapt == null ) {
67                     m_materialAdapt =
new Material(shaderAdapt);
68                     m_materialAdapt.hideFlags = HideFlags.HideAndDontSave;
69                 }
70                 
return m_materialAdapt;
71             }
72         }
73
74         
// Final pass - stretches the color values of the original scene, based on currently
75         
// adpated minimum/maximum values.
76         
public Shader shaderApply;
77         
private Material m_materialApply;
78         
protected Material materialApply {
79             
get {
80                 
if ( m_materialApply == null ) {
81                     m_materialApply =
new Material(shaderApply);
82                     m_materialApply.hideFlags = HideFlags.HideAndDontSave;
83                 }
84                 
return m_materialApply;
85             }
86         }
87
88         
void Start()
89         {
90             
// Disable if we don't support image effects
91             
if (!SystemInfo.supportsImageEffects) {
92                 enabled =
false;
93                 
return;
94             }
95
96             
if (!shaderAdapt.isSupported || !shaderApply.isSupported || !shaderLum.isSupported || !shaderReduce.isSupported) {
97                 enabled =
false;
98                 
return;
99             }
100         }
101
102         
void OnEnable()
103         {
104             
for( int i = 0; i < 2; ++i )
105             {
106                 
if ( !adaptRenderTex[i] ) {
107                     adaptRenderTex[i] =
new RenderTexture(1, 1, 0);
108                     adaptRenderTex[i].hideFlags = HideFlags.HideAndDontSave;
109                 }
110             }
111         }
112
113         
void OnDisable()
114         {
115             
for( int i = 0; i < 2; ++i )
116             {
117                 DestroyImmediate( adaptRenderTex[i] );
118                 adaptRenderTex[i] =
null;
119             }
120             
if ( m_materialLum )
121                 DestroyImmediate( m_materialLum );
122             
if ( m_materialReduce )
123                 DestroyImmediate( m_materialReduce );
124             
if ( m_materialAdapt )
125                 DestroyImmediate( m_materialAdapt );
126             
if ( m_materialApply )
127                 DestroyImmediate( m_materialApply );
128         }

129
130
131         ///
Apply the filter
132         
void OnRenderImage (RenderTexture source, RenderTexture destination)
133         {
134             
// Blit to smaller RT and convert to luminance on the way
135             
const int TEMP_RATIO = 1; // 4x4 smaller
136             RenderTexture rtTempSrc = RenderTexture.GetTemporary(source.width/TEMP_RATIO, source.height/TEMP_RATIO);
137             Graphics.Blit (source, rtTempSrc, materialLum);
138
139             
// Repeatedly reduce this image in size, computing min/max luminance values
140             
// In the end we'll have 1x1 image with min/max luminances found.
141             
const int FINAL_SIZE = 1;
142             
//const int FINAL_SIZE = 1;
143             
while( rtTempSrc.width > FINAL_SIZE || rtTempSrc.height > FINAL_SIZE )
144             {
145                 
const int REDUCE_RATIO = 2; // our shader does 2x2 reduction
146                 
int destW = rtTempSrc.width / REDUCE_RATIO;
147                 
if ( destW < FINAL_SIZE ) destW = FINAL_SIZE;
148                 
int destH = rtTempSrc.height / REDUCE_RATIO;
149                 
if ( destH < FINAL_SIZE ) destH = FINAL_SIZE;
150                 RenderTexture rtTempDst = RenderTexture.GetTemporary(destW,destH);
151                 Graphics.Blit (rtTempSrc, rtTempDst, materialReduce);
152
153                 
// Release old src temporary, and make new temporary the source
154                 RenderTexture.ReleaseTemporary( rtTempSrc );
155                 rtTempSrc = rtTempDst;
156             }
157
158             
// Update viewer's adaptation level
159             CalculateAdaptation( rtTempSrc );
160
161             
// Apply contrast strech to the original scene, using currently adapted parameters
162             materialApply.SetTexture(
"_AdaptTex", adaptRenderTex[curAdaptIndex] );
163             Graphics.Blit (source, destination, materialApply);
164
165             RenderTexture.ReleaseTemporary( rtTempSrc );
166         }

167
168
169         ///
Helper function to do gradual adaptation to min/max luminances
170         
private void CalculateAdaptation( Texture curTexture )
171         {
172             
int prevAdaptIndex = curAdaptIndex;
173             curAdaptIndex = (curAdaptIndex+
1) % 2;
174
175             
// Adaptation speed is expressed in percents/frame, based on 30FPS.
176             
// Calculate the adaptation lerp, based on current FPS.
177             
float adaptLerp = 1.0f - Mathf.Pow( 1.0f - adaptationSpeed, 30.0f * Time.deltaTime );
178             
const float kMinAdaptLerp = 0.01f;
179             adaptLerp = Mathf.Clamp( adaptLerp, kMinAdaptLerp,
1 );
180
181             materialAdapt.SetTexture(
"_CurTex", curTexture );
182             materialAdapt.SetVector(
"_AdaptParams", new Vector4(
183                                                         adaptLerp,
184                                                         limitMinimum,
185                                                         limitMaximum,
186                                                         
0.0f
187                                                         ));
188             
// clear destination RT so its contents don't need to be restored
189             Graphics.SetRenderTarget(adaptRenderTex[curAdaptIndex]);
190             GL.Clear(
false, true, Color.black);
191             Graphics.Blit (
192                 adaptRenderTex[prevAdaptIndex],
193                 adaptRenderTex[curAdaptIndex],
194                 materialAdapt);
195         }
196     }
197 }


Adaptation speed - percents per frame, if playing at 30FPS.

Default is 0.02 (2% each 130s).

If our scene is really dark (or really bright), we might not want to

stretch its contrast to the full range.

limitMinimum=0, limitMaximum=1 is the same as not applying the effect at all.

limitMinimum=1, limitMaximum=0 is always stretching colors to full range.

The limit on the minimum luminance (0...1) - we won't go above this.

The limit on the maximum luminance (0...1) - we won't go below this.

To maintain adaptation levels over time, we need two 1x1 render textures

and ping-pong between them.

Computes scene luminance (grayscale) image

Reduces size of the image by 2x2, while computing maximumminimum values.

By repeatedly applying this shader, we reduce the initial luminance image

to 1x1 image with minimummaximum luminances found.

Adaptation shader - gradually "adapts" minimummaximum luminances,

based on currently adapted 1x1 image and the actual 1x1 image of the current scene.

Final pass - stretches the color values of the original scene, based on currently

adpated minimummaximum values.

Disable if we don't support image effects

Apply the filter

Blit to smaller RT and convert to luminance on the way

const int TEMP_RATIO = 1; 4x4 smaller

Repeatedly reduce this image in size, computing minmax luminance values

In the end we'll have 1x1 image with minmax luminances found.

const int FINAL_SIZE = 1;

const int REDUCE_RATIO = 2; our shader does 2x2 reduction

Release old src temporary, and make new temporary the source

Update viewer's adaptation level

Apply contrast strech to the original scene, using currently adapted parameters

Helper function to do gradual adaptation to minmax luminances

Adaptation speed is expressed in percentsframe, based on 30FPS.

Calculate the adaptation lerp, based on current FPS.

clear destination RT so its contents don't need to be restored



Gõ tìm kiếm nhanh...