OpenGL pixel shader: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|JavaScript}} (WebGL): improve highlighting)
(Tcl implementation added)
Line 121: Line 121:
// Create shader object
// Create shader object
var shader;
var shader;
shader= gl.createShader(gl[scriptElement.type.replace('text/x-','').toUpperCase()]);
shader= gl.createShader(gl[scriptElement.type.replace('text/x-','').toUpperCase()]);
// Compile shader from source
// Compile shader from source
gl.shaderSource(shader, scriptElement.textContent);
gl.shaderSource(shader, scriptElement.textContent);
Line 197: Line 197:
</body>
</body>
</html></lang>
</html></lang>

=={{header|Tcl}}==
{{libheader|tcl3d}}
{{trans|C}}

Using the [http://www.tcl3d.org Tcl3d] library and liberally borrowing from [http://wiki.tcl.tk/41477 this pixel shader demo on the wiki], here is a brute translation of the C implementation.

<lang Tcl>
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 render {{angle 0}} {
glClear $::GL_COLOR_BUFFER_BIT
glUniform1f $::uloc_rmod [expr {rand()}]
glLoadIdentity
glRotatef $angle 1.0 1.0 1.0
glBegin GL_TRIANGLES
glVertex3f -1 -.5 0
glVertex3f 0 1 0
glVertex3f 1 0 0
glEnd

.w swapbuffers
after 40 [list render [expr {$angle+.2}]]
}

proc set_shader {} {
set f {
varying float x, y, z;
uniform float rmod;
float rand(float s, float r) { return mod(mod(s, r + rmod)*112341.0, 1.0); }
void main() {
gl_FragColor = vec4(rand(gl_FragCoord.x, x), rand(gl_FragCoord.y, y), rand(gl_FragCoord.z, z), 1);
}
}
set v {
varying float x, y, z;
void main() {
gl_Position = ftransform();
x = gl_Position.x; y = gl_Position.y; z = gl_Position.z;
x += y; y -= x; z += x - y;
}
}

set vs [mkshader $::GL_VERTEX_SHADER $v]
set ps [mkshader $::GL_FRAGMENT_SHADER $f]

set proc [glCreateProgram]
glAttachShader $proc $ps
glAttachShader $proc $vs
glLinkProgram $proc
glUseProgram $proc

set ::uloc_rmod [glGetUniformLocation $proc "rmod"]
}

togl .w -w 640 -h 480 -double true
pack .w -expand 1 -fill both
bind .w <Key-Escape> exit
wm protocol . WM_DELETE_WINDOW exit

set_shader
render
</lang>


{{omit from|Blast}}
{{omit from|Blast}}

Revision as of 05:04, 30 June 2015

OpenGL pixel shader is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Using the triangle geometry from OpenGL. But instead of using a mechanism such as glColor3d, use a pixel shader for each pixel in the triangle. The pixel shader should pick a random RGB color for each pixel. Most pixels should have colors which are different from that of most other pixels.

Optional: provide an update mechanism, to repeatedly re-render the triangle. (Possibilities include a mouse event handler, a timer event handler or an infinite loop, or even window expose events.) Shader generated color for each pixel should be different in each render.

Optional: after updating the opengl rendering target but before rendering the triangle, query the opengl implementation to determine which versions of shaders are supported by the rendering target, list the tested shaders and the available shaders and then use a supported shader.

See also: opengl.org's gl shader language documentation, and lighthouse3d.com's glsl tutorial.

C

Library: GLUT

Getting a true (pseudo) random number is surprisingly tricky. The following code makes something noisy, but not at all random:

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <GL/glew.h>
  3. include <GL/glut.h>

GLuint ps, vs, prog, r_mod; float angle = 0; void render(void) { glClear(GL_COLOR_BUFFER_BIT); glUniform1f(r_mod, rand() / (float)RAND_MAX);

glLoadIdentity(); glRotatef(angle, angle * .1, 1, 0); glBegin(GL_TRIANGLES); glVertex3f(-1, -.5, 0); glVertex3f(0, 1, 0); glVertex3f(1, 0, 0); glEnd(); angle += .02; glutSwapBuffers(); }

void set_shader() { const char *f = "varying float x, y, z;" "uniform float r_mod;" "float rand(float s, float r) { return mod(mod(s, r + r_mod) * 112341, 1); }" "void main() {" " gl_FragColor = vec4(rand(gl_FragCoord.x, x), rand(gl_FragCoord.y, y), rand(gl_FragCoord.z, z), 1);" "}"; const char *v = "varying float x, y, z;" "void main() {" " gl_Position = ftransform();" " x = gl_Position.x; y = gl_Position.y; z = gl_Position.z;" " x += y; y -= x; z += x - y;" "}";

vs = glCreateShader(GL_VERTEX_SHADER); ps = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(ps, 1, &f, 0); glShaderSource(vs, 1, &v, 0);

glCompileShader(vs); glCompileShader(ps);

prog = glCreateProgram(); glAttachShader(prog, ps); glAttachShader(prog, vs);

glLinkProgram(prog); glUseProgram(prog); r_mod = glGetUniformLocation(prog, "r_mod"); }

int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(200, 200); glutCreateWindow("Stuff"); glutIdleFunc(render);

glewInit(); if (!glewIsSupported("GL_VERSION_2_0")) { fprintf(stderr, "GL 2.0 unsupported\n"); return 1; }

set_shader(); glutMainLoop();

return 0; }</lang>

JavaScript (WebGL)

