Draw wire cube using OpenTK - c#

I am trying to draw a wire cube (edges only) using ElementBufferObject. I have set the coordinates of the eight vertices of the cube and an array of indices. Next, I initialize VAO, VBO and EBO for the future cube. Then I try to draw it, but I don't see any result.
Cube vertices and indices:
private readonly float[] _cubeVertices =
{
// Bottom side
-0.5f, -0.5f, 0.0f, // [0] Front-left
0.5f, -0.5f, 0.0f, // [1] Front-right
-0.5f, -0.5f, -1.0f, // [2] Rear-left
0.5f, -0.5f, -1.0f, // [3] Rear-right
// Upper side
-0.5f, 0.5f, 0.0f, // [4] Front-left
0.5f, 0.5f, 0.0f, // [5] Front-right
-0.5f, 0.5f, -1.0f, // [6] Rear-left
0.5f, 0.5f, -1.0f // [7] Rear-right
};
//indices
private readonly uint[] _cubeEdges =
{
0, 1,
0, 2,
0, 4,
3, 2,
3, 1,
3, 7,
5, 6,
5, 4,
5, 1,
6, 7,
6, 4,
6, 2
};
onLoad():
_cubeShader = new Shader("../../../Shaders/cubeShader.vert", "../../../Shaders/shader.frag");
_cubeShader.Use();
_vboCube = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, _vboCube);
GL.BufferData(BufferTarget.ArrayBuffer, _cubeVertices.Length * sizeof(float), _cubeVertices, BufferUsageHint.StaticDraw);
_vaoCube = GL.GenVertexArray();
GL.BindVertexArray(_vaoCube);
var vertexLocation = _cubeShader.GetAttribLocation("aPosition");
GL.VertexAttribPointer(vertexLocation, 3, VertexAttribPointerType.Float, false, 3 * sizeof(float), 0);
_eboCube = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _eboCube);
GL.BufferData(BufferTarget.ElementArrayBuffer, _cubeEdges.Length * sizeof(uint), _cubeEdges, BufferUsageHint.StaticDraw);
Actual drawing:
_cubeShader.Use();
GL.BindVertexArray(_vaoCube);
//GL.LineWidth(2.0f);
GL.DrawElements(PrimitiveType.Lines, _cubeEdges.Length, DrawElementsType.UnsignedInt, 0);
cubeShader.vert:
#version 330 core
in vec3 aPosition;
void main(void)
{
gl_Position = vec4(aPosition, 1.0);
}
shader.frag:
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0);
}
Shader.cs code you can find here GitHub.
Actually, all my code based on LearnOpenTK repo
This is my first introduction to OpenGL, so most likely I'm missing something important in the process. Is it even possible to draw lines using EBO? I have already tried the same thing with triangles and everything worked out.

I figured it out. I forgot the line
GL.EnableVertexAttribArray(vertex Location);
after calling
GL.vertexAttribPointer()

Related

How to fit an image (texture) inside a quad in OpenTK?

