Data structure:
sky: sky box
wavefild: water surface
wavesource: raindrop representation
waveEvaluator: height field. represent as 1-dimension texture, used wavesource as input, each pixel value is the superposition of each raindrop in this pixel
the equation of ripple as follow:
\( W(t,d) = \frac{A}{1+λ_1*t^2+λ_2*d^2}cos(\frac{Ω}{1+λ_3*t}*(t+\frac{d}{v})+π) \)
where :
t: time
d: distance
λ_1: coefficient of space
λ_2: coefficient of time
λ_3: coefficient of frequency
A: amplitude
v: velocity
Ω: initialization of frequency
wavefielddraw: for scene rendering, included sky, water surface, height fileld. using GPU speedup
GPU pipeline
result:
No raindrop |
Raindrop number: 100 |
Raindrop number: 500 |
Appendix:
GLSL Shader language for computing height field
fragment shader file:
void main()
{
vec2 cpos = gl_TexCoord[0].xy * poolSize;
int i;
float Amplitude = 0.0;
for (i=0; i<n-1; i++)
{
int base = i * SourceSize;
vec4 v1 = texture1D(source, (base * InvN)*0.9998+0.0001);
vec4 v2 = texture1D(source, ((base + 1) * InvN)*0.9998+0.0001);
float InitT = v1.x;
float PosX = v1.y;
float PosY = v1.z;
float A = v1.w;
float Lambda = v2.x;
float Omega = v2.y;
float Velocity = v2.z;
float MaxPhase = v2.w;
float dTime = time - InitT;
float dist = distance(cpos, v1.yz);
float x = dTime - dist / Velocity;
float phase = Omega/(1.0+Lambda2*dTime) * x - PI/2;
Amplitude += A /(1+Lambda*dist*dist+Lambda1*dTime*dTime) *
(cos(phase)) * (x>0?1:0)*(phase<MaxPhase?1:0);
}
gl_FragData[0] = vec4(Amplitude,Amplitude,Amplitude,1.0) ;
}
vertex shader file:
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
}
GLSL Shader language for Rendering
fragment shader file:
void main()
{
vec3 lp = lightPosition;
// vec3 eyedir=(eye-pos).xyz;
vec3 eyedir = (pos-eye).xyz;
vec3 n = normalize(normal.xyz);
vec3 I = normalize(lp - pos.xyz);
vec3 R = normalize(-reflect(-normalize(eyedir), n));
vec3 color = LightColor * max(0.0,dot(I, n)) +
LightSpecularColor * pow(max(0.0,dot(R,I)),4.0);
gl_FragColor = vec4(color,1.0);
}
vertex shader file:
void main()
{
vec4 h = texture2D(height, gl_MultiTexCoord0.xy);
vec4 h1 = texture2D(height, gl_MultiTexCoord0.xy+vec2(dx,0));
vec4 h2 = texture2D(height, gl_MultiTexCoord0.xy+vec2(-dx,0));
vec4 h3 = texture2D(height, gl_MultiTexCoord0.xy+vec2(0,dy));
vec4 h4 = texture2D(height, gl_MultiTexCoord0.xy+vec2(0,-dy));
pos = vec4(gl_Vertex.x, h.y, gl_Vertex.z, 1);
vec3 pos1 = vec3(gl_Vertex.x+dpx, h1.y, gl_Vertex.z);
vec3 pos2 = vec3(gl_Vertex.x-dpx, h2.y, gl_Vertex.z);
vec3 pos3 = vec3(gl_Vertex.x, h3.y, gl_Vertex.z+dpy);
vec3 pos4 = vec3(gl_Vertex.x, h4.y, gl_Vertex.z-dpy);
vec3 n1 = cross(pos1-pos.xyz, pos3-pos.xyz);
vec3 n3 = cross(pos2-pos.xyz, pos4-pos.xyz);
normal = -vec4(0.5*(normalize(n1)+normalize(n3)),1);
eye = gl_ModelViewMatrixInverse * vec4(0,0,0,1);
pos = gl_ModelViewMatrix * pos;
gl_Position = gl_ProjectionMatrix * pos;
gl_TexCoord[0] = gl_MultiTexCoord0;
}