Color Math
Өнгийг тохируулж хянах нь шэйдр хөгжүүлэлтийн маш том хэсэг юм. Нэг орон зайд орших өнгийг өөр орон руу шилжүүлэн тооцоолол хийхэд тухайн даалгавар ихээхэн хялбарчлагдах боломжтой. Өнгөнүүдийг өмнөхтэй адил нэмж хасаж үржүүлж болно. Энэ хэсэгт өнгөн дээр хийгдэж болох математик үйлдлүүд болон онолтой танилцана.
Өнгө гэж юу вэ? Улаан цэнхэр хоёр юугаараа өөр вэ? Өнгө нь хэрхэн дүрслэгддэгийг мэдэхийн тулд түүний физик шинж чанарыг ойлгох хэрэгтэй. 1666 онд Исаак Ньютон призм дундуур нэвтэрсэн нарны гэрэл спектрийн өнгөнүүдэд хуваагддаг болохыг нээсэн. Спектрийн өнгөнүүд нь улаанаас ягаан хүртэлхи бүхий л өнгө юм. Байгаль дээрхи жишээ нь солонго юм. Агаарт байх чийг призмийн үүрэг гүйцэтгэнэ. Гэрлийн туяа объект дээр тусахад объект нэг хэсгийг нь шингээж үлдсэнийг нь ойлгодог.
Бид ойсон туяаг нь харж объект ямар өнгөтэй болохыг мэднэ. Цагаан өнгө бүх спектрийг ойлгож хар өнгө бүгдийг шингээдэг гэдгийг бид мэднэ.Үндсэн өнгийг ашиглан бүх өнгийг гаргаж авах хэд хэдэн арга байдаг. Нэмэх арга нь улаан ногоон цэнхэр, хасах арга нь ягаан, магента шар хар зэрэг үндсэн өнгүүдийг ашигладаг. Зураг 5.32-д дээрхи 2 арга хоорондоо ямар хамааралтай болохыг харуулж байна.
Бид ойсон туяаг нь харж объект ямар өнгөтэй болохыг мэднэ. Цагаан өнгө бүх спектрийг ойлгож хар өнгө бүгдийг шингээдэг гэдгийг бид мэднэ.Үндсэн өнгийг ашиглан бүх өнгийг гаргаж авах хэд хэдэн арга байдаг. Нэмэх арга нь улаан ногоон цэнхэр, хасах арга нь ягаан, магента шар хар зэрэг үндсэн өнгүүдийг ашигладаг. Зураг 5.32-д дээрхи 2 арга хоорондоо ямар хамааралтай болохыг харуулж байна.
Зураг 5.32
RenderMan-д өнгө нь RGB (улаан, ногоон, цэнхэр) орон зайд орших ба бутархай тоогоор илэрхийлэгдэнэ. RGB нь гурван сувагтай бөгөөд сувгуудийн утгыг нэмж байж эцсийн өнгийг тодорхойлно. Интернэт дээр байгаа болон дижитал аппаратаар авсан ихэнхи зурагнууд 8 бит хэмжээтэй RGB байдаг. Зургийг бүрдүүлэгч гурван суваг нь тус бүрдээ 256 хүртэлхи утга хадгалах чадвартай. RGB/8 бит зургийн хувьд (0,0,0) нь хар (255,255,255) нь цагаан өнгийг төлөөлнө. Эдгээр зурагнууд өдөр тутмын энгийн хэрэглээнд тохиромжтой. Харин кино,VFX, анимаци зэрэгт хангалтгүй. Ийм учраас RenderMan нь өнгөний тооцоо хийхдээ бутархай тоо ашигладаг. Танд хэрэгтэй бүх өнгийг бутархай зургаан орноор хангалттай илэрхийлж чадна.
Өнгө нь бутархай тоогоор өгөгдсөн бол (0,0,0) нь хар (1,1,1) нь цагаан гэсэн үг. Бутархай тоогооор илэрхийлэгддэг учраас заавал тэгээс нэгийн хооронд байх ёстой биш юм. Тооцооллын үр дүнд (10,10,10) гэсэн утга гарч болно. Энэ утга бидний нүдэнд цагаан л гэж харагдана. Энэ үр дүнг эцсийн зурганд хадгалвал сүүлд угсрах комп хийхэд асуудал тулгарна. Хоёр элемент дээр гүйцэтгэж болох энгийн математик үйлдлүүд бол нэмэх хасах үржих хуваах. Харин энэ аргыг өнгөн (3 элемэнттэй) дээр ашиглахдаа цэг вектор, нормалтай адил зарчмаар үйлдэнэ. Ижил бүрэлдэхүүн хэсгүүд дээр үйлдэл хийнэ. Өөрөөр хэлбэл (0.5,0.4,0.1) гэсэн өнгөн дээр (0.3,0.2,0.3) өнгийг нэмбэл (0.8,0.6,0.4) гэсэн хариу гарна.
Үржүүлэх үйлдэл мөн адилхан. Үржүүлэх нэмэх үйлдэл коммутатив учир элемэнтүүдийн байрлал чухал биш. Харин хасах хуваах үйлдлүүд ялгаатай байх нь мэдээж.
(0.7,0.5,0.8) - (0.5,0.4,0.1) = (0.2,0.1,0.7)
(0.9,0.4,0.6) / (0.3,0.2,0.3) = (3,2,2);
Эдгээр үйлдлийг хийхдээ болгоомжлохгүй бол 0-ээс 1-ийн хоорондох утгаас хальж гарах магадлал тун их. Хэтэрсэн тохиолдолд буруу өнгө гэж тооцоод комп хийхдээ засах шаардлагатай. Дээрхий үйлдлийг гүйцэтгэсэний дараа илрэх үр дүнгүүд.
Нэмэх: гэрэлтэй болох ба 2 өнгөний хослол харагдана. washed out харагдана. 1-ээс илүү гарах магадлалтай.
Хасах: Өнгө нь бүүдийж манантай бохир болсон мэт харагдана. Сөрөг утга гарах нь түгээмэл тохиолддог.
Үржүүлэх: Өнгөнд филтер тависан мэт харанхуйлж харагдана.
Хуваах: Ихэвчлэн цагаан болно.
Color to Float
Стандарт RenderMan нь бутархайг өнгө болгож хувиргах дотоод функцийг агуулсан байдаг. Нэг утга дамжуулбал тухайн утгыг гурав хувилаад харгалзах гурван сувагт онооно. Өөрөөр хэлбэл color white = 1; гэж бичвэл дотоод хэсэгтээ color white = (1,1,1) утгыг хадгална. Хоёр өнгийг харьцуулах үйлдэл хийвэл хөрвүүлэлтийн алдааг илгээнэ. Ихэнхи өнгөний хувьсагч varying төрлийх байдаг ба үүнийг нөхцөл шалгах, цикл зэрэгт ашиглахад хурд удаашрахыг тооцолгүй орхилоо гэхэд л өөр баахан хүндрэл тулгарна. Ийм учраас бид өөрийн гэсэн бутархайг өнгө рүү хувиргах функцыг үүсгэх болно. Хэрвээ та өнгийг гурван тоогоор илэрхийлэгддэгийг мэдэж байгаа бол энэ гурвыг нэмээд гуравт хувааж дундаж утгыг нь гаргаж авна. Энэ бол өнгийг бутархай руу хувиргах хамгийн энгийн арга юм. Энэ хувиргалтыг хийх хоёр аргыг бид үзнэ. Эхнийх нь RSL функц бол хоёр дахь нь C++ макро юм. Бид өнгөний бүрэлдэхүүнүүд рүү массив хандалтаар хандана. Хэрэв таны сонгосон зурагч тань RSL-ийн шинэ төрлийг дэмждэггүй бол (comp())-ийн тусламжтайгаар элемэнтүүд рүү хандана.
float color2float (color col)
{
return (col[0]+col[1]+col[2])/3;
}
#define COLOR2FLOAT(x) (x[0]+x[1]+x[2])/3
float color2float (color col)
{
return (col[0]+col[1]+col[2])/3;
}
#define COLOR2FLOAT(x) (x[0]+x[1]+x[2])/3
Advanced Color Mixing Operations
Adobe Photoshop-ийг ашиглаж байсан хүмүүс зургийн давхаргууд хэрхэн хоорондоо холигдож уусдагийг сайн мэдэж байгаа. Дижитал зургийг засаж янзлахдаа screen болон overlay төрлийн холбоосыг маш өргөн ашигладаг. Эдгээр нь үнэхээр ашигтай учраас гол гол аргуудтай адил үүрэгтэй RSL функцуудыг бид үүсгэнэ. Энэ номонд танилцуулагдаж байгаа функцууд нь дараахь нэршлийг ашиглана:
■ colorMode, функцийн гүйцэтгэх үүргийг тайлбарлаж ямар үр дүн харуулахыг заана.
■ BaseMap доод буюу үндсэн давхаргын өнгийг илэрхийлнэ
■ Layer дээд давхаргын өнгө.
■ LayerOpac холилтыг тохируулах утгыг илэрхийлнэ.
Холих функцыг хөгжүүлэх үйл явцын туршид доорхи хоёр зурагт харагдаж байгаа өнгөний утгыг ашиглана.
■ colorMode, функцийн гүйцэтгэх үүргийг тайлбарлаж ямар үр дүн харуулахыг заана.
■ BaseMap доод буюу үндсэн давхаргын өнгийг илэрхийлнэ
■ Layer дээд давхаргын өнгө.
■ LayerOpac холилтыг тохируулах утгыг илэрхийлнэ.
Холих функцыг хөгжүүлэх үйл явцын туршид доорхи хоёр зурагт харагдаж байгаа өнгөний утгыг ашиглана.
Зураг 5.33
Зураг 5.34
Эдгээр функцууд Jens Gruschel-ийн ажиллагаан дээр тулгуурлаж бүтээгдсэн.
colorOver()
The most basic of the blending modes is Over, a simple linear interpolation
between BaseMap and Layer using the value of LayerOpac as a mixing value. The code
uses the built-in function mix() to perform the operation. You could use mix()
instead of colorOver() any time; we are just defining colorOver() mode for consistency.
Figure 5.35 illustrates the output of using an Over operation.
Хамгийн энгийн холих арга бол Over бөгөөд BaseMap Layer хоёрыг LayerOpac-ын утгыг харгалзан шугаман хамаарлын зарчмаар нийлүүлдэг. Энэ аргыг хэрэгжүүлэхдээ RSL-ийн mix() функцыг ашиглана. Ер нь colorOver()-ийн оронд mix() хэрэглэхэд тохиромжтой.
/***********Хамгийн энгийн холих арга бол Over бөгөөд BaseMap Layer хоёрыг LayerOpac-ын утгыг харгалзан шугаман хамаарлын зарчмаар нийлүүлдэг. Энэ аргыг хэрэгжүүлэхдээ RSL-ийн mix() функцыг ашиглана. Ер нь colorOver()-ийн оронд mix() хэрэглэхэд тохиромжтой.
* Over mode
* Over mode is a simple linear interpolation between the base map
* and the blending layer
********/
color colorOver(color BaseMap; color Layer; float LayerOpac){
return( color mix(BaseMap,Layer,LayerOpac));
}
Зураг 5.35
colorAdd(), colorSubtract(), and colorMultiply()
These three modes are pretty much the same as using the regular add, subtract,
and multiply operators except that these operations allow you to use a mixing value
that can be any float value, even an alpha or luminance map. The result of
colorAdd() and colorSubtract() can be seen in Figures 5.36 and 5.37.
/*********** Add mode
* Color add mode performs a simple color addition
**********/
color colorAdd(color BaseMap; color Layer; float LayerOpac){
return BaseMap + (Layer * LayerOpac);}
/**********
* subtract mode
* Color subtract mode performs a simple color subtraction
***********/
color colorSubtract(color BaseMap; color Layer; float LayerOpac){
return BaseMap + ((Layer-1)* LayerOpac);}
Зураг 5.36
Зураг 5.37
Notice that there is a small amount of extra code in the multiply function. This
is done so that we can use a blending value to control the multiplication. First
multiply the Layer color by the LayerOpac value. The effect of this operation is that
Layer will be dimmed by the value of LayerOpac. If we multiply this value directly
into BaseMap, the output of the multiplication will be a darkening of the whole texture
based on the LayerOpac value (whenever there is a 0 in a series of multiplications,
the result will be always be 0). This is not the desired effect. We want the
multiplication of the two layers to be driven by LayerOpac, not to be darkened by
it. We solve the problem by adding the inverted value of LayerOpac back into the
multiplication of Layer and LayerOpac. Figures 5.38, 5.39, and 5.40 demonstrate
what would happen if we didn’t do the inversion at the end compared to what our
colorMultiply function returns.
/*********
* Multiply mode
* Multiply mode performs as simple multiplication, taking into account the
* value of LayerOpac
**********/
* Multiply mode
* Multiply mode performs as simple multiplication, taking into account the
* value of LayerOpac
**********/
color colorMultiply(color BaseMap; color Layer; float LayerOpac)
{
return BaseMap * ((Layer * LayerOpac) + ( 1 - LayerOpac));
}
return BaseMap * ((Layer * LayerOpac) + ( 1 - LayerOpac));
}
Зураг 5.38
Зураг 5.39
Зураг 5.40
colorDissolve()
Dissolve uses a random noise value to mix between the two supplied colors.
Actually, it compares the value returned by the rand() lookup against the supplied
LayerOpac value. If the value from rand is less, then the Layer color is used; if it is
higher, the BaseMap color is used. The result is a noisy blend of Layer on top of
BaseMap. The output of this function can be seen in Figure 5.41.
/******* Dissolve
*
* Use the value of LayerOpac to randomly choose between Layer
* BaseMap
*
******/
color colorDissolve(color BaseMap; color Layer; float LayerOpac)
{
color out;
if (float random() < (LayerOpac))
out = Layer;
else
out = BaseMap;
return out;
}
color out;
if (float random() < (LayerOpac))
out = Layer;
else
out = BaseMap;
return out;
}
Зураг 5.41
colorScreen()
Screen mode is probably one of the most useful blending modes in Photoshop. It
can be thought of as inverted multiplication because both colors will be inverted,
multiplied by each other, and then finally inverted once again to make the colors
positive again. We need to do a little bit of trickery to get the LayerOpac value to
have the right effect. Figure 5.42 illustrates colorScreen().
/***** Screen Mode
*
* Screen is almost the opposite of Multiply. Both layers are
* inverted, multiplied by each other and then the result is
* inverted one more time
*
*****/
color colorScreen(color BaseMap;color Layer; float LayerOpac)
{
return 1 - ((1-BaseMap) * (1-Layer * LayerOpac));
}
return 1 - ((1-BaseMap) * (1-Layer * LayerOpac));
}
Зураг 5.42
colorOverlay()
The Overlay mode is a combination of colorMultiply() and colorScreen(). It uses the
value of the blending layer to decide whether to multiply or to screen. If the value of
the blending layer is greater than 0.5, then we multiply; if it is less, we screen. For this
function we had to modify how we used the LayerOpac value so that when the opacity
of the layer is set to 0, BaseMap remains unchanged as shown in Figure 5.43.
/***** Overlay Mode
*
* is almost the opposite of Multiply. Both layers are
* inverted, multiplied by each other and then the result is
* inverted one more time
*
*****/
color colorOverlay(color BaseMap; color Layer; float LayerOpac){
float layerval= colorToFloat(Layer);
return (layerval > 0.5) ? (2 * BaseMap * Layer * LayerOpac)+ BaseMap * (1-LayerOpac):
1 - ((1-BaseMap) * ( 1 - Layer * LayerOpac))*(2 - (1-LayerOpac));
}
1 - ((1-BaseMap) * ( 1 - Layer * LayerOpac))*(2 - (1-LayerOpac));
}
Зураг 5.43
colorDarken() and colorLighten()
The Darken blending mode produces visual results that are somewhat similar to
the results of the Multiply mode, where a completely white layer won’t change the
background image, and a black layer will generate a black image output. However,
the math used in this mode is very different from that used in Multiply. In Darken
mode, both images are compared to each other pixel by pixel. If the value of the
layer is smaller than the base, the base color is used; if not, the Layer color is used.
Figure 5.44 illustrates the output of colorDarken().
/***** Darken Mode
* Both layers are compared to each other. If the layer is greater than
* the base then the base is used, if not then the layer is used
*****/
color colorDarken(color BaseMap; color Layer; float LayerOpac){
float baseval = colorToFloat(BaseMap);
float layerval= colorToFloat(Layer);
return (baseval < layerval) ? BaseMap: Layer * LayerOpac +(BaseMap * (1-LayerOpac));
}
float baseval = colorToFloat(BaseMap);
float layerval= colorToFloat(Layer);
return (baseval < layerval) ? BaseMap: Layer * LayerOpac +(BaseMap * (1-LayerOpac));
}
Зураг 5.44
As it would be expected, colorLighten() does exactly the opposite of colorDarken(),
as shown in Figure 5.45. All we need to do is switch the comparing term in the
return line. The rest of the operation still applies.
/***** Lighten Mode
* Both layers are compared to each other. If the layer is smaller than
* the base then the base is used, if not then the layer is used
*****/
color colorLighten(color BaseMap; color Layer; float LayerOpac){
float baseval = colorToFloat(BaseMap);
float layerval= colorToFloat(Layer);
return (baseval > layerval) ? BaseMap: Layer * LayerOpac +(BaseMap * (1-LayerOpac));
}
float layerval= colorToFloat(Layer);
return (baseval > layerval) ? BaseMap: Layer * LayerOpac +(BaseMap * (1-LayerOpac));
}
Зураг 5.45
colorDifference()
Using the value from the top layer to invert the colors of the base layer results in
a very interesting effect, reminiscent of those psychedelic posters from the 1960s
and 1970s. I haven’t used this mode that much, but I’m sure it can be handy while
painting textures.
Here is how it works. We simply subtract the value of the layer from the basemap.
We then apply an abs() function to the output; otherwise we would end up with
negative values, which are usually not that useful. Since RSL’s built-in abs() doesn’t
support colors, just floats, we will create a function that will allow us to return
the absolute value of a color.
a very interesting effect, reminiscent of those psychedelic posters from the 1960s
and 1970s. I haven’t used this mode that much, but I’m sure it can be handy while
painting textures.
Here is how it works. We simply subtract the value of the layer from the basemap.
We then apply an abs() function to the output; otherwise we would end up with
negative values, which are usually not that useful. Since RSL’s built-in abs() doesn’t
support colors, just floats, we will create a function that will allow us to return
the absolute value of a color.
/*********
* colorAbs()
* Returns the absolute value of a color
********/
color colorAbs(color col){
return color( abs(col[0]), abs(col[1]), abs(col[2])); }
* Difference mode
* Returns the absolute value of the subtraction of layer from basemap
********/
color colorDifference (color BaseMap; color Layer; float LayerOpac){
return colorAbs(BaseMap – (Layer * LayerOpac));}
* colorAbs()
* Returns the absolute value of a color
********/
color colorAbs(color col){
return color( abs(col[0]), abs(col[1]), abs(col[2])); }
Once again we must take into consideration the use of an alpha value to control
the opacity of the blend. In this case it is very simple to implement the opacity.
All we have to do is multiply the opacity value by the layer color before we subtract
it from the base layer. This is what the final colorDifference() function will
look like, followed by Figure 5.46, which is its output.
/********** Difference mode
* Returns the absolute value of the subtraction of layer from basemap
********/
color colorDifference (color BaseMap; color Layer; float LayerOpac){
return colorAbs(BaseMap – (Layer * LayerOpac));}
Зураг 5.46
colorHardlight() and colorSoftlight()
* Hardlight mode
* Hardlight is pretty much the same as overlay but we reverse the conditional
* statement so that if the value of the blending layers is LESS than 0.5
* we multiply and if it is larger we screen
*********/
color colorHardlight(color BaseMap;color Layer; float LayerOpac){
float layerval= colorToFloat(Layer);
return (layerval < 0.5) ? (2 *BaseMap*Layer * LayerOpac) +BaseMap * (1-LayerOpac): 1 - ((1-BaseMap) * ( 1 - Layer *LayerOpac))*(2 - (1-LayerOpac));
}
These two blending modes are also very popular, and despite their associative
names, internally they are very different from each other. Hardlight mode darkens
the base layer where the blending layer is dark and lightens it where the blending
layer is bright. It is somewhat of a mix between the Screen and Multiply modes.
Softlight provides a similar visual effect but with a lot less intensity. The dark areas
of the blending layer darken the base layer, but only a little bit.
As previously mentioned, Hardlight is a mix between colorMultiply() and
colorScreen(). It is almost identical to colorOverlay() mode, with the difference
that we switch when we multiply and screen. In Overlay we multiplied when the
value of the blending layer was greater than 0.5. Hardlight is exactly the opposite,
as shown in Figure 5.47.
/*************** Hardlight mode
* Hardlight is pretty much the same as overlay but we reverse the conditional
* statement so that if the value of the blending layers is LESS than 0.5
* we multiply and if it is larger we screen
*********/
color colorHardlight(color BaseMap;color Layer; float LayerOpac){
float layerval= colorToFloat(Layer);
return (layerval < 0.5) ? (2 *BaseMap*Layer * LayerOpac) +BaseMap * (1-LayerOpac): 1 - ((1-BaseMap) * ( 1 - Layer *LayerOpac))*(2 - (1-LayerOpac));
}
Зураг 5.47
Softlight mode produces a similar visual output to Hardlight, but the code is
entirely different internally. The output is obtained through a series of operations
that begins with a multiplication of the two layers. Then we add the base layer,
which is multiplied by a screened blend layer. For simplicity we will use the mix()
function to control the contribution of LayerOpac in this blend mode. Figure 5.48
shows the output of colorSoftlight().
/*************** Softlight mode
* Softlight generates an output similar to Hardlight but with a more subtle
* effect.
*********/
color colorSoftlight(color BaseMap; color Layer; float LayerOpac){
color ctemp = BaseMap * Layer;
return mix(BaseMap,ctemp + (BaseMap * (1-((1-BaseMap)*(1-Layer)) - ctemp)),LayerOpac);
}
Зураг 5.48
colorDodge() and colorBurn()
The final pair of operations that we will introduce are Dodge (brighten) and Burn
(darken). The brightening effect of Dodge is different from that attained by applying
colorLighten(). The Dodge operation will increase the color value of the BaseMap
based on the intensity of the blending layer. If the blending layer is black, then
the Dodge operation has no effect. The final result is that a Dodge operation makes
the BaseMap a lot more saturated and intense where the blending layer is bright.
colordodge() is calculated by dividing the color value of the BaseMap by the color
value of the blending layer. As simple as it sounds, there are several things that we
need to consider to have a finished colorDodge() function that will behave properly.
First we need to always beware of division by zero, which will result in rendering
errors. We solve this problem by using a max() function. We then use a mix() function
to control how much the layer is blended on top of the BaseMap. The division
can easily return values that are beyond the 0 to 1 range, so we apply a clamp()
function to make sure the function returns colors within the 0 to 1 range. Figure
5.49 shows the output of colorDodge().
(darken). The brightening effect of Dodge is different from that attained by applying
colorLighten(). The Dodge operation will increase the color value of the BaseMap
based on the intensity of the blending layer. If the blending layer is black, then
the Dodge operation has no effect. The final result is that a Dodge operation makes
the BaseMap a lot more saturated and intense where the blending layer is bright.
colordodge() is calculated by dividing the color value of the BaseMap by the color
value of the blending layer. As simple as it sounds, there are several things that we
need to consider to have a finished colorDodge() function that will behave properly.
First we need to always beware of division by zero, which will result in rendering
errors. We solve this problem by using a max() function. We then use a mix() function
to control how much the layer is blended on top of the BaseMap. The division
can easily return values that are beyond the 0 to 1 range, so we apply a clamp()
function to make sure the function returns colors within the 0 to 1 range. Figure
5.49 shows the output of colorDodge().
/**********
* Dodge mode
* The Dodge mode is obtained by dividing the BaseMap by the inverse of the
* Layer value.
* NOTE - we must use a max() to prevent a division by zero which
* would result in rendering errors.
***************/
color colorDodge(color BaseMap; color Layer; float LayerOpac){
color ctemp = mix(BaseMap,BaseMap / max(1-Layer,color(0.00001)),LayerOpac);
return clamp(ctemp,color(0),color(1));
}
* Dodge mode
* The Dodge mode is obtained by dividing the BaseMap by the inverse of the
* Layer value.
* NOTE - we must use a max() to prevent a division by zero which
* would result in rendering errors.
***************/
color colorDodge(color BaseMap; color Layer; float LayerOpac){
color ctemp = mix(BaseMap,BaseMap / max(1-Layer,color(0.00001)),LayerOpac);
return clamp(ctemp,color(0),color(1));
}
Зураг 5.49
Burn mode is similar in properties to Dodge mode, but instead of brightening the
image where the blending layer is bright and having no effect where it is dark, Burn
mode will darken the BaseMap where Layer is dark, and it will oversaturate the BaseMap where Layer is bright, as you can see in Figure 5.50. The calculation of Burn is very
similar to Dodge except that we divide the inverse of the BaseMap by the blending layer,
and the result of that division is inverted again to make a positive image.
/*********** Burn mode
* The burn mode is obtained by dividing the inverse BaseMap by the
* Layer value and then inverting that result.
* NOTE - we must use a max() to prevent a division by zero which
* would result in rendering errors.
***************/
color colorBurn(color BaseMap; color Layer; float LayerOpac){
color ctemp = mix(BaseMap,1-((1-BaseMap)/max(Layer,color(0.00001))),LayerOpac);
return clamp(ctemp,color(0),color(1));
}
Зураг 5.50
There are many other ways to combine color values. There are also other blending
modes that we will not cover because they are not used as often as those
described here. Using the previously described modes as examples, it is very easy
to create new blending modes using Jens Gruschel’s Blend Modes page as a reference.
The development of blending modes is left as an exercise for the reader.
modes that we will not cover because they are not used as often as those
described here. Using the previously described modes as examples, it is very easy
to create new blending modes using Jens Gruschel’s Blend Modes page as a reference.
The development of blending modes is left as an exercise for the reader.
No comments:
Post a Comment