Reference:Color Expressions

From POV-Wiki
Jump to navigation Jump to search
COLOR:
    COLOR_BODY             |
    color COLOR_BODY       | (this means the keyword color or
    colour COLOR_BODY        colour may optionally precede any color specification)
COLOR_BODY:
    COLOR_VECTOR           |
    COLOR_KEYWORD_GROUP    |
    COLOR_IDENTIFIER
COLOR_VECTOR:
    rgb <3_Term_Vector>    |
    rgbf <4_Term_Vector>   |
    rgbt <4_Term_Vector>   |
    [ rgbft ] <5_Term_Vector> |
    srgb <3_Term_Vector>   |
    srgbf <4_Term_Vector>  |
    srgbt <4_Term_Vector>  |
    srgbft <5_Term_Vector>
COLOR_KEYWORD_GROUP:
    [ COLOR_KEYWORD_ITEM ]...
COLOR_KEYWORD_ITEM:
    COLOR_IDENTIFIER       |
    red Red_Amount         |
    blue Blue_Amount       |
    green Green_Amount     |
    filter Filter_Amount   |
    transmit Transmit_Amount

Note: COLOR_IDENTIFIERS are identifiers previously declared to have color values. The 3, 4, and 5 term vectors are usually vector literals but may be vector expressions or floats promoted to vectors. See Operator Promotion and the sections below.

POV-Ray often requires you to specify a color. Colors consist of five values or color components. The first three are called red, green, and blue. They specify the intensity of the primary colors red, green and blue using an additive color system like the one used by the red, green and blue color phosphors on a color monitor.

The 4th component, called filter, specifies the amount of filtered transparency of a substance. Some real-world examples of filtered transparency are stained glass windows or tinted cellophane. The light passing through such objects is tinted by the appropriate color as the material selectively absorbs some frequencies of light while allowing others to pass through. The color of the object is subtracted from the light passing through so this is called subtractive transparency.

The 5th component, called transmit, specifies the amount of non-filtered light that is transmitted through a surface. Some real-world examples of non-filtered transparency are thin see-through cloth, fine mesh netting and dust on a surface. In these examples, all frequencies of light are allowed to pass through tiny holes in the surface. Although the amount of light passing through is diminished, the color of the light passing through is unchanged.

The color of the object and the color transmitted through the object together contribute 100% of the final color. So if transmit is set to 0.9, the transmitted color contributes 90% and the color of the object contributes only 10%. This is also true outside of the 0-1 range, so for example if transmit is set to 1.7, the transmitted color contributes with 170% and the color of the object contributes with minus 70%. Using transmit values outside of the 0-1 range can be used to create interesting special effects, but does not correspond to any phenomena seen in the real world. An example:

camera {location -2.5*z look_at 0 orthographic}

box {
  0,1
  texture {
    pigment {
    gradient y
      colour_map {
        [0, red 1]
        [1, blue 1]
        }
      }
    finish{ambient 1}
    }
  texture {
    pigment {
    gradient x
      colour_map {
        [0, rgb 0.5 transmit -3]
        [1, rgb 0.5 transmit  3]
        }
      }
    finish{ambient 1}
    }
  translate <-0.5,-0.5,0>
  scale <3,2,1>
  }

When using the transmit value for special effects, you can visualize it this way: The transmit value means contrast. 1.0 is no change in contrast, 0.5 is half contrast, 2.0 is double contrast and so on. You could say that transmit scales the colors. The color of the object is the center value. All colors will get closer to the center value if transmit is between 0 and 1, and all colors will spread away from the center value if transmit is greater than 1. If transmit is negative the colors will be inverted around the center value. Rgb 0.5 is common to use as center value, but other values can be used for other effects. The center value really is a color, and non-gray colors can be used for interesting effects. The red, green and blue components are handled separately.

Note: Earlier versions of POV-Ray used the keyword alpha to specify filtered transparency. However that word is often used to describe non-filtered transparency. For this reason alpha is no longer used.

Each of the five components of a color are float values which are normally in the range between 0.0 and 1.0. However any values, even negatives may be used.

Under most circumstances the keyword color is optional and may be omitted. We also support the British or Canadian spelling colour. Colors may be specified using vectors, keywords with floats or identifiers. You may also create very complex color expressions from combinations of any of these using various familiar operators. The syntax for specifying a color has evolved since POV-Ray was first released. We have maintained the original keyword-based syntax and added a short-cut vector notation. Either the old or new syntax is acceptable however the vector syntax is easier to use when creating color expressions.

The syntax for combining color literals into color expressions is almost identical to the rules for vector and float expressions. In the syntax for vector expressions, some of the syntax items are defined in the section for float expressions. See Float Expressions for those definitions. Detailed explanations of color-specific issues are given in the following sub-sections.

Color Vectors

The syntax for a color vector is...

