Have you heard about
glslsandox
website ?
It shows (using WebGL) what can be done with pixel shaders.
There are some really impressive ones ...
Here is a small Tcl script using the tcl3d package that can be used to try the shaders of
glslsandox
You only need to replace the pixel shader code to try another one ...
Hope you'll enjoy !
#! /bin/sh
# next line restarts using tclsh \
exec tclsh85 "$0" ${1+"$@"}
package require tcl3d
proc mkshader {type src} {
set sh [glCreateShader $type]
tcl3dOglShaderSource $sh $src
glCompileShader $sh
puts "compilation report : [tcl3dOglGetShaderState $sh $::GL_COMPILE_STATUS] [tcl3dOglGetShaderInfoLog $sh]"
return $sh
}
proc mkprogram {v f} {
set p [glCreateProgram]
glAttachShader $p $v
glAttachShader $p $f
glLinkProgram $p
puts "link report : [tcl3dOglGetProgramState $p $::GL_LINK_STATUS] [tcl3dOglGetProgramInfoLog $p]"
return $p
}
proc createcb { toglwin } {
glClearColor 0.0 0.0 0.0 0.0
glShadeModel $::GL_SMOOTH
set v [mkshader $::GL_VERTEX_SHADER {
void main() {
gl_Position = ftransform();
}
}]
# --- replace the code below to try another shader
set f [mkshader $::GL_FRAGMENT_SHADER {
#ifdef GL_ES
precision mediump float;
#endif
uniform float time;
//uniform vec2 mouse;
//uniform vec2 resolution;
float lengthsq(vec2 p) { return dot(p, p); }
float noise(vec2 p){
return fract(sin(fract(sin(p.x) * (43.13311)) + p.y) * 31.001);
}
float worley(vec2 p) {
// Initialise distance to a large value
float d = 20.0;
for (int xo = -2; xo <= 2; xo++) {
for (int yo = -2; yo <= 2; yo++) {
// Test all surrounding cells to see if distance is smaller.
vec2 test_cell = floor(p) + vec2(xo, yo);
// Update distance if smaller.
float n0 = noise(test_cell);
float n1 = noise(test_cell + vec2(134.0,8413.0));
float ox = mix( n0, n1, sin(time) );
float oy = mix( n0, n1, cos(time) );
vec2 c = test_cell + vec2(ox,oy);
d = min(d, lengthsq(p - c));
}
}
return d;
}
void main() {
vec2 uv = gl_FragCoord.xy;
float t = 0.9 * worley(gl_FragCoord.xy / 20.0);
gl_FragColor = vec4(vec3(t,sqrt(t),t), 1.0);
}
}]
set p [mkprogram $v $f]
glUseProgram $p
set ::uloc_time [glGetUniformLocation $p "time"]
set ::uloc_mouse [glGetUniformLocation $p "mouse"]
set ::uloc_resolution [glGetUniformLocation $p "resolution"]
}
proc displaycb { toglwin } {
incr ::time
glUniform1f $::uloc_time [expr {0.05*$::time}]
glClear $::GL_COLOR_BUFFER_BIT
glLoadIdentity
glBegin GL_QUADS
glVertex2f -1 -1
glVertex2f -1 1
glVertex2f 1 1
glVertex2f 1 -1
glEnd
$toglwin swapbuffers
}
proc reshapecb { toglwin { w -1 } { h -1 } } {
set w [$toglwin width]
set h [$toglwin height]
glUniform2f $::uloc_resolution $w $h
glViewport 0 0 $w $h
}
proc Animate {} {
.w postredisplay
set ::animateId [after 40 ::Animate]
}
proc StartAnimation {} {
puts "starting animation"
if { ! [info exists ::animateId] } {
Animate
}
}
proc StopAnimation {} {
if { [info exists ::animateId] } {
after cancel $::animateId
unset ::animateId
}
}
togl .w -w 640 -h 480 -double true -createproc createcb -displayproc displaycb -reshapeproc reshapecb
pack .w -expand 1 -fill both
bind .w <Key-Escape> exit
bind .w <Motion> {
glUniform2f $::uloc_mouse %x %y
}
wm protocol . WM_DELETE_WINDOW exit
StartAnimation
Here are two screenshots made using the above program and 2 different shaders :

See also edit