We are trying to make an app using Xamarin which will have a small animated face in a GLKView on a particular screen. We have looked for solutions for rendering sprites, and the best solution we came up with stems from this solution here. We are having trouble even drawing a simple image in the GLKView, and the error in the output does not really make sense. We are converting this from iOS to Xamarin C# so there are differences between certain calls, but we have tried to keep most pieces in tact.
Here are the parts of the code this is related to:
public class Sprite : NSObject
{
public void Render()
{
Effect.Texture2d0.GLName = TextureInfo.Name;
Effect.Texture2d0.Enabled = true;
Effect.PrepareToDraw();
GL.EnableVertexAttribArray((int)GLKVertexAttrib.Position);
GL.EnableVertexAttribArray((int)GLKVertexAttrib.TexCoord0);
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(Quad));
Marshal.StructureToPtr(Quad, ptr, false);
int offset = (int)ptr;
GL.VertexAttribPointer((uint)GLKVertexAttrib.Position, 2, VertexAttribPointerType.Float, false, Marshal.SizeOf(typeof(TexturedVertex)), offset + (int)Marshal.OffsetOf(typeof(TexturedVertex), "geomertryVertex"));
GL.VertexAttribPointer((uint)GLKVertexAttrib.Position, 2, VertexAttribPointerType.Float, false, Marshal.SizeOf(typeof(TexturedVertex)), offset + (int)Marshal.OffsetOf(typeof(TexturedVertex), "textureVertex"));
GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);
Marshal.FreeHGlobal(ptr);
}
}
Sprite.Render() is called in this GLKViewController here:
public class AnimationViewController : GLKViewController
{
GLKView animationView;
EAGLContext context;
Sprite player;
GLKBaseEffect effect;
public override void ViewDidLoad()
{
base.ViewDidLoad();
context = new EAGLContext(EAGLRenderingAPI.OpenGLES2);
if (context == null)
Console.WriteLine("Failed to create ES context...");
animationView = new GLKView(new RectangleF(UIScreen.MainScreen.Bounds.Width * 0.05f,
UIScreen.MainScreen.Bounds.Height * 0.05f,
UIScreen.MainScreen.Bounds.Width * 0.9f,
UIScreen.MainScreen.Bounds.Height * 0.75f), context);
EAGLContext.SetCurrentContext(context);
animationView.DrawInRect += new EventHandler<GLKViewDrawEventArgs>(animationView_DrawInRect);
View.AddSubview(animationView);
effect = new GLKBaseEffect();
Matrix4 projectionMatrix = Matrix4.CreateOrthographicOffCenter(0, animationView.Frame.Width, 0, animationView.Frame.Height, -1024, 1024);
effect.Transform.ProjectionMatrix = projectionMatrix;
player = new Sprite(#"Player.png", effect);
}
void animationView_DrawInRect(object sender, GLKViewDrawEventArgs e)
{
GL.ClearColor(0.98f, 0.98f, 0.98f, 1.0f);
//GL.Clear((uint)(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit));
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.Enable(EnableCap.Blend);
player.Render();
}
}
Links to whole code files:
Sprite Class and related Structs
AnimationViewController Class
Looks like the problem is just a typo in the second call to VertexAttribPointer. The second GLKVertexAttrib.Position should instead be GLKVertexAttrib.TexCoord0:
GL.VertexAttribPointer((uint)GLKVertexAttrib.Position, 2, VertexAttribPointerType.Float, false, Marshal.SizeOf(typeof(TexturedVertex)), offset + (int)Marshal.OffsetOf(typeof(TexturedVertex), "geomertryVertex"));
GL.VertexAttribPointer((uint)GLKVertexAttrib.TexCoord0, 2, VertexAttribPointerType.Float, false, Marshal.SizeOf(typeof(TexturedVertex)), offset + (int)Marshal.OffsetOf(typeof(TexturedVertex), "textureVertex"));
Related
I have an interresting thing.
I want to get the rendered objects window coordinates. When i use this in OpenGLDraw event:
var modelview = new double[16];
gl.GetDouble(OpenGL.GL_MODELVIEW_MATRIX, modelview);
Drawing doenes't work.
Environment: VS 2019 community edition, SharpGL.WinForms 3.1.1., c# winform project, framework 4.6.1
OpenGLControl events:
Init, I need only 2D space.
private void RenderPanel_OpenGLInitialized(object sender, EventArgs e)
{
gl = RenderPanel.OpenGL;
gl.Disable(OpenGL.GL_DEPTH_TEST);
gl.Enable(OpenGL.GL_BLEND);
gl.BlendFunc(OpenGL.GL_SRC_ALPHA, OpenGL.GL_ONE_MINUS_SRC_ALPHA);
gl.LoadIdentity();
gl.MatrixMode(OpenGL.GL_PROJECTION);
gl.LoadIdentity();
gl.Viewport(0, 0, RenderPanel.Width, RenderPanel.Height);
gl.Ortho(0, RenderPanel.Width, RenderPanel.Height, 0, 1, -1);
gl.MatrixMode(OpenGL.GL_MODELVIEW);
gl.LoadIdentity();
}
Draw: It's works fine, drawing objects
private void RenderPanel_OpenGLDraw(object sender, RenderEventArgs args)
{
gl.ClearColor(1, 1, 1, 1);
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
gl.LoadIdentity();
glColor(Color.White);
gl.Enable(OpenGL.GL_TEXTURE_2D);
foreach (ImageItem img in ImageItems.Items)
{
img.Draw();
}
}
I want use this in foreach loop, after the img.Draw() (part of code)
var modelview = new double[16];
var projection = new double[16];
var viewport = new int[4];
var winx = new double[1];
var winy = new double[1];
var winz = new double[1];
gl.GetDouble(OpenGL.GL_MODELVIEW_MATRIX, modelview);
gl.GetDouble(OpenGL.GL_PROJECTION_MATRIX, projection);
gl.GetInteger(OpenGL.GL_VIEWPORT, viewport);
gl.Project(0, 0, 0, modelview, projection, viewport, winx, winy, winz);
try to debug, comment row by row. I see when use gl.GetDouble() drawing gone. I get a correct window coordinates just last object disappear.
.Draw() is simple
gl.BindTexture(OpenGL.GL_TEXTURE_2D, TextureID);
gl.LoadIdentity();
gl.Color(1f, 1f, 1f, pos.a);
gl.Translate(pos.x, pos.y, 0);
gl.Rotate(pos.r, 0, 0);
OpenGLDraw.DrawQuad(pos.w, pos.h);
It's a bug. I planted this 2 rows to some sample projects and drawing method borken(some objects disappear).
I try to lots of thing. Finally changed renderContextType and the last object appear. I think so not a good solution but works.
I' trying to implement a renderer which uses only one VBO and one EBO to store all object vertices and indices.
For that, I found some tutorials and finally came up with a rather good result.
The problem is that it only works properly with ONE single object. As soon as I want to add another one, the rendering shows weird behaviour.
Can you help me with this?
You can find the full code here: https://github.com/BanditBloodwyn/TerritorySimulator.
The important classes are:
Rendering.Core.Rendering.Renderer.cs
Rendering.Core.Classes.Shapes.GLShape.cs
Rendering.Core.RenderGUI.RenderGUI.cs
This is the initializing method in the Renderer:
public void Initialize(GLShape[] shapeArray)
{
Shapes = shapeArray;
GL.Enable(EnableCap.DepthTest);
GL.ClearColor(0.0f, 0.0f, 0.10f, 1.0f);
InitializeBuffers(Shapes);
InitializeVertexArrayObject(Shapes);
SetupShader();
BindBuffers();
}
The submethods look like this.
private void InitializeBuffers(GLShape[] shapeArray)
{
int vertexBufferSize = shapeArray.Sum(shape => shape.VertexBufferSize);
int indexBufferSize = shapeArray.Sum(shape => shape.IndexBufferSize);
// Vertex buffer
vertexBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
GL.BufferData(BufferTarget.ArrayBuffer, vertexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in shapeArray)
{
GL.BufferSubData(BufferTarget.ArrayBuffer, offset, shape.VertexBufferSize, shape.Vertices);
offset += shape.VertexBufferSize;
}
// Element buffer
elementBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
GL.BufferData(BufferTarget.ElementArrayBuffer, indexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
offset = (IntPtr)0;
foreach (GLShape shape in shapeArray)
{
GL.BufferSubData(BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, shape.Indices);
offset += shape.IndexBufferSize;
}
}
private void InitializeVertexArrayObject(GLShape[] shapeArray)
{
foreach (GLShape shape in shapeArray)
{
shape.VertexArrayObject = GL.GenVertexArray();
GL.BindVertexArray(shape.VertexArrayObject);
}
}
private void SetupShader()
{
// shader
string vertexPath = Path.Combine(Environment.CurrentDirectory, #"GLSL\", "Vertex.vert");
string fragmentPath = Path.Combine(Environment.CurrentDirectory, #"GLSL\", "Fragment.frag");
shader = new Shader(vertexPath, fragmentPath);
shader.Use();
int vertexLocation = shader.GetAttribLocation("aPosition");
GL.EnableVertexAttribArray(vertexLocation);
GL.VertexAttribPointer(
vertexLocation,
3,
VertexAttribPointerType.Float,
false,
5 * sizeof(float),
0);
int texCoordLocation = shader.GetAttribLocation("aTexCoord");
GL.EnableVertexAttribArray(texCoordLocation);
GL.VertexAttribPointer(
texCoordLocation,
2,
VertexAttribPointerType.Float,
false,
5 * sizeof(float),
3 * sizeof(float));
shader.SetInt("texture0", 0);
shader.SetInt("texture1", 1);
}
private void BindBuffers()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
}
The render function itself looks like this.
public void Render()
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
if (Shapes == null || Shapes.Length == 0)
return;
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in Shapes)
{
foreach (var texture in shape.Textures)
{
if (LayerConfiguration.ShowEarthTexture)
texture.Key.Use(texture.Value);
else
texture.Key.MakeTransparent(texture.Value);
}
ApplyModelTransforms(shape, out Matrix4 model);
shader.SetMatrix4("model", model);
shader.SetMatrix4("view", Camera.GetViewMatrix());
GL.DrawElements(PrimitiveType.Triangles, shape.Indices.Length, DrawElementsType.UnsignedInt, offset);
offset += shape.IndexBufferSize;
}
shader.SetMatrix4("projection", Camera.GetProjectionMatrix());
shader.Use();
}
As soon as I want to add another one, the rendering shows weird behavior
Of course, because the indices for the 2nd and following objects are wrong. You need to add the sum of the vertices of the previous meshes to the indexes. To the indices of the first mesh you have to add 0, to the indices of the 2nd mesh you have to add the number of vertices of the 1st mesh, to the indices of the 3rd mesh you have to add the sum of the vertices of the 1st and 2nd mesh, ...
offset = (IntPtr)0;
uint firstVertexIndex = 0;
foreach (GLShape shape in shapeArray)
{
var indexArray = shape.Indices.Select(index => index + firstVertexIndex).ToArray();
GL.BufferSubData(
BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, indexArray);
offset += shape.IndexBufferSize;
firstVertexIndex += (uint)(shape.VertexBufferSize / (5 * sizeof(float)));
}
Complete method InitializeBuffers:
private void InitializeBuffers(GLShape[] shapeArray)
{
int vertexBufferSize = shapeArray.Sum(shape => shape.VertexBufferSize);
int indexBufferSize = shapeArray.Sum(shape => shape.IndexBufferSize);
// Vertex buffer
vertexBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
GL.BufferData(BufferTarget.ArrayBuffer, vertexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in shapeArray)
{
GL.BufferSubData(BufferTarget.ArrayBuffer, offset, shape.VertexBufferSize, shape.Vertices);
offset += shape.VertexBufferSize;
}
// Element buffer
elementBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
GL.BufferData(BufferTarget.ElementArrayBuffer, indexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
offset = (IntPtr)0;
uint firstVertexIndex = 0;
foreach (GLShape shape in shapeArray)
{
var indexArray = shape.Indices.Select(index => index + firstVertexIndex).ToArray();
GL.BufferSubData(BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, indexArray);
offset += shape.IndexBufferSize;
firstVertexIndex += (uint)(shape.VertexBufferSize / (5 * sizeof(float)));
}
}
I looked at the code in How to draw line in OpenGl? but glBegin and glEnd are marked as deprecated. How are you supposed to draw a line in the current OpenGL version? I found articles that talk about using VBO, and articles that talk about glVertexPointer and glColorPointer, but there's so much framework around building these methods with the shader program compiling and linking and the vertex attribute bit twiddling. Isn't there a simple way to draw a line without using deprecated functions?
I tried this without success:
OpenTK.Vector2[] linepts = { new Vector2(0, 0), new Vector2(1, 1), new Vector2(50, 0), new Vector2(0, 50) };
int h = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, h);
GL.BufferData<Vector2>(BufferTarget.ArrayBuffer, 16, linepts, BufferUsageHint.StreamDraw);
GL.DrawArrays(PrimitiveType.LineStrip, 0, 4);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.DeleteBuffer(h);
I don't know if I'm even in the right ballpark using DrawArrays or if that method requires a whole mess of framework to go along with it, so I don't necessarily want to make this code work. I just want to find the simplest code for drawing a line that's advisable to use in modern OpenGL.
This is the simplest program (using OpenTK) that I can create to draw a line.
using System;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
namespace OpenGLLine
{
static class Program
{
static OpenTK.GameWindow gw;
static int shaderProgram;
static int vertexInfo;
static int lineVertexBuffer;
static int vertexCount;
[STAThread]
static void Main()
{
gw = new OpenTK.GameWindow(800, 600, OpenTK.Graphics.GraphicsMode.Default, "Game", OpenTK.GameWindowFlags.FixedWindow);
Initialize();
gw.RenderFrame += Gw_RenderFrame;
gw.Closed += Gw_Closed;
gw.Run(60);
}
private static void Gw_Closed(object sender, EventArgs e)
{
CleanUp();
}
private static void Initialize()
{
int vshader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vshader, #"#version 130
in vec2 vPosition;
void main()
{
gl_Position = vec4(vPosition, -1.0, 1.0);
}");
GL.CompileShader(vshader);
int fshader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fshader, #"#version 130
out vec4 fragColor;
void main()
{
fragColor = vec4(1.0, 1.0, 1.0, 1.0);
}");
GL.CompileShader(fshader);
shaderProgram = GL.CreateProgram();
GL.AttachShader(shaderProgram, vshader);
GL.AttachShader(shaderProgram, fshader);
GL.LinkProgram(shaderProgram);
GL.DetachShader(shaderProgram, vshader);
GL.DetachShader(shaderProgram, fshader);
GL.UseProgram(shaderProgram);
lineVertexBuffer = GL.GenBuffer();
Vector2[] lineVertices = { new Vector2(0, 0), new Vector2(.5f, .5f) };
vertexCount = lineVertices.Length;
GL.BindBuffer(BufferTarget.ArrayBuffer, lineVertexBuffer);
GL.BufferData(BufferTarget.ArrayBuffer, System.Runtime.InteropServices.Marshal.SizeOf(lineVertices[0]) * vertexCount,
lineVertices, BufferUsageHint.StreamDraw);
vertexInfo = GL.GenVertexArray();
GL.BindVertexArray(vertexInfo);
int locVPosition = GL.GetAttribLocation(shaderProgram, "vPosition");
GL.EnableVertexAttribArray(locVPosition);
GL.VertexAttribPointer(locVPosition, 2, VertexAttribPointerType.Float, false,
System.Runtime.InteropServices.Marshal.SizeOf(lineVertices[0]), 0);
GL.BindVertexArray(0);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.UseProgram(0);
}
static void CleanUp()
{
GL.DeleteProgram(shaderProgram);
GL.DeleteVertexArray(vertexInfo);
GL.DeleteBuffer(lineVertexBuffer);
}
private static void Gw_RenderFrame(object sender, OpenTK.FrameEventArgs e)
{
GL.ClearColor(Color4.Black);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.BindBuffer(BufferTarget.ArrayBuffer, lineVertexBuffer);
GL.UseProgram(shaderProgram);
GL.BindVertexArray(vertexInfo);
GL.DrawArrays(PrimitiveType.LineStrip, 0, vertexCount);
GL.BindVertexArray(0);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.UseProgram(0);
gw.SwapBuffers();
}
}
}
Getting started using SharpGL after using other frameworks for OpenGL in C# I decided to start with the most simplest of examples to make sure I understood any syntax changes/niceties of SharpGL.
So I'm attempting to render a single solid coloured triangle which shouldn't be too difficult.
I have two Vertex Buffers, one that stores the points of the Triangle and the other that stores the colours at each of the points. These are built up like so (The points one is the same except it uses the points array):
var colorsVboArray = new uint[1];
openGl.GenBuffers(1, colorsVboArray);
openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, colorsVboArray[0]);
this.colorsPtr = GCHandle.Alloc(this.colors, GCHandleType.Pinned).AddrOfPinnedObject();
openGl.BufferData(OpenGL.GL_ARRAY_BUFFER, this.colors.Length * Marshal.SizeOf<float>(), this.colorsPtr,
OpenGL.GL_STATIC_DRAW);
These are then set with the correct attrib pointer and enabled:
openGl.VertexAttribPointer(0, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero);
openGl.EnableVertexAttribArray(0);
But now when I draw using the call:
openGl.DrawArrays(OpenGL.GL_TRIANGLES, 0, 3);
I don't get anything on the screen. No exceptions, but the background is simply blank.
Naturally I presumed that there were compilation issues with my shaders, fortunately SharpGL gives me an easy way of checking and both the Vertex and Fragment shaders are showing as correctly compiled and linked.
Can anyone see why this code does not correctly display any objects, it's basically the same code that I've used before.
Full Source:
internal class Triangle
{
private readonly float[] colors = new float[9];
private readonly ShaderProgram program;
private readonly float[] trianglePoints =
{
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f
};
private IntPtr colorsPtr;
private IntPtr trianglePointsPtr;
private readonly VertexBufferArray vertexBufferArray;
public Triangle(OpenGL openGl, SolidColorBrush solidColorBrush)
{
for (var i = 0; i < this.colors.Length; i+=3)
{
this.colors[i] = solidColorBrush.Color.R / 255.0f;
this.colors[i + 1] = solidColorBrush.Color.G / 255.0f;
this.colors[i + 2] = solidColorBrush.Color.B / 255.0f;
}
this.vertexBufferArray = new VertexBufferArray();
this.vertexBufferArray.Create(openGl);
this.vertexBufferArray.Bind(openGl);
var colorsVboArray = new uint[1];
openGl.GenBuffers(1, colorsVboArray);
openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, colorsVboArray[0]);
this.colorsPtr = GCHandle.Alloc(this.colors, GCHandleType.Pinned).AddrOfPinnedObject();
openGl.BufferData(OpenGL.GL_ARRAY_BUFFER, this.colors.Length * Marshal.SizeOf<float>(), this.colorsPtr,
OpenGL.GL_STATIC_DRAW);
var triangleVboArray = new uint[1];
openGl.GenBuffers(1, triangleVboArray);
openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, triangleVboArray[0]);
this.trianglePointsPtr = GCHandle.Alloc(this.trianglePoints, GCHandleType.Pinned).AddrOfPinnedObject();
openGl.BufferData(OpenGL.GL_ARRAY_BUFFER, this.trianglePoints.Length * Marshal.SizeOf<float>(), this.trianglePointsPtr,
OpenGL.GL_STATIC_DRAW);
openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,triangleVboArray[0]);
openGl.VertexAttribPointer(0, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero);
openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, colorsVboArray[0]);
openGl.VertexAttribPointer(1, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero);
openGl.EnableVertexAttribArray(0);
openGl.EnableVertexAttribArray(1);
var vertexShader = new VertexShader();
vertexShader.CreateInContext(openGl);
vertexShader.SetSource(new StreamReader(
Assembly.GetExecutingAssembly()
.GetManifestResourceStream(#"OpenGLTest.Shaders.Background.SolidColor.SolidColorVertex.glsl"))
.ReadToEnd());
vertexShader.Compile();
var fragmentShader = new FragmentShader();
fragmentShader.CreateInContext(openGl);
fragmentShader.SetSource(new StreamReader(
Assembly.GetExecutingAssembly()
.GetManifestResourceStream(#"OpenGLTest.Shaders.Background.SolidColor.SolidColorFragment.glsl"))
.ReadToEnd());
fragmentShader.Compile();
this.program = new ShaderProgram();
this.program.CreateInContext(openGl);
this.program.AttachShader(vertexShader);
this.program.AttachShader(fragmentShader);
this.program.Link();
}
public void Draw(OpenGL openGl)
{
this.program.Push(openGl, null);
this.vertexBufferArray.Bind(openGl);
openGl.DrawArrays(OpenGL.GL_TRIANGLES, 0, 3);
this.program.Pop(openGl, null);
}
}
Vertex Shader:
#version 430 core
layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec3 vertex_color;
out vec3 color;
void main()
{
color = vertex_color;
gl_Position = vec4(vertex_position, 1.0);
}
Fragment Shader:
#version 430 core
in vec3 colour;
out vec4 frag_colour;
void main ()
{
frag_colour = vec4 (colour, 1.0);
}
Fixed this in the end fairly simply.
I had previously reviewed the SharpGL code and had noted that GL_DEPTH_TEST had been enabled, so I had presumed that the GL_DEPTH_BUFFER_BIT had been correctly cleared and I didn't have to do this.
After reviewing the Render code in SharpGL it turns out that this is not cleared by default but instead the onus is passed to the user to correctly clear the depth buffer.
Therefore I needed a simple call to clear to fix this:
this.openGl.Clear(OpenGL.GL_DEPTH_BUFFER_BIT);
Im getting an Access Violation when ever I run this code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using System.IO;
namespace OpenTKTutorial1
{
class Game : GameWindow
{
int pgmID;
int vsID;
int fsID;
int attribute_vcol;
int attribute_vpos;
int uniform_mview;
int vbo_position;
int vbo_color;
int vbo_mview;
Vector3[] vertdata;
Vector3[] coldata;
Matrix4[] mviewdata;
void initProgram()
{
pgmID = GL.CreateProgram();
loadShader("vs.glsl", ShaderType.VertexShader, pgmID, out vsID);
loadShader("fs.glsl", ShaderType.FragmentShader, pgmID, out fsID);
GL.LinkProgram(pgmID);
Console.WriteLine(GL.GetProgramInfoLog(pgmID));
attribute_vpos = GL.GetAttribLocation(pgmID, "vPosition");
attribute_vcol = GL.GetAttribLocation(pgmID, "vColor");
uniform_mview = GL.GetUniformLocation(pgmID, "modelview");
if (attribute_vpos == -1 || attribute_vcol == -1 || uniform_mview == -1)
{
Console.WriteLine("Error binding attirbutes");
}
GL.GenBuffers(1, out vbo_position);
GL.GenBuffers(1, out vbo_color);
GL.GenBuffers(1, out vbo_mview);
}
void loadShader(String filename, ShaderType type, int program, out int address)
{
address = GL.CreateShader(type);
using (StreamReader sr = new StreamReader(filename))
{
GL.ShaderSource(address, sr.ReadToEnd());
}
GL.CompileShader(address);
GL.AttachShader(program, address);
Console.WriteLine(GL.GetShaderInfoLog(address));
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
initProgram();
vertdata = new Vector3[]{
new Vector3(-0.8f, -0.8f, 0f),
new Vector3(0.8f, -0.8f, 0f),
new Vector3(0f, 0.8f, 0f)};
coldata = new Vector3[]{
new Vector3(1f, 0f, 0f),
new Vector3(0f, 0f, 1f),
new Vector3(0f, 1f, 0f)};
mviewdata = new Matrix4[]{
Matrix4.Identity};
Title = "Title";
GL.ClearColor(Color.CornflowerBlue);
GL.PointSize(5f);
}
protected override void OnRenderFrame(FrameEventArgs e)
{
base.OnRenderFrame(e);
GL.Viewport(0, 0, Width, Height);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Enable(EnableCap.DepthTest);
GL.EnableVertexAttribArray(attribute_vpos);
GL.EnableVertexAttribArray(attribute_vcol);
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
GL.DisableVertexAttribArray(attribute_vpos);
GL.DisableVertexAttribArray(attribute_vcol);
GL.Flush();
//Everything before this
SwapBuffers();
}
protected override void OnUpdateFrame(FrameEventArgs e)
{
base.OnUpdateFrame(e);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, (IntPtr)(vertdata.Length * Vector3.SizeInBytes), vertdata, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(attribute_vpos, 3, VertexAttribPointerType.Float, false, 0, 0);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_color);
GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, (IntPtr)(coldata.Length * Vector3.SizeInBytes), coldata, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(attribute_vcol, 3, VertexAttribPointerType.Float, true, 0, 0);
GL.UniformMatrix4(uniform_mview, false, ref mviewdata[0]);
GL.UseProgram(pgmID);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
}
}
}
It makes it to rendering the background then crashes.
I'm quite new to OpenTK and OpenGL so I'm not 100% sure what the problem is.
The error is thrown at
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
There are a few minor issues with your code, but it works for me without changes.
Regardless, I have made a few changes and added commentary to explain why, maybe something fixes it for you. If not please post your shaders and more detail on the exact exception, if there is any.
using System;
using System.Drawing;
using System.IO;
using OpenTK;
using OpenTK.Graphics.OpenGL;
namespace OpenTKTutorial1
{
public class Game
: GameWindow
{
int pgmID;
int vsID;
int fsID;
int attribute_vcol;
int attribute_vpos;
int uniform_mview;
int vbo_position;
int vbo_color;
int vbo_mview;
Vector3[] vertdata;
Vector3[] coldata;
Matrix4[] mviewdata;
public Game()
{
// better use the events instead of overriding the inherited methods
// at least thats what the documentation on Update- and RenderFrame says
Load += OnLoad;
UpdateFrame += OnUpdateFrame;
RenderFrame += OnRenderFrame;
}
void InitProgram()
{
pgmID = GL.CreateProgram();
LoadShader("vs.glsl", ShaderType.VertexShader, pgmID, out vsID);
LoadShader("fs.glsl", ShaderType.FragmentShader, pgmID, out fsID);
GL.LinkProgram(pgmID);
Console.WriteLine(GL.GetProgramInfoLog(pgmID));
attribute_vpos = GL.GetAttribLocation(pgmID, "vPosition");
attribute_vcol = GL.GetAttribLocation(pgmID, "vColor");
uniform_mview = GL.GetUniformLocation(pgmID, "modelview");
if (attribute_vpos == -1 || attribute_vcol == -1 || uniform_mview == -1)
{
Console.WriteLine("Error binding attributes");
}
GL.GenBuffers(1, out vbo_position);
GL.GenBuffers(1, out vbo_color);
// what is this buffer for?
//GL.GenBuffers(1, out vbo_mview);
}
void LoadShader(String filename, ShaderType type, int program, out int address)
{
address = GL.CreateShader(type);
using (StreamReader sr = new StreamReader(filename))
{
GL.ShaderSource(address, sr.ReadToEnd());
}
GL.CompileShader(address);
GL.AttachShader(program, address);
Console.WriteLine(GL.GetShaderInfoLog(address));
}
protected void OnLoad(object sender, EventArgs eventArgs)
{
InitProgram();
vertdata = new Vector3[]{
new Vector3(-0.8f, -0.8f, 0f),
new Vector3(0.8f, -0.8f, 0f),
new Vector3(0f, 0.8f, 0f)};
coldata = new Vector3[]{
new Vector3(1f, 0f, 0f),
new Vector3(0f, 0f, 1f),
new Vector3(0f, 1f, 0f)};
mviewdata = new Matrix4[]{
Matrix4.Identity};
Title = "Title";
GL.ClearColor(Color.CornflowerBlue);
GL.PointSize(5f);
}
protected void OnRenderFrame(object sender, FrameEventArgs frameEventArgs)
{
// if you only have one viewport you can safely move this to the OnResize event
GL.Viewport(0, 0, Width, Height);
// if the state never changes move it to OnLoad
GL.Enable(EnableCap.DepthTest);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.EnableVertexAttribArray(attribute_vpos);
GL.EnableVertexAttribArray(attribute_vcol);
// always make sure the program is enabled ..
GL.UseProgram(pgmID);
// .. before you set any uniforms
GL.UniformMatrix4(uniform_mview, false, ref mviewdata[0]);
// .. or draw anything
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
GL.DisableVertexAttribArray(attribute_vpos);
GL.DisableVertexAttribArray(attribute_vcol);
// do not call glFlush unless you have a very good reason to
// it can result in significant slow downs
//GL.Flush();
SwapBuffers();
}
protected void OnUpdateFrame(object sender, FrameEventArgs frameEventArgs)
{
// your vertex and color data never changes, thus everything you do here
// could be moved to OnLoad instead of having it repeated all the time
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertdata.Length * Vector3.SizeInBytes), vertdata, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(attribute_vpos, 3, VertexAttribPointerType.Float, false, 0, 0);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_color);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(coldata.Length * Vector3.SizeInBytes), coldata, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(attribute_vcol, 3, VertexAttribPointerType.Float, true, 0, 0);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
}
}
}