# How to Build and Draw a simple Triangle Remark: in the following article, words GLSL Hacker and GeeXLab are swappable! They represent the same software with a different name…

Today we are going to see how to build and render a simple scene that includes a camera, a triangle, a reference grid and a GPU program (in GLSL). GLSL Hacker supports both Lua and Python programming languages. We will use Lua for this article. So let’s go!

Article index:

Note: the overview of GLSL Hacker can be useful to understand the concept of INIT and FRAME scripts

## 1 – The Camera (INIT script)

Here is the code to create and initialize a perspective camera. The camera is the core element of the viewing pipeline and we need a perspective camera to see the 3D world. The camera has a field of view (fov) of 60 degrees and its position is X=2, Y=2 and Z=4.

```winW, winH = gh_window.getsize(0)   local aspect = winW / winH camera_params = { fov=60, znear=1.0, zfar=1000.0 } camera = gh_camera.create_persp(camera_params.fov, aspect, camera_params.znear, camera_params.zfar) gh_camera.set_viewport(camera, 0, 0, winW, winH) gh_camera.set_position(camera, 2, 2, 4) gh_camera.set_lookat(camera, 0, 0, 0) gh_camera.set_upvec(camera, 0, 1, 0, 0)```

## 2 – The Triangle (INIT script)

GLSL Hacker has a built-in function that creates a triangle (gh_mesh.create_triangle). This function works fine but I prefer to show you how to build a triangle manually using a more flexible way. The triangle is the most simple mesh and is made up of 3 vertices:

```triangle = gh_mesh.create_v2() local num_vertices = 3 local num_faces = 0 -- non-indexed rendering gh_mesh.alloc_mesh_data(triangle, num_vertices, num_faces)```

gh_mesh.create_v2 creates a generic mesh. gh_mesh.alloc_mesh_data allocates memory for storing the vertices (and the faces if we build an indexed mesh). After the call to gh_mesh.alloc_mesh_data, we have a mesh with enough room to store 3 vertices. Let’s see now how to initialize the position and color of these vertices:

```gh_mesh.set_vertex_position(triangle, 0, -1, -1, 0, 1) gh_mesh.set_vertex_position(triangle, 1, 0, 1, 0, 1) gh_mesh.set_vertex_position(triangle, 2, 1, -1, 0, 1)   gh_mesh.set_vertex_color(triangle, 0, 1, 0, 0, 1) gh_mesh.set_vertex_color(triangle, 1, 0, 1, 0, 1) gh_mesh.set_vertex_color(triangle, 2, 0, 0, 1, 1)```

That’s all for the triangle.

## 3 – The Reference Grid (INIT script)

The reference grid is a helper object that allows to easily visualize the ground. The creation and initialization of the grid is really simple:

```grid = gh_utils.grid_create() gh_utils.grid_set_geometry_params(grid, 10, 10, 20, 20)```

More parameters to customize the grid have been covered in THIS ARTICLE.

## 4 – The GPU Program (INIT script)

We live today in full shader world so we need a GPU program to draw (render) 3D objects on the screen. To draw both the triangle and the grid, all we need is a GPU program that can deal with the position and color of objects vertices. This GPU program has a vertex shader to transform the geometry (the vertices) and a pixel shader to draw the pixels of the primitives (here a triangle and lines).

Here is the source code of the GPU program in GLSL (the OpenGL Shading Language) for an OpenGL 3.0 demo:

```<gpu_program name="vertex_color_prog" > <raw_data_vs><![CDATA[ #version 130 // To support OpenGL 3.0 drivers (Gallium on Linux...) in vec4 gxl3d_Position; in vec4 gxl3d_Color; uniform mat4 gxl3d_ModelViewProjectionMatrix; out vec4 Vertex_Color; void main() { gl_Position = gxl3d_ModelViewProjectionMatrix * gxl3d_Position; Vertex_Color = gxl3d_Color; } ]]></raw_data_vs> <raw_data_ps><![CDATA[ #version 130 // To support OpenGL 3.0 drivers (Gallium on Linux...) in vec4 Vertex_Color; out vec4 FragColor; void main() { FragColor = Vertex_Color; } ]]></raw_data_ps> </gpu_program>```

Remark: I used the version 130 in this GLSL program because it’s supported by any OpenGL 3.2+ implementation but and that’s the important thing, it’s supported by some Gallium drivers on Linux. Those drivers do not support OpenGL 3.2 (version 150) but only OpenGL 3.0 (version 130). A good example of such a driver is the default driver that is installed with Linux Mint 17 when a NVIDIA GeForce card is present.

If you want to test this demo on a Raspberry Pi, you have to use this GPU program (OpenGL ES 2.0):

```<gpu_program name="vertex_color_prog" > <raw_data_vs><![CDATA[ attribute vec4 gxl3d_Position; attribute vec4 gxl3d_Color; uniform mat4 gxl3d_ModelViewProjectionMatrix; varying vec4 Vertex_Color; void main() { gl_Position = gxl3d_ModelViewProjectionMatrix * gxl3d_Position; Vertex_Color = gxl3d_Color; } ]]></raw_data_vs> <raw_data_ps><![CDATA[ varying vec4 Vertex_Color; void main() { gl_FragColor = Vertex_Color; } ]]></raw_data_ps> </gpu_program>```

To get the handle to the GPU program in the Lua code, just include this instruction:

```vertex_color_prog = gh_node.getid("vertex_color_prog")
```

## 5 – Scene Rendering (FRAME script)

All the previous steps took place in the INIT script. Now let’s see the FRAME script that will perform the real drawing of the scene:

```-- Apply the params of the main camera and clear the color -- and depth buffers. -- gh_camera.bind(camera) gh_renderer.clear_color_depth_buffers(0.2, 0.2, 0.2, 1.0, 1.0) gh_renderer.set_depth_test_state(1)     -- Bind vertex_color_prog to make it the active GPU program. -- gh_gpu_program.bind(vertex_color_prog)     -- Render the triangle and the grid -- gh_object.render(triangle) gh_object.render(grid)```

Simple isn’t it?

## 6 – The Demo

The demo is available in GLSL Hacker GeeXLab code sample pack in the host_api/Triangle/ folder. You can download both GLSL Hacker GeeXLab and the code sample pack from THIS PAGE.

The demo is available in two flavors: GL3 for desktop systems (Windows, Linux and OS X) and GLES2 for the Raspberry Pi.