Allright so I've taken some code that works fine on other programs, I've copied it into a new program I'm working on and it doesn't seem to work, as far as I know I've got all the needed lines in there, but the areas where a texture is suppost to appear just display black squares.
I think I'm missing a line but I've got no idea what it is. I'm quite puzzled to say the least.
Here is my opengl setup:
GL.ClearColor(Color.Black);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
GL.Ortho(0, 800, 600, 0, -30, 30);
This is the method that loads the textures and returns the texture id, I store that in my variable. (the file.writeallbytes is just a test, I could open that no problem in photoshop)
private int loadTexture(String path)
{
GL.Enable(EnableCap.Texture2D);
byte[] ddsBytes = Media.GetFile("\\"+path.Replace("\\\\","\\")).Skip(20).ToArray();
File.WriteAllBytes("Derp.dds", ddsBytes);
int texId = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, texId);
Bitmap image = null;
DDSReader.DDSImage ddsImg = new DDSReader.DDSImage(ddsBytes);
image = ddsImg.BitmapImage;
ddsImg = null;
BitmapData bmpData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmpData.Width, bmpData.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bmpData.Scan0);
image.UnlockBits(bmpData);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)All.Modulate);
return texId;
}
And my drawing method looks like this:
public void Draw()
{
if (TexID == -1)
{
GL.Color4(Color[0], Color[1], Color[2], (byte)100);
}
else
{
GL.Color3((byte)255,(byte)255,(byte)255);
GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, TexID);
}
GL.Begin(BeginMode.TriangleStrip);
GL.TexCoord2(0, 0);
GL.Vertex2(X, Y + Height);
GL.TexCoord2(0, 1);
GL.Vertex2(X, Y);
GL.TexCoord2(1, 0);
GL.Vertex2(X + Width, Y + Height);
GL.TexCoord2(1, 1);
GL.Vertex2(X +Width, Y);
GL.End();
GL.Disable(EnableCap.Texture2D);
}
EDIT: The texture does show up, but the texture is full black, even when I set another color value (which usually changes the hue of the texture)
Related
im trying to add post processing to my game but i can't understand the framebuffer tutorial on learnopengl and opengl-tutorial i just need a simple framebuffer example with color and depth textures and how to use it and render it
im not sure how to implement a framebuffer
public class FrameBuffer
{
public int FBO,DBO;
public int Width, Height;
public int tex,depth;
public FrameBuffer(int width, int height)
{
this.Width = width;
this.Height = height;
FBO = GL.GenFramebuffer();
Bind();
tex = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, tex);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, Width, Height, 0, PixelFormat.Rgb, PixelType.UnsignedByte, (IntPtr)null);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, tex, 0);
}
public void Bind()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, FBO);
}
public void Unbind()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}
Your code sets up a proper framebuffer with a color plane.
If the framebufer has to have a depth buffer, then you've to create a depth texture, with the format PixelFormat.DepthComponent and one of the internal formats PixelInternalFormat.DepthComponent16, PixelInternalFormat.DepthComponent24, PixelInternalFormat.DepthComponent32 or PixelInternalFormat.DepthComponent32f:
depth = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, depth);
GL.TexParameter(TextureTarget.Texture2D,
TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D,
TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.DepthComponent24,
Width, Height, 0, PixelFormat.DepthComponent, PixelType.Float, (IntPtr)null);
Attach it to the framebuffer, to FramebufferAttachment.DepthAttachment
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer,
FramebufferAttachment.DepthAttachment,
TextureTarget.Texture2D, depth, 0);
Note after you've attached the color buffer and the depth buffer you should validate the framebuffer completeness, which should return a status value of FramebufferErrorCode.FramebufferComplete.:
FramebufferErrorCode status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
Alternatively to a depth texture you can attach a (depth) renderbuffer:
depth = GL.GenRenderbuffer();
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depth);
GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer,
RenderbufferStorage.DepthComponent24, Width, Height);
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0);
GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer,
FramebufferAttachment.DepthAttachment,
RenderbufferTarget.Renderbuffer, depth);
This question already has an answer here:
C# OpenTK - Textured Quad
(1 answer)
Closed 5 years ago.
So im trying to render a texture to a quad using OpenGL and im getting a really weird artifact and I think it being caused by my loading method but im not truly sure.
When you get close to the quad you can see that it is tring to render the red green and blue next to each other. kinda looks like what a pixel on a tv looks like
Rendered Quad
Close up of quad
Texture
LoadTexture
public static uint LoadTexture(string filePath)
{
Bitmap bitmap = new Bitmap("Res/" + filePath);
Gl.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
uint textureID = Gl.GenTexture();
Gl.BindTexture(TextureTarget.Texture2d, textureID);
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Gl.TexImage2D(TextureTarget.Texture2d, 0, InternalFormat.Rgb8, data.Width, data.Height, 0, OpenGL.PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
bitmap.UnlockBits(data);
Gl.TexParameter(TextureTarget.Texture2d, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
Gl.TexParameter(TextureTarget.Texture2d, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
return textureID;
}
Rendering
public void Render(TexturedModel texturedModel, StaticShader shader)
{
RawModel model = texturedModel.model;
using (MemoryLock vertexPositions = new MemoryLock(model.vertexPositions))
using (MemoryLock texturePositions = new MemoryLock(texturedModel.textureCords))
{
Gl.VertexAttribPointer((uint)shader.locationPosition, model.dimension, VertexAttribType.Float, false, 0, vertexPositions.Address);
Gl.EnableVertexAttribArray((uint)shader.locationPosition);
Gl.VertexAttribPointer((uint)shader.locationTexturedCoords, 2, VertexAttribType.Float, false, 0, texturePositions.Address);
Gl.EnableVertexAttribArray((uint)shader.locationTexturedCoords);
Gl.PixelStore(PixelStoreParameter.UnpackAlignment, 0);
Gl.ActiveTexture(TextureUnit.Texture0);
Gl.BindTexture(TextureTarget.Texture2d, texturedModel.texture.TextureID);
Gl.Uniform1(shader.locationTextureSampler, 0);
Gl.UniformMatrix4(shader.locationProjectionMatrix, false, projectionMatrix.ToArray());
viewMatrix = Maths.CreateViewMatrix(camera);
Gl.UniformMatrix4(shader.locationViewMatrix, false, viewMatrix.ToArray());
Gl.UniformMatrix4(shader.locationTransformationMatrix, false, model.modelMatrix.ToArray());
//Gl.DrawArrays(PrimitiveType.Triangles, 0, model.vertexPositions.Length / model.dimension);
Gl.DrawElements(PrimitiveType.Triangles, model.indices.Length, DrawElementsType.UnsignedInt, model.indices);
}
}
Shader program
public class StaticShader : ShaderProgram
{
private static string VERTEX_FILE = #"Shader/VertexShader.txt";
private static string FRAGMENTSHADER = #"Shader/FragmentShader.txt";
public int locationPosition;
public int locationTexturedCoords;
public int locationTransformationMatrix;
public int locationProjectionMatrix;
public int locationViewMatrix;
public int locationTextureSampler;
public StaticShader() : base(VERTEX_FILE, FRAGMENTSHADER)
{
locationTransformationMatrix = this.GetUniformLocation("transformationMatrix");
locationProjectionMatrix = this.GetUniformLocation("projectionMatrix");
locationViewMatrix = this.GetUniformLocation("viewMatrix");
locationTexturedCoords = this.GetAttribLocation("textureCords");
locationPosition = this.GetAttribLocation("position");
locationTextureSampler = this.GetUniformLocation("textureSampler");
}
}
Fragment shader
varying vec2 outTextureCords;
uniform sampler2D textureSampler;
void main() {
gl_FragColor = texture(textureSampler, outTextureCords);
}
vertices
public float[] vertexPositions = new float[] {
-0.5f,0.5f,0, //V0
-0.5f,-0.5f,0, //V1
0.5f,-0.5f,0, //V2
0.5f,0.5f,0 //V3
};
public int[] indices = new int[] {
0,1,3, //Top left triangle (V0,V1,V3)
3,1,2 //Bottom right triangle (V3,V1,V2)
};
public float[] textureCords = {
0,0,
0,1,
1,1,
1,0
};
Change the opengl format in the TexImage2d to B and switch internalFormat to rgba
Gl.TexImage2D(TextureTarget.Texture2d, 0, InternalFormat.Rgba, data.Width, data.Height, 0, OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
I've been trying to figure out how to get this to work. I'm using OpenTK for C# to modify images. Right now I'm able to load an image successfully, but when I try to modify the image with shaders is where I begin to have problems. I have 3 basic methods:
1) LoadTexture (sets the texture to GL)
2) DrawImage (actually draws the texture)
3) AddShaders (this method is called inside DrawImage.It applies the
shaders)
So here are the 2 problems I'm having:
1) I'm trying to create 2 triangles that span the entire texture.
This is because I want my fragment shader to do work over the entire
texture. What I'm actually getting is a large triangle that covers
the left side of the screen, and a rectangle on the right side of the
screen. EDIT: Made some progress! But still looking weird...Shader scripts updated..EDIT2: Newer progress pic uploaded
2) The shapes are showing up green, when I want them to use the
colors from the texture but red channel modified. What's important to
know is that I need to be able to analyze each pixel. Changing the
red channel of every pixel is JUST a proof of concept for what I want
to actually do (using color distance formulas, hue shifting, etc. but
I need to start simpler first)
This is the image I've successfully loaded as a texture:Loaded Texture
Here's the code for LoadTexture:
public int LoadTexture(string file)
{
Bitmap bitmap = new Bitmap(file);
int tex;
GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
GL.GenTextures(1, out tex);
GL.BindTexture(TextureTarget.Texture2D, tex);
BitmapData data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,
OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
bitmap.UnlockBits(data);
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);
return tex;
}
Here's the code for DrawImage:
public static void DrawImage(int image)
{
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
GL.Ortho(0, 1920, 0, 1080, -1, 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.Begin(PrimitiveType.Quads);
GL.TexCoord2(0,1);
GL.Vertex3(0, 0, 0);
GL.TexCoord2(1, 1);
GL.Vertex3(1920, 0, 0);
GL.TexCoord2(1, 0);
GL.Vertex3(1920, 1080, 0);
GL.TexCoord2(0, 0);
GL.Vertex3(0, 1080, 0);
GL.End();
AddShaders();
GL.Disable(EnableCap.Texture2D);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Modelview);
ErrorCode ec = GL.GetError();
if (ec != 0)
System.Console.WriteLine(ec.ToString());
Console.Read();
}
And here's the code for AddShaders:
private static void AddShaders()
{
/***********Vert Shader********************/
var vertShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShader, #"attribute vec3 a_position;
varying vec2 vTexCoord;
void main() {
vTexCoord = a_position.xy;
gl_Position = vec4(a_position, 1);
}");
GL.CompileShader(vertShader);
/***********Frag Shader ****************/
var fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShader, #"uniform sampler2D sTexture;
varying vec2 vTexCoord;
void main ()
{
vec4 color = texture2D (sTexture, vTexCoord);
color.r = 0.5;
// Save the result
gl_FragColor = color;
}");
GL.CompileShader(fragShader);
var program = GL.CreateProgram();
GL.AttachShader(program, vertShader);
GL.AttachShader(program, fragShader);
GL.LinkProgram(program);
GL.ClearColor(Color.AliceBlue);
// OpenGL expects vertices to be defined counter clockwise by default
float[] vertices = {
// Left bottom triangle
-1f, 1f, 0f,
-1f, -1f, 0f,
1f, -1, 0f,
// Right top triangle
1f, -1f, 0f,
1f, 1f, 0f,
-1f, 1f, 0f
};
var buffer = GL.GenBuffer();
var positionLocation = GL.GetAttribLocation(program, "a_position");
GL.EnableVertexAttribArray(positionLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float,false,0,0);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(ushort)), vertices, BufferUsageHint.StaticDraw);
GL.DrawArrays(PrimitiveType.Triangles, 0, vertices.Length);
GL.UseProgram(program);
}
I've researched this for a few days and I'm just completely stuck. Thanks to anyone who can see what I'm doing wrong. It HAS to be something small and dumb on my part!
EDIT: When I remove ALL vertex related code in AddShaders, I get the output I want, except its 1/4 the size and flipped in the top right of the screen. So, somehow my shaders don't even care about the vertices. Why is it being scaled down to 1/4 size and flipped?
EDIT2: Ok so thanks to Robert Rouhani, I've ALMOST got this working! Progress It looks like the triangle vertices might be messed up??
Here's my new code. I refactored functionality into methods, stopped creating programs / buffers every frame, etc. Now I have class level variables to hold the GL specific data, methods to create the GL program for the app, create the shaders, create the buffers, etc. Also I know that the 1920x1080 hardcode is, well, hardcoded. That is on my plate to make dynamic.
string file = "lambo2.png";
int program;
int vertShader;
int fragShader;
int buffer;
int positionLocation;
int texture;
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 CreateProgram()
{
program = GL.CreateProgram();
GL.AttachShader(program, vertShader);
GL.AttachShader(program, fragShader);
GL.LinkProgram(program);
}
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);
if(color.r < 0.3){color.r = 1.0;}
// Save the result
gl_FragColor = color;
}");
// GL.ShaderSource(fragShader, System.IO.File.ReadAllText(#"C:\Users\Matt\Desktop\hue-shader-backup.ps"));
GL.CompileShader(fragShader);
}
private void InitBuffers()
{
buffer = GL.GenBuffer();
positionLocation = GL.GetAttribLocation(program, "a_position");
GL.EnableVertexAttribArray(positionLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(ushort)), vertices, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, 0, 0);
}
private void Init()
{
texture = LoadTexture(file);
CreateShaders();
CreateProgram();
InitBuffers();
}
public int LoadTexture(string file)
{
Bitmap bitmap = new Bitmap(file);
int tex;
GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
GL.GenTextures(1, out tex);
GL.BindTexture(TextureTarget.Texture2D, tex);
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
BitmapData data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,
OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
bitmap.UnlockBits(data);
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.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
return tex;
}
public void DrawImage(int image)
{
GL.Viewport(new Rectangle(0, 0, 1920, 1080));
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.Begin(PrimitiveType.Quads);
GL.TexCoord2(0, 1);
GL.Vertex3(0, 0, 0);
GL.TexCoord2(1, 1);
GL.Vertex3(1920, 0, 0);
GL.TexCoord2(1, 0);
GL.Vertex3(1920, 1080, 0);
GL.TexCoord2(0, 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);
ErrorCode ec = GL.GetError();
if (ec != 0)
System.Console.WriteLine(ec.ToString());
Console.Read();
}
private void RunShaders()
{
GL.ClearColor(Color.AliceBlue);
GL.UseProgram(program);
GL.DrawArrays(PrimitiveType.Triangles, 0, vertices.Length / 3);
ErrorCode ec = GL.GetError();
if (ec != 0)
System.Console.WriteLine(ec.ToString());
Console.Read();
}
Going to start an answer instead of continuing the comments. You've still got a few minor issues that are compounding. You should comment out everything between and including GL.Begin and GL.End as the RunShaders function should do draw everything you need to the screen. Also comment out the GL.Ortho line, you don't need it if you're working with the vertices in the [-1, 1] range.
Second, your issue is that you're only uploading half your vertex buffer to the GPU. In InitBuffers on the GL.BufferData line, change sizeof(ushort) to sizeof(float), since your vertices are floats (4 bytes long) and not ushorts (2 bytes long).
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
Together this should get your program working.
I working with C# and OpenTK.
Currently I only want to map a texture on a triangle.
It seems to be working but on nearest texture filter, the whole triangle is only colored with the upper left pixel color of the bmp image and if I set the texture filter to linear the triangle shows still only one color, but it seems whether it is now mixed with the other pixels.
Can someone find the error in the code ?
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
GL.Enable(EnableCap.Texture2D);
GL.ClearColor(0.5F, 0.5F, 0.5F, 1.0F);
int vertexShaderHandle = GL.CreateShader(ShaderType.VertexShader);
int fragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
string vertexShaderSource = #"#version 400
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 uv;
out vec2 texture_uv;
void main()
{
gl_Position = vec4(inPosition.xyz, 1);
texture_uv = uv;
}";
string fragmentShaderSource = #"#version 400
in vec2 texture_uv;
out vec3 outColor;
uniform sampler2D uniSampler;
void main()
{
outColor = texture( uniSampler, texture_uv ).rgb;
}";
GL.ShaderSource(vertexShaderHandle, vertexShaderSource);
GL.ShaderSource(fragmentShaderHandle, fragmentShaderSource);
GL.CompileShader(vertexShaderHandle);
GL.CompileShader(fragmentShaderHandle);
prgHandle = GL.CreateProgram();
GL.AttachShader(prgHandle, vertexShaderHandle);
GL.AttachShader(prgHandle, fragmentShaderHandle);
GL.LinkProgram(prgHandle);
GL.DetachShader(prgHandle, vertexShaderHandle);
GL.DetachShader(prgHandle, fragmentShaderHandle);
GL.DeleteShader(vertexShaderHandle);
GL.DeleteShader(fragmentShaderHandle);
uniSamplerLoc = GL.GetUniformLocation(prgHandle, "uniSampler");
texHandle = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, texHandle);
Bitmap bmp = new Bitmap("C:/Users/Michael/Desktop/Test.bmp");
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmpData.Width, bmpData.Height, 0,
OpenTK.Graphics.OpenGL4.PixelFormat.Bgra, PixelType.UnsignedByte, bmpData.Scan0);
bmp.UnlockBits(bmpData);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
vaoHandle = GL.GenVertexArray();
GL.BindVertexArray(vaoHandle);
vboHandle = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, vboHandle);
float[] bufferData = { 0.5F, 1, 0, 1, 1,
0, 0, 0, 0, 0,
1, 0, 0, 1, 0 };
GL.BufferData<float>(BufferTarget.ArrayBuffer, (IntPtr) (15 * sizeof(float)), bufferData, BufferUsageHint.StaticDraw);
GL.EnableVertexAttribArray(0);
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 5 * sizeof(float), 0);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 3 * sizeof(float));
}
protected override void OnUnload(EventArgs e)
{
base.OnUnload(e);
GL.DeleteTexture(texHandle);
GL.DeleteProgram(prgHandle);
GL.DeleteBuffer(vboHandle);
GL.DeleteVertexArray(vaoHandle);
}
protected override void OnRenderFrame(FrameEventArgs e)
{
base.OnRenderFrame(e);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.UseProgram(prgHandle);
GL.Uniform1(uniSamplerLoc, texHandle);
GL.BindVertexArray(vaoHandle);
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
SwapBuffers();
}
EDIT:
I tried this:
protected override void OnRenderFrame(FrameEventArgs e)
{
base.OnRenderFrame(e);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.UseProgram(prgHandle);
GL.BindVertexArray(vaoHandle);
GL.ActiveTexture(TextureUnit.Texture3);
GL.BindTexture(TextureTarget.Texture2D, texHandle);
GL.Uniform1(uniSamplerLoc, 3);
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
SwapBuffers();
}
But nothing changed :(
The value of a sampler uniform variable needs to be the texture unit it should sample from. In your code, it is set to the texture name (aka texture id, aka texture handle) instead:
GL.Uniform1(uniSamplerLoc, texHandle);
The texture unit can be set with ActiveTexture(). When glBindTexture() is called, the value of the currently active texture unit determines which unit the texture is bound to. The default for the active texture unit is 0. So if you never called ActiveTexture(), the uniform should be set as:
GL.Uniform1(uniSamplerLoc, 0);
Just as a heads-up, another related source of errors is that the value of the uniform is a 0-based index of the texture unit, while the glActiveTexture() call takes an enum starting with GL_TEXTURE0. For example with the C bindings (not sure how exactly this looks with C# and OpenTK, but it should be similar enough), this would bind a texture to texture unit 3, and set a uniform sampler variable to use it:
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, texId);
glUniform1i(texUniformLoc, 3);
Note how GL_TEXTURE3 is used in the argument for glActiveTexture(), but a plain 3 in glUniform1i().
I know the glGetTexImage OpenGL function allows reading the pixels from an entire texture. Is there an OpenGL function that does the same thing but allows passing a rectangle to restrict the pixels read?
Here is how I ended up doing it in OpenTK (should translate easily to C++ or other OpenGL / OpenGL ES enabled languages):
public Bitmap GetBitmap()
{
int fboId;
GL.Ext.GenFramebuffers(1, out fboId);
CheckGLError();
GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, fboId);
CheckGLError();
GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, TextureId, 0);
CheckGLError();
Bitmap b = new Bitmap(Width, Height);
var bits = b.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.ReadPixels(Rect.Left, Rect.Top, Width, Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0);
GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);
GL.Ext.DeleteFramebuffers(1, ref fboId);
b.UnlockBits(bits);
return b;
}