Sign in to follow this  

Help with blending puzzle blocks

This topic is 2786 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all. I've been struggling with this blending issue for a little while and I am sure you guys can point me in the right direction. I'm currently building a puzzle game with different colored blocks. I want to color each block with a different color and then blend in a texture. I can do a glBlendFunc(GL_ONE, GL_ONE) with a solid color and the texture but it's not quite the effect I want. What I'd really like do is color the polygon with a solid color and then throw the texture on top of that as a decal (imagine the texture is a drawing of a four screws or bolts). I think what I need to do is have the two textures, the actual texture and it's mask. With that I could do something like:
glBlendFunc(GL_ONE,GL_ZERO);

//draw the solid color to the verts.

//Load the mask texture
glBlendFunc(GL_DST_COLOR, GL_ZERO);

//draw the mask by blending the source with the destination (white maintains the original color, black removes it)

//Load the actual texture
glBlendFunc(GL_ONE, GL_ONE);

//draw the texture normally


Am I going about this in the right way or am I completely off? I feel like decaling models that are already colored (or even textured) is a pretty common thing but I haven't seen any solid posts on how to do it.

Share this post


Link to post
Share on other sites
If you want to decal a colored object then blending is not really what you want to be messing with. Blending is for transparency or combining objects from different draw calls.

It is certainly possible to have a texture apply on top of a colored object. Do you have any familiarity with using shaders? I don't have much memory of how alpha textures work in the old fixed function pipeline, but I'm certain that it should be possible. I think if you just use the alpha channel of your decal texture it might do what you want by default, but you might need to enable it with some other state variable that I can't remember.

Make the alpha zero in places where you don't want a texture, and have a value in places where you want your texture to appear. This is essentially the "mask" texture you mentioned, although you can combine it into the fourth channel of the original texture instead of having a second texture.

Share this post


Link to post
Share on other sites
@Karwosts I'm kind of curious about this. Does a texture contain alpha data on a per pixel level as well as color data? For instance in a png? I know I can apply an alpha to each vertex of the texture but I wasn't sure if the image itself stored alpha. I'm using the same masking texture NeHe technique from a few years ago so I'm willing to try something new.

Haven't done anything with shaders yet, I should mention this project is using OpenGLES on an IPhone so that limits me in various ways.


@szecs Would this do what I'm looking for with one glDrawArrays call, one glTexCoordPointer call, and one glColorPointer call? That would be incredible.

Do either of you know of a good texture editor I should be using? Thanks for the responses!

Share this post


Link to post
Share on other sites
No, two passes. First with color and no texture, than with texture. How many tiles do you want to draw? I mean are you sure the performance is an issue?

Draw all the non-textured colored tiles in the first pass, than draw the textured tiles in the second pass.

_____________

I use Photoshop 7

Share this post


Link to post
Share on other sites
I'll be rendering up to 6 rings of tiles, 20 per ring, so 120 tiles as most. If that's a problem with 2 or 3 passes per tile I can get it down to half of that by rendering only tiles on the top hemisphere (my block structure creates a circle with only the top half on screen at a time).

Currently with 1 to 2 passes it runs fine so I'm not worried about this being a performance issue at it at all.

Share this post


Link to post
Share on other sites
Yes, you can store the alpha per-pixel inside the texture. I don't know exactly how to create this in whatever image software you're using, but if you have two separate images (3 channel color + mask) you can combine them in CPU before you upload the data.

Instead of calling glTexImage2D with a GL_RGB type, you will want a GL_RGBA type (four channels). Then instead of uploading (RGB)(RGB)(RGB) pixel data, you'll upload a fourth data component per pixel (RGBA)(RGBA)(RGBA).

Unfortunately I can't remember at the moment how fixed pipeline treats the alpha component, if it uses it to cause transparency, or if it controls the texture blending.


Share this post


Link to post
Share on other sites
@szecs: I feel kind of dumb now, I never thought about using the alpha channel of an image to help me with my opengl goodness. I realized now that the masking textures I've been creating were more or less 2bit alpha channels and

(GL_DST_COLOR, GL_ZERO) with the mask on the first pass then, (GL_DST_COLOR, GL_ONE) with the texture on the second pass is totally unnecessary.

I have a decent grasp of blending and I've textured plenty before. Back to your original suggestion:

(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

If I do the math for 2 cases it makes sense to me:
(using just the red channel and the alpha channel)
red source = .2
alpha source = 1
red destination = .8

we get .2*1 + (1-1)*.8 = .2 (the color of the red source!)

or we can do
red source = .2
alpha source = 0
red destination = .8

we get .2*0 + (1-0)*.8 = .8 (the color of the red destination!)

So, am I understanding this correctly? It definitely seems like what I want. I'll try it when I get home.

Share this post


Link to post
Share on other sites
Ok, I've been screwing around with this for a while and I'm still not getting it to work.

I've made a png in gimp with an alpha channel here

My texture is loaded with a GL_RGBA type as so:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);




Then, as a very simple test, I try to do two passes on a square. I'm doing a red base color and then blending the texture using the src_alpha method we talked about:



//TESTING
point_t verts[] = {
1.0f,-1.0f,0,
1.0f,1.0f,0,
-1.0f,-1.0f,0,
-1.0f,1.0f,0
};
uv_t uvs[] = {0,1,0,0,1,1,1,0};
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);

//FIRST PASS
glBlendFunc(GL_ONE, GL_ZERO);

glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(0.8f,0.0f,0.0f,1.0f);
glVertexPointer(3, GL_FLOAT, 0, verts);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);

//SECOND PASS
glBindTexture(GL_TEXTURE_2D, texture);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glColor4f(1.0f,1.0f,1.0f,1.0f);
glVertexPointer(3, GL_FLOAT, 0, verts);
glTexCoordPointer(2, GL_FLOAT, 0, uvs);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);





I keep ending up with just the second pass and no red:



Any ideas on what I'm missing here?

[Edited by - tacostev on April 26, 2010 11:58:55 PM]

Share this post


Link to post
Share on other sites
If you comment out the second pass, do you see the red square? My concern is that you're enabling texturing before your first pass, so I'm not sure if you're really drawing a red square, or just drawing a textured square with a null texture and all uv's at 0.0f.

Also you should disable blending on your first pass. Blending with GL_ONE, GL_ZERO is equivalent to doing no blending at all, but I don't know if the driver is smart enough to realize this (may be a performance hit for no reason).

Share this post


Link to post
Share on other sites
This is perfect! Thank you szecs and karwosts!

Here's the code I ended up with:

[source lang='cpp']
//TESTING
point_t verts[] = {
1.0f,-1.0f,0,
1.0f,1.0f,0,
-1.0f,-1.0f,0,
-1.0f,1.0f,0
};
uv_t uvs[] = {0,1,0,0,1,1,1,0};

glDisable(GL_DEPTH_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(0.8f,0.0f,0.0f,1.0f);
glVertexPointer(3, GL_FLOAT, 0, verts);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);

glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);

glBindTexture(GL_TEXTURE_2D, texture);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glColor4f(1.0f,1.0f,1.0f,1.0f);
glVertexPointer(3, GL_FLOAT, 0, verts);
glTexCoordPointer(2, GL_FLOAT, 0, uvs);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);

glEnable(GL_DEPTH_TEST);



and a screenshot of the idea working:


Now to make the blocks not look like crap...

Share this post


Link to post
Share on other sites

This topic is 2786 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this