I tried to implement a simple test program following the OpenTK official tutorial (here) but I can't achieve any result. Following the exact coding sequence proposed my output is just a white square. I tried several patches such as avoiding the fragment shader mix() function and what I found is that the tutorial-proposed code transferred to the fragment shader only the last loaded texture.
In particular, the proposed code lets you generate a texture and assign attributes without binding the texture, while I found some answers that suggest the binding should happen before assigning any attribute (for example here).
So I tried any combination of GL function calls, and I still don't have a working code, but some insights (my latest code below):
- if I load a texture by activating the Texture Unit before, it consistently assigns texture regardless the texture object creation order, however only
TextureUnit.Texture0
seems to reach the fragment shader and be assigned to any declared sampler2D - calling the
GL.GetUniformLocation
and subsequentGL.Uniform1()
to assign the uniform indexes doesn't produce any visible change in the behaviour - changing the position where I call
GL.UseProgram(shader.Handle)
; doesn't make any difference - as mentioned above, the fragment shader function
texture(tex0, texCoord)
shows the first texture, and so thetexture(tex1, texCoord)
or any other declared sampler - the
mix(texture(tex0, TexCoord), texture(tex1, TexCoord), 0.2);
fragment shader function shows always white pixels, even when mixing the same texture callingmix(texture(tex0, TexCoord), texture(tex0, TexCoord), 0.2);
(note that such texture show up instead when I calltexture(tex0, texCoord)
)
I run out of ideas and I can't find any resources. Thanks for helping.
Fragment Shader Source:
#version 330 core
in vec2 texCoord;
out vec4 outputColor;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
void main() {
//outputColor = mix(texture(tex0, TexCoord), texture(tex1, TexCoord), 0.2);
outputColor = texture(tex0, texCoord);
//outputColor = vec4(1.0, 0.0, 0.0, 1.0);
}
Vertex Shader Source:
#version 330 core
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec2 aTexCoord;
out vec2 texCoord;
void main(void)
{
texCoord = aTexCoord;
gl_Position = vec4(aPosition, 1.0);
}
Texture Class Source:
internal class Texture {
public int Handle { get; private set; }
public Texture(string sourceFile, TextureUnit unit = TextureUnit.Texture0)
{
Image<Rgba32> image = Image.Load<Rgba32>(sourceFile);
image.Mutate(x => x.Flip(FlipMode.Vertical));
var pixels = new byte[4 * image.Width * image.Height];
image.CopyPixelDataTo(pixels);
GL.ActiveTexture(unit);
this.Handle = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, this.Handle);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexImage2D(
TextureTarget.Texture2D, // Texture type
0, // Level of detail
PixelInternalFormat.Rgba, // GPU storing format
image.Width, image.Height, // Width, Height
0, // Border of the image, legacy param
PixelFormat.Rgba, // Format: ImgSharp use this
PixelType.UnsignedByte, // Pixel type
pixels); // Actual pixels
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Use()
{
GL.BindTexture(TextureTarget.Texture2D, this.Handle);
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Use(TextureUnit unit)
{
// GL.ActiveTexture(unit);
// GL.BindTexture(TextureTarget.Texture2D, this.Handle);
}
} // Texture Class
Shader Class Source (only relevant methods):
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Use()
{
GL.UseProgram(program);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetInt(string name, int value)
{
int location = GL.GetUniformLocation(program, name);
GL.Uniform1(location, value);
}
Loading method of the game class:
protected override void onl oad()
{
GL.ClearColor(0.2f, 0.2f, 0.2f, 1.0f);
VertexArrayObject = GL.GenVertexArray();
VertexBufferObject = GL.GenBuffer();
ElementBufferObject = GL.GenBuffer();
// 1. bind Vertex Array Object
GL.BindVertexArray(VertexArrayObject);
// 2. copy our vertices array in a buffer for OpenGL to use
GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBufferObject);
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw);
// 3. then set our vertex attributes pointers
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 5 * sizeof(float), 0);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 3 * sizeof(float));
GL.EnableVertexAttribArray(1);
// Indices to ElementBufferObject
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ElementBufferObject);
GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(uint), indices, BufferUsageHint.StaticDraw);
shader = new Shader("./ShadersSrc/vshader6_textures2.glsl", "./ShadersSrc/fshader6_textures2.glsl");
texture0 = new Texture("./Textures/src/container.jpg", TextureUnit.Texture0);
shader.SetInt("tex0", 0);
texture1 = new Texture("./Textures/src/awesomeface.png", TextureUnit.Texture1);
shader.SetInt("tex1", 1);
texture2 = new Texture("./Textures/src/wall.jpg", TextureUnit.Texture2);
shader.SetInt("tex1", 2);
base.OnLoad();
}
Frame drawing method of the game class:
protected override void OnRenderFrame(FrameEventArgs e)
{
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.BindVertexArray(VertexArrayObject);
shader.Use();
//texture0.Use(TextureUnit.Texture0);
//texture1.Use(TextureUnit.Texture1);
GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0);
Context.SwapBuffers();
base.OnRenderFrame(e);
}
CodePudding user response:
GL.Uniform1()
sets the value of a uniform variable in the standard uniform block of the current program object. Therefore, you must install the program with GL.UseProgram
before you can set a uniform:
shader.Use();
shader.SetInt("tex0", 0);
shader.SetInt("tex1", 1);