public static void Run() { using (var w = new GameWindow(720, 480, null, "ComGr", GameWindowFlags.Default, DisplayDevice.Default, 4, 0, OpenTK.Graphics.GraphicsContextFlags.ForwardCompatible)) { int hProgram = 0; int hTexture = 0; int hHeight = 0; int vaoTriangle = 0; int[] triangleIndices = null; int vboTriangleIndices = 0; byte[] imageData; byte[] heightData; double time = 0; int gridSize = 100; w.Load += (o, ea) => { //set up opengl GL.ClearColor(0.5f, 0.5f, 0.5f, 0); GL.ClearDepth(1); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Less); //GL.Enable(EnableCap.CullFace); //load, compile and link shaders //see https://www.khronos.org/opengl/wiki/Vertex_Shader var VertexShaderSource = @" #version 400 core in vec3 pos; in vec2 uvVertex; uniform mat4 model; uniform mat4 projection; uniform sampler2D height; out vec2 uvFragment; out vec3 absolutePos; out vec3 normalFragment; float getHeight(in vec2 pos) { float h = texture(height, pos).x; return log(h*30+1) * 8; } vec3 getNormal(in vec2 pos) { float offset = 1.0/float(textureSize(height,0).x); vec2 xOff = vec2(offset, 0); vec2 zOff = vec2(0, offset); vec3 x = vec3(offset*2, getHeight(pos+xOff) - getHeight(pos-xOff), 0); vec3 z = vec3(0, getHeight(pos+zOff) - getHeight(pos-zOff), offset*2); return normalize(cross(z, x)); } void main() { uvFragment = uvVertex; absolutePos = (model * vec4(pos, 1)).xyz; vec3 n = getNormal(uvVertex); normalFragment = normalize((model * vec4(n, 0)).xyz); vec3 p = pos; p.y = getHeight(uvVertex); gl_Position = projection * vec4(p,1); } "; var hVertexShader = GL.CreateShader(ShaderType.VertexShader); GL.ShaderSource(hVertexShader, VertexShaderSource); GL.CompileShader(hVertexShader); GL.GetShader(hVertexShader, ShaderParameter.CompileStatus, out int status); if (status != 1) { throw new Exception(GL.GetShaderInfoLog(hVertexShader)); } //see https://www.khronos.org/opengl/wiki/Fragment_Shader var FragmentShaderSource = @" #version 400 core uniform sampler2D tex; in vec3 absolutePos; in vec2 uvFragment; in vec3 lightPos; in vec3 normalFragment; out vec4 color; void main() { vec4 col = texture(tex, uvFragment); vec3 lightPos = vec3(2, 7, 0); vec3 toLight = normalize(lightPos - absolutePos); float diffuse = max(0, dot(toLight, normalFragment)); vec3 eye = vec3(0, 0, 0); vec3 viewDir = normalize(absolutePos - eye); vec3 specularDir = normalFragment * (2 * dot(normalFragment, toLight)) - toLight; specularDir = normalize(specularDir); vec3 specular = vec3(0.8) * pow(max(0.0, -dot(specularDir, viewDir)), 5); color = vec4(0.1)*col + diffuse * col + vec4(specular, 1); } "; var hFragmentShader = GL.CreateShader(ShaderType.FragmentShader); GL.ShaderSource(hFragmentShader, FragmentShaderSource); GL.CompileShader(hFragmentShader); GL.GetShader(hFragmentShader, ShaderParameter.CompileStatus, out status); if (status != 1) { throw new Exception(GL.GetShaderInfoLog(hFragmentShader)); } //link shaders to a program hProgram = GL.CreateProgram(); GL.AttachShader(hProgram, hFragmentShader); GL.AttachShader(hProgram, hVertexShader); GL.LinkProgram(hProgram); GL.GetProgram(hProgram, GetProgramParameterName.LinkStatus, out status); if (status != 1) { throw new Exception(GL.GetProgramInfoLog(hProgram)); } var triangleVertices = new float[(gridSize + 1) * (gridSize + 1) * 3]; var uvs = new float[(gridSize + 1) * (gridSize + 1) * 2]; triangleIndices = new int[gridSize * gridSize * 2 * 3]; for (int i = 0; i < gridSize + 1; i++) { for (int j = 0; j < gridSize + 1; j++) { triangleVertices[((gridSize + 1) * i + j) * 3 + 0] = i; triangleVertices[((gridSize + 1) * i + j) * 3 + 1] = 0; triangleVertices[((gridSize + 1) * i + j) * 3 + 2] = j; uvs[((gridSize + 1) * i + j) * 2 + 0] = i / (float)gridSize; uvs[((gridSize + 1) * i + j) * 2 + 1] = j / (float)gridSize; } } for (int i = 0; i < gridSize; i++) { for (int j = 0; j < gridSize; j++) { triangleIndices[(gridSize * i + j) * 6 + 0] = ((gridSize + 1) * i + j) + (gridSize + 1) * 0 + 0; triangleIndices[(gridSize * i + j) * 6 + 1] = ((gridSize + 1) * i + j) + (gridSize + 1) * 0 + 1; triangleIndices[(gridSize * i + j) * 6 + 2] = ((gridSize + 1) * i + j) + (gridSize + 1) * 1 + 0; triangleIndices[(gridSize * i + j) * 6 + 3] = ((gridSize + 1) * i + j) + (gridSize + 1) * 1 + 0; triangleIndices[(gridSize * i + j) * 6 + 4] = ((gridSize + 1) * i + j) + (gridSize + 1) * 0 + 1; triangleIndices[(gridSize * i + j) * 6 + 5] = ((gridSize + 1) * i + j) + (gridSize + 1) * 1 + 1; } } //upload model vertices to a vbo var vboTriangleVertices = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, vboTriangleVertices); GL.BufferData(BufferTarget.ArrayBuffer, triangleVertices.Length * sizeof(float), triangleVertices, BufferUsageHint.StaticDraw); // upload model indices to a vbo vboTriangleIndices = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, vboTriangleIndices); GL.BufferData(BufferTarget.ElementArrayBuffer, triangleIndices.Length * sizeof(int), triangleIndices, BufferUsageHint.StaticDraw); var vboUvs = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, vboUvs); GL.BufferData(BufferTarget.ArrayBuffer, uvs.Length * sizeof(float), uvs, BufferUsageHint.StaticDraw); //set up a vao vaoTriangle = GL.GenVertexArray(); GL.BindVertexArray(vaoTriangle); GL.EnableVertexAttribArray(GL.GetAttribLocation(hProgram, "pos")); GL.BindBuffer(BufferTarget.ArrayBuffer, vboTriangleVertices); GL.VertexAttribPointer(GL.GetAttribLocation(hProgram, "pos"), 3, VertexAttribPointerType.Float, false, 0, 0); GL.EnableVertexAttribArray(GL.GetAttribLocation(hProgram, "uvVertex")); GL.BindBuffer(BufferTarget.ArrayBuffer, vboUvs); GL.VertexAttribPointer(GL.GetAttribLocation(hProgram, "uvVertex"), 2, VertexAttribPointerType.Float, false, 0, 0); var image = new Bitmap("./stones.bmp"); var imageW = image.Width; var h = image.Height; imageData = new byte[imageW * h * 3]; BitmapData data = image.LockBits(new Rectangle(0, 0, imageW, h), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); unsafe { byte *p = (byte *)data.Scan0; for (int i = 0; i < imageW * h * 3; i += 3) { imageData[i] = *(p++); //r imageData[i + 1] = *(p++); //g imageData[i + 2] = *(p++); //b } image.UnlockBits(data); } GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); GL.GenTextures(1, out hTexture); GL.BindTexture(TextureTarget.Texture2D, hTexture); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Srgb8, image.Width, image.Height, 0, OpenTK.Graphics.OpenGL4.PixelFormat.Rgb, PixelType.UnsignedByte, imageData); GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); image = new Bitmap("./height.bmp"); imageW = image.Width; h = image.Height; heightData = new byte[imageW * h * 3]; data = image.LockBits(new Rectangle(0, 0, imageW, h), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); unsafe { byte *p = (byte *)data.Scan0; for (int i = 0; i < imageW * h * 3; i += 3) { heightData[i] = *(p++); //r heightData[i + 1] = *(p++); //g heightData[i + 2] = *(p++); //b } image.UnlockBits(data); } GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); GL.GenTextures(1, out hHeight); GL.BindTexture(TextureTarget.Texture2D, hHeight); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Srgb8, image.Width, image.Height, 0, OpenTK.Graphics.OpenGL4.PixelFormat.Rgb, PixelType.UnsignedByte, heightData); GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); { //check for errors during all previous calls var error = GL.GetError(); if (error != ErrorCode.NoError) { throw new Exception(error.ToString()); } } }; w.UpdateFrame += (o, fea) => { //perform logic time += fea.Time; }; w.RenderFrame += (o, fea) => { //clear screen and z-buffer GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); //switch to our shader GL.UseProgram(hProgram); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, hTexture); GL.Uniform1(GL.GetUniformLocation(hProgram, "tex"), 0); GL.ActiveTexture(TextureUnit.Texture1); GL.BindTexture(TextureTarget.Texture2D, hHeight); GL.Uniform1(GL.GetUniformLocation(hProgram, "height"), 1); var scale = Matrix4.CreateScale(5f / gridSize); var transCenter = Matrix4.CreateTranslation(-gridSize / 2, 0f, -gridSize / 2); var rotate = Matrix4x4.CreateFromYawPitchRoll((float)time / 2, 0, 0).ToGlMatrix(); var tilt = Matrix4x4.CreateFromYawPitchRoll(0, 0.2f, 0).ToGlMatrix(); var translate = Matrix4.CreateTranslation(0f, -1.5f, -5f); var perspective = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 2, 1, 1, 100); var allTransforms = transCenter * scale * rotate * tilt * translate; GL.UniformMatrix4(GL.GetUniformLocation(hProgram, "model"), false, ref allTransforms); allTransforms = allTransforms * perspective; GL.UniformMatrix4(GL.GetUniformLocation(hProgram, "projection"), false, ref allTransforms); //render our model GL.BindVertexArray(vaoTriangle); GL.BindBuffer(BufferTarget.ElementArrayBuffer, vboTriangleIndices); GL.DrawElements(PrimitiveType.Triangles, triangleIndices.Length, DrawElementsType.UnsignedInt, 0); //display w.SwapBuffers(); var error = GL.GetError(); if (error != ErrorCode.NoError) { throw new Exception(error.ToString()); } }; w.Resize += (o, ea) => { GL.Viewport(w.ClientRectangle); }; w.Run(); } }
public static void Run() { using (var w = new GameWindow(720, 480, null, "ComGr", GameWindowFlags.Default, DisplayDevice.Default, 4, 0, OpenTK.Graphics.GraphicsContextFlags.ForwardCompatible)) { int hProgram = 0; int hTexture = 0;; int vaoTriangle = 0; int[] triangleIndices = null; int vboTriangleIndices = 0; byte[] imageData; double time = 0; w.Load += (o, ea) => { //set up opengl GL.ClearColor(0.5f, 0.5f, 0.5f, 0); GL.ClearDepth(1); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Less); //GL.Enable(EnableCap.CullFace); //load, compile and link shaders //see https://www.khronos.org/opengl/wiki/Vertex_Shader var VertexShaderSource = @" #version 400 core in vec3 pos; in vec3 col; in vec2 uvVertex; in vec3 normalVertex; uniform mat4 model; uniform mat4 projection; out vec3 vertexColor; out vec2 uvFragment; out vec3 absolutePos; out vec3 normalFragment; void main() { uvFragment = uvVertex; vertexColor = col; normalFragment = (model * vec4(normalVertex,0)).xyz; absolutePos = (model * vec4(pos,1)).xyz; gl_Position = projection * vec4(pos,1); } "; var hVertexShader = GL.CreateShader(ShaderType.VertexShader); GL.ShaderSource(hVertexShader, VertexShaderSource); GL.CompileShader(hVertexShader); GL.GetShader(hVertexShader, ShaderParameter.CompileStatus, out int status); if (status != 1) { throw new Exception(GL.GetShaderInfoLog(hVertexShader)); } //see https://www.khronos.org/opengl/wiki/Fragment_Shader var FragmentShaderSource = @" #version 400 core uniform sampler2D tex; in vec3 absolutePos; in vec3 vertexColor; in vec2 uvFragment; in vec3 lightPos; in vec3 normalFragment; out vec4 color; void main() { vec4 texColor = texture(tex, uvFragment); vec4 col = vec4(vertexColor, 1.0) * texColor; vec3 lightPos = vec3(2, 3, 0); vec3 toLight = normalize(lightPos - absolutePos); float diffuse = max(0, dot(toLight, normalFragment)); vec3 eye = vec3(0, 0, 0); vec3 viewDir = normalize(absolutePos - eye); vec3 specularDir = normalFragment * (2 * dot(normalFragment, toLight)) - toLight; specularDir = normalize(specularDir); vec3 specular = vec3(0.8) * pow(max(0.0, -dot(specularDir, viewDir)), 50); color = vec4(0.2)*col + diffuse * col + vec4(specular, 1); } "; var hFragmentShader = GL.CreateShader(ShaderType.FragmentShader); GL.ShaderSource(hFragmentShader, FragmentShaderSource); GL.CompileShader(hFragmentShader); GL.GetShader(hFragmentShader, ShaderParameter.CompileStatus, out status); if (status != 1) { throw new Exception(GL.GetShaderInfoLog(hFragmentShader)); } //link shaders to a program hProgram = GL.CreateProgram(); GL.AttachShader(hProgram, hFragmentShader); GL.AttachShader(hProgram, hVertexShader); GL.LinkProgram(hProgram); GL.GetProgram(hProgram, GetProgramParameterName.LinkStatus, out status); if (status != 1) { throw new Exception(GL.GetProgramInfoLog(hProgram)); } //upload model vertices to a vbo var triangleVertices = new float[] { //top -1, -1, -1, +1, -1, -1, +1, +1, -1, -1, +1, -1, //bottom -1, -1, +1, +1, -1, +1, +1, +1, +1, -1, +1, +1, //left -1, -1, -1, -1, +1, -1, -1, +1, +1, -1, -1, +1, //right +1, +1, -1, +1, -1, -1, +1, -1, +1, +1, +1, +1, //front -1, +1, -1, +1, +1, -1, +1, +1, +1, -1, +1, +1, //back +1, -1, -1, -1, -1, -1, -1, -1, +1, +1, -1, +1, }; var vboTriangleVertices = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, vboTriangleVertices); GL.BufferData(BufferTarget.ArrayBuffer, triangleVertices.Length * sizeof(float), triangleVertices, BufferUsageHint.StaticDraw); triangleIndices = new int[] { 0, 1, 2, 0, 2, 3, 7, 6, 5, 7, 5, 4, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23, }; // upload model indices to a vbo vboTriangleIndices = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, vboTriangleIndices); GL.BufferData(BufferTarget.ElementArrayBuffer, triangleIndices.Length * sizeof(int), triangleIndices, BufferUsageHint.StaticDraw); var colors = new float[] { 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0 }; var vboColor = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, vboColor); GL.BufferData(BufferTarget.ArrayBuffer, colors.Length * sizeof(float), colors, BufferUsageHint.StaticDraw); var uvs = new float[] { 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, }; var vboUvs = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, vboUvs); GL.BufferData(BufferTarget.ArrayBuffer, uvs.Length * sizeof(float), uvs, BufferUsageHint.StaticDraw); var normals = new float[] { 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, }; var vboNorms = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, vboNorms); GL.BufferData(BufferTarget.ArrayBuffer, normals.Length * sizeof(float), normals, BufferUsageHint.StaticDraw); //set up a vao vaoTriangle = GL.GenVertexArray(); GL.BindVertexArray(vaoTriangle); GL.EnableVertexAttribArray(GL.GetAttribLocation(hProgram, "pos")); GL.BindBuffer(BufferTarget.ArrayBuffer, vboTriangleVertices); GL.VertexAttribPointer(GL.GetAttribLocation(hProgram, "pos"), 3, VertexAttribPointerType.Float, false, 0, 0); GL.EnableVertexAttribArray(GL.GetAttribLocation(hProgram, "col")); GL.BindBuffer(BufferTarget.ArrayBuffer, vboColor); GL.VertexAttribPointer(GL.GetAttribLocation(hProgram, "col"), 3, VertexAttribPointerType.Float, false, 0, 0); GL.EnableVertexAttribArray(GL.GetAttribLocation(hProgram, "uvVertex")); GL.BindBuffer(BufferTarget.ArrayBuffer, vboUvs); GL.VertexAttribPointer(GL.GetAttribLocation(hProgram, "uvVertex"), 2, VertexAttribPointerType.Float, false, 0, 0); GL.EnableVertexAttribArray(GL.GetAttribLocation(hProgram, "normalVertex")); GL.BindBuffer(BufferTarget.ArrayBuffer, vboNorms); GL.VertexAttribPointer(GL.GetAttribLocation(hProgram, "normalVertex"), 3, VertexAttribPointerType.Float, false, 0, 0); var image = new Bitmap("./stones.bmp"); var imageW = image.Width; var h = image.Height; imageData = new byte[imageW * h * 3]; BitmapData data = image.LockBits(new Rectangle(0, 0, imageW, h), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); unsafe { byte *p = (byte *)data.Scan0; for (int i = 0; i < imageW * h * 3; i += 3) { imageData[i] = *(p++); //r imageData[i + 1] = *(p++); //g imageData[i + 2] = *(p++); //b } image.UnlockBits(data); } GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); GL.GenTextures(1, out hTexture); GL.BindTexture(TextureTarget.Texture2D, hTexture); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Srgb8, image.Width, image.Height, 0, OpenTK.Graphics.OpenGL4.PixelFormat.Rgb, PixelType.UnsignedByte, imageData); GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); { //check for errors during all previous calls var error = GL.GetError(); if (error != ErrorCode.NoError) { throw new Exception(error.ToString()); } } }; w.UpdateFrame += (o, fea) => { //perform logic time += fea.Time; }; w.RenderFrame += (o, fea) => { //clear screen and z-buffer GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); //switch to our shader GL.UseProgram(hProgram); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, hTexture); GL.Uniform1(GL.GetAttribLocation(hProgram, "tex"), 0); var scale = Matrix4.CreateScale(1f); var rotate = Matrix4x4.CreateFromYawPitchRoll((float)time * 0.5f, (float)time, (float)time).ToGlMatrix(); var translate = Matrix4.CreateTranslation(0f, 0f, -5f); var perspective = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 2, 1, 1, 100); var allTransforms = rotate * scale * translate; GL.UniformMatrix4(GL.GetUniformLocation(hProgram, "model"), false, ref allTransforms); allTransforms = allTransforms * perspective; GL.UniformMatrix4(GL.GetUniformLocation(hProgram, "projection"), false, ref allTransforms); //render our model GL.BindVertexArray(vaoTriangle); GL.BindBuffer(BufferTarget.ElementArrayBuffer, vboTriangleIndices); GL.DrawElements(PrimitiveType.Triangles, triangleIndices.Length, DrawElementsType.UnsignedInt, 0); rotate = Matrix4x4.CreateFromYawPitchRoll((float)time, (float)time * 0.5f, (float)time).ToGlMatrix(); translate = Matrix4.CreateTranslation(2f, 2f, -5f); allTransforms = rotate * scale * translate; GL.UniformMatrix4(GL.GetUniformLocation(hProgram, "model"), false, ref allTransforms); allTransforms = allTransforms * perspective; GL.UniformMatrix4(GL.GetUniformLocation(hProgram, "projection"), false, ref allTransforms); //render our model GL.BindVertexArray(vaoTriangle); GL.BindBuffer(BufferTarget.ElementArrayBuffer, vboTriangleIndices); GL.DrawElements(PrimitiveType.Triangles, triangleIndices.Length, DrawElementsType.UnsignedInt, 0); rotate = Matrix4x4.CreateFromYawPitchRoll((float)time, (float)time, (float)time * 0.5f).ToGlMatrix(); translate = Matrix4.CreateTranslation(-2f, -2f, -5f); perspective = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 2f, 1, 1, 100); allTransforms = rotate * scale * translate; GL.UniformMatrix4(GL.GetUniformLocation(hProgram, "model"), false, ref allTransforms); allTransforms = allTransforms * perspective; GL.UniformMatrix4(GL.GetUniformLocation(hProgram, "projection"), false, ref allTransforms); //render our model GL.BindVertexArray(vaoTriangle); GL.BindBuffer(BufferTarget.ElementArrayBuffer, vboTriangleIndices); GL.DrawElements(PrimitiveType.Triangles, triangleIndices.Length, DrawElementsType.UnsignedInt, 0); //display w.SwapBuffers(); var error = GL.GetError(); if (error != ErrorCode.NoError) { throw new Exception(error.ToString()); } }; w.Resize += (o, ea) => { GL.Viewport(w.ClientRectangle); }; w.Run(); } }