# JRuby, LWJGL & OpenGL – Getting Started with Shaders

In Part 2 we drew a triangle using a Vertex Buffer, and some basic shaders. While on the surface this can seem overtly complicated, it actually becomes the basis of a powerful OpenGL achitecture to enable you to leverage the GPU is a variety of very interesting ways without having to rely on the CPU.

We’ll be look at the example show_triangle_vert_frag_offset.rb, which can be run from the command bin/triangle_vert_frag_offset.

This also comes from the “OpenGL’s Moving Triangle” section of the Learning Modern 3D Graphics Programming online book.

With this code, we are going to take our original triangle, and we will make it move around a bit, and also change colour at the same time.

The clever thing about this is, we won’t be changing the vertex data stored in the buffer, but will instead be manipulating it with Fragment and Vertex shaders. This almost feels like Uber-CSS over the top of HTML.

This is pretty powerful stuff, as we can let the GPU do a lot of the processing by using shader programs, and passing them attributes to control the overall affect that we want.

Let’s look at our vertex shader offset_vertex.glsl

`#version 330`

layout(location = 0) in vec4 position;
uniform vec2 offset;

```void main() { vec4 totalOffset = vec4(offset.x, offset.y, 0.0, 0.0); gl_Position = position + totalOffset; }```

You can see we now have a `uniform vec2 offset;`. This defines a value that is going to get passed in from outside the Shader. It has the keyword `uniform` as the value stays the same on the same rendering frame.

The `offset` attribute will be expecting a vector with an x and y coordinate to be passed through (vec2) for the uniform value.

We convert the offset vec2 to a vec4, as you can’t add a vec2 to a vec4. Then we can add these two together (GLSL will do vector arithmatic for you out of the box) to get our final gl_Position vector.

This means we can change the position of our triangle with relative ease, just by changing the offset of each of the vertices.

To do this from our JRuby code, is quite straight forward. The first thing we need to do is find out the location / position of the `offset` attribute. This is done through:

`@offset_location = GL20.gl_get_uniform_location(@program_id, "offset")`

Now we have the capability to change this value as we need to. In our `display` function, we have:

`x_offset, y_offset = compute_position_offsets(time)`

`compute_position_offsets` calculates x and y offsets based on the current time. (Check out the code for more details, it’s just some fun trig). To set the uniform value, we then do:

`GL20.gl_uniform2f(@offset_location, x_offset, y_offset)`

That’s it. The shader then does the rest of the work. Our triangle will now go round and round in a circle.

We do similar things to change the colour of the triangle as it goes around in a circle. Here is our fragment shader:

```#version 330 out vec4 outputColor; uniform float fragLoopDuration; uniform float time;```

const vec4 firstColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
const vec4 secondColor = vec4(0.0f, 1.0f, 0.0f, 1.0f);

```void main() { float currTime = mod(time, fragLoopDuration); float currLerp = currTime / fragLoopDuration; outputColor = mix(firstColor, secondColor, currLerp); }```

You can see we can define constants with the `const` keyword. This sets up two colours to mix between, in this case, white and green.

We have two uniform attributes to in this time, `fragLoopDuration` the loop duration of the colour change, and `time`, how many seconds have passed since the application began.

`mix` is a GLSL function that blends two colours together based on the third float that is passed through, and gives us the slow fade between the two as the time value changes.

Setting this up is almost exactly the same as before. We will set the `fragLoopDuration` in our `init_program` method, as it never changes across the execution of our code.

```frag_loop_location = GL20.gl_get_uniform_location(@program_id, "fragLoopDuration") @frag_loop = 50.0 GL20.gl_uniform1f(frag_loop_location, @frag_loop) ```

For the `time` uniform attribute, we have some code that tracks how much time passes between frames and we just add it all up, and then set the uniform attribute with `gl_uniform` like usual:

```current_time = Sys.get_time @elapsed_time += (current_time - @last_time) @last_time = current_time time = @elapsed_time / 1000.0```

`GL20.gl_uniform1f(@time_location, time)`

That’s the basics of using shaders with vertex data. We now have a triangle that goes around in a circle!