I'm doing a cross between following some NeHe tutorials (translating it to OpenTK) and an OpenTK sample I found online to draw a triangle (for a simple initial setup):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.IO;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using System.Windows.Forms;
namespace GravSimBasic
{
class GLMain : GameWindow
{
int vbo;
Vector3[,] vertices;
float time = 0.01f;
void CreateVertexBuffer()
{
vertices = new Vector3[2,3];
vertices[0,0] = new Vector3(-1f, -1f, (float)Math.Sin(time));
vertices[0, 1] = new Vector3(0.5f, -1f, (float)Math.Sin(time));
vertices[0, 2] = new Vector3(-0.25f, 1f, -(float)Math.Sin(time));
vertices[1, 0] = new Vector3(-0.5f, -1f, (float)Math.Cos(time));
vertices[1, 1] = new Vector3(1f, -1f, (float)Math.Cos(time));
vertices[1, 2] = new Vector3(0.25f, 1f, -(float)Math.Cos(time));
//MessageBox.Show("Length: " + vertices.Length.ToString());
GL.GenBuffers(1, out vbo);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
new IntPtr(vertices.Length * Vector3.SizeInBytes),
vertices, BufferUsageHint.StaticDraw);
}
protected override void OnLoad(EventArgs e)
{
//set the window area
GL.Viewport(0, 0, 400, 400);
//background color
GL.ClearColor(Color.Black);
//set the view area
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(-2, 2, -2, 2, 2, -2);
//now back to 'scene editing' mode
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
//make things look nice
GL.ShadeModel(ShadingModel.Smooth);
//set up our z-rendering logic
GL.ClearDepth(2.0000f);
GL.Enable(EnableCap.DepthTest);
GL.DepthFunc(DepthFunction.Lequal);
//other improvements to quality
GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
//initialize our scene data
CreateVertexBuffer();
}
protected override void OnRenderFrame(FrameEventArgs e)
{
time += 0.01f;
vertices[0, 0].Z = (float)Math.Sin(time);
vertices[0, 1].Z = (float)Math.Sin(time);
vertices[0, 2].Z = -(float)Math.Sin(time);
vertices[1, 0].Z = (float)Math.Cos(time);
vertices[1, 1].Z = (float)Math.Cos(time);
vertices[1, 2].Z = -(float)Math.Cos(time);
GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
new IntPtr(vertices.Length * Vector3.SizeInBytes),
vertices, BufferUsageHint.StaticDraw);
System.Threading.Thread.Sleep(10);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.EnableVertexAttribArray(0);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.Color4(0.75f,0.0f,0.0f,0.25f);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
GL.DrawArrays(BeginMode.Triangles, 0, 3);
GL.Color4(0.0f, 0.75f, 0.0f, 0.55f);
GL.VertexAttribPointer(3, 3, VertexAttribPointerType.Float, false, 0, 0);
GL.DrawArrays(BeginMode.Triangles, 3, 3);
GL.DisableVertexAttribArray(0);
SwapBuffers();
}
}
}
I suspect the issue is in lines 58-60, but I've changed the value in line 58 between -2.0, 0.00001, and 2.0, none changed the results. It could be the perspective setup a few lines earlier, though.
I've tried almost all the functions available as a parameter for line 60 - Lequal seems to be the best option by what I would expect, and it does produce the closest result to what I want, but it isn't quite correct.
Setup: There is a green and red triangle. They partially overlap on the x-y axis. The top z-axis of one is mapped by a -sin(time) function, and the bottom, a sin(time) function. The other uses cos() instead of sin, but is otherwise the same. The 'time' value changes each rendering.
What I want/expect: Two overlapping triangles - one red, one green. As that rotate back and forth, the non-overlapping portion of each should always be visible, and the overlapping portions should only show the foremost triangle.
What I get:
(a) nothing
(b) a display of both triangles, one on top of other.
(c) A changing image of bits of one, both or none of the triangles - even if one or both are showing, the are bits of either triangle, that should be visible, that are missing (background).
If I remove time, it shows a correct snapshot - the red triangle in front in the bottom half, and the green in front on the top.
Can anyone help diagnose this?
On line 86 you're only clearing the color buffer, not the depth buffer, so any changes to 58 won't have any effect:
GL.Clear(ClearBufferMask.ColorBufferBit);
I've never used OpenTK, but I'd guess it needs to go something along these lines:
GL.Clear(ClearBufferMask.ColorBufferBit|ClearBufferMask.DepthBufferBit);
Related
I have probably a very simple question in OpenGL. I want to draw different shapes with textures on them.
So I defined a vertex struct, which contains the positions of knots and additional information (normal vector, texture coordinates, reference to texture):
public struct Vertex
{
public Vector3 position;
public Vector3 normal;
public Vector2 texCoord;
public int texid;
public static int SizeInBytes
{
get { return Vector3.SizeInBytes * 2 + Vector2.SizeInBytes + sizeof(int); }
}
public Vertex(Vector3 position, Vector3 normal, Vector2 texCoord, int texid)
{
this.position = position;
this.normal = normal;
this.texCoord = texCoord;
this.texid = texid;
}
}
Then I create 2 vertex arrays (VA_TopBottom_WP and VA_Side_WP) with its vertex buffers (VB_TopBottom_WP and VB_Side_WP). Moreover, I create all textures.
internal void init()
{
// Create Buffer for top and bottom part
GL.GenVertexArrays(1, out VA_TopBottom_WP);
GL.BindVertexArray(VA_TopBottom_WP);
VB_TopBottom_WP = GL.GenBuffer();
// Create Buffer for side part
GL.GenVertexArrays(1, out VA_Side_WP);
GL.BindVertexArray(VA_Side_WP);
VB_Side_WP = GL.GenBuffer();
// Create textures
texes = new List<STL_Tools.Texture2D>();
texes.Add(new STL_Tools.Texture2D());//Default texture
for (int n = 0; n < session.pgm.Count(); n++)
{
texes.Add(new STL_Tools.Texture2D());
}
updateFrame();
}
Then I update the buffer content:
public void updateFrame()
{
// Top and bottom buffer
GL.BindVertexArray(VA_TopBottom_WP);
GL.BindBuffer(BufferTarget.ArrayBuffer, VB_TopBottom_WP);
//Fill vertex structure
vertBuffer_TopBottom = poly.GetTopBottomMeshesVertex();
GL.BufferData<Vertex>(BufferTarget.ArrayBuffer, (IntPtr)(Vertex.SizeInBytes * vertBuffer_TopBottom.Length), vertBuffer_TopBottom, BufferUsageHint.StaticDraw);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0,3, VertexAttribPointerType.Float,false, Vertex.SizeInBytes, (IntPtr)0);//Position
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex.SizeInBytes, (IntPtr)(Vector3.SizeInBytes*2));//Texture
GL.VertexAttribPointer(2, 3, VertexAttribPointerType.Float, false, Vertex.SizeInBytes, (IntPtr)(Vector3.SizeInBytes));//Normal
// Side buffer
GL.BindVertexArray(VA_Side_WP);
GL.BindBuffer(BufferTarget.ArrayBuffer, VB_Side_WP);
vertBuffer_Side = poly.GetSideVertex();//Fill vertices
GL.BufferData<Vertex>(BufferTarget.ArrayBuffer, (IntPtr)(Vertex.SizeInBytes * vertBuffer_Side.Length), vertBuffer_Side, BufferUsageHint.StaticDraw);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, Vertex.SizeInBytes, (IntPtr)0);//Position
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex.SizeInBytes, (IntPtr)(Vector3.SizeInBytes * 2));//Texture
GL.VertexAttribPointer(2, 3, VertexAttribPointerType.Float, false, Vertex.SizeInBytes, (IntPtr)(Vector3.SizeInBytes));//Normal
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
}
The Vertex variables contain afterwards reasonable texture coordinates (Vector2 objects in the following). E. g.:
vertBuffer_Side = new Vertex[4]
{new Vertex(new Vector3(0,0,0),new Vector3(1,0,0),new Vector2(0,0),0),
new Vertex(new Vector3(0,-80,0),new Vector3(1,0,0),new Vector2(1,0),0),
new Vertex(new Vector3(0,-80,-10),new Vector3(1,0,0),new Vector2(1,1),0),
new Vertex(new Vector3(0,0,-10),new Vector3(1,0,0),new Vector2(0,0),0)};
Then I draw everything with the following function:
public void renderFrame()
{
GL.PushMatrix();
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.NormalArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
// Draw Side
GL.BindVertexArray(VA_Side_WP);
GL.Color3(Color.White);
GL.Enable(EnableCap.Texture2D);
for (int n = 0; n < (vertBuffer_Side.Length / 4); n++)
{
//GL.BindTexture(TextureTarget.Texture2D, 0);
GL.BindTexture(TextureTarget.Texture2D, texes[vertBuffer_Side[n*4].texid].ID);
GL.DrawArrays(PrimitiveType.Quads, n*4,4);
}
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.Disable(EnableCap.Texture2D);
//Draw top and bottom
GL.BindVertexArray(VA_TopBottom_WP);
...
GL.PopMatrix();
}
The geometry is drawn correctly. But the texture is not drawn correctly. It is drawn only with one color. It is the color of the far right pixel of the textures.
Probably, the following function does not work correctly:
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex.SizeInBytes, (IntPtr)(Vector3.SizeInBytes * 2));//Texture
Where is my mistake?
The client-side capabilities are states of the Vertex Array Object. Therefor you need to bind the VAO before setting the client-side capabilities. Also, you are not using a shader, but a shader program. Therefore, you must define the VertexPointer, NormalVector and TexCoordPointer instead of specifying generic arrays of vertex attributes. Note that it is possible to specify the vertex attribute 0 instead of the VertexPointer, but this is not possible for the normals and texture coordinates (also see What are the Attribute locations for fixed function pipeline in OpenGL 4.0++ core profile?):
GL.VertexPointer(3, VertexAttribPointerType.Float, false, Vertex.SizeInBytes, (IntPtr)0);//Position
GL.TexCoordPointer(2, VertexAttribPointerType.Float, false, Vertex.SizeInBytes, (IntPtr)(Vector3.SizeInBytes*2));//Texture
GL.NormalPointer(VertexAttribPointerType.Float, false, Vertex.SizeInBytes, (IntPtr)(Vector3.SizeInBytes));//Normal
GL.BindVertexArray(VA_Side_WP);
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.NormalArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
I have a sphere and I want to color it and add a light effect on it, so when I shed a light on it, the original color of the sphere is gone, replaced by the color of the illuminating light.
I don't know what is the problem, help me.
Here is my code:
enter code here
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using SharpGL;
using SharpGL.SceneGraph;
namespace SharpGLWinformsApplication1
{
public partial class SharpGLForm : Form
{
public SharpGLForm()
{
InitializeComponent();
}
private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e)
{
// Get the OpenGL object.
OpenGL gl = openGLControl.OpenGL;
IntPtr quad=gl.NewQuadric();
// Clear the color and depth buffer.
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
gl.LoadIdentity();
gl.Translate(0.0f, 0.0f, 12.0f);
gl.Scale(0.1,0.1,0.1);
//*
gl.PushMatrix();
gl.Color(1.0f, 1.0f, 0.0f);
gl.Sphere(quad, 15, 20, 20);
gl.PopMatrix();
//------------------------------------//
gl.PushMatrix();
gl.Color(0.0f, 1.0f, 0.0f);
gl.Rotate(rotation, 0.0f, 1.0f, 0.0f);
gl.Translate(0, 1, 30);
gl.Sphere(quad, 12, 20, 20);
gl.PopMatrix();
rotation += 3.0f;
}
private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
{
// TODO: Initialise OpenGL here.
// Get the OpenGL object.
OpenGL gl = openGLControl.OpenGL;
// Set the clear color.
gl.ClearColor(0, 0, 0, 0);
gl.Enable(OpenGL.GL_LIGHTING);
gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_AMBIENT, ambient);
gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_DIFFUSE, diffuse);
gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_SPECULAR, specular);
gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_POSITION, new float[] { 0.0f, 2f, -30f, 0 });
gl.Enable(OpenGL.GL_LIGHT1);
gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_SPOT_CUTOFF, 180.0f);
}
private void openGLControl_Resized(object sender, EventArgs e)
{
// TODO: Set the projection matrix here.
// Get the OpenGL object.
OpenGL gl = openGLControl.OpenGL;
// Set the projection matrix.
gl.MatrixMode(OpenGL.GL_PROJECTION);
// Load the identity.
gl.LoadIdentity();
gl.Viewport(0, 0, (int)Width, (int)Height);
// Create a perspective transformation.
gl.Perspective(45.0f, (double)Width / (double)Height, 1, 200.0);
// Use the 'look at' helper function to position and aim the camera.
gl.LookAt(0, -3, -10, 0, 0, 0, 0, 1, 0);
// Set the modelview matrix.
gl.MatrixMode(OpenGL.GL_MODELVIEW);
}
private float rotation = 0.0f;
private GLColor ambient = new GLColor(1, 1, 1, 1f);
private GLColor diffuse = new GLColor(1, 1, 1, 1);
private GLColor specular = new GLColor(1, 1, 1, 1);
private GLColor shadowColor = new GLColor(0, 0, 0, 0.4f);
}
}
I think you need to setup materials using gl.Materials(). otherwise opengl will take the sphere with a surface that reflects no light.
I'm making 2D games in OpenTK (a C# wrapper for OpenGL 4), and all was well except for jagged edges of polygons and things jumping and stuttering instead of moving smoothly - so I'm trying to add in multisampling to antialias my textures.
My setup has several Cameras which render all their scene objects onto a FrameBufferObject texture (I would like this to be MSAA), which are then all drawn to the screen (no multisampling needed), one on top of the other.
Without multisampling, it worked fine, but now I tried to change all my Texture2D calls to Texture2DMultisample etc but now I get FBO Not Complete errors and it draws wrong. I believe I need to change my shaders too, but I want to solve this first.
The code below references a few classes like Texture that I've made, but I don't think that should impact this, and I don't want to clutter the post - will give mroe details if needed.
I set up the FBO for each camera with:
private void SetUpFBOTex()
{
_frameBufferTexture = new Texture(GL.GenTexture(), Window.W, Window.H);
GL.BindTexture(TextureTarget.Texture2DMultisample, _frameBufferTexture.ID);
GL.TexImage2DMultisample(TextureTargetMultisample.Texture2DMultisample, 0, PixelInternalFormat.Rgba8, Window.W, Window.H, true);
_frameBufferID = GL.GenFramebuffer();
}
and draw with:
public void Render(Matrix4 matrix)
{
GL.Enable(EnableCap.Multisample);
//Bind FBO to be the draw destination and clear it
GL.BindFramebuffer(FramebufferTarget.Framebuffer, _frameBufferID);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2DMultisample, _frameBufferTexture.ID, 0);
GL.ClearColor(new Color4(0,0,0,0));
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
//draw stuff here
foreach (Layer l in Layers)
l.Render(Matrix);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
//Bind the FBO to be drawn
_frameBufferTexture.Bind();
//Translate to camera window position
Matrix4 fbomatrix = matrix * Matrix4.CreateTranslation(_window.x, _window.y, 0) * FBOMatrix;
//Bind shader
shader.Bind(ref fbomatrix, DrawType);
//Some OpenGL setup nonsense, binding vertices and index buffer and telling OpenGL where in the vertex struct things are, pointers &c
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBuffer);
GL.EnableVertexAttribArray(shader.LocationPosition);
GL.VertexAttribPointer(shader.LocationPosition, 2, VertexAttribPointerType.Float, false, Stride, 0);
if (shader.LocationTexture != -1)
{
GL.EnableVertexAttribArray(shader.LocationTexture);
GL.VertexAttribPointer(shader.LocationTexture, 2, VertexAttribPointerType.Float, false, Stride, 8);
}
GL.EnableVertexAttribArray(shader.LocationColour);
GL.VertexAttribPointer(shader.LocationColour, 4, VertexAttribPointerType.UnsignedByte, true, Stride, 16);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBuffer);
//Draw the damn quad
GL.DrawArrays(DrawType, 0, Vertices.Length);
//Cleanup
GL.DisableVertexAttribArray(shader.LocationPosition);
if (shader.LocationTexture != -1)
GL.DisableVertexAttribArray(shader.LocationTexture);
GL.DisableVertexAttribArray(shader.LocationColour);
}
Ok #Andon gets credit for this - if you write it as an answer I'll mark that as the solution. I was indeed doing antialiasing with 0 samples!
I'm posting the working antialiased drawing to multiple FBOS code for future OpenTK googlers.
private void SetUpFBOTex()
{
_frameBufferTexture = new Texture(GL.GenTexture(), Window.W, Window.H);
GL.BindTexture(TextureTarget.Texture2DMultisample, _frameBufferTexture.ID);
GL.TexImage2DMultisample(TextureTargetMultisample.Texture2DMultisample, 8, PixelInternalFormat.Rgba8, Window.W, Window.H, false);
_frameBufferID = GL.GenFramebuffer();
}
public void Render(Matrix4 matrix)
{
//Bind FBO to be the draw destination and clear it
GL.BindFramebuffer(FramebufferTarget.Framebuffer, _frameBufferID);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2DMultisample, _frameBufferTexture.ID, 0);
GL.ClearColor(new Color4(0,0,0,0));
GL.Clear(ClearBufferMask.ColorBufferBit);
//draw stuff here
foreach (Layer l in Layers)
l.Render(Matrix);
//unbind FBO to allow drawing to screen again
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
//Bind the FBO to be drawn
GL.BindTexture(TextureTarget.Texture2DMultisample, _frameBufferTexture.ID);
//Translate to camera window position
Matrix4 fbomatrix = matrix * Matrix4.CreateTranslation(_window.x, _window.y, 0) * FBOMatrix;
//Rotate camera FBO texture
if (_rotationAngle != 0f)
{
fbomatrix = Matrix4.CreateTranslation(RotationCentre.x, RotationCentre.y, 0) * fbomatrix;
fbomatrix = Matrix4.CreateRotationZ(_rotationAngle) * fbomatrix;
fbomatrix = Matrix4.CreateTranslation(-RotationCentre.x, -RotationCentre.y, 0) * fbomatrix;
}
shader.Bind(ref fbomatrix, DrawType);
//Some OpenGL setup nonsense, binding vertices and index buffer and telling OpenGL where in the vertex struct things are, pointers &c
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBuffer);
GL.EnableVertexAttribArray(shader.LocationPosition);
GL.VertexAttribPointer(shader.LocationPosition, 2, VertexAttribPointerType.Float, false, Stride, 0);
if (shader.LocationTexture != -1)
{
GL.EnableVertexAttribArray(shader.LocationTexture);
GL.VertexAttribPointer(shader.LocationTexture, 2, VertexAttribPointerType.Float, false, Stride, 8);
}
GL.EnableVertexAttribArray(shader.LocationColour);
GL.VertexAttribPointer(shader.LocationColour, 4, VertexAttribPointerType.UnsignedByte, true, Stride, 16);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBuffer);
//Draw the damn quad
GL.DrawArrays(DrawType, 0, Vertices.Length);
//Cleanup
GL.DisableVertexAttribArray(shader.LocationPosition);
if (shader.LocationTexture != -1)
GL.DisableVertexAttribArray(shader.LocationTexture);
GL.DisableVertexAttribArray(shader.LocationColour);
}
I have a wrapper class to control Shader code, here's the bind call:
internal void Bind(ref Matrix4 matrixMVP)
{
//Set this shader as active shader
GL.UseProgram(programID);
//Load position matrix into vertex shaders
GL.UniformMatrix4(LocationMVPMatrix, false, ref matrixMVP);
//Load active texture into fragment shaders
GL.Uniform1(LocationSampler, 0);
}
Fragment shader:
/// <summary>
/// Test for a Multisampled fragment shader - http://www.opentk.com/node/2251
/// </summary>
public const string fragmentShaderTestSrc =
#"
#version 330
uniform sampler2DMS Sampler;
in vec2 InTexture;
in vec4 OutColour;
out vec4 OutFragColor;
int samples = 16;
float div= 1.0/samples;
void main()
{
OutFragColor = vec4(0.0);
ivec2 texcoord = ivec2(textureSize(Sampler) * InTexture); // used to fetch msaa texel location
for (int i=0;i<samples;i++)
{
OutFragColor += texelFetch(Sampler, texcoord, i) * OutColour; // add color samples together
}
OutFragColor*= div; //devide by num of samples to get color avg.
}
";
Vertex shader:
/// <summary>
/// Default vertex shader that only applies specified matrix transformation
/// </summary>
public const string vertexShaderDefaultSrc =
#"
#version 330
uniform mat4 MVPMatrix;
layout (location = 0) in vec2 Position;
layout (location = 1) in vec2 Texture;
layout (location = 2) in vec4 Colour;
out vec2 InVTexture;
out vec4 vFragColorVs;
void main()
{
gl_Position = MVPMatrix * vec4(Position, 0, 1);
InVTexture = Texture;
vFragColorVs = Colour;
}";
I cannot render triangles for the life of me with a VBO in OpenTK. I am loading my data to the VBO in glControl_Load() event. I get a background screen with no triangles when running. The data is a from a mesh m.OpenGLArrays(out data, out indices) outputs a list of floats and ints. The list of floats for the vertices T1v1, T1v2, T1v3, T2v1, T2v2, T2v3, .... , all three vertices for each triangle back to back.
However given a blank screen with the code when I comment the "intermediate" rendering code everything renders fine....??? What am I doing wrong?
private void glControl_Load(object sender, EventArgs e)
{
loaded = true;
glControl.MouseMove += new MouseEventHandler(glControl_MouseMove);
glControl.MouseWheel += new MouseEventHandler(glControl_MouseWheel);
GL.ClearColor(Color.DarkSlateGray);
GL.Color3(1f, 1f, 1f);
m.OpenGLArrays(out data, out indices);
this.indicesSize = (uint)indices.Length;
GL.GenBuffers(1, out VBOid[0]);
GL.GenBuffers(1, out VBOid[1]);
SetupViewport();
}
private void SetupViewport()
{
if (this.WindowState == FormWindowState.Minimized) return;
glControl.Width = this.Width - 32;
glControl.Height = this.Height - 80;
Frame_label.Location = new System.Drawing.Point(glControl.Width / 2, glControl.Height + 25);
GL.MatrixMode(MatrixMode.Projection);
//GL.LoadIdentity();
GL.Ortho(0, glControl.Width, 0, glControl.Height, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
GL.Viewport(0, 0, glControl.Width, glControl.Height); // Use all of the glControl painting area
GL.Enable(EnableCap.DepthTest);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOid[0]);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(data.Length * sizeof(float)), data, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
float aspect_ratio = this.Width / (float)this.Height;
projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 1024);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projection);
}
private void glControl_Paint(object sender, PaintEventArgs e)
{
if (loaded)
{
GL.Clear(ClearBufferMask.ColorBufferBit |
ClearBufferMask.DepthBufferBit |
ClearBufferMask.StencilBufferBit);
modelview = Matrix4.LookAt(0f, 0f, -200f + zoomFactor, 0, 0, 0, 0.0f, 1.0f, 0.0f);
var aspect_ratio = Width / (float)Height;
projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 512);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projection);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref modelview);
GL.Rotate(angleY, 1.0f, 0, 0);
GL.Rotate(angleX, 0, 1.0f, 0);
GL.EnableClientState(ArrayCap.VertexArray);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOid[0]);
GL.Color3(Color.Yellow);
GL.VertexPointer(3, VertexPointerType.Float, Vector3.SizeInBytes, new IntPtr(0));
GL.DrawArrays(PrimitiveType.Triangles, 0, data.Length);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.DisableClientState(ArrayCap.VertexArray);
//GL.Color3(Color.Yellow);
//GL.PolygonMode(MaterialFace.Front, PolygonMode.Fill);
//GL.Begin(PrimitiveType.Triangles);
//for (int i = 0; i < this.md.mesh.Count; i++)
//{
// GL.Normal3(this.md.mesh[i].normal);
// GL.Vertex3(this.md.mesh[i].vertices[0]);
// GL.Vertex3(this.md.mesh[i].vertices[1]);
// GL.Vertex3(this.md.mesh[i].vertices[2]);
//}
//GL.End();
//GL.EndList();
glControl.SwapBuffers();
Frame_label.Text = "Frame: " + frameNum++;
}
}
If something doesn't seem right, then it probably isn't. I seriously questioned my understanding of opengl and spent hours looking at this. However it was just a simple error of forgetting to iterate a count variable in a for loop to transfer the mesh from one object to another. Each triangle had identical vertices! Always expect the unexpected when it comes to debugging!
I'm trying to learn how to draw with VBOs in C# OpenTK - following examples like http://www.opentk.com/node/2292 and VBOs Using Interleaved Vertices in C#.
I'm pretty sure I want the interleaved single array method like this, with a neat struct for each vertex. I got the code to compile with no errors, but it simply draws a blank brown screen, no white triangle. I'm sure I've made a stupid error, please help me learn from it!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using System.Drawing;
using System.Runtime.InteropServices;
namespace VBOTest2
{
[StructLayout(LayoutKind.Sequential)]
public struct Vertex
{
public Vector3 Position;
public byte[] Colour;
public Vertex(byte[] colour, Vector3 position)
{
Colour = colour;
Position = position;
}
public static readonly int Stride = Marshal.SizeOf(default(Vertex));
}
public class VBOTest2 : GameWindow
{
uint vbo;
public VBOTest2() :
base(1, 1, new GraphicsMode(32, 24, 8, 0), "Test")
{
Width = 1500;
Height = 800;
VSync = VSyncMode.On;
ClientSize = new Size(1500, 800);
this.Location = new System.Drawing.Point(100, 300);
GL.Viewport(0, 0, Width, Height);
}
void CreateVertexBuffer()
{
Vertex[] vertices = new Vertex[3];
vertices[0] = new Vertex(new byte[]{255,255,255,255}, new Vector3(-1f, -1f, 0f));
vertices[1] = new Vertex(new byte[] { 255, 255, 255, 255 }, new Vector3(1f, -1f, 0f));
vertices[2] = new Vertex(new byte[] { 255, 255, 255, 255 }, new Vector3(0f, 1f, 0f));
GL.GenBuffers(1, out vbo);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData<Vertex>(BufferTarget.ArrayBuffer, (IntPtr)Vertex.Stride, vertices, BufferUsageHint.StaticDraw);
}
protected override void OnLoad(EventArgs e)
{
GL.ClearColor(Color.Brown);
CreateVertexBuffer();
}
protected override void OnRenderFrame(FrameEventArgs e)
{
base.OnRenderFrame(e);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.ColorArray);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.VertexPointer(3, VertexPointerType.Float, Vertex.Stride, (IntPtr)(0));
GL.ColorPointer(4, ColorPointerType.UnsignedByte, Vertex.Stride, (IntPtr)(3 * sizeof(float)));
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
//release buffer
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.DisableClientState(ArrayCap.VertexArray);
GL.DisableClientState(ArrayCap.ColorArray);
SwapBuffers();
}
}
}