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;
}";
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 made solar system with sun in the centre and planets rotating around him. I wanted to add skybox, it is added properly but I cant see my planets.
Before adding skybox:
After adding skybox:
main skybox code:
// skybox VAO
unsigned int skyboxVAO, skyboxVBO;
glGenVertexArrays(1, &skyboxVAO);
glGenBuffers(1, &skyboxVBO);
glBindVertexArray(skyboxVAO);
glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
vector<std::string> faces
{
"res/textures/skybox/right.png",
"res/textures/skybox/left.png",
"res/textures/skybox/top.png",
"res/textures/skybox/bot.png",
"res/textures/skybox/front.png",
"res/textures/skybox/back.png"
};
unsigned int cubemapTexture = loadCubemap(faces);
window skybox code:
// draw skybox as last
glDepthFunc(GL_LEQUAL); // change depth function so depth test passes when values are equal to depth buffer's content
skyboxShader.use();
view = glm::mat4(glm::mat3(camera.GetViewMatrix())); // remove translation from the view matrix
skyboxShader.setMat4("view", view);
skyboxShader.setMat4("projection", projection);
// skybox cube
glBindVertexArray(skyboxVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glDepthFunc(GL_LESS); // set depth function back to default
vertex shader and fragment shader:
#version 330 core
layout (location = 0) in vec3 aPos;
out vec3 TexCoords;
uniform mat4 projection;
uniform mat4 view;
void main()
{
TexCoords = aPos;
vec4 pos = projection * view * vec4(aPos, 1.0);
gl_Position = projection * view * vec4(aPos, 1.0);
}
#version 330 core
out vec4 FragColor;
in vec3 TexCoords;
uniform samplerCube skybox;
void main()
{
FragColor = texture(skybox, TexCoords);
}
I'm been stuck on this for two days. I have a height map which plots fine. The vertices are stored in a Vector3 with x and z regularly spaced and the height is y. I want to color the vertices according to height which varies from 0 to 1;
I am using the opengl4CSharp libraries. I am a complete beginner here and every example I see is for c++ and 2D textures. So this is what I have so far. I am sure I am missing some commands or done things wrong.
I define a byte array for the texture
byte[] data = new byte[]
{
255, 000, 000,
000, 255, 000,
000, 000, 255
};
I then define the various opengl parameters as follows:
Gl.Enable(EnableCap.Texture1D);
Gl.PixelStorei(PixelStoreParameter.UnpackAlignment, 1);
// Create a texture name
var textureID = Gl.GenTexture();
IntPtr myTexturePtr = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data, 0, myTexturePtr, data.Length);
// Marshal.FreeHGlobal(myTexturePtr);
Gl.BindTexture(TextureTarget.Texture1D, textureID);
Gl.TexParameteri(TextureTarget.Texture1D, TextureParameterName.TextureWrapS, TextureParameter.Repeat);
Gl.TexParameteri(TextureTarget.Texture1D, TextureParameterName.TextureWrapT, TextureParameter.Repeat);
Gl.TexParameteri(TextureTarget.Texture1D, TextureParameterName.TextureMinFilter, TextureParameter.Linear);
Gl.TexParameteri(TextureTarget.Texture1D, TextureParameterName.TextureMagFilter, TextureParameter.Linear);
Gl.TexImage1D(TextureTarget.Texture1D, 0, PixelInternalFormat.Three, 3, 0, PixelFormat.Rgb, PixelType.UnsignedByte, myTexturePtr);
Next I do the following but I am hung up on these steps...I get an error on the samplerLocation in particular the program parameter. What is that supposed to be? The shader programs?
uint samplerLocation = Gl.GetUniformLocation(plottingProgram, "ColorRamp");
Gl.Uniform1i(samplerLocation, 0);
Gl.ActiveTexture(TextureUnit.Texture0);
Gl.BindTexture(TextureTarget.Texture1D, textureID);
and here are the shaders
public static string VertexShader = #"
#version 130
layout(location = 0) in vec3 vertexPosition;
out float height;
uniform mat4 projection_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;
void main(void)
{
height = vertexPosition.y;
gl_Position = projection_matrix * view_matrix * model_matrix * vec4(vertexPosition, 1);
}
";
public static string FragmentShader = #"
#version 130
uniform sampler1D colorRamp;
in float height;
out vec4 FragColor;
void main(void)
{
FragColor = texture(colorRamp, height).rgba;
}
";
Can somebody please help out? Thanks
You can create a pointer to your byte[] like so:
IntPtr myTexturePtr = Marshal.AllocHGlobal(myTexture.Length);
Marshal.Copy(myTexture, 0, myTexturePtr, myTexture.Length);
Then you should be able to pass the myTexturePtr in place of where you are currently trying to pass myTexture.
Gl.TexImage1D(TextureTarge
t.Texture1D, 0,
PixelInternalFormat.Three, 3, 0,
PixelFormat.Rgb, PixelType.UnsignedByte,
myTexturePtr);
Afterwards, free the pointer when you are done.
Marshal.FreeHGlobal(myTexturePtr);
I have been trying to make my first ever game engine (in OpenTK and Im stuck. I am trying to incoperate animations and I'm trying to use sprite sheets because they would greatly decrease filesize.
I know that I need to use a for loop to draw all the sprites in sequence, but I dont have a clue about what I should do to make it work with spritesheets.
Here is my current drawing code:
//The Basis fuction for all drawing done in the application
public static void Draw (Texture2D texture, Vector2 position, Vector2 scale, Color color, Vector2 origin, RectangleF? SourceRec = null)
{
Vector2[] vertices = new Vector2[4]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(1, 1),
new Vector2(0, 1),
};
GL.BindTexture(TextureTarget.Texture2D, texture.ID);
//Beginning to draw on the screen
GL.Begin(PrimitiveType.Quads);
GL.Color3(color);
for (int i = 0; i < 4; i++)
{
GL.TexCoord2((SourceRec.Value.Left + vertices[i].X * SourceRec.Value.Width) / texture.Width, (SourceRec.Value.Left + vertices[i].Y * SourceRec.Value.Height) / texture.Height);
vertices[i].X *= texture.Width;
vertices[i].Y *= texture.Height;
vertices[i] -= origin;
vertices[i] *= scale;
vertices[i] += position;
GL.Vertex2(vertices[i]);
}
GL.End();
}
public static void Begin(int screenWidth, int screenHeight)
{
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(-screenWidth / 2, screenWidth / 2, screenHeight / 2, -screenHeight / 2, 0f, 1f);
}
Thanks in advance!!! :)
Firstly, I beg you, abandon the fixed function pipeline. It blinds you and restricts your understanding and creativity. Move to core 3.1+, it's structural perfection is matched only by it's potentiality, and the collaborative forethought and innovation will truly move you.
Now, you'll want to store your sprite sheet images as a Texture2DArray. It took me some time to figure out how to load these correctly:
public SpriteSheet(string filename, int spriteWidth, int spriteHeight)
{
// Assign ID and get name
this.textureID = GL.GenTexture();
this.spriteSheetName = Path.GetFileNameWithoutExtension(filename);
// Bind the Texture Array and set appropriate parameters
GL.BindTexture(TextureTarget.Texture2DArray, textureID);
GL.TexParameter(TextureTarget.Texture2DArray, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2DArray, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2DArray, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2DArray, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
// Load the image file
Bitmap image = new Bitmap(#"Tiles/" + filename);
BitmapData data = image.LockBits(new System.Drawing.Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
// Determine columns and rows
int spriteSheetwidth = image.Width;
int spriteSheetheight = image.Height;
int columns = spriteSheetwidth / spriteWidth;
int rows = spriteSheetheight / spriteHeight;
// Allocate storage
GL.TexStorage3D(TextureTarget3d.Texture2DArray, 1, SizedInternalFormat.Rgba8, spriteWidth, spriteHeight, rows * columns);
// Split the loaded image into individual Texture2D slices
GL.PixelStore(PixelStoreParameter.UnpackRowLength, spriteSheetwidth);
for (int i = 0; i < columns * rows; i++)
{
GL.TexSubImage3D(TextureTarget.Texture2DArray,
0, 0, 0, i, spriteWidth, spriteHeight, 1,
OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte,
data.Scan0 + (spriteWidth * 4 * (i % columns)) + (spriteSheetwidth * 4 * spriteHeight * (i / columns))); // 4 bytes in an Bgra value.
}
image.UnlockBits(data);
}
Then you can simply draw a quad, and the Z texture co-ordinate is the Texture2D index in the Texture2DArray. Note frag_texcoord is of type vec3.
#version 330 core
in vec3 frag_texcoord;
out vec4 outColor;
uniform sampler2DArray tex;
void main()
{
outColor = texture(tex, vec3(frag_texcoord));
}
I want to draw a texture in my shader but get an exception (see below).
I have following code:
int vertexArray;
//Pointer to Buffers
int vertexBuffer;
int colorBuffer;
int coordBuffer;
int texUniform; //Pointer to Uniform
int texture; //Pointer to Texture
Init
GL.Enable(EnableCap.Texture2D);
texture = LoadPNG("Resources\\Test.png");
//...
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)All.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)All.Nearest);
GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
vertexArray = GL.GenVertexArray();
GL.BindVertexArray(vertexArray);
float[] TexCoords = new float[] {
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
}; //(Array.Length = 2*3)
//Arrays for Vertex (3*3) and Color (4*3)
//GenBuffer, BindBuffer and BufferData for Color and Vertex
coordBuffer = GL.GenBuffer();
GL.BindBuffer(BufferTarget.TextureBuffer, coordBuffer);
GL.BufferData(BufferTarget.TextureBuffer, (IntPtr)(sizeof(float) * TexCoords.Length), TexCoords, BufferUsageHint.StaticDraw);
//Load shader
texUniform = GL.GetUniformLocation(shaderProgram, "tex");
GL.Uniform1(texUniform, 0);
GL.ActiveTexture(TextureUnit.Texture0);
Draw
GL.UseProgram(shaderProgram);
GL.BindTexture(TextureTarget.Texture2D, texture);
GL.EnableVertexAttribArray(0);
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBuffer);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableVertexAttribArray(1);
GL.BindBuffer(BufferTarget.ArrayBuffer, colorBuffer);
GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, 0, 0);
GL.EnableClientState(ArrayCap.ColorArray);
GL.BindBuffer(BufferTarget.TextureBuffer, coordBuffer);
GL.TexCoordPointer(2, TexCoordPointerType.Float, Vector2.SizeInBytes, 0);
GL.EnableClientState(ArrayCap.TextureCoordArray);
GL.DrawArrays(PrimitiveType.Triangles, 0, 6); //<------ Exception
GL.DisableVertexAttribArray(0);
GL.DisableVertexAttribArray(1);
I get a System.AccessViolationException at GL.DrawArrays(...);. I suspect that i haven't loaded a buffer correctly or used a pointer in an incorrect way. The exception is caused by changes i did to get a texture with texture coordinates into the shader, that means vertex and color buffer are working.
I'm not sure what i am doing wrong. I tried different things with the shader but it seems it doesn't matter what i am doing with the shader...
At my last try:
Vertex Shader
#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec4 color;
layout(location = 2) in vec2 texCoord;
out vec4 vColor;
out vec2 texCoords[];
void main(){
gl_Position = vec4(position, 1.0);
texCoords[0] = texCoord;
vColor = color;
}
Fragment Shader
#version 330 core
in vec4 vColor;
in vec2 texCoords[];
uniform sampler2D tex;
out vec4 fColor;
void main(void)
{
//fColor = vColor;
fColor = texture2D(Texture0, texCoords[0].st);
}
GetShaderInfoLog and GetProgramInfoLog do not return any errors when i comment GL.DrawArrays(...) and run the application.
What is wrong with my code?
Do not enable client state vertex arrays.
Replace the following:
GL.EnableClientState(ArrayCap.VertexArray);
...
GL.EnableClientState(ArrayCap.ColorArray);
...
GL.EnableClientState(ArrayCap.TextureCoordArray);
With:
GL.EnableVertexAttribArray(0);
...
GL.EnableVertexAttribArray(1);
...
GL.EnableVertexAttribArray(2);
At present, you are telling GL to source vertex attributes from glVertexPointer (...), glColorPointer (...) and glTexCoordPointer (...), none of which you actually have setup.
You might be able to get away with enabling the client state: ArrayCap.VertexArray because many drivers alias that to attribute 0, but the others are a recipe for disaster. Nevertheless, until you remove the EnableClientState (...) calls you are going to continue crashing.
Update:
I missed something in your texture coordinate setup...
You also need to replace this line:
GL.TexCoordPointer(2, TexCoordPointerType.Float, Vector2.SizeInBytes, 0);
With this:
GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, 0, 0);