I always implemented this effect by actually writing a complete raytracer/caster, however the version of this effect in ShaderToy greatly simplifies this effect using some old fashioned trigonometry. With some help from my old democoding partner Fractoid we generated a mathematical explanation for this routine.
In essence we use the properties of self-similar triangles to find the intersection distance from the viewer to the plane (see image below).
The camera is shown in red, and the ray from the viewer to the plane is shown in green. The height of the plane above the viewer is 'h', and the distance along the plane to the intersection point is 'd'. We can use our friend from last time, the tangent function, to find the intersection point.
For the lower triangle, if we assume one unit of travel (x) then the angle (theta) will be y / 1.
Now, to solve the same problem but flipped by 90 degrees for the horizontal axis we have the same formulation, except we no longer have a unit travel distance, but 'x' instead. This gives:
Now we can plug these into our texture map to give us the overall effect:
In essence we use the properties of self-similar triangles to find the intersection distance from the viewer to the plane (see image below).
The camera is shown in red, and the ray from the viewer to the plane is shown in green. The height of the plane above the viewer is 'h', and the distance along the plane to the intersection point is 'd'. We can use our friend from last time, the tangent function, to find the intersection point.
For the lower triangle, if we assume one unit of travel (x) then the angle (theta) will be y / 1.
tan(theta) = y/1;For the upper triangle, theta will be h / d.
tan(theta) = h/d;Since the triangles are similar triangles, both theta values are the same, so we can equate these two equations. That is:
y / 1 = h / d y = h / d d = h / y
Now, to solve the same problem but flipped by 90 degrees for the horizontal axis we have the same formulation, except we no longer have a unit travel distance, but 'x' instead. This gives:
y / x = h / d y = h.x / d d = h.x / y
Now we can plug these into our texture map to give us the overall effect:
uniform vec2 resolution;
uniform float time;
uniform sampler2D tex;
void main(void)
{
vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
vec2 uv;
float h = 0.25;
uv.x = h*p.x / p.y;
uv.y = 0.1*time + h / abs(p.y);
gl_FragColor = vec4(texture2D(tex,uv).xyz * p.y*p.y, 1.0);
}
You can see the result below. (You will need a WebGL enabled browser)
3 comments:
I had always wondered this. Thanks for the post!
Buy Rc Planes
Thanks a lot.Keep it up.Keep blogging.
Quadcopter in India
This is the best blog for anybody who needs to find out about this topic. You realize a lot its nearly hard to argue with you (not that I truly would want…HaHa). You definitely put a new spin on a subject thats been written about for years. Great stuff, just nice! online casino gambling
Post a Comment