Announcement

Collapse
No announcement yet.

Exposure/Contrast Math

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Exposure/Contrast Math

    I'm trying to reproduce the VFB exposure settings in Nuke. But the exposure and contrast settings seem to be following some non-obvious math. Are there some published specs on how to recreate those in comp?

    It feels pretty close but not exactly like a:


    Where Contrast == X
    =========
    Multiply = 1/X
    Gamma = X

    But not exactly.
    Last edited by im.thatoneguy; 18-02-2016, 12:01 PM.
    Gavin Greenwalt
    im.thatoneguy[at]gmail.com || Gavin[at]SFStudios.com
    Straightface Studios

  • #2
    The exposure math is:

    Code:
    RGB * ( if (exposure > 0)  then { 2^( exposure )} else { 1 / 4 ^( abs( exposure / 2 ))} )
    Highlight burn is similar to a (log base 2 / 2) with a scalar factor but not exactly. Not exactly sure what the formula is yet.

    Contrast is close to but not quite:

    Code:
    cFactor = if (constrast > 0) then {1/(1.0000001-constrast)} else {constrast+1.000001}
    if (rgb <=0.5) then { rgb*2^cFactor / 2} 
    else { 1 - ((((1.5-rgb)*2)-1)^cFactor / 2) }
    I'll update as I get closer.
    Last edited by im.thatoneguy; 27-02-2016, 06:18 PM.
    Gavin Greenwalt
    im.thatoneguy[at]gmail.com || Gavin[at]SFStudios.com
    Straightface Studios

    Comment


    • #3
      I'll get you the math, just need to get in front of a computer...

      Best regards,
      Vlado
      I only act like I know everything, Rogers.

      Comment


      • #4
        Here you go:
        Code:
        void ExposureWnd::ContChange(float pos) {
        	contrast=pos;
        
        	// Calculate the bias
        	const float eps=1e-3f;
        	float bias=-contrast*0.5f+0.5f;
        	bias=clamp(bias, eps, 1.0f-eps);
        	contrastBiasMult=1.0f/bias-2.0f;
        
        	// Calculate the slope of the contrast function at t>=1.0
        	contrastSlope=bias/(1.0f-bias);
        	
        	exponotify->ExpoChanged();
        }
        
        // Schlick's bias function with a precomputed multiplier. It's used for the contrast correction and it's defined in [0.0, 0.5].
        template <typename T>
        static T schlickBiasPrecomputedMult(T t, float biasMult) {
        	return t/(biasMult*(1.0f-2.0f*t)+1.0f);
        }
        
        // Nonlinear contrast correction function which preserves the detail in dark and bright areas.
        template <typename T>
        static T contrastFunc(T c, float slope, float biasMult) {
        	T res;
        
        	// Use Schlick's gain function in [0.0, 1.0] (which is a bias function in [0.0, 0.5] and a reflected bias in [0.5, 1.0]).
        	// Outside [0.0, 1.0] use a linear function with a slope equal to the slope of the gain function at 0.0 and 1.0.
        	if (c<=0.0f) res=c*slope;
        	else if (c<0.5f) res=schlickBiasPrecomputedMult(c, biasMult);
        	else if (c<1.0f) res=1.0f-schlickBiasPrecomputedMult(1.0f-c, biasMult);
        	else res=(c-1.0f)*slope+1.0f;
        
        	return res;
        }
        
        int ExposureWnd::Correct(VUtils::Color *colors, const VUtils::Color *alpha, int count, int x, int y, int notForDisplay) {
        	float mv=powf(2.0f, exposure);
        	for (int i=0; i<count; i++) { 
        		Color res = colors[i];
        		//apply exposure
        		res*=mv;
        
        		//apply highlight burn 
        		res=res*(Color(1.0f, 1.0f, 1.0f)+res*sqr(highlight))/(Color(1.0f, 1.0f, 1.0f)+res);
        
        		//apply contrast
        		res.r=contrastFunc(res.r, contrastSlope, contrastBiasMult);
        		res.g=contrastFunc(res.g, contrastSlope, contrastBiasMult);
        		res.b=contrastFunc(res.b, contrastSlope, contrastBiasMult);
        
        		res.clampMin();
        		colors[i] = res;
        	}
        	return 0;
        }
        Best regards,
        Vlado
        I only act like I know everything, Rogers.

        Comment


        • #5
          Thanks Vlado.

          For future generations here is a Nuke Gizmo implementation that will match the VFB settings.

          Code:
          Group {
           name VrayExposure
           selected true
           xpos 539
           ypos 22
           addUserKnob {20 User}
           addUserKnob {41 exposure l Exposure T ExposureNode.exposure}
           addUserKnob {41 highlight l "Highlight Burn" T HighlightBurnExpression.highlight}
           addUserKnob {41 contrast l Contrast T ContrastExpression.contrast}
          }
           Input {
            inputs 0
            name Input1
            xpos 683
            ypos -19
           }
           Multiply {
            channels rgb
            value {{this.exposure>0?pow(2,this.exposure):1/pow(4,(abs(this.exposure/2))) x1 0.28}}
            name ExposureNode
            xpos 683
            ypos 35
            addUserKnob {20 User}
            addUserKnob {7 exposure l Exposure R -5 5}
           }
           Expression {
            expr0 r*((1+(r*highlightSquare))/(1+r))
            expr1 g*((1+(g*highlightSquare))/(1+g))
            expr2 b*((1+(b*highlightSquare))/(1+b))
            name HighlightBurnExpression
            selected true
            xpos 683
            ypos 79
            addUserKnob {20 User}
            addUserKnob {7 highlight l "Highlight Burn"}
            highlight 1
            addUserKnob {7 highlightSquare l "Highlight Square"}
            highlightSquare {{pow(highlight,2)}}
           }
           Expression {
            expr0 (r>1)?((r-1)*this.contrastSlope+1):((r>0)?((r<0.5)?(r/(this.contrastBiasMult*(1.0-(2.0*r))+1)):(1-((1-r)/(this.contrastBiasMult*(1.0-(2.0*(1-r)))+1)))):(r*contrastSlope))
            expr1 (g>1)?((g-1)*this.contrastSlope+1):((g>0)?((g<0.5)?(g/(this.contrastBiasMult*(1.0-(2.0*g))+1)):(1-((1-g)/(this.contrastBiasMult*(1.0-(2.0*(1-g)))+1)))):(g*contrastSlope))
            expr2 (b>1)?((b-1)*this.contrastSlope+1):((b>0)?((b<0.5)?(b/(this.contrastBiasMult*(1.0-(2.0*b))+1)):(1-((1-b)/(this.contrastBiasMult*(1.0-(2.0*(1-b)))+1)))):(b*contrastSlope))
            name ContrastExpression
            xpos 683
            ypos 119
            addUserKnob {20 User}
            addUserKnob {7 contrast l Contrast R -1 1}
            addUserKnob {7 bias}
            bias {{1-(max(min((contrast*0.5)+0.5,.999),0.001))}}
            addUserKnob {7 contrastBiasMult R -1 1000}
            contrastBiasMult {{(1.0/bias)-2.0 x1 0}}
            addUserKnob {7 contrastSlope}
            contrastSlope {{bias/(1.0-bias)}}
           }
           Output {
            name Output1
            xpos 683
            ypos 185
           }
          end_group
          Attached Files
          Gavin Greenwalt
          im.thatoneguy[at]gmail.com || Gavin[at]SFStudios.com
          Straightface Studios

          Comment


          • #6
            sick! will need to try this gizmo at work. thanks!
            Brendan Coyle | www.brendancoyle.com

            Comment

            Working...
            X