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);
Related
I want to draw multiple images in to framebuffer and then also draw framebuffer on screen.
I also want to ReadPixels from frame buffer to store image on disk.
Is there some tutorial or example how to use framebuffer in OpenTK.
I found one example but is not in C# openTK
https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/minimalfbo/minimalfbo.c
Currently my code crashes application, and the ReadPixels returns an empty image.
namespace test
{
class Class1
{
int FramebufferName = -1;
int depthrenderbuffer;
int fbo_width = 0;
int fbo_height = 0;
public bool createImage = false;
DirectBitmap masterBitmap = null;
object masterBitmapSync = new object();
public int renderedTexture = 0;
public override void OnRender()
{
//https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/minimalfbo/minimalfbo.c
calculateMasterBitmapSize();
#region init
if (FramebufferName == -1)
{
//do this only once
//Framebuffer
GL.GenFramebuffers(1, out FramebufferName);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, FramebufferName);
checkGlError();
//Color renderbuffer.
lock (masterBitmapSync)
{
if (masterBitmap != null)
createTexture();
}
if (renderedTexture <= 0 || FramebufferName < 0)
{
Console.WriteLine("ERROR:");
}
checkGlError();
GL.BindTexture(TextureTarget.Texture2D, renderedTexture);
checkGlError();
//GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderedTexture);
//checkGlError();
/* Storage must be one of: */
/* GL_RGBA4, GL_RGB565, GL_RGB5_A1, GL_DEPTH_COMPONENT16, GL_STENCIL_INDEX8. */
//GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent16, fbo_width, fbo_height);
//checkGlError();
//GL.FramebufferRenderbuffer(FramebufferTarget.DrawFramebuffer, FramebufferAttachment.ColorAttachment0, RenderbufferTarget.Renderbuffer, renderedTexture);
//checkGlError();
/* Depth renderbuffer. */
GL.GenRenderbuffers(1, out depthrenderbuffer);
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthrenderbuffer);
GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent16, fbo_width, fbo_height);
GL.FramebufferRenderbuffer(FramebufferTarget.DrawFramebuffer, FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, depthrenderbuffer);
checkGlError();
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
checkGlError();
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, fbo_width, fbo_height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.FramebufferTexture2D(FramebufferTarget.DrawFramebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, renderedTexture, 0); //original texture 1280x720
checkGlError();
FramebufferErrorCode errorCode = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if (errorCode != FramebufferErrorCode.FramebufferComplete)
{
if (errorCode == FramebufferErrorCode.FramebufferUnsupported)
Console.WriteLine("FramebufferUnsupported");
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
GL.DeleteFramebuffers(1, ref FramebufferName);
GL.DeleteFramebuffers(1, ref depthrenderbuffer);
return;
}
checkGlError();
}
#endregion
#region drawInFramebuffer
checkGlError();
lock (masterBitmapSync)
{
if (masterBitmap != null)
createTexture();
}
checkGlError();
GL.BindTexture(TextureTarget.Texture2D, 0);
GL.Enable(EnableCap.Texture2D);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, FramebufferName);
checkGlError();
//GL.ColorMask(true, true, true, true);
GL.ClearColor(0, 0, 0, 0);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
checkGlError();
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, renderedTexture);
checkGlError();
GL.Begin(PrimitiveType.Quads);
{
GL.TexCoord2(0.0f, 0.0f); GL.Vertex2(LocalPoints[0].X, LocalPoints[0].Y);
GL.TexCoord2(1.0f, 0.0f); GL.Vertex2(LocalPoints[1].X, LocalPoints[1].Y);
GL.TexCoord2(1.0f, 1.0f); GL.Vertex2(LocalPoints[2].X, LocalPoints[2].Y);
GL.TexCoord2(0.0f, 1.0f); GL.Vertex2(LocalPoints[3].X, LocalPoints[3].Y);
}
GL.End();
GL.Disable(EnableCap.Texture2D);
//TODO draw multipla images
//loop over all images and calling OnRender2()
if (createImage)
{
createImage = false;
GPoint p = new GPoint(0, 0); //TODO get correct x,y
using (Bitmap bitmap = new Bitmap(fbo_width, fbo_height))
{
BitmapData bits = bitmap.LockBits(new Rectangle(0, 0, fbo_width, fbo_height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
checkGlError();
GL.ReadPixels((int)p.X, (int)p.Y, fbo_width, fbo_height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0);
checkGlError();
bitmap.UnlockBits(bits);
bitmap.RotateFlip(RotateFlipType.Rotate180FlipX);
bitmap.Save(#"c:\Downloads\aaa\ReadPixels_" + DateTime.Now.ToString("HHmmss_fff") + ".png", ImageFormat.Png);
}
}
checkGlError();
//does command in next line, draw framebuffer on the screen?
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); //would draw to the default framebuffer again, basically finishing the drawing to the other framebuffer(the backbuffer which will be brought to front by SwapBuffers)
checkGlError();
#endregion
}
private void calculateMasterBitmapSize()
{
//for test example
fbo_width = 256;
fbo_height = 256 * 2;
DirectBitmap newBitmap = new DirectBitmap(fbo_width, fbo_height);
newBitmap.Bitmap.MakeTransparent();
setBitmap(newBitmap);
}
public void setBitmap(DirectBitmap bmp)
{
lock (masterBitmapSync)
{
if (masterBitmap != null)
masterBitmap.Dispose();
masterBitmap = bmp;
if (masterBitmap == null)
deleteTexture();
}
}
void deleteTexture()
{
if (renderedTexture > 0)
{
GL.DeleteTexture(renderedTexture);
renderedTexture = 0;
}
}
public void createTexture()
{
if (masterBitmap == null)
return;
int t = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, t);
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);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, masterBitmap.Width, masterBitmap.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
Rectangle rect = new Rectangle(0, 0, masterBitmap.Width, masterBitmap.Height);
System.Drawing.Imaging.BitmapData data = masterBitmap.Bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.BindTexture(TextureTarget.Texture2D, t);
GL.TexSubImage2D(TextureTarget.Texture2D, 0, rect.X, rect.Y, rect.Width, rect.Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
masterBitmap.Bitmap.UnlockBits(data);
masterBitmap.Dispose();
masterBitmap = null;
if (renderedTexture > 0)
GL.DeleteTexture(renderedTexture);
renderedTexture = t;
}
private void checkGlError()
{
ErrorCode errorCode = GL.GetError();
if (errorCode != ErrorCode.NoError)
{
Console.WriteLine("ERROR: " + errorCode);
}
}
public void OnRender2()
{
/*
//this is example only
lock (bitmapSync)
{
if (bitmap != null)
createTexture();
}
GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, texture);
GL.Begin(PrimitiveType.Quads);
{
GL.TexCoord4(texCoords[0]); GL.Vertex4(LocalPoints[0].X, LocalPoints[0].Y, 1, 1); //UL
GL.TexCoord4(texCoords[1]); GL.Vertex4(LocalPoints[1].X, LocalPoints[1].Y, 1, 1); //UR
GL.TexCoord4(texCoords[2]); GL.Vertex4(LocalPoints[2].X, LocalPoints[2].Y, 1, 1); //LR
GL.TexCoord4(texCoords[3]); GL.Vertex4(LocalPoints[3].X, LocalPoints[3].Y, 1, 1); //LL
}
GL.End();
GL.Disable(EnableCap.Texture2D);
*/
}
}
}
"framebuffer" usually means memory on the graphics device used for final output to the screen. This is typically tricky to access from c#.
If you simply want to combine multiple images, and do not have any strict performance requirements, it would be much simpler to use a regular buffer to do the combining and then draw this buffer to the screen. The oldschool way to do this is to use a GDI graphics object to do the drawing.
An example using GDI & winforms
public class BitmapPaint : Control
{
private Bitmap buffer;
public BitmapPaint()
{
// Find out how large you want the output image to be
// This example does not handle disposal or resizing etc
buffer = new Bitmap(this.Width, this.Height);
}
public void Compose(IEnumerable<Bitmap> images)
{
using (var g = Graphics.FromImage(buffer))
{
foreach (var img in images)
{
// Adjust position etc if you need to
g.DrawImageUnscaled(img, 0, 0);
}
}
buffer.Save(#"c:\myFilename.bmp");
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Draw the buffer to the screen
e.Graphics.DrawImageUnscaled(buffer, 0, 0);
}
}
If you want higher performance it might be more appropriate to look for something like a 2D game engine that can manage the blitting and much more internally. Doing low level buffer manipulation is not a great fit for .Net since it typically involves raw pointers and resource management that is often easier to manage in C/C++.
I'm trying to render an image with a compute shader. For testing purposes, I try to render the gl_GlobalInvocationID to the image, but that only gives me a black screen. It does, however, work when I give the imageStore a predefined color. For example vec4(1, 0, 0, 1);. After some testing, it appears that the gl_GlobalInvocationID.xy doesn't get any further than [0,0]. What am I doing wrong?
I tested the values of gl_GlobalInvocationID by rendering a different color if the x or y coordinates got higher than 0, which they didn't.
Compute shader:
#version 440
layout (local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, binding = 0) uniform image2D frameBuffer;
void main()
{
ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy);
ivec2 size = ivec2(imageSize(frameBuffer));
vec4 pixel;
pixel = vec4(vec2(pixel_coords) / vec2(size.x, size.y),0, 1);
imageStore(frameBuffer, pixel_coords, pixel);
}
Framebuffer creation:
frameBuffer = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, frameBuffer);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba32f, Width, Height, 0, PixelFormat.Rgba, PixelType.Float, IntPtr.Zero);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Nearest);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba32f, Width, Height, 0, PixelFormat.Rgba, PixelType.Float, IntPtr.Zero);
GL.BindImageTexture(0, frameBuffer, 0, false, 0, TextureAccess.WriteOnly, SizedInternalFormat.Rgba32f);
Compute shader initialization
//Initialise compute shader in Onload()
cShader = new ComputeShader("../../RayTracer.glsl");
cShader.Use();
cShader.Dispatch(Width, Height, 1);
Compute shader class
class ComputeShader {
int handle;
//Initialize the compute shader given by the path
public ComputeShader(string path) {
handle = GL.CreateProgram();
int shader = GL.CreateShader(ShaderType.ComputeShader);
string source;
using (StreamReader sr = new StreamReader(path)) {
source = sr.ReadToEnd();
}
GL.ShaderSource(shader, source);
GL.CompileShader(shader);
string shaderError = GL.GetShaderInfoLog(shader);
if (shaderError.Length > 0) {
Console.WriteLine(shaderError);
}
GL.AttachShader(handle, shader);
GL.LinkProgram(handle);
GL.DetachShader(handle, shader);
GL.DeleteShader(shader);
}
//Sets a uniform 4x4 matrix in the compute shader
public void SetMatrix4x4(string name, Matrix4 matrix) {
int location = GL.GetUniformLocation(handle, name);
GL.UniformMatrix4(location, false, ref matrix);
}
//Sets a uniform float in the compute shader
public void SetUniformFloat(string name, float val) {
int location = GL.GetUniformLocation(handle, name);
GL.Uniform1(location, val);
}
//Use the compute shader
public void Use() {
GL.UseProgram(handle);
}
//Dispatch the compute shader
public void Dispatch(int xGroups, int yGroups, int zGroups) {
GL.DispatchCompute(xGroups, yGroups, zGroups);
}
}
OnRenderFrameMethod:
protected override void OnRenderFrame(FrameEventArgs e) {
//Launch computer shaders
cShader.Use();
cShader.Dispatch(Width, Height, 1);
//Make sure frame is finsihed before proceeding
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
//Clear previous frame
GL.Clear(ClearBufferMask.ColorBufferBit);
//Bind VAO
GL.BindVertexArray(VertexArrayObject);
//Bind texture
GL.BindTexture(TextureTarget.Texture2D, frameBuffer); //Renders GPU
//Draw primitives
GL.DrawElements(PrimitiveType.Triangles, canvasIndices.Length, DrawElementsType.UnsignedInt, 0);
//Swap buffers
Context.SwapBuffers();
base.OnRenderFrame(e);
}
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);
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().
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)