POV-Ray : Newsgroups : povray.beta-test : Colors.inc-macros incomplete : Re: Colors.inc-macros incomplete Server Time
1 May 2024 19:58:29 EDT (-0400)
  Re: Colors.inc-macros incomplete  
From: Tor Olav Kristensen
Date: 11 Sep 2001 21:34:45
Message: <3B9EBB7A.98563AFE@hotmail.com>
Hello again Rune.

It seems that the combination of your modifications
to my macro and your CRGB2HSL() macro makes it 
possible to convert back and forth between both RGB
and HSL coded colors.

Right now I have no time to test and study your 
modifications thoroughly    :(
- So now I only have to hope that you have good 
reasons for making these changes.

Below is my suggestion for a somewhat rewritten
(and hopefully simplified) version of your 
CRGB2HSL() macro.

There's also a version of my CHSL2RGB() macro that
shows how I would like it to appear with your
modifications.

Please note that I think that both the CRGB2HSL() 
macro and the CHSL2RGB() macro has problems with 
RGB and HSL color vectors with "out of range 
components" (E.g.: Greater than 1 or less than 0).

But I'm not at all sure if it is wise to attempt
to fix this.




Tor Olav

Btw.:

I think that these color conversion macros 
should not only be tested with with sphere pairs 
with these pigments:

pigment { color CHSL2RGB(<H, S, L>) }
pigment { color CHSL2RGB(CRGB2HSL(CHSL2RGB(<H, S, L>))) }

but also with these pigments:

pigment { color <R, G, B>) }
pigment { color CHSL2RGB(CRGB2HSL(<R, G, B>)) }




#macro CRGB2HSL(Color)

  #local RGBFT = color Color;
  #local R = (RGBFT.red);
  #local G = (RGBFT.green);
  #local B = (RGBFT.blue);
  #local Min = min(R, min(G, B));
  #local Max = max(R, max(G, B));
  #local Span = Max - Min;
  #local Mid = (Min + Max)/2;
  #local H = 0;
  #local S = 0;
  #if (Mid > 0 & Mid < 1)
    #if (Span > 0)
      #local H = (
                   (R = Max ? 0 + (G - B)/Span : 0) +
                   (G = Max ? 2 + (B - R)/Span : 0) +
                   (B = Max ? 4 + (R - G)/Span : 0)
                 )*60;
    #end // if
    #local S = Span/2/(Mid < 0.5 ? Mid : 1 - Mid);
  #end // if
  #local L = min(1, max(0, Mid));

  <H, S, L, RGBFT.filter, RGBFT.transmit>

#end // macro CRGB2HSL


#macro CHSL2RGB(Color)

  #local HSLFT = color Color;
  #local H = (HSLFT.red);
  #local S = (HSLFT.green);
  #local L = (HSLFT.blue);
  #local H = mod(H, 360) + (H < 0 ? 360 : 0);
  #switch (H)
    #range (  0, 120)
      #local SR = (120 -   H)/60;
      #local SG = (  H -   0)/60;
      #local SB = 0;
    #break
    #range (120, 240)
      #local SR = 0;
      #local SG = (240 -   H)/60;
      #local SB = (  H - 120)/60;
    #break
    #range (240, 360)
      #local SR = (  H - 240)/60;
      #local SG = 0;
      #local SB = (360 -   H)/60;
    #break
  #end // switch
  #local SaturatedRGB = <min(SR, 1), min(SG, 1), min(SB, 1)>;
  #local Col = 2*S*SaturatedRGB + (1 - S)*<1, 1, 1>;
  #switch (L)
    #range (0.0, 0.5)
      #local RGB = Col*L;
    #break
    #range (0.5, 1.0)
      #local RGB = Col*(1 - L) + (2*L - 1)*<1, 1, 1>;
    #break
  #end // switch

  <RGB.red, RGB.green, RGB.blue, HSLFT.filter, HSLFT.transmit>

#end // macro CHSL2RGB



