Simulation of Iridescence and Translucency on Thin Surfaces
Simulation of Iridescence and Translucency on Thin Surfaces Simulation of Iridescence and Translucency on Thin Surfaces
From ShaderX 2 – Shader Programming Tips
- Page 2 and 3: Simulation <strong
- Page 4 and 5: Pixel Shader Simulation</st
- Page 6 and 7: Simulation <strong
- Page 8 and 9: Simulation <strong
- Page 10 and 11: Simulation <strong
From ShaderX 2 – Shader Programming Tips <str<strong>on</strong>g>and</str<strong>on</strong>g> Tricks with DirectX 9<br />
<str<strong>on</strong>g>Simulati<strong>on</strong></str<strong>on</strong>g> <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>Iridescence</str<strong>on</strong>g> <str<strong>on</strong>g>and</str<strong>on</strong>g><br />
<str<strong>on</strong>g>Translucency</str<strong>on</strong>g> <strong>on</strong> <strong>Thin</strong> <strong>Surfaces</strong><br />
Introducti<strong>on</strong><br />
Natalya Tatarchuk <str<strong>on</strong>g>and</str<strong>on</strong>g> Chris Brennan<br />
3D Applicati<strong>on</strong> Research Group<br />
ATI Research<br />
This chapter will focus <strong>on</strong> simulating the visual effect <str<strong>on</strong>g>of</str<strong>on</strong>g> translucency <str<strong>on</strong>g>and</str<strong>on</strong>g><br />
iridescence <str<strong>on</strong>g>of</str<strong>on</strong>g> thin surfaces such as butterfly wings. When creating a visual impressi<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g><br />
a particular material, an important characteristic <str<strong>on</strong>g>of</str<strong>on</strong>g> that surface is the luminosity <str<strong>on</strong>g>of</str<strong>on</strong>g> the<br />
material. There are various ways a surface can be luminous. Those include sources with<br />
or without heat, from an outside source, <str<strong>on</strong>g>and</str<strong>on</strong>g> from the object itself (other than a mere<br />
reflecti<strong>on</strong>). Luminous objects that exhibit certain combinati<strong>on</strong>s <str<strong>on</strong>g>of</str<strong>on</strong>g> these characteristics<br />
can be described as translucent or iridescent, depending <strong>on</strong> the way that the surface<br />
“scatters” incoming light.<br />
<str<strong>on</strong>g>Translucency</str<strong>on</strong>g> <str<strong>on</strong>g>of</str<strong>on</strong>g> a material is determined by the ability <str<strong>on</strong>g>of</str<strong>on</strong>g> that surface to allow<br />
light to pass through without full transparency. Translucent materials can <strong>on</strong>ly receive<br />
light <str<strong>on</strong>g>and</str<strong>on</strong>g> thus can be luminous <strong>on</strong>ly when lit from an outside source. Although there has<br />
been ample research in the recent years in interactive simulati<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g> fully translucent<br />
surfaces such as marble or wax [Jensen01], this chapter will focus <strong>on</strong> simulating<br />
translucency for thin surfaces. A good example <str<strong>on</strong>g>of</str<strong>on</strong>g> the visual effect <str<strong>on</strong>g>of</str<strong>on</strong>g> translucency <str<strong>on</strong>g>of</str<strong>on</strong>g> thin<br />
surfaces would be if you were to take a piece <str<strong>on</strong>g>of</str<strong>on</strong>g> rice paper <str<strong>on</strong>g>and</str<strong>on</strong>g> hold it against a light<br />
source (for example, Chinese lanterns). You would see that the light makes the rice paper<br />
seem to glow from within, yet you cannot see the light source through the paper because<br />
the paper scatters incoming light.<br />
<str<strong>on</strong>g>Iridescence</str<strong>on</strong>g> is an effect caused by the interference <str<strong>on</strong>g>of</str<strong>on</strong>g> light waves resulting from<br />
multiple reflecti<strong>on</strong>s <str<strong>on</strong>g>of</str<strong>on</strong>g> light <str<strong>on</strong>g>of</str<strong>on</strong>g>f <str<strong>on</strong>g>of</str<strong>on</strong>g> surfaces <str<strong>on</strong>g>of</str<strong>on</strong>g> varying thickness. This visual effect can be<br />
detected as a rainbow pattern <strong>on</strong> the surface <str<strong>on</strong>g>of</str<strong>on</strong>g> soap bubbles <str<strong>on</strong>g>and</str<strong>on</strong>g> gasoline spills, <str<strong>on</strong>g>and</str<strong>on</strong>g> in<br />
general, <strong>on</strong> surfaces covered with thin film diffracting different frequencies <str<strong>on</strong>g>of</str<strong>on</strong>g> incoming<br />
light in different directi<strong>on</strong>s. The surface <str<strong>on</strong>g>of</str<strong>on</strong>g> a soap bubble exhibits iridescence due to a<br />
layer <str<strong>on</strong>g>of</str<strong>on</strong>g> air, which varies in thickness, between the top <str<strong>on</strong>g>and</str<strong>on</strong>g> bottom surfaces <str<strong>on</strong>g>of</str<strong>on</strong>g> the bubble.<br />
The reflected colors vary al<strong>on</strong>g with the thickness <str<strong>on</strong>g>of</str<strong>on</strong>g> the surface. Mother-<str<strong>on</strong>g>of</str<strong>on</strong>g>-pearl,<br />
compact discs <str<strong>on</strong>g>and</str<strong>on</strong>g> various gem st<strong>on</strong>es share that quality. Perhaps most captivating <str<strong>on</strong>g>of</str<strong>on</strong>g> all,<br />
however, is the iridescence seen <strong>on</strong> the wings <str<strong>on</strong>g>of</str<strong>on</strong>g> many beautiful butterflies, such as Blue<br />
pansy butterflies, Jun<strong>on</strong>ia orithya, or the Malachite butterflies, Siproeta stelenes. These<br />
wings exhibit vivid colorful iridescence (see Figure 1 for examples), the color <str<strong>on</strong>g>of</str<strong>on</strong>g> which<br />
1
<str<strong>on</strong>g>Simulati<strong>on</strong></str<strong>on</strong>g> <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>Iridescence</str<strong>on</strong>g> <str<strong>on</strong>g>and</str<strong>on</strong>g> <str<strong>on</strong>g>Translucency</str<strong>on</strong>g> <strong>on</strong> <strong>Thin</strong> <strong>Surfaces</strong><br />
has been shown to be independent <str<strong>on</strong>g>of</str<strong>on</strong>g> pigmentati<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g> the wings, <str<strong>on</strong>g>and</str<strong>on</strong>g> is attributed to the<br />
microstructure <str<strong>on</strong>g>of</str<strong>on</strong>g> the scales located <strong>on</strong> <str<strong>on</strong>g>and</str<strong>on</strong>g> within butterfly wings.<br />
Blue pansy butterfly<br />
Jun<strong>on</strong>ia orithya<br />
Malachite butterflies<br />
Siproeta stelenes<br />
Figure 1 - Butterflies in nature<br />
The effect described in this chapter simulates translucency <str<strong>on</strong>g>and</str<strong>on</strong>g> iridescence<br />
patterns <str<strong>on</strong>g>of</str<strong>on</strong>g> delicate butterfly wings. To generate iridescence we have merged the<br />
approaches described in “Bubble Shader” [Isidoro02] <str<strong>on</strong>g>and</str<strong>on</strong>g> in “Textures as Lookup Tables<br />
for Per-Pixel Lighting Computati<strong>on</strong>s” [Vlachos02].<br />
Algorithm<br />
Inputs<br />
This effect uses a geometric model with a positi<strong>on</strong>, a normal, a set <str<strong>on</strong>g>of</str<strong>on</strong>g> texture<br />
coordinates, a tangent <str<strong>on</strong>g>and</str<strong>on</strong>g> a binormal vector. All <str<strong>on</strong>g>of</str<strong>on</strong>g> these comp<strong>on</strong>ents are supplied to the<br />
vertex shader. At the pixel level, we combine gloss, opacity, <str<strong>on</strong>g>and</str<strong>on</strong>g> normal maps for a<br />
multi-layered final look. The gloss map is used to c<strong>on</strong>tribute to satiny highlights <strong>on</strong> the<br />
butterfly wings. The opacity map allows the wings to have variable transparency <str<strong>on</strong>g>and</str<strong>on</strong>g> the<br />
normal map is used to give wings a bump-mapped look to allow for more surface<br />
thickness variati<strong>on</strong>s. The input texture coordinates are used to sample all texture maps.<br />
Sample RenderM<strong>on</strong>key TM Workspace<br />
The CD that comes with this book c<strong>on</strong>tains a build <str<strong>on</strong>g>of</str<strong>on</strong>g> the RenderM<strong>on</strong>key IDE<br />
which is an envir<strong>on</strong>ment for shader development. Al<strong>on</strong>g with the applicati<strong>on</strong> itself, the<br />
RenderM<strong>on</strong>key installer installs a series <str<strong>on</strong>g>of</str<strong>on</strong>g> workspaces including <strong>on</strong>e called HLSL<br />
Iridescent Butterfly.xml. This workspace c<strong>on</strong>tains the effect we are describing in this<br />
chapter. Feel free to modify any <str<strong>on</strong>g>of</str<strong>on</strong>g> the parameters to the shaders to explore their effect <strong>on</strong><br />
the final visual result. Of course, you can also modify the actual shaders to underst<str<strong>on</strong>g>and</str<strong>on</strong>g><br />
their algorithms in greater depth.<br />
2
Vertex Shader<br />
From ShaderX 2 – Shader Programming Tips <str<strong>on</strong>g>and</str<strong>on</strong>g> Tricks with DirectX 9<br />
The vertex shader for this effect computes vectors that will be used by the pixel<br />
shader to compute the illuminati<strong>on</strong> result. At the pixel level, the view vector <str<strong>on</strong>g>and</str<strong>on</strong>g> the light<br />
vector will be used for calculating diffuse illuminati<strong>on</strong> <str<strong>on</strong>g>and</str<strong>on</strong>g> scattered illuminati<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g>f <str<strong>on</strong>g>of</str<strong>on</strong>g><br />
the surface <str<strong>on</strong>g>of</str<strong>on</strong>g> the wings, which c<strong>on</strong>tributes to the translucency effect. The halfway vector<br />
will be used for generati<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g> glossy highlights <strong>on</strong> the wings’ surface. In the vertex<br />
shader, however, these vectors will simply be transformed to tangent space.<br />
struct VS_OUTPUT<br />
{<br />
float4 Pos : POSITION;<br />
float2 Tex : TEXCOORD0;<br />
float3 View : TEXCOORD1;<br />
float3 Light : TEXCOORD2;<br />
float3 Half : TEXCOORD3;<br />
};<br />
VS_OUTPUT main( float4 Pos : POSITION,<br />
float4 Normal : NORMAL0,<br />
float2 Tex : TEXCOORD0,<br />
float3 Tangent : TANGENT0,<br />
float3 Binormal : BINORMAL0 )<br />
{<br />
VS_OUTPUT Out = (VS_OUTPUT) 0;<br />
}<br />
// Output transformed vertex positi<strong>on</strong>:<br />
Out.Pos = mul( view_proj_matrix, Pos );<br />
// Propagate input texture coordinates:<br />
Out.Tex = Tex;<br />
// Compute the light vector (object space):<br />
float3 vLight = normalize( mul( inv_view_matrix, lightPos ) - Pos );<br />
// Define tangent space matrix:<br />
float3x3 mTangentSpace;<br />
mTangentSpace[0] = Tangent;<br />
mTangentSpace[1] = Binormal;<br />
mTangentSpace[2] = Normal;<br />
// Output light vector in tangent space:<br />
Out.Light = mul( mTangentSpace, vLight );<br />
// Compute the view vector (object space):<br />
float3 vView = normalize( view_positi<strong>on</strong> - Pos );<br />
// Output view vector in tangent space:<br />
Out.View = mul( mTangentSpace, vView );<br />
// Compute the half angle vector (in tangent space):<br />
Out.Half = mul( mTangentSpace, normalize( vView + vLight ) );<br />
return Out;<br />
3
Pixel Shader<br />
<str<strong>on</strong>g>Simulati<strong>on</strong></str<strong>on</strong>g> <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>Iridescence</str<strong>on</strong>g> <str<strong>on</strong>g>and</str<strong>on</strong>g> <str<strong>on</strong>g>Translucency</str<strong>on</strong>g> <strong>on</strong> <strong>Thin</strong> <strong>Surfaces</strong><br />
The pixel shader computes the illuminati<strong>on</strong> value for a particular pixel <strong>on</strong> the<br />
surface <str<strong>on</strong>g>of</str<strong>on</strong>g> the butterfly wings taking into account the light propagated through the surface<br />
<str<strong>on</strong>g>of</str<strong>on</strong>g> the wings due to the translucency effect <str<strong>on</strong>g>and</str<strong>on</strong>g> light emitted due to the iridescence <str<strong>on</strong>g>of</str<strong>on</strong>g> the<br />
wings.<br />
First, we load the color value from a base texture map. For efficiency reas<strong>on</strong>s, we<br />
have stored the opacity in the alpha channel <str<strong>on</strong>g>of</str<strong>on</strong>g> the base texture map. We also load a<br />
normal vector (in tangent space) from precomputed normal map <str<strong>on</strong>g>and</str<strong>on</strong>g> a gloss value which<br />
will be used to modulate highlights <strong>on</strong> the surface <str<strong>on</strong>g>of</str<strong>on</strong>g> the wings. The scalar gloss map is<br />
stored in the alpha channel <str<strong>on</strong>g>of</str<strong>on</strong>g> the normal map. Combining three-channel texture maps<br />
with a single-channel grayscale value maps allows us to load two values with a single<br />
texture fetch.<br />
float3 vNormal, baseColor;<br />
float fGloss, fTransparency;<br />
// Load normal <str<strong>on</strong>g>and</str<strong>on</strong>g> gloss map:<br />
float4( vNormal, fGloss ) = tex2D( bump_glossMap, Tex );<br />
// Load base <str<strong>on</strong>g>and</str<strong>on</strong>g> opacity map:<br />
float4 (baseColor, fTransparency) = tex2D( base_opacityMap, Tex );<br />
D<strong>on</strong>’t forget to scale <str<strong>on</strong>g>and</str<strong>on</strong>g> bias the fetched normal map into the [-1.0, 1.0] range:<br />
// Signed scale the normal:<br />
vNormal = vNormal * 2 - 1;<br />
4
From ShaderX 2 – Shader Programming Tips <str<strong>on</strong>g>and</str<strong>on</strong>g> Tricks with DirectX 9<br />
Figure 2 displays the c<strong>on</strong>tents <str<strong>on</strong>g>of</str<strong>on</strong>g> the texture maps used for this effect:<br />
Base texture map for wings texture<br />
Normal map for bump mapping<br />
Figure 2 - Input Texture Maps<br />
Opacity texture map<br />
Gloss map<br />
The texture address mode should be set to CLAMP in u <str<strong>on</strong>g>and</str<strong>on</strong>g> v for both <str<strong>on</strong>g>of</str<strong>on</strong>g> these<br />
texture maps. Also they should be trilinearly filtered (MAGFILTER = linear,<br />
MINFILTER = linear, <str<strong>on</strong>g>and</str<strong>on</strong>g> MIPFILTER = anisotropic).<br />
<str<strong>on</strong>g>Translucency</str<strong>on</strong>g><br />
Next we will compute the translucency effect. The amount <str<strong>on</strong>g>of</str<strong>on</strong>g> light scattered<br />
through a thin surface is proporti<strong>on</strong>al to the incident angle <str<strong>on</strong>g>of</str<strong>on</strong>g> the light <strong>on</strong> the back side.<br />
So, similar to a Lambertian diffuse calculati<strong>on</strong>, we dot the light vector but with the<br />
negative <str<strong>on</strong>g>of</str<strong>on</strong>g> the normal vector. We also use a pre-specified translucency coefficient in<br />
additi<strong>on</strong> to the fetched opacity value to c<strong>on</strong>trol the amount <str<strong>on</strong>g>of</str<strong>on</strong>g> scattered light:<br />
float3 scatteredIlluminati<strong>on</strong> = saturate(dot(-vNormal, Light)) *<br />
fTransparency * translucencyCoeff;<br />
5
<str<strong>on</strong>g>Simulati<strong>on</strong></str<strong>on</strong>g> <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>Iridescence</str<strong>on</strong>g> <str<strong>on</strong>g>and</str<strong>on</strong>g> <str<strong>on</strong>g>Translucency</str<strong>on</strong>g> <strong>on</strong> <strong>Thin</strong> <strong>Surfaces</strong><br />
As described above, the scattered light c<strong>on</strong>tributi<strong>on</strong> is dependent <strong>on</strong> both the<br />
directi<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g> incident light as well as the surface normal for the pixel locati<strong>on</strong>. This<br />
c<strong>on</strong>tributi<strong>on</strong> to diffuse illuminati<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g> the wings surface is what accounts for their subtle<br />
glow. Figure 3 illustrates the c<strong>on</strong>tributi<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g> scattered reflected light <strong>on</strong> the surface <str<strong>on</strong>g>of</str<strong>on</strong>g> the<br />
wings. If you modify the pixel shader for this effect in RenderM<strong>on</strong>key workspace found<br />
<strong>on</strong> the CD in this book to output <strong>on</strong>ly the scattered light c<strong>on</strong>tributi<strong>on</strong>, you will be able to<br />
investigate how this c<strong>on</strong>tributi<strong>on</strong> changes as you rotate the model.<br />
To simulate varying thickness <str<strong>on</strong>g>of</str<strong>on</strong>g> scales <strong>on</strong> the surface <str<strong>on</strong>g>of</str<strong>on</strong>g> butterfly wings as well<br />
as within them, we use a normal map to perturb the normal vectors. The usual diffuse<br />
illuminati<strong>on</strong> is computed with a simple dot product <str<strong>on</strong>g>and</str<strong>on</strong>g> a global ambient term:<br />
float3 diffuseC<strong>on</strong>tributi<strong>on</strong> = saturate(dot(vNormal,Light)) +<br />
ambient;<br />
Figure 3 below shows the result <str<strong>on</strong>g>of</str<strong>on</strong>g> computing diffusely reflected light for the butterfly<br />
wings.<br />
Scattered light c<strong>on</strong>tributi<strong>on</strong><br />
Figure 3 - Diffuse Illuminati<strong>on</strong><br />
Diffuse term<br />
In the next step we combine the base texture map with the diffuse term <str<strong>on</strong>g>and</str<strong>on</strong>g> the<br />
scattered reflected light c<strong>on</strong>tributi<strong>on</strong> to compute final value for diffuse surface<br />
illuminati<strong>on</strong>:<br />
baseColor *= scatteredIlluminati<strong>on</strong> + diffuseC<strong>on</strong>tributi<strong>on</strong>;<br />
Figure 4 illustrates the results <str<strong>on</strong>g>of</str<strong>on</strong>g> this operati<strong>on</strong>. Now we can notice how scattered<br />
reflected light c<strong>on</strong>tributes to the translucency effect <str<strong>on</strong>g>of</str<strong>on</strong>g> the butterfly wings in the more<br />
illuminated porti<strong>on</strong>s <str<strong>on</strong>g>of</str<strong>on</strong>g> wings in the final picture in Figure 4.<br />
6
From ShaderX 2 – Shader Programming Tips <str<strong>on</strong>g>and</str<strong>on</strong>g> Tricks<br />
with DirectX 9<br />
+<br />
* =<br />
Figure 4 - Combining the base texture map with scattered reflected light <str<strong>on</strong>g>and</str<strong>on</strong>g> diffusely<br />
Since butterfly wings in nature have varying transparency, we had our artists paint<br />
in the appropriate opacity values. However, since the desired effect has transparent<br />
geometry which also has specular highlights, we must take care when doing blending to<br />
achieve transparency properly. Typically, blending transparent materials is d<strong>on</strong>e during<br />
the blending stage <str<strong>on</strong>g>of</str<strong>on</strong>g> the rendering pipeline. However, if the object that you are rendering<br />
as transparent is a specular surface, blending should be d<strong>on</strong>e before actually applying<br />
specular highlights to the surface. A brute force approach for this would be to render two<br />
separate passes: diffuse alpha-blended pass first; <str<strong>on</strong>g>and</str<strong>on</strong>g> adding specular highlights in the<br />
sec<strong>on</strong>d pass. But to speed up our effect we wanted to do to it all in <strong>on</strong>e pass. This requires<br />
some tricks with the way alpha-blending is used. Since the specular pass is additive <str<strong>on</strong>g>and</str<strong>on</strong>g><br />
diffuse is blended, we want to pre-blend the diffuse color <str<strong>on</strong>g>and</str<strong>on</strong>g> add the specular color in<br />
the shader. Then during the blending stage the source color is not modified, it’s simply<br />
added since that porti<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g> the blending equati<strong>on</strong> is already taken care <str<strong>on</strong>g>of</str<strong>on</strong>g> in the shader<br />
code. The destinati<strong>on</strong> has the same blend as it normally would with the st<str<strong>on</strong>g>and</str<strong>on</strong>g>ard two-pass<br />
“brute force” approach. If we look at the blending equati<strong>on</strong>, the two pass approach would<br />
be expressed in the following form:<br />
Pass 1: diffuseIlluminati<strong>on</strong>Color * α+ destinati<strong>on</strong> * (1 – α)<br />
Pass 2: specularColor + destinati<strong>on</strong><br />
And the single pass approach can be expressed as follows:<br />
Pass 1: (diffuseIlluminati<strong>on</strong>Color * α + specularColor ) * 1+<br />
destinati<strong>on</strong> * (1 - α)<br />
7
<str<strong>on</strong>g>Simulati<strong>on</strong></str<strong>on</strong>g> <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>Iridescence</str<strong>on</strong>g> <str<strong>on</strong>g>and</str<strong>on</strong>g> <str<strong>on</strong>g>Translucency</str<strong>on</strong>g> <strong>on</strong> <strong>Thin</strong> <strong>Surfaces</strong><br />
Here’s the porti<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g> the shader that pre-multiplies the diffuse illuminati<strong>on</strong> result<br />
with the alpha:<br />
float fOpacity = 1 - fTransparency;<br />
// Premultiply alpha blend to avoid clamping:<br />
baseColor *= fOpacity;<br />
Figure 5 illustrates effect <str<strong>on</strong>g>of</str<strong>on</strong>g> this acti<strong>on</strong> <strong>on</strong> the diffuse illuminati<strong>on</strong> result.<br />
<str<strong>on</strong>g>Iridescence</str<strong>on</strong>g><br />
Figure 5 - Pre-multiplied alpha-blending<br />
One <str<strong>on</strong>g>of</str<strong>on</strong>g> the reas<strong>on</strong>s why butterflies are so captivating in nature is the iridescence<br />
<str<strong>on</strong>g>of</str<strong>on</strong>g> their wings. To simulate iridescent patterns <strong>on</strong> the surface <str<strong>on</strong>g>of</str<strong>on</strong>g> our simulated butterfly<br />
wings, we use an approach similar to the technique described in the “Bubble Shader”<br />
chapter in the original ShaderX book [Isidoro02]. <str<strong>on</strong>g>Iridescence</str<strong>on</strong>g> is a view dependent effect,<br />
so we will use the view vector which was computed in the vertex shader <str<strong>on</strong>g>and</str<strong>on</strong>g> interpolated<br />
across the polyg<strong>on</strong> in tangent space. We also use scale <str<strong>on</strong>g>and</str<strong>on</strong>g> bias coefficients to scale <str<strong>on</strong>g>and</str<strong>on</strong>g><br />
bias index to make iridescence change more quickly or slowly across the surface <str<strong>on</strong>g>of</str<strong>on</strong>g> the<br />
wings. You can explore the effects <str<strong>on</strong>g>of</str<strong>on</strong>g> these parameters by modifying the variables<br />
iridescence_speed_scale <str<strong>on</strong>g>and</str<strong>on</strong>g> iridescence_speed_bias in the HLSL Iridescent<br />
Butterfly.xml RenderM<strong>on</strong>key workspace.<br />
// Compute index into the iridescence gradient map,<br />
// which c<strong>on</strong>sists <str<strong>on</strong>g>of</str<strong>on</strong>g> N·V coefficients<br />
float fGradientIndex =<br />
dot( vNormal, View ) * iridescence_speed_scale +<br />
iridescence_speed_bias;<br />
// Load the iridescence value from the gradient map based <strong>on</strong> the<br />
// index we just computed above:<br />
float4 iridescence = tex1D( gradientMap, fGradientIndex );<br />
8
From ShaderX 2 – Shader Programming Tips <str<strong>on</strong>g>and</str<strong>on</strong>g> Tricks with DirectX 9<br />
This effect uses a 1D gradient texture map (Figure 6) for computing color-shifted<br />
iridescence values. This texture should have trilinear filtering enabled <str<strong>on</strong>g>and</str<strong>on</strong>g> MIRROR<br />
texture address mode selected for both u <str<strong>on</strong>g>and</str<strong>on</strong>g> v coordinates.<br />
Figure 6 - Gradient texture map<br />
Figure 7 illustrates the resulting iridescence value.<br />
Figure 7 - <str<strong>on</strong>g>Iridescence</str<strong>on</strong>g> <str<strong>on</strong>g>of</str<strong>on</strong>g> butterfly wings<br />
To add satiny highlights to the surface <str<strong>on</strong>g>of</str<strong>on</strong>g> the wings we use a gloss map generated<br />
by the artist. We compute the gloss value based <strong>on</strong> the result fetched from the gloss map<br />
<str<strong>on</strong>g>and</str<strong>on</strong>g> N·V for determining the placement <str<strong>on</strong>g>of</str<strong>on</strong>g> specular highlights. Finally we add the gloss<br />
c<strong>on</strong>tributi<strong>on</strong> to the previously compute diffuse illuminati<strong>on</strong> result to obtain the final<br />
result:<br />
// Compute the final color using this equati<strong>on</strong>:<br />
// N*H * Gloss * <str<strong>on</strong>g>Iridescence</str<strong>on</strong>g> + Diffuse<br />
float fGlossIndex = fGloss *<br />
( saturate( dot( vNormal, Half )) *<br />
gloss_scale + gloss_bias );<br />
baseColor += fGlossIndex * iridescence;<br />
Figure 8 shows the final color for the butterfly wings.<br />
9
<str<strong>on</strong>g>Simulati<strong>on</strong></str<strong>on</strong>g> <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>Iridescence</str<strong>on</strong>g> <str<strong>on</strong>g>and</str<strong>on</strong>g> <str<strong>on</strong>g>Translucency</str<strong>on</strong>g> <strong>on</strong> <strong>Thin</strong> <strong>Surfaces</strong><br />
Figure 8 - Assembled final color<br />
To render the final effect correctly, we output the previously-computed scalar fOpacity<br />
in the alpha channel <str<strong>on</strong>g>of</str<strong>on</strong>g> our result:<br />
return float4( baseColor, fOpacity );<br />
Because <str<strong>on</strong>g>of</str<strong>on</strong>g> the premultiplicati<strong>on</strong> menti<strong>on</strong>ed earlier, this means that our alpha<br />
blend factors should be ONE for SRCBLEND render state <str<strong>on</strong>g>and</str<strong>on</strong>g> IVRSRCALPHA for<br />
DESTBLEND.<br />
Summary<br />
In this chapter we presented a technique for simulating translucency <str<strong>on</strong>g>and</str<strong>on</strong>g><br />
iridescence <strong>on</strong> thin surfaces such as butterfly wings. Our technique combines scattered<br />
reflected light with diffusely reflected light <str<strong>on</strong>g>and</str<strong>on</strong>g> a color-shifted iridescence value for a<br />
visually interesting final result. You can see this effect in the Chimp Demo in the ATI<br />
RADEON TM 9800 demo suite <strong>on</strong> the ATI website as shown in Figure 9.<br />
10
References<br />
From ShaderX 2 – Shader Programming Tips <str<strong>on</strong>g>and</str<strong>on</strong>g> Tricks with DirectX 9<br />
Figure 9 - A snapshot from the Chimp demo<br />
1. [Demers01] [digital] Texturing <str<strong>on</strong>g>and</str<strong>on</strong>g> Painting, Owen Demers, New Riders, 2001.<br />
2. [Isidoro02] “Bubble Shader”, J. Isidoro, D. Gosselin, ShaderX, 2002.<br />
3. [Vlachos02] “Textures as Lookup Tables for Per-Pixel Lighting Computati<strong>on</strong>s”,<br />
A. Vlachos, J. Isidoro, C. Oat, Game Programming Gems III, 2002.<br />
4. [Jensen01] “A Practical Model for Subsurface Light Transport”, H.W. Jensen,<br />
S.R.Marschner, M. Levoy, P. Hanrahan, Proceedings <str<strong>on</strong>g>of</str<strong>on</strong>g> SIGGRAPH 2001.<br />
11