@@ -89,6 +89,15 @@ struct CurvesSettings
8989 CurveEditor m_CurveEditor ;
9090 Dictionary < SerializedProperty , Color > m_CurveDict ;
9191
92+ // Neutral tonemapping curve helper
93+ const int k_CurveResolution = 24 ;
94+ const float k_NeutralRangeX = 2f ;
95+ const float k_NeutralRangeY = 1f ;
96+ Vector3 [ ] m_RectVertices = new Vector3 [ 4 ] ;
97+ Vector3 [ ] m_LineVertices = new Vector3 [ 2 ] ;
98+ Vector3 [ ] m_CurveVertices = new Vector3 [ k_CurveResolution ] ;
99+ Rect m_NeutralCurveRect ;
100+
92101 public override void OnEnable ( )
93102 {
94103 // Tonemapping settings
@@ -214,6 +223,8 @@ void DoTonemappingGUI()
214223
215224 if ( tid == ( int ) Tonemapper . Neutral )
216225 {
226+ DrawNeutralTonemappingCurve ( ) ;
227+
217228 EditorGUILayout . PropertyField ( m_Tonemapping . neutralBlackIn , EditorGUIHelper . GetContent ( "Black In" ) ) ;
218229 EditorGUILayout . PropertyField ( m_Tonemapping . neutralWhiteIn , EditorGUIHelper . GetContent ( "White In" ) ) ;
219230 EditorGUILayout . PropertyField ( m_Tonemapping . neutralBlackOut , EditorGUIHelper . GetContent ( "Black Out" ) ) ;
@@ -225,6 +236,129 @@ void DoTonemappingGUI()
225236 m_Tonemapping . tonemapper . intValue = tid ;
226237 }
227238
239+ void DrawNeutralTonemappingCurve ( )
240+ {
241+ using ( new GUILayout . HorizontalScope ( ) )
242+ {
243+ GUILayout . Space ( EditorGUI . indentLevel * 15f ) ;
244+ m_NeutralCurveRect = GUILayoutUtility . GetRect ( 128 , 80 ) ;
245+ }
246+
247+ // Background
248+ m_RectVertices [ 0 ] = PointInRect ( 0f , 0f ) ;
249+ m_RectVertices [ 1 ] = PointInRect ( k_NeutralRangeX , 0f ) ;
250+ m_RectVertices [ 2 ] = PointInRect ( k_NeutralRangeX , k_NeutralRangeY ) ;
251+ m_RectVertices [ 3 ] = PointInRect ( 0f , k_NeutralRangeY ) ;
252+
253+ Handles . DrawSolidRectangleWithOutline (
254+ m_RectVertices ,
255+ Color . white * 0.1f ,
256+ Color . white * 0.4f
257+ ) ;
258+
259+ // Horizontal lines
260+ for ( var i = 1 ; i < k_NeutralRangeY ; i ++ )
261+ DrawLine ( 0 , i , k_NeutralRangeX , i , 0.4f ) ;
262+
263+ // Vertical lines
264+ for ( var i = 1 ; i < k_NeutralRangeX ; i ++ )
265+ DrawLine ( i , 0 , i , k_NeutralRangeY , 0.4f ) ;
266+
267+ // Label
268+ Handles . Label (
269+ PointInRect ( 0 , k_NeutralRangeY ) + Vector3 . right ,
270+ "Neutral Tonemapper" , EditorStyles . miniLabel
271+ ) ;
272+
273+ // Precompute some values
274+ var tonemap = ( ( ColorGradingModel ) target ) . settings . tonemapping ;
275+
276+ const float scaleFactor = 20f ;
277+ const float scaleFactorHalf = scaleFactor * 0.5f ;
278+
279+ float inBlack = tonemap . neutralBlackIn * scaleFactor + 1f ;
280+ float outBlack = tonemap . neutralBlackOut * scaleFactorHalf + 1f ;
281+ float inWhite = tonemap . neutralWhiteIn / scaleFactor ;
282+ float outWhite = 1f - tonemap . neutralWhiteOut / scaleFactor ;
283+ float blackRatio = inBlack / outBlack ;
284+ float whiteRatio = inWhite / outWhite ;
285+
286+ const float a = 0.2f ;
287+ float b = Mathf . Max ( 0f , Mathf . LerpUnclamped ( 0.57f , 0.37f , blackRatio ) ) ;
288+ float c = Mathf . LerpUnclamped ( 0.01f , 0.24f , whiteRatio ) ;
289+ float d = Mathf . Max ( 0f , Mathf . LerpUnclamped ( 0.02f , 0.20f , blackRatio ) ) ;
290+ const float e = 0.02f ;
291+ const float f = 0.30f ;
292+ float whiteLevel = tonemap . neutralWhiteLevel ;
293+ float whiteClip = tonemap . neutralWhiteClip / scaleFactorHalf ;
294+
295+ // Tonemapping curve
296+ var vcount = 0 ;
297+ while ( vcount < k_CurveResolution )
298+ {
299+ float x = k_NeutralRangeX * vcount / ( k_CurveResolution - 1 ) ;
300+ float y = NeutralTonemap ( x , a , b , c , d , e , f , whiteLevel , whiteClip ) ;
301+
302+ if ( y < k_NeutralRangeY )
303+ {
304+ m_CurveVertices [ vcount ++ ] = PointInRect ( x , y ) ;
305+ }
306+ else
307+ {
308+ if ( vcount > 1 )
309+ {
310+ // Extend the last segment to the top edge of the rect.
311+ var v1 = m_CurveVertices [ vcount - 2 ] ;
312+ var v2 = m_CurveVertices [ vcount - 1 ] ;
313+ var clip = ( m_NeutralCurveRect . y - v1 . y ) / ( v2 . y - v1 . y ) ;
314+ m_CurveVertices [ vcount - 1 ] = v1 + ( v2 - v1 ) * clip ;
315+ }
316+ break ;
317+ }
318+ }
319+
320+ if ( vcount > 1 )
321+ {
322+ Handles . color = Color . white * 0.9f ;
323+ Handles . DrawAAPolyLine ( 2.0f , vcount , m_CurveVertices ) ;
324+ }
325+ }
326+
327+ void DrawLine ( float x1 , float y1 , float x2 , float y2 , float grayscale )
328+ {
329+ m_LineVertices [ 0 ] = PointInRect ( x1 , y1 ) ;
330+ m_LineVertices [ 1 ] = PointInRect ( x2 , y2 ) ;
331+ Handles . color = Color . white * grayscale ;
332+ Handles . DrawAAPolyLine ( 2f , m_LineVertices ) ;
333+ }
334+
335+ Vector3 PointInRect ( float x , float y )
336+ {
337+ x = Mathf . Lerp ( m_NeutralCurveRect . x , m_NeutralCurveRect . xMax , x / k_NeutralRangeX ) ;
338+ y = Mathf . Lerp ( m_NeutralCurveRect . yMax , m_NeutralCurveRect . y , y / k_NeutralRangeY ) ;
339+ return new Vector3 ( x , y , 0 ) ;
340+ }
341+
342+ float NeutralCurve ( float x , float a , float b , float c , float d , float e , float f )
343+ {
344+ return ( ( x * ( a * x + c * b ) + d * e ) / ( x * ( a * x + b ) + d * f ) ) - e / f ;
345+ }
346+
347+ float NeutralTonemap ( float x , float a , float b , float c , float d , float e , float f , float whiteLevel , float whiteClip )
348+ {
349+ x = Mathf . Max ( 0f , x ) ;
350+
351+ // Tonemap
352+ float whiteScale = 1f / NeutralCurve ( whiteLevel , a , b , c , d , e , f ) ;
353+ x = NeutralCurve ( x * whiteScale , a , b , c , d , e , f ) ;
354+ x *= whiteScale ;
355+
356+ // Post-curve white point adjustment
357+ x /= whiteClip ;
358+
359+ return x ;
360+ }
361+
228362 void DoBasicGUI ( )
229363 {
230364 EditorGUILayout . PropertyField ( m_Basic . exposure , EditorGUIHelper . GetContent ( "Post Exposure (EV)" ) ) ;
0 commit comments