I've been trying to look into different examples for texturing in OpenTK, however, little to no code examples use the same approach as I desire or a lot of pointless workarounds are required that do not fit my needs. I am simply trying to draw images in OpenTK without their UVs being distorted or malformed. Or rather, how do I malform them to fit the primitive (in this case quad/square) wherever its positioned at in the 2D world?
Consider this image (It's my texture I'm trying to fit inside a quad primitive):
This is the unwanted result. As you can see, it is cropped. I don't care about the wrapping because I plan on fitting the whole image inside the square (No aspect ratio needed). Different wrapping settings did nothing. The image's center is still outside the square.
The transparency and palette is my thing to worry about, I only need help fitting the whole image inside the square!
This is my code for loading textures:
public Texture(Bitmap image)
{
ID = GL.GenTexture();
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, ID);
BitmapData data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, image.Width, image.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
}
Then here's my code for loading the vertex data into the shaders and drawing the primitive:
List<float> vertex_data = {
-.25f, -.25f,
-.25f, .25f,
.25f, .25f,
.25f, -.25f
};
// Load the 2D object
GL.UseProgram(program);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, vertex_data.Count * sizeof(float), vertex_data.ToArray(), BufferUsageHint.DynamicDraw);
GL.EnableVertexAttribArray(attr_pos);
GL.VertexAttribPointer(attr_pos, 2, VertexAttribPointerType.Float, false, 2 * sizeof(float), 0);
GL.EnableVertexAttribArray(attr_uv);
GL.VertexAttribPointer(attr_uv, 2, VertexAttribPointerType.Float, false, 2 * sizeof(float), 0);
// ^^ Using the same position data for the UV as well.
// ...
// Drawing the 2D object
GL.UseProgram(program);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, ID);
GL.DrawArrays(PrimitiveType.Quads, 0, 4);
And the vertex and fragment shaders:
vert:
#version 330 core
layout(location = 1) in vec3 vertex_pos;
layout(location = 2) in vec2 vertex_uv;
out vec2 uv;
uniform mat4 mvp;
void main() {
gl_Position = mvp * vec4(vertex_pos, 1);
uv = vertex_uv;
}
frag:
#version 330 core
in vec2 uv;
out vec4 color;
uniform sampler2D texture0;
void main() {
color = texture(texture0, uv);
}
All you need to do is to specifytexture coordinates in range [0.0, 1.0]:
List<float> vertex_data = {
// x y u v
-.25f, -.25f, 0.0f, 0.0f,
-.25f, .25f, 0.0f, 1.0f,
.25f, .25f, 1.0f, 1.0f,
.25f, -.25f, 1.0f, 0.0f,
};
// Load the 2D object
GL.UseProgram(program);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, vertex_data.Count * sizeof(float),
vertex_data.ToArray(), BufferUsageHint.DynamicDraw);
GL.EnableVertexAttribArray(attr_pos);
GL.VertexAttribPointer(attr_pos, 2, VertexAttribPointerType.Float, false,
4 * sizeof(float), 0);
GL.EnableVertexAttribArray(attr_uv);
GL.VertexAttribPointer(attr_uv, 2, VertexAttribPointerType.Float, false,
4 * sizeof(float), 2 * sizeof(float));
The texture coordinate (0, 0) address the bottom left edge of the texture and the texture coordinate (1, 1) address the top right edge of the texture.
You must associate the texture coordinate (0, 0) to the bottom left of the quad and the texture coordinate (1, 1) the top right of the quad.
The 4th argument of GL.VertexAttribPointe (strid) specifies the byte offset between consecutive generic vertex attributes. Since each attribute consists of 4 elements of type flaot (x, y, u, v), this is 4*sizeof(float). The last argument is the byte offset of the attribute. The offset of the vertex coordinates is 0 and and the offset of the texture coordinates is 2*sizeof(float)
Of course you can use 2 separate the attribute arrays. In this case, stride is 2*sizeof(float) for the vertex coordinates and texture coordinates. The offset of the vertex coordinates is 0 and and the offset of the texture coordinates is the size of all the vertex coordinates (8*sizeof(float)):
Use GL.BufferSubData to initialize buffer data:
List<float> vertex_data = {
// x y
-.25f, -.25f,
-.25f, .25f,
.25f, .25f,
.25f, -.25f,
}
List<float> texture_data = {
// u v
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
};
// Load the 2D object
GL.UseProgram(program);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer,
vertex_data.Count * sizeof(float) + texture_data.Count * sizeof(float),
IntPtr.Zero, BufferUsageHint.DynamicDraw);
GL.BufferSubData(BufferTarget.ArrayBuffer, 0,
vertex_data.Count * sizeof(float), vertex_data.ToArray())
GL.BufferSubData(BufferTarget.ArrayBuffer, vertex_data.Count * sizeof(float),
texture_data.Count * sizeof(float), texture_data.ToArray())
GL.EnableVertexAttribArray(attr_pos);
GL.VertexAttribPointer(attr_pos, 2, VertexAttribPointerType.Float, false,
2 * sizeof(float), 0);
GL.EnableVertexAttribArray(attr_uv);
GL.VertexAttribPointer(attr_uv, 2, VertexAttribPointerType.Float, false,
2 * sizeof(float), vertex_data.Count * sizeof(float));

