Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID
Please do not post the same thing multiple times. The board software automatically flags certain posts as needing moderator attention. This happens the most often for new users. I'm pretty sure this is made clear at the time you attempt to post. Posting the same thing over and over again just makes that many more posts the moderators have to weed through later. This makes us sad. Don't make us sad. If your post/thread doesn't appear, just wait a while. Don't post it again. If it hasn't shown up by the next day, then you can try again. I normally go through posts in the mornings, and try to check a few times throughout the day, but I'm not here 24/7. There will typically be a significant delay before posts are approved. Just be patient.

How can I display multiple separate textures (not multi-texturing) with OpenGL ES 2.0?

My iOS 4 app uses OpenGL ES 2.0 and renders elements with a single texture. I would like to draw elements using multiple different textures and am having problems getting things to work.

I added a variable to my vertex shader to indicate which texture to apply:
...
attribute float TextureIn;
varying float TextureOut;

void main(void)
{
...
TextureOut = TextureIn;
}
I use that value in the fragment shader to select the texture:
...
varying lowp float TextureOut;

uniform sampler2D Texture0;
uniform sampler2D Texture1;

void main(void)
{
if (TextureOut == 1.0)
{
gl_FragColor = texture2D(Texture1, TexCoordOut);
}
else // 0
{
gl_FragColor = texture2D(Texture0, TexCoordOut);
}
}
Compile shaders:
...
_texture = glGetAttribLocation(programHandle, "TextureIn");
glEnableVertexAttribArray(_texture);
_textureUniform0 = glGetUniformLocation(programHandle, "Texture0");
_textureUniform1 = glGetUniformLocation(programHandle, "Texture1");
Init/Setup:
...
GLuint _texture;
GLuint _textureUniform0;
GLuint _textureUniform1;

...
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D); // ?
glBindTexture(GL_TEXTURE_2D, _textureUniform0);
glUniform1i(_textureUniform0, 0);

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D); // ?
glBindTexture(GL_TEXTURE_2D, _textureUniform1);
glUniform1i(_textureUniform1, 1);

glActiveTexture(GL_TEXTURE0);
Render:
...
glVertexAttribPointer(_texture, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 13));

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _textureUniform0);
glUniform1i(_textureUniform0, 0);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _textureUniform1);
glUniform1i(_textureUniform1, 1);

glActiveTexture(GL_TEXTURE0);

glDrawElements(GL_TRIANGLES, indicesCountA, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * 0));
glDrawElements(GL_TRIANGLES, indicesCountB, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * indicesCountA));
glDrawElements(GL_TRIANGLES, indicesCountC, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * (indicesCountA + indicesCountB)));
My hope was to dynamically apply the texture associated with a vertex but it seems to only recognize GL_TEXTURE0.

The only way I have been able to change textures is to associated each texture with GL_TEXTURE0 and then draw:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _textureUniformX);
glUniform1i(_textureUniformX, 0);
glDrawElements(GL_TRIANGLES, indicesCountA, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * 0));
...
In order to render all the textures, I would need a separate glDrawElements() call for each texture, and I have read that glDrawElements() calls are a big hit to performance and the number of calls should be minimized. Thats why I was trying to dynamically specifiy which texture to use for each vertex.

It's entirely possible that my understanding is wrong or I am missing something important. I'm still new to OpenGL and the more I learn the more I feel I have more to learn.

It must be possible to use textures other than just GL_TEXTURE0 but I have yet to figure out how.

Any guidance or direction would be greatly appreciated.