COLOR_VECTOR:
  rgb <3_Term_Vector>   |
  rgbf <4_Term_Vector>  |
  rgbt <4_Term_Vector>  |
  [ rgbft ] <5_Term_Vector>

...where the vectors are any valid vector expressions of 3, 4 or 5 components. For example

color rgb <1.0, 0.5, 0.2>

This specifies a color whose red component is 1.0 or 100% of full intensity. The green component is 0.5 or 50% of full intensity and the blue component is 0.2 or 20% of full intensity. Although the filter and transmit components are not explicitly specified, they exist and are set to their default values of 0 or no transparency.

The rgbf keyword requires a four component vector. The 4th component is the filter component and the transmit component defaults to zero. Similarly the rgbt keyword requires four components where the 4th value is moved to the 5th component which is transmit and then the

filter component is set to zero.

The rgbft keyword allows you to specify all five components. Internally in expressions all five are always used.

Under some circumstances, if the vector expression is a 5 component expression or there is a color identifier in the expression then the rgbft keyword is optional.

sRGB Colors

While POV-Ray will normally expect colors to be expressed in whatever working gamma space you have set via assumed_gamma, as of version 3.7 the srgb, srgbf, srgbt and srgbft keywords have been added to specify colors encoded according to the sRGB standard (roughly corresponding to a display gamma pre-correction of 2.2). Using these keywords instead of rgb, rgbf, rgbt or rgbft, respectively, instructs POV-Ray to automatically convert the color components to the working gamma space, being approximately equivalent to:

Effective_Red_Amount      = pow ( Red_Amount,   2.2/AssumedGamma )
Effective_Green_Amount    = pow ( Green_Amount, 2.2/AssumedGamma )
Effective_Blue_Amount     = pow ( Blue_Amount,  2.2/AssumedGamma )
Effective_Filter_Amount   = Filter_Amount
Effective_Transmit_Amount = Transmit_Amount

Note: Defining sRGB colors before assumed_gamma has been set will halt parsing and issue a warning.

The syntax is primarily intended for convenience when working with a physically accurate assumed_gamma of 1.0, as many people find this way of specifying colors more intuitive (for instance a value of about srgb 0.5 is commonly perceived as a medium grey, despite having an actual brightness of no more than 21.4%), and most image processing software and tools also use gamma pre-corrected colours in their user interface; while those may use slightly different color spaces, sRGB is a good approximation, and also has the advantage of being the official recommendation for the World Wide Web.

Note: Colors specified this way are not a different flavor of colors, but are rather converted on the fly to linear color values. When interpreting such values as a vector or accessing individual components, you will get the linear values rather than the pre-corrected values you originally specified.

For instance, the following color statements are all fully equivalent (except for rounding errors):

#declare Foo = color srgbt <51,76,102,127>/255;
#debug concat("<",vstr(5,Foo,",",0,3),">\n")
#declare Foo = color srgbt <0.2, 0.3, 0.4, 0.5>;
#debug concat("<",vstr(5,Foo,",",0,3),">\n")
#declare Foo = color srgb <0.2, 0.3, 0.4> transmit 0.5;
#debug concat("<",vstr(5,Foo,",",0,3),">\n")
#declare Foo = color rgbt <0.033,0.073,0.133,0.5>;
#debug concat("<",vstr(5,Foo,",",0,3),">\n")

Note: The srgb, srgbf, srgbt and srgbft keywords do not affect the way filter or transmit components are interpreted; these are always expected to be linear.

Color Keywords

The older keyword method of specifying a color is still useful and many users prefer it.

COLOR_KEYWORD_GROUP:
  [ COLOR_KEYWORD_ITEM ]...
  COLOR_KEYWORD_ITEM:
  COLOR_IDENTIFIER |
  red Red_Amount | blue Blue_Amount | green Green_Amount | 
  filter Filter_Amount | transmit Transmit_Amount

Although the color keyword at the beginning is optional, it is more common to see it in this usage. This is followed by any of five additional keywords red, green, blue, filter, or transmit. Each of these component keywords is followed by a float expression. For example

color red 1.0 green 0.5

This specifies a color whose red component is 1.0 or 100% of full intensity and the green component is 0.5 or 50% of full intensity. Although the blue, filter and transmit components are not explicitly specified, they exist and are set to their default values of 0. The component keywords may be given in any order and if any component is unspecified its value defaults to zero. A COLOR_IDENTIFIER can also be specified but it should always be first in the group. See Common Color Pitfalls for details.

Color Identifiers

Color identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. An identifier is declared as follows.

COLOR_DECLARATION:
  #declare IDENTIFIER = COLOR; |
  #local IDENTIFIER = COLOR;

Where IDENTIFIER is a valid identifier name and COLOR is any valid color specification.

Note: There should be a semi-colon at the end of the declaration. If omitted, it generates a warning and some macros may not work properly.

See also: Identifiers and #declare vs. #local for additional information on identifier naming and scope.