vTextCoord value is not working - c# OPENTK

My app is displaying an image in full screen by using OpenGL shader code as shown below. The vertex shader I used here is copied from somewhere. Can anyone explain why here used vTexCoord = (a_position.xy+1)/2;? When I'm trying with vTexCoord = a_position.xy, my OpenGL output is split into four rectangles and only it's top right portion is showing the image. Other three sides are seem as blurred. What change should I do to work it with vTexCoord = a_position.xy ?
Some important functions used in the project are shown below. Please check and help to correct.
float[] vertices = {
// Left bottom triangle
-1f, -1f, 0f,
1f, -1f, 0f,
1f, 1f, 0f,
// Right top triangle
1f, 1f, 0f,
-1f, 1f, 0f,
-1f, -1f, 0f
};
private void CreateShaders()
{
/***********Vert Shader********************/
vertShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShader, #"attribute vec3 a_position;
varying vec2 vTexCoord;
void main() {
vTexCoord = (a_position.xy+1)/2;
gl_Position = vec4(a_position, 1);
}");
GL.CompileShader(vertShader);
/***********Frag Shader ****************/
fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShader, #"precision highp float;
uniform sampler2D sTexture;varying vec2 vTexCoord;
void main ()
{
vec4 color= texture2D (sTexture, vTexCoord);
gl_FragColor =color;
}");
GL.CompileShader(fragShader);
}
private void InitBuffers()
{
buffer = GL.GenBuffer();
positionLocation = GL.GetAttribLocation(program, "a_position");
positionLocation1 = GL.GetUniformLocation(program, "sTexture");
GL.EnableVertexAttribArray(positionLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, 0, 0);
}
public void DrawImage(int image)
{
GL.Viewport(new Rectangle(0, 0, ScreenWidth, ScreenHeight));
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
//GL.Ortho(0, 1920, 0, 1080, 0, 1);
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
GL.Disable(EnableCap.Lighting);
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, image);
GL.Uniform1(positionLocation1, 0);
GL.Begin(PrimitiveType.Quads);
GL.TexCoord2(0, 1);
GL.Vertex3(0, 0, 0);
GL.TexCoord2(0, 0);
GL.Vertex3(1920, 0, 0);
GL.TexCoord2(1, 1);
GL.Vertex3(1920, 1080, 0);
GL.TexCoord2(1, 0);
GL.Vertex3(0, 1080, 0);
GL.End();
RunShaders();
GL.Disable(EnableCap.Texture2D);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Modelview);
glControl1.SwapBuffers();
}
private void RunShaders()
{
GL.UseProgram(program);
GL.DrawArrays(PrimitiveType.Triangles, 0, vertices.Length / 3);
}
Can anyone explain why here used vTexCoord = (a_position.xy+1)/2;?
The vertex coordinates in you example are in range [-1, 1], for the x and component. This matches to the normalized device space. The normalized device space is a cube from the left-lower-front (-1, -1, -1), to the right-top-back (1, 1, 1), this is the area wich is "visible". This area is mapped to the viewport.
This causes that the vertex coordinates, in your example, form a rectangle, which covers the entire viewport.
If the texture coordinates should wrap the entire texture to the quad, then the texture coordinates (u, v) have to be in range [0, 1]. (0, 0) is the lower left of the texture and (1, 1) the upper right.
See also How do OpenGL texture coordinates work?
So the x and y component of a_position have to be mapped form the range [-1, 1], to the range [0, 1], to be used as uv coordinates for the texture lookup:
u = (a_position.x + 1) / 2
v = (a_position.y + 1) / 2
What change should I do to work it with vTexCoord = a_position.xy?
This is not possible, but you can generate a separate texture coordinate attribute, which is common:
attribute vec3 a_position;
attribute vec2 a_texture;
varying vec2 vTexCoord;
void main() {
vTexCoord = a_texture;
gl_Position = vec4(a_position, 1);
}
float[] vertices = {
// x y z u v
// Left bottom triangle
-1f, -1f, 0f, 0f, 0f
1f, -1f, 0f, 1f, 0f
1f, 1f, 0f, 1f, 1f
// Right top triangle
1f, 1f, 0f, 1f, 1f
-1f, 1f, 0f, 0f, 1f
-1f, -1f, 0f 0f, 0f
};
buffer = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
positionLocation = GL.GetAttribLocation(program, "a_position");
tetureLocation = GL.GetAttribLocation(program, "a_texture");
GL.EnableVertexAttribArray(positionLocation);
GL.EnableVertexAttribArray(tetureLocation);
int stride = sizeof(float) * 5; // 5 because of (x, y, z, u, v)
int offsetUV = sizeof(float) * 3; // 3 because the u and v coordinates are the 4th and 5th coordinate
GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, stride, 0);
GL.VertexAttribPointer(tetureLocation, 2, VertexAttribPointerType.Float, false, stride, (IntPtr)(offsetUV));

