Pulsating Bubble Shader

advertisement
Bubble Shader
Bubble Shader
John Isidoro
ATI Research
David Gosselin
ATI Research
Introduction
One of the most visually interesting objects in the real world are soap bubbles.
The reflective and partially transparent nature of them as well as the way they pulsate
makes them a key candidate for vertex and pixel shaders. Strangely enough, on a vertex
and pixel shader level, they are implemented in a very similar manner to the ocean water
shader described in “Rendering Ocean Water.” There are a variety of different effects
that make up the bubble shader.
Setup
As input this shader uses a model with a position, a normal, the tangent vector (in
v direction of texture coordinates), and one set of texture coordinates for a rainbow like
base map (shown in the following figure),
Figure 1 – Base “rainbow” map
This shader, like the “Crystal/Candy Shader” uses a cubic environment map
shown below.
Excerpted from ShaderX: Vertex and Pixel Shader Tips and Tricks
1
Bubble Shader
Figure 2 – Cubic environment map color
Figure 3 – Cubic environment map alpha
Also, like the candy shader, we want this object to be semi-transparent which
requires drawing the model in two passes, back faces first then front faces with alpha
blending enabled.
Vertex Shader
The vertex shader uses four sine waves traveling in different directions over the
surface of the bubble to perturb the vertex. The vertex is perturbed in the direction of the
normal. In order to perturb the normal, cosine waves traveling in the same four
directions are used. In order to provide a consistent looking warping across vertices, the
tangent and bi-normal are used to guide the direction of the sinusoidal warp. The first
portion of the vertex shader looks almost identical to the ocean shader and is shown
below.
//
//
//
//
//
//
//
//
v0
v3
v7
v8
c0
c1
c2
c3
-
- Vertex Position
Vertex Normal
Vertex Texture Data u,v
Vertex Tangent (v direction of tex coords)
{ 0.0, 0.5, 1.0, 2.0}
{ 4.0, .5pi, pi, 2pi}
{1, -1/3!, 1/5!, -1/7!} for sin
{1/2!, -1/4!, 1/6!, -1/8!} for cos
Excerpted from ShaderX: Vertex and Pixel Shader Tips and Tricks
2
Bubble Shader
// c4-7
// c8
// c9
// c10
// c11
// c12
// c13
// c14
// c15
// c16
// c17
vs.1.1
mul r0,
mad r0,
mov
mad
add
frc
frc
mov
-
Composite World-View-Projection Matrix
Model Space Camera Position
Model Space Light Position
{1.02, 0.04, 0, 0} fixup factor for Taylor series imprecision
{0.5, 0.5, 0.25, 0.25} waveHeight0, waveHeight1, waveHeight2, waveHeight3
{0.0, 0.0, 0.0, 0.0} waveOffset0, waveOffset1, waveOffset2, waveOffset3
{0.6, 0.7, 1.2, 1.4} waveSpeed0, waveSpeed1, waveSpeed2, waveSpeed3
{0.0, 2.0, 0.0, 4.0} waveDirX0, waveDirX1, waveDirX2, waveDirX3
{2.0, 0.0, 4.0, 0.0} waveDirY0, waveDirY1, waveDirY2, waveDirY3
{ time, sin(time)}
{-0.00015, 1.0, 0.0, 0.0} base texcoord distortion x0, y0, x1, y1
c14, v7.x
c15, v7.y, r0
r1, c16.x
r0, r1, c13, r0
r0, r0, c12
r0.xy, r0
r1.xy, r0.zwzw
r0.zw, r1.xyxy
// use tex coords as inputs to sinusoidal warp
// use tex coords as inputs to sinusoidal warp
// time...
// add scaled time to move bumps according to frequency
// take frac of all 4 components
mul r0, r0, c10.x
sub r0, r0, c0.y
mul r0, r0, c1.w
// multiply by fixup factor (due to inaccuracy of taylor series)
// subtract .5
// mult tex coords by 2pi coords range from(-pi to pi)
mul
mul
mul
mul
mul
mul
mul
//
//
//
//
//
//
//
r5,
r1,
r6,
r2,
r7,
r3,
r8,
r0,
r5,
r1,
r6,
r2,
r7,
r3,
r0
r0
r0
r0
r0
r0
r0
(wave
(wave
(wave
(wave
(wave
(wave
(wave
vec)^2
vec)^3
vec)^4
vec)^5
vec)^6
vec)^7
vec)^8
mad r4, r1, c2.y, r0
mad r4, r2, c2.z, r4
mad r4, r3, c2.w, r4
//(wave vec) - ((wave vec)^3)/3!
// + ((wave vec)^5)/5!
// - ((wave vec)^7)/7!
mov
mad
mad
mad
mad
//1
//-(wave
//+(wave
//-(wave
//+(wave
r0,
r5,
r5,
r5,
r5,
c0.z
r5, c3.x ,r0
r6, c3.y, r5
r7, c3.z, r5
r8, c3.w, r5
vec)^2/2!
vec)^4/4!
vec)^6/6!
vec)^8/8!
dp4 r0, r4, c11
//multiply wave heights by waves
mul r0, r0, v3
//apply deformation in direction of normal
add r10.xyz, r0, v0
mov r10.w, c0.z
//add to position
//homogenous component
m4x4
mov
// OutPos = WorldSpacePos * Composite View-Projection Matrix
// Pass along texture coordinates
oPos, r10, c4
oT0, v7
This is where the shader starts to diverge a bit from the Ocean shader. First the
binormal is computed
mov
mul
mad
r3, v3
r4, v8.yzxw, r3.zxyw
r4, v8.zxyw, -r3.yzxw, r4
//cross product to find binormal
Then the normal is warped based on the tangent space basis vectors (tangent and
binormal).
mul
dp4
dp4
mul
r1, r5, c11
r9.x, -r1, c14
r9.y, -r1, c15
r1, r4, r9.x
//cos * waveheight
//amount of normal warping in direction of binormal
//amount of normal warping in direction of tangent
//normal warping in direction of binormal
Excerpted from ShaderX: Vertex and Pixel Shader Tips and Tricks
3
Bubble Shader
mad
mad
r1, v8, r9.y, r1
r5, r1, c10.y, v3
//normal warping in direction of tangent
//warped normal move nx, ny: cos * wavedir * waveheight
The normal is then renormalized.
dp3
rsq
mul
r10.x, r5, r5
r10.y, r10.x
r5, r5, r10.y
//normalize warped normal
Next the view vector is computed:
sub
dp3
rsq
mul
r2, c8, r0
r10.x, r2, r2
r10.y, r10.x
r2, r2, r10.y
//view vector
//normalized view vector
Then the dot product of the view vector and the warped normal is computed:
dp3
mov
r7, r5, r2
oT2, r7
//N.V
//Pass along N.V
This is used to compute the reflection vector.
add
mad
mov
r6, r7, r7
r6, r6, r5, -r2
oT1, r6
//2N.V
//2N(N.V)-V
//reflection vector
And finally the distance to the camera is computed.
rcp
mad
r10.y, r10.y
//distance from camera
oD0, r10.y, c17.x, c17.y //scale and bias distance
The vertex shader then passes along the texture coordinates of the base map, the
reflection vector, the value of N·V, and the distance to the camera along to the pixel
shader for further processing.
Pixel Shader
The pixel shader uses the brightly colored rainbow film map as a base texture.
This texture map is meant to simulate the soap film appearance of a bubble. The
environment map is modulated with this texture. The white highlights are stored in the
alpha of the environment map as a glow map, and are linearly interpolated into the result.
The final alpha value used from blending with the frame buffer is the (1-abs(N·V)) +
glow map. The full shader is shown below and further descriptions follow.
// c0 – (0.0, 0.5, 1.0, -0.75)
// c1 - (0.6, 0.1, 0.0, 0.0) Alpha Scale and bias
ps.1.4
texld r0, t0
texld r1, t1
texcrd r2.rgb, t2
cmp r2.r, r2.r, r2.r, -r2.r
// abs(V.N)
+mad_x4_sat r1.a, r1.a, r1.a, c0.a
Excerpted from ShaderX: Vertex and Pixel Shader Tips and Tricks
4
Bubble Shader
mul_x2_sat r2.rgb, r0, r1
+mad r2.a, 1-r2.r, c1.x, c1.y
// base * env (may change scale factor later)
// alphascale * abs(V.N) + alphabias
lrp r0.rgb, r1.a, r1, r2
+add r0.a, r2.a, r1.a
// Lerp between Env and Base*Env based on glow map
// Add glow map to Fresnel term for alpha
The first thing that happens in this pixel shader is the sampling of the environment
map. This happens in the following line of the pixel shader:
texld r1, t1
It produces the following image:
Figure 4 – Cubic environment map only
Figure 5 – Base map
This is multiplied by the base texture color (shown in figure 5) using the
following code.
mul_x2_sat r2.rgb, r0, r1
//
base * env (may change scale factor later)
With the results shown below.
Excerpted from ShaderX: Vertex and Pixel Shader Tips and Tricks
5
Bubble Shader
Figure 6 – Cubic environment map modulated with base map
Figure 7 – Alpha for environment map
Now that the basic colors are computed the opacity needs to be computed. The
first step is to create strong specular looking term. The alpha of the environment map
(show in figure 7) is squared, multiplied by four and then given a bit of a bias. The
following pixel shader co-issued instruction accomplishes this.
+mad_x4_sat r1.a, r1.a, r1.a, c0.a
The resulting image is shown below.
Figure 8 – Alpha of the environment map squared and multiplied by four.
Excerpted from ShaderX: Vertex and Pixel Shader Tips and Tricks
6
Bubble Shader
Next the Fresnel term is computed. This takes place in few stages the first is to
take the absolute value of V·N and the second is to invert this value by computing 1abs(V·N). This value is then scaled and biased. The following code shows how this is
computed.
cmp r2.r, r2.r, r2.r, -r2.r
// abs(V.N)
+mad r2.a, 1-r2.r, c1.x, c1.y
// alphascale * abs(V.N) + alphabias
The following picture shows the result of this computation.
Figure 9 – Scaled and biased Fresnel term.
The next step is to add the Fresnel term with the glow map. Using the following code.
+add r0.a, r2.a, r1.a
// Add glowmap to Fresnel term for alpha
This produces the final alpha result used for blending and is shown below.
Figure 10 – Final alpha values
Next the glow map is used to linearly interpolate between just the environment
map and the base multiplied by the environment map based on the alpha value in the
environment map.
lrp r0.rgb, r1.a, r1, r2
// Lerp between Env and Base*Env based on glow map
Excerpted from ShaderX: Vertex and Pixel Shader Tips and Tricks
7
Bubble Shader
This produces the final color values shown below.
Figure 11 – Final color values
The next figure shows the blend produced by the alpha and color to produce the final
image.
Figure 12 – Final Image
The next shot shows what this shader produces within a scene produced by the
ATI Sushi engine.
Excerpted from ShaderX: Vertex and Pixel Shader Tips and Tricks
8
Bubble Shader
Figure 13 – Bubble in an environment
Summary
This section has shown a technique to produce an interesting bubble effect built
on top of some techniques described in other sections. It used sine waves computed
within a vertex shader to produce and undulating shape and cubic environment mapping
to give interesting reflections.
Excerpted from ShaderX: Vertex and Pixel Shader Tips and Tricks
9
Download