I need to clear a specific cubemap layer within a cubemap array. I think this may be achievable with glClearTexSubImage but I'm not having any luck with it.
To give context, I'm shadow mapping. A cubemap array is encompassing 8 cubemap layers, with each containing scene/depth information for one of 8 light sources.
First, the entire cubemap array is cleared with
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
Next, the scene is rendered into the 8 cubemaps from the viewpoint of the 8 light sources.
for (int j = 0; j < lights.Count; j++)
{
// Create the light's view matrices
List<Matrix4> shadowTransforms = new List<Matrix4>();
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(1, 0, 0), new Vector3(0, -1, 0)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(-1, 0, 0), new Vector3(0, -1, 0)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 1, 0), new Vector3(0, 0, 1)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, -1, 0), new Vector3(0, 0, -1)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, 1), new Vector3(0, -1, 0)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, -1), new Vector3(0, -1, 0)));
// Send uniforms to the shader
for (int i = 0; i < 6; i++)
{
Matrix4 shadowTransform = shadowTransforms[i];
GL.UniformMatrix4(shader.getUniformID("shadowTransforms[" + i + "]"), false, ref shadowTransform);
}
GL.Uniform1(shader.getUniformID("lightID"), j);
// Draw Scene
DrawSceneInstanced(shader);
}
This all works fine, updating every shadow map each frame. However in favour of optimisation I wish to update only a single shadow map each frame, meaning I need to clear individual cubemap layers separately.
How is this done?
FBO/Cubemap Array creation and attachment:
public CubeMapArray()
{
// Create the FBO
GL.GenFramebuffers(1, out FBO_handle);
// Create and bind the CubeMap array
GL.GenTextures(1, out cubeMapTextureHandle);
GL.BindTexture(TextureTarget.TextureCubeMapArray, cubeMapTextureHandle);
// Allocate storage space
GL.TexImage3D(TextureTarget.TextureCubeMapArray, 0, PixelInternalFormat.Rg16, size, size, layers * 6, 0, PixelFormat.Red, PixelType.Float, IntPtr.Zero);
// Set the suitable texture parameters
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapR, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureBaseLevel, 0);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMaxLevel, 0);
// Create and bind the CubeMap depth array
GL.GenTextures(1, out cubeMapDepthHandle);
GL.BindTexture(TextureTarget.TextureCubeMapArray, cubeMapDepthHandle);
// Allocate storage space
GL.TexImage3D(TextureTarget.TextureCubeMapArray, 0, PixelInternalFormat.DepthComponent, size, size, layers * 6, 0, PixelFormat.DepthComponent, PixelType.UnsignedByte, IntPtr.Zero);
// Set the suitable texture parameters
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapR, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureBaseLevel, 0);
GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMaxLevel, 0);
// Attach cubemap texture as the FBO's color buffer
GL.BindFramebuffer(FramebufferTarget.Framebuffer, FBO_handle);
GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, cubeMapTextureHandle, 0);
GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, cubeMapDepthHandle, 0);
// Error check
var errorcheck = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
Console.WriteLine("CUBEMAP ARRAY: " + errorcheck);
// Bind default framebuffer
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}
Attach a specific layer of the texture array to the FBO using glFramebufferTextureLayer then use glClear() to clear that attachment.
Solution Attempt:
GL.BindFramebuffer(FramebufferTarget.Framebuffer, shadowMapArray.FBO_handle);
FramebufferTarget target = FramebufferTarget.Framebuffer;
FramebufferAttachment attachment = FramebufferAttachment.ColorAttachment0;
int level = 0;
int layer = currentShadowMap;
int texture = shadowMapArray.FBO_handle;
GL.FramebufferTextureLayer(target, attachment, texture, level, layer);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
Related
I pass the vertices to a buffer and the texture coordinates to an another buffer the vertices are draw perfectly, but the texture coordinate pointer is not doing anything, but in an another project it works without problems, I tried to copy from the other project but nothing happened. It produces the same problem without throwing any errors. However, it works perfectly in the immediate drawing mode.
void renderFrame(object o, FrameEventArgs e)
{
// Clear screen
GL.Translate(Input.GetMoveDir(.1f));
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
//Render image
//Enable thing before use
GL.BindTexture(TextureTarget.Texture2D, texture.ID);
GL.Enable(EnableCap.Texture2D);
//Setup blending
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
// Immedaiate test
/*GL.Begin(BeginMode.Triangles);
for (int i = 0; i < vertexBuffer.Length; i++)
{
GL.Normal3(normalBuffer[i]);
GL.TexCoord2(uvBuffer[i]);
GL.Vertex3(vertexBuffer[i]);
}
GL.End();*/
//Enable arrays
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
//GL.EnableClientState(ArrayCap.NormalArray);
//GL.Color3(Color.Red);
//Set vertex pointer
GL.BindBuffer(BufferTarget.ArrayBuffer, VEB);
GL.VertexPointer(3, VertexPointerType.Float, Vector3.SizeInBytes, 0);
//Set uv pointer
GL.BindBuffer(BufferTarget.ArrayBuffer, UVB);
GL.TexCoordPointer(2, TexCoordPointerType.Float, Vector2.SizeInBytes, 0);
//Set normal pointer
/*GL.BindBuffer(BufferTarget.ArrayBuffer, NOB);
GL.NormalPointer(NormalPointerType.Float, Vector3.SizeInBytes, 0);*/
//Draw
GL.DrawArrays(PrimitiveType.Quads, 0, vertexBuffer.Length);
// Swap buffers
GL.Flush();
window.SwapBuffers();
}
public void UpdateBuffers(Vector3[] vertices, Vector2[] uvs, Vector3[] normals)
{
//Vertex buffer
vertexBuffer = vertices;
GL.BindBuffer(BufferTarget.ArrayBuffer, VEB);
GL.BufferSubData<Vector3>(BufferTarget.ArrayBuffer, (IntPtr)0, (int)(Vector3.SizeInBytes * vertexBuffer.Length), vertexBuffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
//Uv buffer
uvBuffer = uvs;
GL.BindBuffer(BufferTarget.ArrayBuffer, UVB);
GL.BufferSubData<Vector2>(BufferTarget.ArrayBuffer, (IntPtr)0, (int)(Vector2.SizeInBytes * uvBuffer.Length), uvBuffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
//Normal buffer
normalBuffer = normals;
GL.BindBuffer(BufferTarget.ArrayBuffer, NOB);
GL.BufferSubData<Vector3>(BufferTarget.ArrayBuffer, (IntPtr)0, (int)(Vector3.SizeInBytes * normalBuffer.Length), normalBuffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
Console.WriteLine("Buffers updated");
}
I am working on C# and using OpenTK(OpenGL wrapper) and EmguCV(OpenCV wrapper).
What I want to do is easy to understand: Grab the webcam video stream and put it on a GLControl.
I have a static class called Capturer which has a method that captures a frame and returns it as a cv::Mat wrapped object:
internal static void Initialize()
{
cap = new VideoCapture(1);
cap.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.Fps, 25);
cap.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameWidth, 1920);
cap.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameHeight, 1080);
}
internal static Mat GetCurrentFrame()
{
mat = cap.QueryFrame();
if (!mat.IsEmpty)
{
return mat;
}
return null;
}
Now in my GLControl Load event I initialize the capturer and OpenGL:
Capturer.Initialize();
GL.ClearColor(Color.Blue);
GL.Enable(EnableCap.Texture2D);
GL.Viewport(-glControl1.Width, -glControl1.Height, glControl1.Width * 2, glControl1.Height * 2);
And finally, in the GLControl Paint event:
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
Mat m = Capturer.GetCurrentFrame();
if (m != null)
{
GL.GenTextures(1, out textureId);
GL.BindTexture(TextureTarget.Texture2D, this.textureId);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.Clamp);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (float)TextureWrapMode.Clamp);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, 1920, 1080, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgr, PixelType.UnsignedByte, m.DataPointer);
}
m.Dispose();
glControl1.SwapBuffers();
glControl1.Invalidate();
This is showing a full Blue screen. I think the error is on m.DataPointer.
(I have tried rendering the frames with Bitmap using the property m.Bitmapand it works but the performance is so bad.)
Drawing a rectangle bounding the GLControl solved it:
GL.Begin(PrimitiveType.Quads);
GL.TexCoord2(0, 0); GL.Vertex2(0, 0);
GL.TexCoord2(0, 1); GL.Vertex2(0, 1);
GL.TexCoord2(1, 1); GL.Vertex2(1, 1);
GL.TexCoord2(1, 0); GL.Vertex2(1, 0);
GL.End();
m.Dispose();
Be sure to dispose the object after drawing the frame so you will not run out of memory.
I'm calculating shadows for a number of point lights using Variance Shadow Mapping. All 6 faces of the cubemap are rendered in a single pass with a geometry shader, this repeats for each light source, and the whole lot is stored in a cubemap array. This all runs fine, 16 lights at 60fps no problem.
Chasing further optimisation, I tried to move the entire process to a single geometry shader pass, only to hit the only 113 vertex output limit of my hardware. Out of curiosity I decided to render 4 lights only (72 emitted vertices) and to my surprise it dropped to 24fps.
So why is it that 16 lights with 16 render passes perform significantly better than 4 lights in a single pass?
The code is essentially identical.
#version 400 core
layout(triangles) in;
layout (triangle_strip, max_vertices=18) out;
uniform int lightID;
out vec4 frag_position;
uniform mat4 projectionMatrix;
uniform mat4 shadowTransforms[6];
void main()
{
for(int face = 0; face < 6; face++)
{
gl_Layer = face + (lightID * 6);
for(int i=0; i<3; i++)
{
frag_position = shadowTransforms[face] * gl_in[i].gl_Position;
gl_Position = projectionMatrix * shadowTransforms[face] * gl_in[i].gl_Position;
EmitVertex();
}
EndPrimitive();
}
}
versus
#version 400 core
layout(triangles) in;
layout (triangle_strip, max_vertices=72) out;
out vec4 frag_position;
uniform mat4 projectionMatrix;
uniform mat4 shadowTransforms[24];
void main()
{
for (int lightSource = 0; lightSource < 4; lightSource++)
{
for(int face = 0; face < 6; face++)
{
gl_Layer = face + (lightSource * 6);
for(int i=0; i<3; i++)
{
frag_position = shadowTransforms[gl_Layer] * gl_in[i].gl_Position;
gl_Position = projectionMatrix * shadowTransforms[gl_Layer] * gl_in[i].gl_Position;
EmitVertex();
}
EndPrimitive();
}
}
}
And
public void ShadowMapsPass(Shader shader)
{
// Setup
GL.UseProgram(shader.ID);
GL.Viewport(0, 0, CubeMapArray.size, CubeMapArray.size);
// Clear the cubemarray array data from the previous frame
GL.BindFramebuffer(FramebufferTarget.Framebuffer, shadowMapArray.FBO_handle);
GL.ClearColor(Color.White);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
for (int j = 0; j < lights.Count; j++)
{
// Create the light's view matrices
List<Matrix4> shadowTransforms = new List<Matrix4>();
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(1, 0, 0), new Vector3(0, -1, 0)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(-1, 0, 0), new Vector3(0, -1, 0)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 1, 0), new Vector3(0, 0, 1)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, -1, 0), new Vector3(0, 0, -1)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, 1), new Vector3(0, -1, 0)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, -1), new Vector3(0, -1, 0)));
// Send uniforms to the shader
for (int i = 0; i < 6; i++)
{
Matrix4 shadowTransform = shadowTransforms[i];
GL.UniformMatrix4(shader.getUniformID("shadowTransforms[" + i + "]"), false, ref shadowTransform);
}
GL.Uniform1(shader.getUniformID("lightID"), j);
DrawScene(shader, false);
}
}
versus
public void ShadowMapsPass(Shader shader)
{
// Setup
GL.UseProgram(shader.ID);
GL.Viewport(0, 0, CubeMapArray.size, CubeMapArray.size);
// Clear the cubemarray array data from the previous frame
GL.BindFramebuffer(FramebufferTarget.Framebuffer, shadowMapArray.FBO_handle);
GL.ClearColor(Color.White);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
// Create the light's view matrices
List<Matrix4> shadowTransforms = new List<Matrix4>();
for (int j = 0; j < lights.Count; j++)
{
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(1, 0, 0), new Vector3(0, -1, 0)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(-1, 0, 0), new Vector3(0, -1, 0)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 1, 0), new Vector3(0, 0, 1)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, -1, 0), new Vector3(0, 0, -1)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, 1), new Vector3(0, -1, 0)));
shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, -1), new Vector3(0, -1, 0)));
}
// Send uniforms to the shader
for (int i = 0; i < shadowTransforms.Count; i++)
{
Matrix4 shadowTransform = shadowTransforms[i];
GL.UniformMatrix4(shader.getUniformID("shadowTransforms[" + i + "]"), false, ref shadowTransform);
}
DrawScene(shader, false);
}
I'd guess fewer opportunities for parallel code execution in the second form. The first version of the geometry shader generates 18 vertices and must be executed 4 times, but those 4 executions can run in parallel. The second version generates 72 vertices one after the other.
Lately I have been trying to learn/use OpenGL 3+. I have looked through tutorials and examples but I've run into a wall trying to get textures and 2D projection to work without problems.
The goal for now is to have a function which can draw a textured quad to the screen with it's position specified by pixels (not [-1,1]).
For readability and testing I made a new barebones program with the knowledge I currently have, and it exhibits nearly the same problems. Help would be appreciated since i'm starting to go bald over this :(..
The current code shows a garbled texture instead of the image itself (texture is 128x128px).
[Program.cs]
namespace OpenGLTester
{
static class Program
{
public static GameWindow window;
public static String programDirectory = Directory.GetCurrentDirectory();
public static int testTexture;
public static int uniform_fragment_texture;
public static int shaderProgram;
[STAThread]
static void Main()
{
window = new GameWindow(1024, 768, new GraphicsMode(new ColorFormat(8, 8, 8, 8), 0, 8), "OpenGLTester", GameWindowFlags.Default, DisplayDevice.Default, 3, 1, GraphicsContextFlags.Default);
GL.Viewport(new Size(1024,768));
shaderProgram = GL.CreateProgram();
int vertexShader = GL.CreateShader(ShaderType.VertexShader);
int fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(vertexShader, File.ReadAllText(programDirectory + #"\vertex.vert"));
GL.ShaderSource(fragmentShader, File.ReadAllText(programDirectory + #"\fragment.frag"));
GL.CompileShader(vertexShader);
GL.CompileShader(fragmentShader);
GL.AttachShader(shaderProgram, vertexShader);
GL.AttachShader(shaderProgram, fragmentShader);
GL.LinkProgram(shaderProgram);
if (GL.GetError() != ErrorCode.NoError) { System.Diagnostics.Debugger.Break(); }
Console.WriteLine(GL.GetProgramInfoLog(shaderProgram));
GL.UseProgram(shaderProgram);
Matrix4 projectionMatrix = Matrix4.CreateOrthographic(1024, 768, 0, 1);
GL.UniformMatrix4(GL.GetUniformLocation(shaderProgram, "vertex_projection"), false, ref projectionMatrix);
uniform_fragment_texture = GL.GetUniformLocation(shaderProgram, "fragment_texture");
testTexture = loadTexture(programDirectory + #"\test.png");
GL.Disable(EnableCap.DepthTest);
GL.Disable(EnableCap.Lighting);
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);
window.UpdateFrame += window_UpdateFrame;
window.RenderFrame += window_RenderFrame;
window.Resize += window_Resize;
window.TargetRenderFrequency = 60;
window.Run();
}
static void window_Resize(object sender, EventArgs e)
{
//Don't allow resizing for now.
window.Size = new Size(1024, 768);
}
static void window_UpdateFrame(object sender, FrameEventArgs e)
{
ErrorCode currentError = GL.GetError();
if (currentError != ErrorCode.NoError)
{
Console.WriteLine(Enum.GetName(typeof(ErrorCode), currentError));
System.Diagnostics.Debugger.Break();
}
}
static void window_RenderFrame(object sender, FrameEventArgs e)
{
GL.ClearColor(0, 0, 0, 0);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit);
//test texture is 128x128pixels.
drawTexRect(100, 228, 100, 228, testTexture);
window.SwapBuffers();
}
static int loadTexture(String filePath)
{
GL.Enable(EnableCap.Texture2D);
int id = GL.GenTexture();
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, id);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
Bitmap bmp = new Bitmap(filePath);
BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp_data.Width, bmp_data.Height, 0,
OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, bmp_data.Scan0);
bmp.UnlockBits(bmp_data);
bmp.Dispose();
return id;
}
static void drawTexRect(float top, float bottom, float left, float right, int texture)
{
//topLeft,bottomLeft,bottomRight,topRight
float[] vertices = new float[] {
left, top, 0, 0,
left, bottom, 0, 1,
right, bottom, 1, 1,
right, top, 1, 0,
};
int buffer = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData<float>(BufferTarget.ArrayBuffer, new IntPtr(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
//vec2 - screen position
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4, 0);
//vec2 - texture coordinates
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4, 2 * sizeof(float));
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, texture);
GL.Uniform1(uniform_fragment_texture, 0);
GL.DrawArrays(PrimitiveType.Quads, 0, 4);
GL.DeleteBuffer(buffer);
}
}
}
[vertex.vert]
#version 330
in vec2 vertex_position;
in vec2 vertex_texturePosition;
uniform mat4 vertex_projection;
out vec2 fragment_texturePosition;
void main()
{
gl_Position = vec4(vertex_position,0.0,1.0) * vertex_projection;
fragment_texturePosition = vertex_texturePosition;
}
[fragment.frag]
#version 330
in vec2 fragment_texturePosition;
uniform sampler2D fragment_texture;
out vec4 output_color;
void main()
{
output_color = texture(fragment_texture,fragment_texturePosition);
}
After changes suggested by #j-p one problem remains:
After texture position change suggested by #j-p:
The projection is also wrong given the position i expect it to be 100 px from the left and 100 px from the top, don't see how i can fix this..
The stride parameter is in byte:
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0);
//vec2 - texture coordinates
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2 * sizeof(float));
Also,the corresponding opengl pixel format for windows argb bitmap is BGRA. (link)
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,**OpenTK.Graphics.OpenGL.PixelFormat.Bgra**, PixelType.UnsignedByte, data.Scan0);
And finally, your texture coordinates should be adjusted as follow:
float[] vertices = new float[] {
left, top, 0, 1,
left, bottom, 0, 0,
right, bottom, 1, 0,
right, top, 1, 1
};
I am having issues drawing a texture onto my quad but it remains white. I have looked through a number of guides and I don't seem to be doing anything different from them.
To load the texture:
Bitmap bitmap = new Bitmap("Textures/Sprite_Can.png");
GL.GenTextures(1, out textureID);
GL.BindTexture(TextureTarget.Texture2D, textureID);
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);
Setup and apply an orthographic projection:
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(0, control.Width, 0, control.Height, -1, 1);
GL.Viewport(0, 0, control.Width, control.Height);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
GL.ClearColor(Color4.CornflowerBlue);
And finally the draw:
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.LoadIdentity();
GL.Translate(30, 30, 0);
GL.BindTexture(TextureTarget.Texture2D, textureID);
GL.Begin(BeginMode.Quads);
GL.TexCoord2(0, 0);
GL.Vertex2(-1 * width / 2, 1 * height / 2);
GL.TexCoord2(1, 0);
GL.Vertex2(1 * width / 2, 1 * height / 2);
GL.TexCoord2(1, 1);
GL.Vertex2(1 * width / 2, -1 * height / 2);
GL.TexCoord2(0, 1);
GL.Vertex2(-1 * width / 2, -1 * height / 2);
GL.End();
GL.Flush();
control.SwapBuffers();
So basically, the quad draws just fine. However, the texture is not rendered. As a result, all I have is just a white square.
In the fixed-function OpenGL pipeline, you must also Enable texture units before a texture bound to one will be applied to anything you draw.
The normal OpenGL API binding for this is glEnable (GL_TEXTURE_2D). The OpenTK equivalent would be: GL.Enable (EnableCap.Texture2D).