manjian's picture

A Simple GLSL 1.30 Example

I have had a hard time to learn how to use glsl 1.30,because of lack of example.I had to read both the ogl spec and glsl 1.30 spec all over again.Now I think I work it out.GLSL 1.30 is greatly diffrent from 1.20 because ogl 3 deprecates many functions call related to 1.20,such as glVertex glVertexPointer....etc.In ogl 3,you have to use the vertex attribute to define the vertex's position normal texcoord etc.In a OGL 3.0 compatible environment such as Nvidia's NV8,you can define as many as 15 attributes .

  1. To define a mesh 's attribute,you have to get a vertex array object first and bind a vertex array buffer to it.There is the example code shows what I mean(use OpenTK's way):
                 int[] _vertexarrayobject=new int[1];
                 int[] _bufferobject=new int[2];
                 GL.GenBuffers(2, _bufferobject);
                 GL.BindBuffer(BufferTarget.ArrayBuffer, _bufferobject[0]);
                 GL.BindBuffer(BufferTarget.ElementArrayBuffer, _bufferobject[1]);
                 GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(Marshal.SizeOf(typeof(ObjMesh.ObjVertex)) * obj.Vertices.Length),
                     obj.Vertices, BufferUsageHint.StaticDraw);
                 GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(Marshal.SizeOf(typeof(ObjMesh.ObjTriangle)) * obj.Triangles.Length),
                     obj.Triangles, BufferUsageHint.StaticDraw);
  2. Create the program and shaders.Set the sources of the shaders,and compile them,attach them to a program,link the program,use the program as you do in ogl 2.0 2.1 .I won't show the code here, refer to the other example.
  3. Get the neccessary uniform variable,e.g. modelviewprojection matrix,and set their value properly.
  4. This is the important part of ogl 3,which is diffrent from other ogl version.It's the only way to set the vertex' attribute.First you bind the vertex array object again in case other codes bind their VAO.And then set the attributes of the verteices,you can set the attributes whose indices range from 0 to 14 to a vertex.But my code just set 0-3 attributes,0 stands for positions,1 stands for normals,2 stands for texcoords.You may change the sequence if you like,e.g. 0 stands for normals,1 stands positions.Hereis my code:
                   GL.BindBuffer(BufferTarget.ArrayBuffer, _bufferobject[0]);
                    GL.BindBuffer(BufferTarget.ElementArrayBuffer, _bufferobject[1]);
                        Marshal.SizeOf(typeof(ObjMesh.ObjVertex )),
                        Marshal.SizeOf(typeof(Vector3 ))+Marshal.SizeOf(typeof(Vector2)));
                        Marshal.SizeOf(typeof(ObjMesh.ObjVertex )),
                        Marshal.SizeOf(typeof(ObjMesh.ObjVertex )),
                        Marshal.SizeOf(typeof(Vector3 )));
  5. BInd the attribute's position in the glsl 1.30 code.In your glsl 1.30 code ,the attribute must define with the "in" prefix,e.g.
    in vec3 position.
    Here's my code.

                     GL.BindAttribLocation(_program, 0, "position");
                    if (GL.GetError() != ErrorCode.NoError)
                        throw new Exception();
                    GL.BindAttribLocation(_program, 1, "normal");
                    GL.BindAttribLocation(_program, 2, "texcoord");
  6. If you want to use secondary color,you may want to output more than 1 color in your fragment shader,you must bind their output sequence so that the ogl pipeline knows about that.Use BindFragDataLocation to achive that goal.But if you just want to output 1 color,ignore this step.
    Here's my code:

    GL.BindFragDataLocation(_program, 0, "out_color0");
    GL.BindFragDataLocation(_program, 1, "out_color1");
  7. Draw your mesh.

And then let's take a look at how to write a simple glsl 1.3 vertex shader and fragment shader
Let's see my vertex shader example:

#version 130
in vec3 position;
in vec3 normal;
in vec2 texcoord;
out vec3 out_normal;
out vec2 out_texcoord;
uniform mat4x4 modelviewproj;
void main()
	out_normal=normal; //Err too lazy to send view matrix 

You can see the old varying keyword gone,I use out vec3 instead.And the old gl_Position is still there.My code get the input position normal and texcoord.And then output them to proper place simply.
Let's see my fragment shader code.

#version 130
 in  vec3 out_normal;
out vec4 out_color;
const vec3 lightDir=vec3(-1,1,0);
void main()
	vec3 nlightDir=normalize(lightDir);
	float diffuse=clamp(dot(nlightDir,out_normal),0,1);

We see the fragment shader simply get the input out_normal,which is related to the vertex shader "out vec3 out_normal",and caculate the diffuse light for that fragment.
The output in vertex shader must share the same name of the input in fragment shader.I don't know how to define the input in geometry shader.
That's it, a simple example.Just to show how things work in ogl 3.0 style.


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

Thanks, this is very helpful.

blueworld's picture

Great tutorial, just what I was looking for. Is there a something already explaining how to do step 3 (setting uniform values)?

blueworld's picture

Also, can anyone explain what ElementArrayBuffer is vs. ArrayBuffer?

nythrix's picture

blueworld: This tutorial is being expanded here. It's a work in progress but the code should work. Check QueryMatrixLocations method.
An ArrayBuffer VBO usually contains vertex position, normal and texture arrays. An ElementArrayBuffer VBO is an array of indices into the ArrayBuffer. You can find VBO's explained here.