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);
Related
I am very new to OpenGL (OpenTK), and I tried to get my first frame buffer working so I could apply post processing effects. However, when I try to draw the frame buffer it draws in the wrong place.
My rendering code is here:
protected override void OnRenderFrame(FrameEventArgs args)
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, this._frameBufferObject);
//GL.BindTexture(TextureTarget.Texture2D, 0);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Enable(EnableCap.DepthTest);
GL.UseProgram(this._shaderProgramHandle);
GL.BindVertexArray(this._vertexArrayHandle);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, this._elementBufferObject);
GL.DrawElements(PrimitiveType.Triangles, 6, DrawElementsType.UnsignedInt, 0);
// Draw frame buffer
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, this._frameBufferTextureColorHandle);
GL.ActiveTexture(TextureUnit.Texture0);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.UseProgram(this._frameBufferProgramHandle);
int screenTextureLocation = GL.GetUniformLocation(this._frameBufferProgramHandle, "screenTexture");
GL.Uniform1(screenTextureLocation, 0);
GL.BindVertexArray(this._rectangleVertexArrayObject);
GL.Disable(EnableCap.DepthTest);
GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
this.Context.SwapBuffers();
base.OnRenderFrame(args);
}
And the code that creates the array object is here:
this._rectangleVertexArrayObject = GL.GenVertexArray();
this._rectangleVertexBufferObject = GL.GenBuffer();
GL.BindVertexArray(this._rectangleVertexArrayObject);
GL.BindBuffer(BufferTarget.ArrayBuffer, this._rectangleVertexBufferObject);
GL.BufferData(BufferTarget.ArrayBuffer, rectangleVertices.Length * sizeof(float), rectangleVertices, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2 * sizeof(float));
GL.EnableVertexAttribArray(0);
GL.EnableVertexAttribArray(1);
GL.BindVertexArray(0);
My shader code if it makes a difference:
string vertexShaderCode =
#"
#version 330 core
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec4 aColor;
layout (location = 2) in vec2 aTexCoord;
layout (location = 3) in float aTexId;
out vec4 vColor;
out vec2 texCoord;
out float texId;
void main(void)
{
vColor = aColor;
texCoord = aTexCoord;
texId = aTexId;
gl_Position = vec4(aPosition, 1.0);
}
";
string fragmentShaderCode =
#"
#version 330 core
in vec4 vColor;
in vec2 texCoord;
in float texId;
uniform sampler2D[2] textures;
out vec4 pixelColor;
void main()
{
if (texId == 0) {
pixelColor = texture(textures[int(0)], texCoord) * vColor;
}
else if (texId == 1) {
pixelColor = texture(textures[int(1)], texCoord) * vColor;
}
}
";
string frameBufferVertexShadeCode =
#"
#version 330 core
layout (location = 0) in vec2 aPosition;
layout (location = 1) in vec2 aTexCoord;
out vec2 texCoord;
void main()
{
gl_Position = vec4(aPosition.x, aPosition.y, 0.0, 1.0);
texCoord = aTexCoord;
}
";
string frameBufferFragmentShaderCode =
#"
#version 330 core
in vec2 texCoord;
out vec4 pixelColor;
uniform sampler2D screenTexture;
void main()
{
pixelColor = texture(screenTexture, texCoord);
}
";
And here is the list of the rectangle vertices:
float[] rectangleVertices =
{
// Coords // texCoords
+1.0f, -1.0f, +1.0f, +0.0f,
-1.0f, -1.0f, +0.0f, +0.0f,
-1.0f, +1.0f, +0.0f, +1.0f,
+1.0f, +1.0f, +1.0f, +1.0f,
+1.0f, -1.0f, +1.0f, +0.0f,
-1.0f, +1.0f, +0.0f, +1.0f,
};
The result created is also here
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));
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));
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'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;
}";