Replies

  • Duncan CDuncan C Posts: 8,031Tutorial Authors, Registered Users
    How many separate objects are you talking about drawing, and how many unique textures?

    It's true that glDrawElements is expensive and you want to minimize the number of calls you make to it. However, if you have 3 textures to render, there's nothing wrong with setting a texture, calling glDrawElements, setting another texture, drawing with that, etc. You just don't want to call glDrawElements dozens of times in a rendering pas if you can avoid it.

    I don't think the way you're trying to switch textures will work. You need to bind a texture with a call to glBindTexture, draw with it, then bind the next texture and draw with that.

    I could be wrong though. When working with OpenGL I find something that works, make sure it's performance is satisfactory, and then move on. I'm hardly an expert on all the different ways you can use it.
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
  • user1102427user1102427 Posts: 12New Users
    Was brought to my attention that glBindTexture was using a uniform location instead of the texture so I fixed that but still having the problem. Also check a range on the float in the shader in case I am having rounding issues, but no success.

    I have 7 textures, and 3 calls to glDrawElements which I could make into 2. I have a different rotation to apply so I need 2 separate calls. Would I need to call glDrawElements for each texture in each element?
         (7 textures x 2 elements = 14 calls)

    I'll be the first to admit I don't know much, but I thought you could specify multiple textures and draw them all at the same time instead of separately.
    GL_TEXTURE0 goes up to GL_TEXTURE31 but I can't seem to figure out how to use more than one at a time.

    Also, eventually I would like to select different areas from my 7 textures to have dozens or hundreds of different textures, but everything will come from the same 7 textures. Read about texture atlases and once I got things working with the 7 base textures I would look into atlases.

    You've given me good advice in the past, even if it takes me a while to figure that out.
    Thanks for your input.
  • user1102427user1102427 Posts: 12New Users
    Found that if I assign a value in the fragment shader to select a texture, that texture does get rendered:
    lowp float temp = 1.0; // TextureOut;

    //if ((TextureOut > 0.5) && (TextureOut < 1.5)) // 1
    if ((temp > 0.5) && (temp < 1.5)) // 1
    {
    gl_FragColor = texture2D(TextureUniform1, TexCoordOut);
    }
    else // 0
    {
    gl_FragColor = texture2D(TextureUniform0, TexCoordOut);
    }
    Always went to the else clause before. Appears to be a problem with the TextureOut value getting passed in dynamically so I'm looking into this.
  • user1102427user1102427 Posts: 12New Users
    Success!

    I found the one missing line of code I forgot to put in:
    vertex.Texture = [(NSNumber *)[vertexBucketAll objectAtIndex:(i+13)] floatValue];
    Not going to make much progress if I don't actually set up the texture data in my vertex array.

    Now on to the next hair-pulling dilema, texture atlases I think.

    Thanks
  • Duncan CDuncan C Posts: 8,031Tutorial Authors, Registered Users

    Success!

    I found the one missing line of code I forgot to put in:

    vertex.Texture = [(NSNumber *)[vertexBucketAll objectAtIndex:(i+13)] floatValue];
    Not going to make much progress if I don't actually set up the texture data in my vertex array.

    Now on to the next hair-pulling dilema, texture atlases I think.

    Thanks
    Cool. Good to know that you can draw with more than one texture at the same time in a shader.

    BTW, there's no reason to use a float as your flag to indicate textures.

    I have a flag in one of my shaders that determines if it draws with textures or solid colors. It's declared as a GLuint in my C code, and as type "bool" in the shader. In my C code, I just set the value to 0 for false and 1 for true.

    You could use "bool" type inside your shader and switch between textures, or make it an "int" inside your shader and support a variety of different textures.
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
  • Duncan CDuncan C Posts: 8,031Tutorial Authors, Registered Users
    Duncan C said:

    Success!

    I found the one missing line of code I forgot to put in:

    vertex.Texture = [(NSNumber *)[vertexBucketAll objectAtIndex:(i+13)] floatValue];
    Not going to make much progress if I don't actually set up the texture data in my vertex array.

    Now on to the next hair-pulling dilema, texture atlases I think.

    Thanks
    Cool. Good to know that you can draw with more than one texture at the same time in a shader.

    BTW, there's no reason to use a float as your flag to indicate textures. Comparing floating point numbers, and especially inequalities like you're using, is fairly slow. Much better to use integers or booleans.

    I have a flag in one of my shaders that determines if it draws with textures or solid colors. It's declared as a GLuint in my C code, and as type "bool" in the shader. In my C code, I just set the value to 0 for false and 1 for true.

    You could use "bool" type inside your shader and switch between textures, or make it an "int" inside your shader and support a variety of different textures.
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
  • user1102427user1102427 Posts: 12New Users
    Yeah, the float was just a short term hack until I got it to work since I figured it was easier to calculate offsets in my vertex array if all the elements were the same size (float).

    Little did I know that it was actually the cause of a problem that was a MAJOR hassle to track down.
    varying lowp float TextureOut;
    Apparently lowp is REALLY low precision with a range of -2 to 2.

    Of course my textures ranged outside of that and I just couldn't figure out how hard it could possibly be to handle numbers up to 6.

    Upgraded to mediump and now it works wonderfully (for now).
    varying mediump float TextureOut;
    Whew!
    Post edited by user1102427 on
  • Duncan CDuncan C Posts: 8,031Tutorial Authors, Registered Users

    Yeah, the float was just a short term hack until I got it to work since I figured it was easier to calculate offsets in my vertex array if all the elements were the same size (float).

    Little did I know that it was actually the cause of a problem that was a MAJOR hassle to track down.

    varying lowp float TextureOut;
    Apparently lowp is REALLY low precision with a range of -2 to 2.

    Of course my textures ranged outside of that and I just couldn't figure out how hard it could possibly be to handle numbers up to 6.

    Upgraded to mediump and now it works wonderfully (for now).
    varying mediump float TextureOut;
    Whew!
    Don't use floating point data types to hold integer values. That's always a bad idea. Floating point types take more bits to store the value, do it with possible error, and are a lot slower to execute.
    Regards,

    Duncan C
    WareTo

    mug

    Animated GIF created with Face Dancer, available for free in the app store.
Sign In or Register to comment.