<lang javascript><html style="margin: 0;">

 <head>
   <title>Fragment Shader WebGL Example</title>
   <script id="shader-fs" type="text/x-fragment_shader">
     precision highp float;
     uniform float u_time;
     void main(void) {
       // some gobbledegook
       vec3 foo = vec3(pow(gl_FragCoord.xy, vec2(1.0 + sin(dot(vec4(1.0, 100.0, 0.0, 0.0), gl_FragCoord)))), 0.0);
       foo *= mat3(1.2, 3.9, 1.4, 4.1, 0.2, 1.4, 2.5, 1.6, 7.2);

       gl_FragColor = vec4(mod(foo + vec3(u_time), 1.0), 1.0);
     }
   </script>
   <script id="shader-vs" type="text/x-vertex_shader">
     attribute vec3 a_position;
     attribute vec4 a_color;
     varying vec4 v_color;
     void main(void) {
       gl_Position = vec4(a_position, 1.0);
       v_color = a_color;
     }
   </script>
   <script type="text/javascript">
     function getShader(gl, id) {
       var scriptElement = document.getElementById(id);
       // Create shader object
       var shader;
       shader= gl.createShader(gl[scriptElement.type.replace('text/x-',).toUpperCase()]);
       // Compile shader from source
       gl.shaderSource(shader, scriptElement.textContent);
       gl.compileShader(shader);
       if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
         throw new Error(gl.getShaderInfoLog(shader));
       return shader;
     }
   </script>
 </head>
 <body style="margin: 0;">
   <canvas id="glcanvas" style="border: none; margin: auto; display: block;" width="640" height="480"></canvas>
   <script type="text/javascript">
     var canvas = document.getElementById("glcanvas");

     // Get WebGL context.
     var gl = canvas.getContext("webgl")
           || canvas.getContext("experimental-webgl");
     if (!gl)
       throw new Error("WebGL context not found");

     // Create shader program from vertex and fragment shader code.
     var shaderProgram = gl.createProgram();
     gl.attachShader(shaderProgram, getShader(gl, "shader-vs"));
     gl.attachShader(shaderProgram, getShader(gl, "shader-fs"));
     gl.linkProgram(shaderProgram);
     if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS))
       throw new Error(gl.getProgramInfoLog(shaderProgram));

     // Specify to render using that program.
     gl.useProgram(shaderProgram);

     // Get the indexes to communicate vertex attributes to the program.
     var positionAttr = gl.getAttribLocation(shaderProgram, "a_position");
     // And specify that we will be actually delivering data to those attributes.
     gl.enableVertexAttribArray(positionAttr);

     var timeUniform = gl.getUniformLocation(shaderProgram, "u_time");

     // Store vertex positions and colors in array buffer objects.
     var vertices;
     var positionBuffer = gl.createBuffer();
     gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices = [
       -0.5, -0.5, 0,
       +0.5, -0.5, 0,
       -0.5, +0.5, 0
     ]), gl.STATIC_DRAW);
     var numVertices = vertices.length / 3; // 3 coordinates per vertex

     // Set GL state
     gl.clearColor(0.3, 0.3, 0.3, 1.0);
     gl.enable(gl.DEPTH_TEST);
     gl.viewport(0, 0, gl.drawingBufferWidth || canvas.width,
                       gl.drawingBufferHeight || canvas.height);

     //Specify the array data to render. 
     gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
     gl.vertexAttribPointer(positionAttr, 3, gl.FLOAT, false, 0, 0);

     var t0 = Date.now();
     function frame() {
       gl.uniform1f(timeUniform, (Date.now() - t0) / 1000);

       gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
       gl.drawArrays(gl.TRIANGLES, 0, numVertices);

       var e;
       while (e = gl.getError())
         console.log("GL error", e);

     }
     setInterval(frame, 1000/20);
   </script>
 </body>

</html></lang>

Tcl

Library: tcl3d
Translation of: C

Using the Tcl3d library and liberally borrowing from this pixel shader demo on the wiki, here is a brute translation of the C implementation.

<lang Tcl> 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 render Template:Angle 0 {

   glClear $::GL_COLOR_BUFFER_BIT
   glUniform1f $::uloc_rmod [expr {rand()}]
   glLoadIdentity
   glRotatef $angle 1.0 1.0 1.0
   glBegin GL_TRIANGLES
       glVertex3f -1 -.5 0
       glVertex3f  0  1  0
       glVertex3f  1  0  0
   glEnd
   .w swapbuffers
   after 40 [list render [expr {$angle+.2}]]

}

proc set_shader {} {

   set f {
       varying float x, y, z;
       uniform float rmod;
       float rand(float s, float r) { return mod(mod(s, r + rmod)*112341.0, 1.0); }
       void main() {
           gl_FragColor = vec4(rand(gl_FragCoord.x, x), rand(gl_FragCoord.y, y), rand(gl_FragCoord.z, z), 1);
       }
   }
   set v {
       varying float x, y, z;
       void main() {
           gl_Position = ftransform();
           x = gl_Position.x; y = gl_Position.y; z = gl_Position.z;
           x += y; y -= x; z += x - y;
       }
   }
   set vs [mkshader $::GL_VERTEX_SHADER $v]
   set ps [mkshader $::GL_FRAGMENT_SHADER $f]
   set proc [glCreateProgram]
   glAttachShader $proc $ps
   glAttachShader $proc $vs
   glLinkProgram $proc
   glUseProgram $proc
   set ::uloc_rmod [glGetUniformLocation $proc "rmod"]

}

togl .w -w 640 -h 480 -double true pack .w -expand 1 -fill both bind .w <Key-Escape> exit wm protocol . WM_DELETE_WINDOW exit

set_shader render </lang>