最近我一直在努力学习/使用OpenGL 3+。我已经查看了教程和示例,但是我遇到了试图让纹理和2D投影无问题地工作的墙。
现在的目标是拥有一个可以在屏幕上绘制纹理四边形的功能,其位置由像素(不是[-1,1])指定。
为了便于阅读和测试,我使用我目前拥有的知识制作了一个新的准系统程序,它表现出几乎相同的问题。我将不胜感激,因为我开始对此赞不绝口:( ..
当前代码显示乱码纹理而不是图像本身(纹理为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);
}
@ j-p建议的更改之后仍然存在一个问题:
@ j-p建议的纹理位置变化后:
投影也是错误的,因为我预计它的位置是从左边100像素,从顶部100像素,不知道如何解决这个问题。
答案 0 :(得分:2)
stride参数以字节为单位:
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));
此外,windows argb位图的相应opengl像素格式为BGRA。 (link)
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,**OpenTK.Graphics.OpenGL.PixelFormat.Bgra**, PixelType.UnsignedByte, data.Scan0);
最后,您的纹理坐标应调整如下:
float[] vertices = new float[] {
left, top, 0, 1,
left, bottom, 0, 0,
right, bottom, 1, 0,
right, top, 1, 1
};