1

I have a full screen quad with two textures.

I want to blend two textures in arbitrary shape according to user selection.

For example, the quad at first is 100% texture0 while texture1 is transparent.

If the user selects a region, for example a circle, by dragging the mouse on the quad, then circle region should display both texture0 and texture1 as translucent.

The region not enclosed by the circle should still be texture0.

Please see example image, textures are simplified as colors.

image

For now, I have achieved blending two textures on the quad, but the blending region can only be vertical slices because I use the step() function.

My frag shader:

uniform sampler2D Texture0;
uniform sampler2D Texture1;
uniform float alpha;
uniform float leftBlend;
uniform float rightBlend;
varying vec4 oColor;
varying vec2 oTexCoord;
void main()
{
vec4 first_sample = texture2D(Texture0, oTexCoord);
vec4 second_sample = texture2D(Texture1, oTexCoord);

float stepLeft = step(leftBlend, oTexCoord.x);
float stepRight = step(rightBlend, 1.0 - oTexCoord.x);
if(stepLeft == 1.0 && stepRight == 1.0)
    gl_FragColor = oColor * first_sample;
else
    gl_FragColor = oColor * (first_sample * alpha + second_sample * (1.0-alpha)); 

if (gl_FragColor.a < 0.4)
   discard;
}

To achieve arbitrary shape, I assume I need to create a alpha mask texture which is the same size as texture0 and texture 1?

Then I pass that texture to frag shader to check values, if value is 0 then texture0, if value is 1 then blend texture0 and texture1.

Is my approach correct? Can you point me to any samples?

I want effect such as OpenGL - mask with multiple textures

but I want to create mask texture in my program dynamically, and I want to implement blending in GLSL

I have got blending working with mask texture of black and white

uniform sampler2D TextureMask;
vec4 mask_sample = texture2D(TextureMask, oTexCoord);
if(mask_sample.r == 0)
  gl_FragColor = first_sample;
else
  gl_FragColor =  (first_sample * alpha + second_sample * (1.0-alpha)); 

now mask texture is loaded statically from a image on disk, now I just need to create mask texture dynamically in opengl

Community
  • 1
  • 1
kevin0228ca
  • 479
  • 1
  • 8
  • 17
  • That arbitrary shape you have got, how is it defined, is it a polygonal model, or a texture? – Kromster Jul 09 '14 at 06:59
  • I am in 2D, so as a simple example, user just drags a region on the quad to create a shape. I think I need to create a texture from dragged shape, but do not know if that is correct – kevin0228ca Jul 09 '14 at 07:06

1 Answers1

1

Here's one approach and sample.

Create a boolean test for whether you want to blend. In my sample, I use an equation for a circle centered on the screen.

Then blend (i blended by weighted addition of the 2 colors).

(NOTE: i didn't have texture coords to work with in this sample, so i used the screen resolution to determine the circle position).

uniform vec2 resolution;

void main( void ) {

    vec2 position = gl_FragCoord.xy / resolution;

    // test if we're "in" or "out" of the blended region
    // lets use a circle of radius 0.5, but you can make this mroe complex and/or pass this value in from the user
    bool isBlended = (position.x - 0.5) * (position.x - 0.5) +
        (position.y - 0.5) * (position.y - 0.5) > 0.25;

    vec4 color1 = vec4(1,0,0,1); // this could come from texture 1
    vec4 color2 = vec4(0,1,0,1); // this could come from texture 2
    vec4 finalColor;

    if (isBlended)
    {
        // blend
        finalColor = color1 * 0.5 + color2 * 0.5;
    }
    else
    {
        // don't blend
        finalColor = color1;
    }
    gl_FragColor = finalColor;
}

See the sample running here: http://glsl.heroku.com/e#18231.0

(tried to post my sample image but i don't have enough rep) sorry :/

Update:

Here's another sample using mouse position to determine the position of the blended area. To run, paste the code in this sandbox site: https://www.shadertoy.com/new This one should work on objects of any shape, as long as you have the mouse data setup correct.

void main(void)
{
vec2 position = gl_FragCoord.xy;

// test if we're "in" or "out" of the blended region
// lets use a circle of radius 10px, but you can make this mroe complex and/or pass this value in from the user
float diffX = position.x - iMouse.x;
float diffY = position.y - iMouse.y;
bool isBlended = (diffX * diffX) + (diffY * diffY) < 100.0;

vec4 color1 = vec4(1,0,0,1); // this could come from texture 1
vec4 color2 = vec4(0,1,0,1); // this could come from texture 2
vec4 finalColor;

if (isBlended)
{
    // blend
    finalColor = color1 * 0.5 + color2 * 0.5;
}
else
{
    // don't blend
    finalColor = color1;
}
gl_FragColor = finalColor;
}
ben
  • 341
  • 1
  • 4
  • How is that supposed to work for an arbitrary shape, for example a teapot? – Kromster Jul 09 '14 at 06:58
  • Obviously the simple circle calculation won't work. But the bool test is not the point of the sample. It can be anything, based off of other inputs to the shader, such as textures, texturecoords, etc. – ben Jul 09 '14 at 07:03
  • thanks, if from a alpha mask texture, how can I determine isBlended? and I need pointer about how to create alpha mask texture in opengl – kevin0228ca Jul 09 '14 at 07:09
  • kevin0228ca: I've updated my answer to show how you could determine the blend region based on mouse input. Hopefully the sample site works, and this gives you an idea of how you can calculate the blended area based on more complex input (maybe send the upper-left/lower-right bounds for a clicked box/circle, etc) – ben Jul 09 '14 at 08:07
  • kevin0228ca: if you want to use a texture for your alpha mask, you can sample it like any other texture. Basically, you will sample color1 from first texture, color2 from second texture, and mask value from third texture. Creating textures programmatically can be done using a Framebuffer Object, or other methods. http://www.opengl.org/wiki/Framebuffer_Object – ben Jul 09 '14 at 08:26
  • thanks, please see my original post where I added sample. I know how to use framebuffer object to create texture, but I do not know what parameters a alpha mask texture should have, and how to process alpha mask texture in GLSL – kevin0228ca Jul 10 '14 at 03:26
  • The format of the texture, and the meaning that you give the value stored in it are up to you. For example, you can use a regular RGBA texture as your mask, and then just look at the R channel in your mask texture. If R is 0 blend, if R > 0 don't blend. Or if you use a more complicated blending method, you can assign the percentage of color1 and color2 based on the exact value of R. – ben Jul 10 '14 at 04:59
  • Even more complex, you could set the blending mask seperately for each color channel (RGB), then in your shader, you can now blend the color1.R with color2.R based on the mask.R, and then blend color1.G color2.G based on mask.G, etc. – ben Jul 10 '14 at 05:00