我正在使用OpenTK(围绕OpenGL的.NET包装),并在表单中使用GLControl。
我已经使用Loading a texture from disk和Loading multiple textures and passing through to a shader教程来完成纹理映射。但是当我尝试设置GL.ActiveTexture(TextureUnit.Texture1),并在该单元上进行所有纹理绑定和加载时,我得到一个纯色显示(看似是texel(0,0)处的颜色)。 p>
我很困惑为什么简单地将纹理单元切换为使用1而不是默认值为0会破坏程序。
我想我会离开固定功能管道,而是使用着色器来进行纹理着色。也没有运气。
我认为这与使用glDrawArrays将顶点提供给顶点着色器的方式有关。我在着色器中使用常量顶点数据,使用gl_VertexID进行挑选,以简化而不是使用属性。
顶点着色器:
#version 420
const mat4x3 vs = mat4x3(-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0);
const mat4x2 ts = mat4x2(0.0, 1.0,1.0, 1.0, 1.0, 0.0, 0.0, 0.0);
out vec2 tcoord;
void main() {
gl_Position = vec4(vs[gl_VertexID],1);
tcoord = ts[gl_VertexID];
}
Fragment Shader:
#version 420
uniform sampler2D MyTexture0;
uniform sampler2D MyTexture1;
uniform sampler2D MyTexture2;
uniform sampler2D MyTexture3;
in vec2 tcoord;
out vec4 color;
void main(void)
{
color = texture2D( MyTexture3, tcoord);
}
绘制命令:
GL.DrawArrays(PrimitiveType.Quads, 0, 4);
整个来源:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using System.Diagnostics;
using System.Drawing.Imaging;
namespace TextureShaderDemoGLControl
{
public partial class Form1 : Form
{
bool immediateMode = true;
public Form1()
{
InitializeComponent();
}
Stopwatch sw = Stopwatch.StartNew();
int fragmentShaderHandle, shaderProgramHandle, texture0, texture1, texture2, texture3;
Bitmap bitmap0 = new Bitmap(@"img.gif");
string vertShaderSource = @"
#version 420
const mat4x3 vs = mat4x3(-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0);
const mat4x2 ts = mat4x2(0.0, 1.0,1.0, 1.0, 1.0, 0.0, 0.0, 0.0);
out vec2 tcoord;
void main() {
gl_Position = vec4(vs[gl_VertexID],1);
tcoord = ts[gl_VertexID];
}
";
string fragmentShaderSource = @"
#version 420
uniform sampler2D MyTexture0;
uniform sampler2D MyTexture1;
uniform sampler2D MyTexture2;
uniform sampler2D MyTexture3;
in vec2 tcoord;
out vec4 color;
void main(void)
{
color = texture2D( MyTexture3, tcoord);
}"
;
void CreateShaders()
{
int vertShaderHandle = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShaderHandle, vertShaderSource);
GL.CompileShader(vertShaderHandle);
Debug.WriteLine(GL.GetShaderInfoLog(vertShaderHandle));
fragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragmentShaderHandle, fragmentShaderSource);
GL.CompileShader(fragmentShaderHandle);
Debug.WriteLine(GL.GetShaderInfoLog(fragmentShaderHandle));
// Create program
shaderProgramHandle = GL.CreateProgram();
GL.AttachShader(shaderProgramHandle, vertShaderHandle);
GL.AttachShader(shaderProgramHandle, fragmentShaderHandle);
GL.LinkProgram(shaderProgramHandle);
Debug.WriteLine(GL.GetProgramInfoLog(shaderProgramHandle));
GL.UseProgram(shaderProgramHandle);
}
private void CreateTexture(out int texture, Bitmap bitmap)
{
// load texture
GL.GenTextures(1, out texture);
// Still required else TexImage2D will be applied on the last bound texture
GL.BindTexture(TextureTarget.Texture2D, texture);
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);
}
private void DrawRect()
{
GL.Begin(PrimitiveType.Quads);
GL.Color3(Color.Silver);
GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, -1.0f);
GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(-1.0f, 1.0f, -1.0f);
GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, 1.0f, -1.0f);
GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(1.0f, -1.0f, -1.0f);
GL.End();
}
private void glControl1_Load(object sender, EventArgs e)
{
CreateShaders();
//GL.Enable(EnableCap.Texture2D);
// Immediate mode drawing works with Texture Unit 0
TextureUnit tUnit = TextureUnit.Texture0;
// Immediate mode drawing fails with Texture Unit 1
// TextureUnit tUnit = TextureUnit.Texture1;
GL.ActiveTexture(tUnit);
CreateTexture(out texture0, bitmap0);
GL.Uniform1(GL.GetUniformLocation(shaderProgramHandle, "MyTexture0"), tUnit - TextureUnit.Texture0);
string a = GL.GetString(StringName.ShadingLanguageVersion);
string b = GL.GetString(StringName.Version);
int vao = GL.GenVertexArray();
GL.BindVertexArray(vao);
glControl1.Invalidate();
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
if (immediateMode) {
// The immediate mode DrawRect which encapsulates GL.Begin(); GL.Vertex2(..) ... ; GL.End() works nicely
DrawRect();
} else {
// Something must be wrong with the way DrawArrays feeds vertices to the vertex shader.
//GL.DrawArrays(PrimitiveType.Quads, 0, 4);
}
sw.Stop();
label1.Text = (1000.0 / sw.Elapsed.TotalMilliseconds).ToString();
sw.Restart();
glControl1.SwapBuffers();
}
private void glControl1_Resize(object sender, EventArgs e)
{
GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
}
}
}