Rune wrote:
> 
> I have tested the CHSL2RGB macro and fixed some bugs in it and I've also
> coded a CRGB2HSL macro that converts the other way. The conversion back and
> forth is perfect at least in the tests I've made. Here are the two macros
> and some code that shows that multiple conversions back and forth produce
> consistent results.
> 
> I will include these macros in colors.inc. The other color formats will be
> dropped.
> 
> Please feel free to make lots of tests, as there might still be some bugs
> left!
> 
> #macro CHSL2RGB(Color)
> 
>    #local Color = color Color;
> 
>    // Extract Hue, Saturation and Lightness components
>    #local H = (Color.red);
>    #local S = (Color.green);
>    #local L = (Color.blue);
> 
>    #local H = mod(H, 360);
>    #local H = (H < 0 ? H+360 : H);
> 
>    // Construct saturaed RGB from Hue
>    #switch (H)
>       #range (0, 120)
>          #local SR = (120 -   H)/60;
>          #local SG = (  H -   0)/60;
>          #local SB = 0;
>       #break
>       #range (120, 240)
>          #local SR = 0;
>          #local SG = (240 -   H)/60;
>          #local SB = (  H - 120)/60;
>       #break
>       #range (240, 360)
>          #local SR = (  H - 240)/60;
>          #local SG = 0;
>          #local SB = (360 -   H)/60;
>       #break
>    #end // switch
> 
>    #local SaturatedRGB = <min(SR,1), min(SG,1), min(SB,1)>;
> 
>    // Incorporate saturation and lightness
>    #switch (L)
>       #range (0.0, 0.5)
>          #local RGB = ((SaturatedRGB*S+0.5*(1-S))*L*2);
>       #break
>       #range (0.5, 1.0)
>          #local RGB = ((SaturatedRGB*S+0.5*(1-S))*(2-L*2)+1*(L*2-1));
>       #break
>    #end
> 
>    <RGB.red,RGB.green,RGB.blue,Color.filter,Color.transmit>
> 
> #end // macro CHSL2RGB
> 
> #macro CRGB2HSL(Color)
> 
>    #local Color = color Color;
> 
>    // Extract Red, Green and Blue components
>    #local R = (Color.red);
>    #local G = (Color.green);
>    #local B = (Color.blue);
> 
>    // Find minimum and maximum component of RGB
>    #local MIN = min(R,min(G,B));
>    #local MAX = max(R,max(G,B));
> 
>    // Find Lightness
>    #local L = (MAX+MIN)/2;
> 
>    #if (L<=0|L>=1)
>       #local HSL = <0,0,min(1,max(0,L))>;
>    #else
> 
>       // Find Saturation
>       #local S = (MAX-MIN) / ( L<0.5 ? (L*2) : (2-L*2) );
> 
>       #if (S<=0)
>          #local HSL = <0,0,L>;
>       #else
> 
>          // Find fully saturated version of Red, Green and Blue
>          #local SR = (R-MIN)/(MAX-MIN);
>          #local SG = (G-MIN)/(MAX-MIN);
>          #local SB = (B-MIN)/(MAX-MIN);
> 
>          // Construct Angle from SR, SG and SB
>          #if (SB=0)
>             #if (SR=1)
>                #local Angle = (  SG)*60      ;
>             #else
>                #local Angle = (1-SR)*60 +  60;
>             #end
>          #end
>          #if (SR=0)
>             #if (SG=1)
>                #local Angle = (  SB)*60 + 120;
>             #else
>                #local Angle = (1-SG)*60 + 180;
>             #end
>          #end
>          #if (SG=0)
>             #if (SB=1)
>                #local Angle = (  SR)*60 + 240;
>             #else
>                #local Angle = (1-SB)*60 + 300;
>             #end
>          #end
> 
>          #local HSL = <Angle,S,L>;
> 
>       #end
> 
>    #end
> 
>    <HSL.x,HSL.y,HSL.z,Color.filter,Color.transmit>
> 
> #end // macro CRGB2HSL
> 
> #declare Xm = 20;
> #declare Ym = 20;
> #declare X = 0;
> #while (X<=Xm)
>    #declare Y = 0;
>    #while (Y<=Ym)
>       #declare Xv = (X/Xm);
>       #declare Yv = (Y/Ym);
>       sphere {
>          <Xv,Yv,0>-0.6*x, 0.1
>          pigment {color CHSL2RGB(<0,Xv,Yv>)}
>          finish {ambient 1 diffuse 0}
>       }
>       sphere {
>          <Xv,Yv,0>+0.6*x, 0.1
>          pigment {color CHSL2RGB(CRGB2HSL(CHSL2RGB(<0,Xv,Yv>)))}
>          finish {ambient 1 diffuse 0}
>       }
>       #declare Y=Y+1;
>    #end
>    #declare X=X+1;
> #end
> camera {translate <0.5,0.5,-2>}
> background {color rgb 0.5}


Post a reply to this message

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