Here are some examples....

#declare White = rgb <1,1,1>;
#declare Cyan = color blue 1.0 green 1.0;
#declare Weird = rgb <Foo*2,Bar-1,Bob/3>;
#declare LightGray = White*0.8;
#declare LightCyan = Cyan red 0.6;

As the LightGray example shows you do not need any color keywords when creating color expressions based on previously declared colors. The last example shows you may use a color identifier with the keyword style syntax. Make sure that the identifier comes first before any other component keywords.

Like floats and vectors, you may re-define colors throughout a scene but the need to do so is rare.

Color Operators

Color vectors may be combined in expressions the same as float or vector values. Operations are performed on a component by component basis. For example rgb <1.0,0.5,0.2>*0.9 evaluates the same as rgb<1.0,0.5,0.2>*<0.9,0.9,0.9> or rgb<0.9,0.45,0.18>. Other operations are done on a similar component by component basis.

You may use the dot operator to extract a single component from a color. Suppose the identifier Shade was previously defined as a color. Then Shade.red is the float value of the red component of Shade. Similarly Shade.green, Shade.blue, Shade.filter and Shade.transmit extract the float value of the other color components. shade.gray returns the gray value of the color vector.

Dot Item Access for Colors

POV-Ray provides an easy method to access the individual components of different types of color expressions, as illustrated in the following code examples:

#declare Color = <1, 2, 3>;
#declare First_Component = Color.red;
#declare Second_Component = Color.green;
#declare Third_Component = Color.blue;

#declare Color = <1, 2, 3, 4, 5>;
#declare First_Component = Color.red;
#declare Second_Component = Color.green;
#declare Third_Component = Color.blue;
#declare Fourth_Component = Color.filter;
#declare Fifth_Component = Color.transmit;

#declare Color = <0.89, 0.47, 0.2>;
#declare Gray_Value = Color.gray;

See also: Dot Item Access for Vectors.

Common Color Pitfalls

The variety and complexity of color specification methods can lead to some common mistakes. Here are some things to consider when specifying a color.

When using filter transparency, the colors which come through are multiplied by the primary color components. For example if gray light such as rgb<0.9,0.9,0.9> passes through a filter such as rgbf<1.0,0.5,0.0,1.0> the result is rgb<0.9,0.45,0.0> with the red let through 100%, the green cut in half from 0.9 to 0.45 and the blue totally blocked. Often users mistakenly specify a clear object by

color filter 1.0

but this has implied red, green and blue values of zero. You have just specified a totally black filter so no light passes through. The correct way is either

color red 1.0  green 1.0  blue 1.0  filter 1.0

or

color transmit 1.0

In the 2nd example it does not matter what the rgb values are. All of the light passes through untouched. Another pitfall is the use of color identifiers and expressions with color keywords. For example...

color My_Color red 0.5

this substitutes whatever was the red component of My_Color with a red component of 0.5 however...

color My_Color + red 0.5

adds 0.5 to the red component of My_Color and even less obvious...

color My_Color * red 0.5

that cuts the red component in half as you would expect but it also multiplies the green, blue, filter and transmit components by zero! The part of the expression after the multiply operator evaluates to rgbft<0.5,0,0,0,0> as a full 5 component color.

The following example results in no change to My_Color.

color red 0.5 My_Color

This is because the identifier fully overwrites the previous value. When using identifiers with color keywords, the identifier should be first. Another issue to consider: some POV-Ray syntax allows full color specifications but only uses the rgb part. In these cases it is legal to use a float where a color is needed. For example:

finish { ambient 1 }

The ambient keyword expects a color so the value 1 is promoted to <1,1,1,1,1> which is no problem. However

pigment { color 0.4 }

is legal but it may or may not be what you intended. The 0.4 is promoted to <0.4,0.4,0.4,0.4,0.4> with the filter and transmit set to 0.4 as well. It is more likely you wanted...

pigment { color rgb 0.4 }

in which case a 3 component vector is expected. Therefore the 0.4 is promoted to <0.4,0.4,0.4,0.0,0.0> with default zero for filter and transmit. Finally there is another problem which arises when using color dot operators in #declare or #local directives. Consider the directive:

#declare MyColor = rgb <0.75, 0.5, 0.75>;
#declare RedAmt = MyColor.red;

Now RedAmt should be a float but unfortunately it is a color. POV-Ray looks at the first keyword after the equals to try to guess what type of identifier you want. It sees the color identifier MyColor and assumes you want to declare a color. It then computes the float value as 0.75 then promotes that into rgbft<0.75,0.75,0.75,0.75,0.75>. It would take a major rewrite to fix this problem so we are just warning you about it. Any of the following work-arounds will work properly.

#declare RedAmt = 0.0+MyColor.red;
#declare RedAmt = 1.0*MyColor.red;
#declare RedAmt = (MyColor.red);