In this MP you will
This MP is elective, with no core components. It assumes you have already completed the WebGL warmup.
You will submit a webpage that has
We supply everything you need except for the GLSL. You should not edit our provided code, only add GLSL to it.
Use the HTML file psychedelic.html, which has built-in JavaScript. Do not edit this file: leave it exactly as it is. It depends on wrapWebGL2.js and should run with no errors or warnings in the console.
The JavaScript in that HTML file loads two GLSL files,
vs.glsl and fs.glsl, which you’ll need to
write.
vs.glslThis shader is invoked with no attribute data for six vertices, with
gl_VertexID 0 through 5 inclusive. IDs 0, 1, and 2 will be
combined into one triangle; 3, 4, and 5 will be combined into
another.
Your implementation must set gl_Position based on
gl_VertexID such that the entire canvas is covered in
fragments.
Avoiding warp-breaking
The most direct way of writing the vertex shader would be
void main() {
if (gl_VertexID == 0) {
gl_Position = (-1,-1,0,1);
} else if (gl_VertexID == 1) {
gl_Position = ( 1,-1,0,1);
} else if (gl_VertexID == 2) {
// ...but this has branches on inputs (in this case the built-in input
gl_VertexID) which breaks warp parallelism and so
is not appropriate.
One way to bypass this is to use expressions like ?: or
|| instead of if. Another is to come up with
some function which, when given the inputs 0, 1, and 2, or the inputs 3,
4, and 5, or both outputs 2D points that, if filled with a triangle,
completely cover the (-1,-1)-to-(1,1) square.
Your implementation should also create and set an out
variable that indicates where on the screen each fragment is. You’ll
need that information for the fragment shader to work properly. This
could literally be a copy of gl_Position in an
out variable if you wish.
Why copy gl_Position?
The (x,y) coordinates in
gl_Position at the end of the vertex shader will be
modified by the
viewport transformation before being available as
gl_FragCoord in the fragment shader, meaning that their
values (and thus the appearance of anything drawn based on them) will
depend on the size of the display. If we copy the
gl_Position into a different out variable in
the vertex shader, that out variable won’t have a viewport
applied to it and will be available as an in in the
fragment shader.
Technically we could pass the size of the screen in as a uniform and
recover the original (x,y) from
gl_FragCoord in the fragment shader by inverting the
viewport transformation, but that would mean extra work every fragment,
not a good use of GPU resources.
fs.glslThis should fill the screen with colorful moving curved shapes. There should be no detectable polygonal artifacts or sharp color transitions.
You should add a uniform float seconds;
to this shader. It will be provided with the seconds since the animation
began.
The easiest way to achieve the desired results is to take the x and y
position of each fragment (passed from an out variable in
the vertex shader to an in variable in the fragment shader)
and the seconds uniform and put them through some kind of polynomial,
likely with a sine or cosine on the seconds to make it repeat.
On both your development machine and when submitted to the submission server and then viewed by clicking the HTML link, the resulting animation should show moving colored patterns filling the screen with no visible polygonal boundaries. Changing the window size should change how large the image is, not how much of it is visible.
Two examples follow. Your submission should be different from both.