POV-Ray : Newsgroups : povray.text.scene-files : Gamut-mapped spectral rendering Server Time: 14 Dec 2018 14:26:28 GMT
  Gamut-mapped spectral rendering (Message 1 to 1 of 1)  
From: Cousin Ricky
Subject: Gamut-mapped spectral rendering
Date: 8 May 2017 17:14:57
Message: <5910a791$1@news.povray.org>
I have made two sets of changes to the file SpectralComposer.pov in 
Lilysoft's spectral rendering rig.

The first set of changes was converting it to a proper include file.  In 
its standard form, SpectralComposer.pov must be edited every time you 
create a new scene, or even render the same scene with different 
parameters; and the final output image must be renamed.  With my 
changes, you can #declare the scene name and other parameters in your 
scene file, and then #include the composer file without having to edit 
it every time.

The second set of changes was to use gamut mapping to deal with colors 
that are too rich for standard computer monitors.

So as not to step on Ive's toes, I am only posting the changes I made, 
and not the entire file.

Change 1:  Insert the following comments under the header block:

----------[BEGIN CODE]----------
// Modifications by Richard Callwood III:
// 2013-Nov-26  Converted to parameter-driven .inc file.
// 2013-Nov-26  Converted npow() to NPow().
// 2013-Dec-02  Does gamut mapping (CIE.inc's method 2).
// 2013-Dec-11  Corrected a grammatical error.
-----------[END CODE]-----------

Change 2:  Replace the FName section with the following.  (Note that, 
notwithstanding how it may appear in your newsreader, the #error string 
should be all on one line.)

----------[BEGIN CODE]----------
// FName: change this to match the name of your set of 36 spectral files
//#declare FName = "";
#ifndef (FName)
   #error "String FName must be set to the name of your 36 .exr files 
(without the frame number and \".exr\" extension)."
#end
-----------[END CODE]-----------

Changes 3 - 10:  Replace the respective parameter declarations with the 
following lines:

----------[BEGIN CODE]----------
#ifndef (Exposure) #declare Exposure = 1.0; #end
#ifndef (Luminance) #declare Luminance = 1.0; #end
#ifndef (Exponent) #declare Exponent = 1.0; #end
#ifndef (Saturation) #declare Saturation = 1.0; #end
#ifndef (Whitepoint) #declare Whitepoint = 6504; #end
#ifndef (HDR_max) #declare HDR_max = 25; #end
#ifndef (HDR_min) #declare HDR_min = -1.0; #end
#ifndef (Use_AdobeRGB) #declare Use_AdobeRGB = off; #end
-----------[END CODE]-----------

Change 11:  Search and replace all instances of npow with NPow, per 
unenforced POV-Ray recommendation.

Change 12:  This section does the gamut mapping.  Replace the line "// 
our canvas" and the following plane object with the following:

----------[BEGIN CODE]----------
// pigment at full dynamic range
#declare p_Full_color = pigment
{ average
   pigment_map
   {
     [ function
       { NPow
         (   CM[0][0] * CMF_x(x,y,z)
           + CM[0][1] * CMF_y(x,y,z)
           + CM[0][2] * CMF_z(x,y,z)
         ) * E + M
       }
       color_map { [0 rgb <L,0,0>] [1 rgb <H,0,0>] }
     ]

     [ function
       { NPow
         (   CM[1][0] * CMF_x(x,y,z)
           + CM[1][1] * CMF_y(x,y,z)
           + CM[1][2] * CMF_z(x,y,z)
         ) * E + M
       }
       color_map { [0 rgb <0,L,0>] [1 rgb <0,H,0>] }
     ]

     [ function
       { NPow
         (   CM[2][0] * CMF_x(x,y,z)
           + CM[2][1] * CMF_y(x,y,z)
           + CM[2][2] * CMF_z(x,y,z)
         ) * E + M
       }
       color_map { [0 rgb <0,0,L>] [1 rgb <0,0,H>] }
     ]
   }
}
#declare fn_Full_color = function { pigment { p_Full_color } }

// gamut map (See MapGamut() in CIE.inc)
#declare WtPt = xyz2RGB (ColSys2xyz (3));
#declare WtR = WtPt.red;
#declare WtG = WtPt.green;
#declare WtB = WtPt.blue;

#declare fn_P = function
{ select
   ( 0.5 - (x <= y & x <= z),
     WtR / (WtR - x),
     select
     ( 0.5 - (y <= x & y <= z),
       WtG / (WtG - y),
       WtB / (WtB - z)
     )
   )
}

#declare fn_Red = function
{ select
   ( min(x,y,z), min (max (WtR + fn_P(x,y,z) * (x - WtR), 0), 1), min (x, 1)
   )
}

#declare fn_Green = function
{ select
   ( min(x,y,z), min (max (WtG + fn_P(x,y,z) * (y - WtG), 0), 1), min (y, 1)
   )
}

#declare fn_Blue = function
{ select
   ( min(x,y,z), min (max (WtB + fn_P(x,y,z) * (z - WtB), 0), 1), min (z, 1)
   )
}

// our canvas
plane
{ -z, 0
   pigment
   { average pigment_map
     { [ function
         { fn_Red
           ( fn_Full_color(x,y,z).red,
             fn_Full_color(x,y,z).green,
             fn_Full_color(x,y,z).blue
           )
         }
         color_map { [0 rgb 0] [1 red 3] }
       ]
       [ function
         { fn_Green
           ( fn_Full_color(x,y,z).red,
             fn_Full_color(x,y,z).green,
             fn_Full_color(x,y,z).blue
           )
         }
         color_map { [0 rgb 0] [1 green 3] }
       ]
       [ function
         { fn_Blue
           ( fn_Full_color(x,y,z).red,
             fn_Full_color(x,y,z).green,
             fn_Full_color(x,y,z).blue
           )
         }
         color_map { [0 rgb 0] [1 blue 3] }
       ]
     }
   }
   finish { ambient 0 diffuse 0 emission 1 }
}
-----------[END CODE]-----------

I adapted the formula from CIE.inc's method 2, but for some reason, the 
results of the gamut mapping appear more like method 3.  I haven't 
figured out the reason for this.

Because the gamut mapping is slow, I actually keep two versions of the 
file: one with all the changes (which I call SpectralComposer-gm2.inc); 
and one with just the #ifndefs and no gamut-mapping changes (which I 
call SpectralComposer.inc).

My typical usage is thus:

----------[BEGIN EXAMPLE]----------
#version 3.7;
#ifndef (Preview) #declare Preview = no; #end
#if (clock_on | Preview)
   #include "spectral.inc"
   // Define the scene here.
#else
   #declare FName = "MySceneFileName"
   #include "SpectralComposer-gm2.inc"
#end
-----------[END EXAMPLE]-----------


Post a reply to this message

Copyright 2003-2008 Persistence of Vision Raytracer Pty. Ltd.