1.3 Applying Hardcoded Vertex Colors

Welcome to our fourth tutorial! We're once again focusing on drawing a triangle, which might seem repetitive, and our progress may appear slow. However, this deliberate approach is crucial. We're taking small, incremental steps, making only a few code updates at a time. This method helps build a solid understanding of the GPU programming model, which is essential before we explore more complex examples.

Launch Playground - 1_03_vertex_color

Rest assured, our pace will accelerate once we reach the second chapter. In this tutorial, we'll make slight changes to the shader code while continuing to use the same rendering pipeline.

In our previous tutorial, we hard-coded the output color in the fragment shader. This time, we'll shift this hard-coding to the vertex stage and pass the color from the vertex stage to the fragment stage. This change illustrates how values are passed between different stages of the pipeline, a crucial concept in GPU programming.

struct VertexOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) color: vec3<f32>,
};

@vertex
fn vs_main(
    @location(0) inPos: vec3<f32>,
) -> VertexOutput {
    var out: VertexOutput;
    out.clip_position = vec4<f32>(inPos, 1.0);
    out.color = vec3<f32>(0.0, 0.0, 1.0);
    return out;
}

Let's examine the changes. In the vertex output struct, we've introduced a new field called color. Since there are no built-ins for vertex color, we use @location(0) to store it. At the end of the vertex stage, we assign a hard-coded color to out.color.

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    return vec4<f32>(in.color, 1.0);
}

In the fragment stage, we can now access this color from the input and directly pass it as the output. Despite this change, you'll observe the same triangle being rendered.

Now, let's consider an important aspect of GPU rendering. In the vertex stage, we process individual vertices, while in the fragment stage, we deal with individual fragments. A fragment is conceptually similar to a pixel but can contain rich metadata such as depth and other values.

Between the vertex and fragment stages, there's an automatic process called rasterization, handled by the GPU. This process converts geometry data to fragments.

Here's an interesting question to ponder: If we assign a different color to each vertex, how will the GPU assign colors to the fragments, especially for those fragments that lie in the middle of the triangle and not directly on any of the vertices?

I encourage you to modify the sample code and experiment with this concept yourself. Try assigning different colors to each vertex and observe how the GPU interpolates these colors across the triangle's surface. This exercise will deepen your understanding of how data flows through the GPU pipeline and how the interpolation process works.

Leave a Comment on Github