Weird OpenGL cube

I just tried to use VBOs. So I render a cube, and here's what's appening.
If I don't rotate it, everything is OK :
But when I rotate it, this thing appens :
It looks like the cube is translucid and... I don't really know, it's messing with my mind.
Here's my code :
internal class CubeRenderer
{
private VertexBuffer vertexBuffer;
private IndexBuffer indexBuffer;
public CubeRenderer()
{
vertexBuffer = new VertexBuffer(new[]
{
// front
new Vertex(-1.0f, -1.0f, 1.0f, Color.Red),
new Vertex(1.0f, -1.0f, 1.0f, Color.Beige),
new Vertex(1.0f, 1.0f, 1.0f, Color.SaddleBrown),
new Vertex(-1.0f, 1.0f, 1.0f, Color.AliceBlue),
//back
new Vertex(-1.0f, -1.0f, -1.0f, Color.DarkBlue),
new Vertex(1.0f, -1.0f, -1.0f, Color.Firebrick),
new Vertex(1.0f, 1.0f, -1.0f, Color.IndianRed),
new Vertex(-1.0f, 1.0f, -1.0f, Color.Yellow)
});
indexBuffer = new IndexBuffer(new uint[]
{
// front
0, 1, 2,
2, 3, 0,
// top
3, 2, 6,
6, 7, 3,
// back
7, 6, 5,
5, 4, 7,
// bottom
4, 5, 1,
1, 0, 4,
// left
4, 0, 3,
3, 7, 4,
// right
1, 5, 6,
6, 2, 1
});
}
public void Draw()
{
// 1) Ensure that the VertexArray client state is enabled.
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.NormalArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
GL.EnableClientState(ArrayCap.ColorArray);
// 2) Bind the vertex and element (=indices) buffer handles.
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBuffer.Id);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBuffer.Id);
GL.VertexPointer(3, VertexPointerType.Float, vertexBuffer.Stride, IntPtr.Zero);
GL.NormalPointer(NormalPointerType.Float, vertexBuffer.Stride, new IntPtr(Vector3.SizeInBytes));
GL.TexCoordPointer(2, TexCoordPointerType.Float, vertexBuffer.Stride, new IntPtr(Vector3.SizeInBytes*2));
GL.ColorPointer(4, ColorPointerType.UnsignedByte, vertexBuffer.Stride, new IntPtr(Vector3.SizeInBytes*2 + Vector2.SizeInBytes));
// 4) Call DrawElements. (Note: the last parameter is an offset into the element buffer and will usually be IntPtr.Zero).
GL.DrawElements(PrimitiveType.Triangles, indexBuffer.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);
//Disable client state
GL.DisableClientState(ArrayCap.VertexArray);
GL.DisableClientState(ArrayCap.NormalArray);
GL.DisableClientState(ArrayCap.TextureCoordArray);
GL.DisableClientState(ArrayCap.ColorArray);
}
}
Edit 1:
Looks like it is a problem of depth buffer. I tried to enable the DepthTest, but it still does the same thing.
Edit 2:
It might be coming from the way that I rotate the matrix...?
GL.Ortho(-Zoom * ratio, Zoom * ratio, -Zoom, Zoom, 0, 100);
Allright I found the answer by myself. The problem came from the fact that I was using glOrtho to zoom, and somehow using wrong values. I switched to glScale and everything is good now!

