Skip to content
Sam edited this page Jul 10, 2020 · 15 revisions

How do I...

This page is trying to guide the user to the API; this is not a tutorial about OpenGL itself. It focuses on the API design, such as overrides and special variations with respect to the C style API.

Call OpenGL functions

OpenGL functions have the same name as the GL specification but without the namespace prefix ('gl', 'egl', 'wgl' and 'glX') and the argument type suffixes ('f', 'd', 'ui', etc...).

Gl.Viewport(0, 0, 800, 600);
Gl.Clear(ClearBufferMask.ColorBufferBit);
Gl.Begin(PrimitiveType.Triangles);
Gl.Color3(1.0f, 0.0f, 0.0f); Gl.Vertex2(0.0f, 0.0f);
Gl.Color3(0.0f, 1.0f, 0.0f); Gl.Vertex2(0.5f, 1.0f);
Gl.Color3(0.0f, 0.0f, 1.0f); Gl.Vertex2(1.0f, 0.0f);
Gl.End();

Create OpenGL objects

Buffers

Create a simple buffer objects:

float[] buffer = new[] { ... };

// Equivalent to glGenBuffers(1, &obj)
uint obj = Gl.GenBuffer();

Gl.BindBuffer(BufferTarget.ArrayBuffer, obj);
Gl.BufferData(BufferTarget.ArrayBuffer, (uint)(4 * buffer.Length), buffer, BufferUsage.StaticDraw);

Shaders

public uint CreateShader()
{
	string[] source = {
		"#version 150 compatibility\n",
		"uniform mat4 uMVP;\n",
		"in vec2 aPosition;\n",
		"in vec3 aColor;\n",
		"out vec3 vColor;\n",
		"void main() {\n",
		"	gl_Position = uMVP * vec4(aPosition, 0.0, 1.0);\n",
		"	vColor = aColor;\n",
		"}\n"
	};

	uint obj = Gl.CreateShader(ShaderType.VertexShader);
	Gl.ShaderSource(ShaderName, source);
	Gl.CompileShader(ShaderName);
	int compiled;

	Gl.GetShader(ShaderName, ShaderParameterName.CompileStatus, out compiled);
	if (compiled != 0)
		return obj;

	// Not compiled!
	Gl.DeleteShader(obj);

	const int logMaxLength = 1024;

	StringBuilder infolog = new StringBuilder(logMaxLength);
	int infologLength;

	Gl.GetShaderInfoLog(ShaderName, logMaxLength, out infologLength, infolog);

	throw new InvalidOperationException($"unable to compile shader: {infolog}");
}

Set shader uniforms

Simple uniforms

Gl.Uniform3(0, 1.0f, 1.0f, 1.0f); // layout(location = 0) uniform vec3 v;
Gl.Uniform1(0, 1.0f);             // layout(location = 0) uniform float v;
Gl.Uniform1(0, 1);                // layout(location = 0) uniform int v;

You have also reference overloads: they take a blittable structures with the proper layout.

Vertex3f v1 = Vertex3f.UnitX;
Gl.Uniform3f(0, 1 /* count */, v1); // layout(location = 0) uniform vec3 v;

Uniform matrices

Gl.UniformMatrix2(0, false, new[] { 1.0f, 0.0f, 0.0f, 1.0f });                    // layout(location = 0) uniform mat2 m;
// Matrix types have (explicit) cast defined
Gl.UniformMatrix4(0, false, (float[])Matrix4x4f.Ortho2D(0.0f, 1.0f, 0.0f, 1.0f)); // layout(location = 0) uniform mat4 m;

Although the above lines are functional, they allocate an array. To avoid performance issues, use generic overrides (note the suffix).

Matrix4x4f m = Matrix4x4f.Ortho2D(0.0f, 1.0f, 0.0f, 1.0f);
Gl.UniformMatrix4f(0, 1, false, m);                // layout(location = 0) uniform mat4 m;

