WebGL - Shader Program
WebGL - Shader Programs
Section titled “WebGL - Shader Programs”WebGL leverages the power of the Graphics Processing Unit (GPU) for rendering. Unlike traditional CPU programming, you can’t just call functions on the GPU directly for every pixel. Instead, you upload data (vertices, textures) and small programs called shaders to the GPU.
Shaders are written in a C-like language called GLSL (OpenGL Shading Language). Specifically, WebGL uses GLSL ES (GLSL for Embedded Systems). WebGL 1 uses GLSL ES 1.00, while WebGL 2 uses GLSL ES 3.00, which offers more features and a slightly different syntax.
These shader programs run massively in parallel on the GPU’s cores, processing vertex data and determining the color of pixels. They define the programmable parts of the WebGL rendering pipeline.
There are two main types of shaders required for a basic WebGL program:
Vertex Shader
Section titled “Vertex Shader”The Vertex Shader’s primary role is to calculate the final position of each vertex. It runs once for every vertex you send to the GPU. Its tasks typically include:
- Vertex Transformation: Applying model, view, and projection matrices to transform vertex coordinates from model space to clip space.
- Processing Vertex Attributes: Handling input data associated with each vertex, such as texture coordinates or normals.
- Passing Data to Fragment Shader: Sending processed data (like interpolated color or texture coordinates) downstream to the fragment shader.
In GLSL ES 1.00 (WebGL 1), input vertex data is received via attribute variables. In GLSL ES 3.00 (WebGL 2), in variables are used.
Fragment Shader (Pixel Shader)
Section titled “Fragment Shader (Pixel Shader)”After the vertices are processed and assembled into primitives (like triangles), the GPU figures out which pixels on the screen are covered by each primitive. This process is called rasterization. The Fragment Shader (often called a Pixel Shader) runs once for every potential pixel (fragment) that a primitive covers.
Its main job is to determine the final color of each fragment. Tasks include:
- Calculating Color: Determining the pixel’s color based on interpolated vertex colors, texture samples, lighting calculations, etc.
- Texture Mapping: Looking up colors from textures (images).
- Applying Effects: Implementing effects like fog or transparency.
The final output color is assigned to a special built-in variable (gl_FragColor in GLSL ES 1.00, or a user-defined out variable in GLSL ES 3.00).
GLSL Variables for Data Transfer
Section titled “GLSL Variables for Data Transfer”GLSL provides specific variable types (qualifiers) to manage data flow between your JavaScript code and the shaders, and between the vertex and fragment shaders:
- Attributes (
attributein GLSL 1.00 /inin GLSL 3.00): Used only in the Vertex Shader. Receive data from WebGL buffers (VBOs). This data changes per vertex (e.g., vertex position, color, texture coordinate). Linked via JavaScript calls likegl.vertexAttribPointer. - Uniforms (
uniform): Used in both Vertex and Fragment Shaders. Hold values that remain constant across all vertices and fragments for a single draw call (e.g., transformation matrices, light positions, global color). Set via JavaScript calls likegl.uniformMatrix4fv,gl.uniform3f, etc. - Varyings (
varyingin GLSL 1.00 /outfrom Vertex,into Fragment in GLSL 3.00): Used to pass data from the Vertex Shader to the Fragment Shader. The GPU interpolates (blends) these values across the surface of the primitive (e.g., smoothly blending colors between vertices).
Understanding how data flows through these variables is crucial for writing functional shaders.
Next, we’ll look at how these concepts fit into the overall WebGL Graphics Pipeline.