openTK c# roatating cube example

i am using C# (visual studio 2008) to develop a slot machine,
using OpenTK for using openGL in my project
we have done the basic functionality but the we cant get a code to draw a cube that can rotate.
THe cude needs to rotate for some time, but i cant figure out how to do it.
we have tried this Cube
but this we want to draw it on a form
OpenTK provides a Windows Forms control called GLControl. It has no built-in main loop, but getting continuous rendering to work on the control isn't that hard if you follow this GLControl tutorial.
Once you have continuous rendering working, you can move over the code to render a cube and it will be continuously rotating on a form.
Here is an example of a rotating cube in C# using OpenTK:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
// adapted from : dreamstatecoding.blogspot.com
namespace RotatingCube
{
public struct Vertex
{
public const int Size = (4 + 4) * 4; // size of struct in bytes
private readonly Vector4 _position;
private readonly Color4 _color;
public Vertex(Vector4 position, Color4 color)
{
_position = position;
_color = color;
}
}
public sealed class MainWindow : GameWindow
{
private readonly string _title;
private int _width;
private int _height;
private int _program;
private double _time;
private bool _initialized;
private int _vertexArray;
private int _buffer;
private int _verticeCount;
private Matrix4 _model;
private Matrix4 _view;
private Matrix4 _projection;
private float _FOV = 45.0f;
private float _lastTimestamp = Stopwatch.GetTimestamp();
private float _freq = Stopwatch.Frequency;
private float _angle;
public MainWindow()
: base(750, // initial width
500, // initial height
GraphicsMode.Default,
"", // initial title
GameWindowFlags.Default,
DisplayDevice.Default,
3, // OpenGL major version
3, // OpenGL minor version
GraphicsContextFlags.ForwardCompatible)
{
_width = 750;
_height = 500;
_title += "Spinning Cube, OpenGL Version: " + GL.GetString(StringName.Version);
}
protected override void OnLoad(EventArgs e)
{
_model = Matrix4.Identity;
Vertex[] vertices =
{
new Vertex(new Vector4(-0.5f, -0.5f, -0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4( 0.5f, -0.5f, -0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4( 0.5f, 0.5f, -0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4( 0.5f, 0.5f, -0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4(-0.5f, 0.5f, -0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4(-0.5f, -0.5f, -0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4(-0.5f, -0.5f, 0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4( 0.5f, -0.5f, 0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4( 0.5f, 0.5f, 0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4( 0.5f, 0.5f, 0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4(-0.5f, 0.5f, 0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4(-0.5f, -0.5f, 0.5f, 1.0f), Color4.Blue),
new Vertex(new Vector4(-0.5f, 0.5f, 0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4(-0.5f, 0.5f, -0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4(-0.5f, -0.5f, -0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4(-0.5f, -0.5f, -0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4(-0.5f, -0.5f, 0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4(-0.5f, 0.5f, 0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4( 0.5f, 0.5f, 0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4( 0.5f, 0.5f, -0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4( 0.5f, -0.5f, -0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4( 0.5f, -0.5f, -0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4( 0.5f, -0.5f, 0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4( 0.5f, 0.5f, 0.5f, 1.0f), Color4.Red),
new Vertex(new Vector4(-0.5f, -0.5f, -0.5f, 1.0f), Color4.Green),
new Vertex(new Vector4( 0.5f, -0.5f, -0.5f, 1.0f), Color4.Green),
new Vertex(new Vector4( 0.5f, -0.5f, 0.5f, 1.0f), Color4.Green),
new Vertex(new Vector4( 0.5f, -0.5f, 0.5f, 1.0f), Color4.Green),
new Vertex(new Vector4(-0.5f, -0.5f, 0.5f, 1.0f), Color4.Green),
new Vertex(new Vector4(-0.5f, -0.5f, -0.5f, 1.0f), Color4.Green),
new Vertex(new Vector4(-0.5f, 0.5f, -0.5f, 1.0f), Color4.Green),
new Vertex(new Vector4( 0.5f, 0.5f, -0.5f, 1.0f), Color4.Green),
new Vertex(new Vector4( 0.5f, 0.5f, 0.5f, 1.0f), Color4.Green),
new Vertex(new Vector4( 0.5f, 0.5f, 0.5f, 1.0f), Color4.Green),
new Vertex(new Vector4(-0.5f, 0.5f, 0.5f, 1.0f), Color4.Green),
new Vertex(new Vector4(-0.5f, 0.5f, -0.5f, 1.0f), Color4.Green),
};
_verticeCount = vertices.Length;
_vertexArray = GL.GenVertexArray();
_buffer = GL.GenBuffer();
GL.BindVertexArray(_vertexArray);
GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexArray);
// create first buffer: vertex
GL.NamedBufferStorage(
_buffer,
Vertex.Size*vertices.Length, // the size needed by this buffer
vertices, // data to initialize with
BufferStorageFlags.MapWriteBit); // at this point we will only write to the buffer
GL.VertexArrayAttribBinding(_vertexArray, 0, 0);
GL.EnableVertexArrayAttrib(_vertexArray, 0);
GL.VertexArrayAttribFormat(
_vertexArray,
0, // attribute index, from the shader location = 0
4, // size of attribute, vec4
VertexAttribType.Float, // contains floats
false, // does not need to be normalized as it is already, floats ignore this flag anyway
0); // relative offset, first item
GL.VertexArrayAttribBinding(_vertexArray, 1, 0);
GL.EnableVertexArrayAttrib(_vertexArray, 1);
GL.VertexArrayAttribFormat(
_vertexArray,
1, // attribute index, from the shader location = 1
4, // size of attribute, vec4
VertexAttribType.Float, // contains floats
false, // does not need to be normalized as it is already, floats ignore this flag anyway
16); // relative offset after a vec4
// link the vertex array and buffer and provide the stride as size of Vertex
GL.VertexArrayVertexBuffer(_vertexArray, 0, _buffer, IntPtr.Zero, Vertex.Size);
_initialized = true;
CursorVisible = true;
try
{
_program = GL.CreateProgram();
var shaders = new List<int>();
ShaderType type = ShaderType.VertexShader;
var shader = GL.CreateShader(type);
string src = #"#version 330 core
layout (location = 0) in vec4 position;
layout(location = 1) in vec4 color;
out vec4 vs_color;
out vec3 original_normal;
out vec3 transformed_normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main(void)
{
gl_Position = projection * view * model * position;
vs_color = color;
original_normal = vec3(color);
mat3 normal_matrix = transpose(inverse(mat3(view * model)));
transformed_normal = normal_matrix * original_normal;
}";
GL.ShaderSource(shader, src);
GL.CompileShader(shader);
var info = GL.GetShaderInfoLog(shader);
if (!string.IsNullOrWhiteSpace(info))
throw new Exception($"CompileShader {type} had errors: {info}");
shaders.Add(shader);
type = ShaderType.FragmentShader;
shader = GL.CreateShader(type);
src = #"#version 330 core
in vec4 vs_color;
in vec3 original_normal;
in vec3 transformed_normal;
out vec4 color;
void main(void)
{
float lighting = abs(dot(transformed_normal, vec3(0,0,-1)));
color = vs_color * lighting;
}";
GL.ShaderSource(shader, src);
GL.CompileShader(shader);
info = GL.GetShaderInfoLog(shader);
if (!string.IsNullOrWhiteSpace(info))
throw new Exception($"CompileShader {type} had errors: {info}");
shaders.Add(shader);
foreach (var shader_ in shaders)
GL.AttachShader(_program, shader_);
GL.LinkProgram(_program);
var info_ = GL.GetProgramInfoLog(_program);
if (!string.IsNullOrWhiteSpace(info_))
throw new Exception($"CompileShaders ProgramLinking had errors: {info}");
foreach (var shader_ in shaders)
{
GL.DetachShader(_program, shader_);
GL.DeleteShader(shader_);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
throw;
}
GL.Enable(EnableCap.DepthTest);
GL.PolygonMode(MaterialFace.Front, PolygonMode.Fill);
GL.PatchParameter(PatchParameterInt.PatchVertices, 3);
Closed += OnClosed;
}
private void OnClosed(object sender, EventArgs eventArgs)
{
Exit();
}
public override void Exit()
{
Debug.WriteLine("Exit called");
GL.DeleteVertexArray(_vertexArray);
GL.DeleteBuffer(_buffer);
GL.DeleteProgram(_program);
base.Exit();
}
protected override void OnResize(EventArgs e)
{
// Resize the viewport to match the window size.
GL.Viewport(0, 0, Width, Height);
base.OnResize(e);
}
private float[] Matrix4ToArray(Matrix4 matrix)
{
float[] data = new float[16];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
data[i*4+j] = matrix[i, j];
}
}
return data;
}
private void PrintMatrix(Matrix4 matrix)
{
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
Console.WriteLine(matrix[i,j]);
}
}
}
protected override void OnRenderFrame(FrameEventArgs e)
{
var timeStamp = Stopwatch.GetTimestamp();
_angle += (float)((timeStamp - _lastTimestamp) / (double)_freq);
_lastTimestamp = timeStamp;
GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Clear the color buffer.
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
// Bind the VBO
GL.BindBuffer(BufferTarget.ArrayBuffer, _buffer);
// Bind the VAO
GL.BindVertexArray(_vertexArray);
// Use/Bind the program
GL.UseProgram(_program);
_model = Matrix4.CreateFromAxisAngle(new Vector3(1.0f, 0.0f, 1.0f), _angle);
_view = Matrix4.LookAt(new Vector3(0.0f,0.0f,5.0f), new Vector3(0.0f,0.0f,0.0f), Vector3.UnitY);
_projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI * (_FOV/180f), _width / (float)_height, 0.2f, 256.0f);
int location = GL.GetUniformLocation(_program, "model");
GL.UniformMatrix4(location, 1, false, Matrix4ToArray(_model));
location = GL.GetUniformLocation(_program, "view");
GL.UniformMatrix4(location, 1, false, Matrix4ToArray(_view));
location = GL.GetUniformLocation(_program, "projection");
GL.UniformMatrix4(location, 1, false, Matrix4ToArray(_projection));
// This draws the triangle.
GL.DrawArrays(PrimitiveType.Triangles, 0, _verticeCount);
// Swap the front/back buffers so what we just rendered to the back buffer is displayed in the window.
Context.SwapBuffers();
base.OnRenderFrame(e);
}
[STAThread]
static void Main()
{
new MainWindow().Run(60);
}
}
}
Result:

SlimDX Direct3D 11 Indexing Problems

I'm trying to draw an indexed square using SlimDX and Direct3D11. I've managed to draw a square without indices, but when I swap to my indexed version I just get a blank screen.
My input layout is set to only take position data (I'm essentially extending from the third tutorial on the SlimDX website) and to draw Triangle Lists.
My render loop code is as follows (I am using the triangle.fx pixel and vertex shader files from the tutorial, they take vertex positions (in screen coordinates) and paint them yellow, D3D is shorthand for SlimDX.Direct3D11)
//clear the render target
context.ClearRenderTargetView(renderTarget, new Color4(0.5f, 0.5f, 1.0f));
context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(mesh.VertexBuffer,12, 0));
context.InputAssembler.SetIndexBuffer(mesh.IndexBuffer, Format.R16_UNorm, 0);
context.DrawIndexed(mesh.indices, 0, 0);
swapChain.Present(0, PresentFlags.None);
"mesh" is a struct that holds a Vertex buffer, Index buffer and vertex count. The data is filled here:
Vertex[] vertexes = new Vertex[4];
vertexes[0].Position = new Vector3(0, 0, 0.5f);
vertexes[1].Position = new Vector3(0, 0.5f, 0.5f);
vertexes[2].Position = new Vector3(0.5f, 0, 0.5f);
vertexes[3].Position = new Vector3(0.5f, 0.5f, 0.5f);
UInt16[] indexes = { 0, 1, 2, 1, 3, 2 };
DataStream vertices = new DataStream(12 * 4, true, true);
foreach (Vertex vertex in vertexes)
{
vertices.Write(vertex.Position);
}
vertices.Position = 0;
DataStream indices = new DataStream(sizeof(int) * 6, true, true);
foreach (UInt16 index in indexes)
{
indices.Write(index);
}
indices.Position = 0;
mesh = new Mesh();
D3D.Buffer vertexBuffer = new D3D.Buffer(device, vertices, 12 * 4, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
mesh.VertexBuffer = vertexBuffer;
mesh.IndexBuffer = new D3D.Buffer(device, indices, 2 * 6, ResourceUsage.Default, BindFlags.IndexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
mesh.vertices = vertexes.GetLength(0);
mesh.indices = indexes.Length;
All of this is nearly identical to my unindexed square method (with the addition of index buffers and indices, and the removal of two duplicate vertices that aren't needed with indexing), but while the unindexed method draws a square, the indexed method doesn't.
My current theory is that there is either something wrong with this line:
mesh.IndexBuffer = new D3D.Buffer(device, indices, 2 * 6, ResourceUsage.Default, BindFlags.IndexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
Or these lines:
context.InputAssembler.SetIndexBuffer(mesh.IndexBuffer, Format.R16_UNorm, 0);
context.DrawIndexed(mesh.indices, 0, 0);
Why don't you just use a vertex and indexbuffer for this simple example?
Like this way (Directx9):
VertexBuffer vb;
IndexBuffer ib;
vertices = new PositionColored[WIDTH * HEIGHT];
//vertex creation
vb = new VertexBuffer(device, HEIGHT * WIDTH * PositionColored.SizeInBytes, Usage.WriteOnly, PositionColored.Format, Pool.Default);
DataStream stream = vb.Lock(0, 0, LockFlags.None);
stream.WriteRange(vertices);
vb.Unlock();
indices = new short[(WIDTH - 1) * (HEIGHT - 1) * 6];
//indicies creation
ib = new IndexBuffer(device, sizeof(int) * (WIDTH - 1) * (HEIGHT - 1) * 6, Usage.WriteOnly, Pool.Default, false);
DataStream stream = ib.Lock(0, 0, LockFlags.None);
stream.WriteRange(indices);
ib.Unlock();
//Drawing
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkSlateBlue, 1.0f, 0);
device.BeginScene();
device.VertexFormat = PositionColored.Format;
device.SetStreamSource(0, vb, 0, PositionColored.SizeInBytes);
device.Indices = ib;
device.SetTransform(TransformState.World, Matrix.Translation(-HEIGHT / 2, -WIDTH / 2, 0) * Matrix.RotationZ(angle));
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, WIDTH * HEIGHT, 0, indices.Length / 3);
device.EndScene();
device.Present();
I use the mesh in another way (directx9 code again):
private void CreateMesh()
{
meshTerrain = new Mesh(device, (WIDTH - 1) * (HEIGHT - 1) * 2, WIDTH * HEIGHT, MeshFlags.Managed, PositionColored.Format);
DataStream stream = meshTerrain.VertexBuffer.Lock(0, 0, LockFlags.None);
stream.WriteRange(vertices);
meshTerrain.VertexBuffer.Unlock();
stream.Close();
stream = meshTerrain.IndexBuffer.Lock(0, 0, LockFlags.None);
stream.WriteRange(indices);
meshTerrain.IndexBuffer.Unlock();
stream.Close();
meshTerrain.GenerateAdjacency(0.5f);
meshTerrain.OptimizeInPlace(MeshOptimizeFlags.VertexCache);
meshTerrain = meshTerrain.Clone(device, MeshFlags.Dynamic, PositionNormalColored.Format);
meshTerrain.ComputeNormals();
}
//Drawing
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkSlateBlue, 1.0f, 0);
device.BeginScene();
device.VertexFormat = PositionColored.Format;
device.SetTransform(TransformState.World, Matrix.Translation(-HEIGHT / 2, -WIDTH / 2, 0) * Matrix.RotationZ(angle));
int numSubSets = meshTerrain.GetAttributeTable().Length;
for (int i = 0; i < numSubSets; i++)
{
meshTerrain.DrawSubset(i);
}
device.EndScene();
device.Present();

Categories

Resources