Matrix4x4d dm = Matrix4x4d.Ortho2D(0.0, 1.0, 0.0, 1.0);
Gl.UniformMatrix4d(0, 1, false, dm);               // layout(location = 0) uniform dmat4 m;

Uniform arrays

Type safety is good, but it doesn't help here, and we have to deal with pointers; fortunately we have unsafe overloads.

Vertex4i[] v = new Vertex4i[4];
unsafe {
    fixed (Vertex4i* p_v = v) {
        Gl.Uniform4(0, v.Length, (int*)p_v);                   // layout(location = 0) uniform ivec4 v[4];
    }
}

Matrix4x4f m = new Matrix4x4f[16];
unsafe {
    fixed (Matrix4x4f* p_m = m) {
        Gl.UniformMatrix4f(0, m.Length, false, (float*)p_v);   // layout(location = 0) uniform mat4 m[16];
    }
}

Math

Using OpenGL.Net.Math package you can execute math on CPU. This is necessary for passing information to the shader programs. Available structures are matrices, vertices, and quaternions.

Vertices

Basics

Vertex3f v1 = new Vertex3f(); // XYZ zeroed
Vertex4f v2 = new Vertex4f(); // XYZW zeroed
Vertex2f v3 = new Vertex2f(1.0f, 2.0f);
Vertex4f v4 = new Vertex4f(2.3f); // XYZW have same values
Vertex2ui v5 = Vertex2ui.UnitX; // X unit vector

Homogeneous coordinates

Vertex4f x = Vertex4f.UnitX; // (1, 0, 0, 1)
Vertex4f v1 = new Vertex4f(10.0f, 10.0f, 10.0f, 10.0f);
Vertex3f v2 = new Vertex3f(1.0f, 1.0f, 1.0f);
Vertex3f v3 = (Vertex3f)v1;

Debug.Assert(v3 == v2);

Matrices

Create projection matrices

Matrix4x4f ortho = Matrix4x4f.Ortho(-1.0f, +1.0f, -1.0f, +1.0f, -1.0f, 1.0f);
Matrix4x4f ortho2D = Matrix4x4f.Ortho2D(-1.0f, +1.0f, -1.0f, +1.0f); // As above
Matrix4x4f perspective = Matrix4x4f.Perspective(45.0f, 1.0f, 0.1f, 1000.0f); // Symmetric

Create model matrices

Matrix4x4f translate = Matrix4x4f.Translated(-1.0f, +1.0f, -1.0f);
Matrix4x4f rotateX = Matrix4x4f.RotatedX(30.0f);
Matrix4x4f scale = Matrix4x4f.Scaled(0.1f, 1.0f, 2.0f);

Create model-view-projection matrices

Matrix4x4f p = Matrix4x4f.Ortho(-1.0f, +1.0f, -1.0f, +1.0f, -1.0f, 1.0f);
Matrix4x4f v = Matrix4x4f.Translated(0.0f, 0.0f, 10.0f).Inverse;
Matrix4x4f m = Matrix4x4f.Identity;

Matrix4x4f mvp = p * v * m;

Create the normal matrix

Matrix4x4f mv = Matrix4x4f.Identity;
Matrix3x3f n = new Matrix3x3f(mv, 3, 3).Inverse.Transposed

Project a vertex

Matrix4x4f p = Matrix4x4f.Ortho(-1.0f, +1.0f, -1.0f, +1.0f, -10.0f, 10.0f);
Matrix4x4f v = Matrix4x4f.Translated(0.0f, 0.0f, 10.0f).Inverse;
Matrix4x4f m = Matrix4x4f.Identity;

Matrix4x4f mvp = p * v * m;
Vertex4f v = new Vertex4f(0.0f, 0.0f, 0.0f);   // (0, 0, 0, 1)
Vertex3f r = (Vertex3f)(mvp * v);              // (0, 0, -10)