neroxt
neroxt

Reputation: 13

OpenTK bind multiple textures on shader

I'm trying to make multitextured terrain. But when I trying to bind 3 textures, there is only one texture displayed. c# code here :

GL.UseProgram(program);
//Active textures, glId - is texture id, generated by GL.GenTexture()
GL.BindTextures(0,3,new int[3]{grass.glId,grass_normal.glId,stone.glId});
//Set shaders uniform, diffuse is a shader class
diffuse.SetUniform("mainTexture",grass.glId);
diffuse.SetUniform("gNormalMap",grass_normal.glId);
diffuse.SetUniform("stoneTexture",stone.glId);    
//Just some render code, for example 
GL.BindVertexArray(mesh.vao);
GL.DrawElements(PrimitiveType.Triangles,
mesh.triangles.Count,DrawElementsType.UnsignedInt, IntPtr.Zero);        
//Unbind all
GL.UseProgram(0);
GL.BindVertexArray(0); 
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindBuffer(BufferTarget.ElementArrayBuffer,0);
GL.BindTextures(0,3,new int[3]{0,0,0});

There is shader fragment program:

#version 140
uniform sampler2D mainTexture;//grass
uniform sampler2D gNormalMap;//grass normal
uniform sampler2D stoneTexture;//stone
out vec4 FragColor;
//hide other uniforms and inputs

void main (void){ 
//Some light code
vec4 x = texture2D(stoneTexture, fract(vTexCoord.st * texSize));
vec4 y = texture2D(mainTexture, fract(vTexCoord.st * texSize));
vec4 tex = x;//display stone, but i want to mix textures later
//I don't know why, but there is no difference,
//if i use stone - 'tex = x', or grass - 'tex = y'
//in both cases, only grass is displayed  
FragColor = color*tex*(diffuse+ambient);//Color
}

I tried first to bind stone then grass, and it's displayed a stone without grass. I mean like this:

GL.BindTextures(0,3,new int[3]{stone.glId,grass_normal.glId,grass.glId});

There is no effect, only one texture is displayed.

Upvotes: 1

Views: 746

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 474366

GL.BindTextures(0,3,new int[3]{grass.glId,grass_normal.glId,stone.glId});

If this function makes sense, that means your glId fields are OpenGL object names.

Which means:

diffuse.SetUniform("mainTexture",grass.glId);
diffuse.SetUniform("gNormalMap",grass_normal.glId);
diffuse.SetUniform("stoneTexture",stone.glId);

This code now does not make sense.

Sampler uniform values are not the actual OpenGL texture names. After all, if they were, there would be no need to bind them to the context.

Sampler uniforms are set to the texture unit indices. Thus, the sampler will fetch from whatever texture is bound to the given texture unit. Since your glBindTextures call used texture image units [0,2], your uniform setting should reflect that:

diffuse.SetUniform("mainTexture", 0);
diffuse.SetUniform("gNormalMap", 1);
diffuse.SetUniform("stoneTexture", 2);

My guess as to why this seemed to work for one case would be that you got lucky. Many OpenGL implementations will return texture names starting with 1. So you probably got a texture name that just so happened to also match the texture unit you bound the texture to.

Upvotes: 2

Related Questions