# Changing the color of some fragment of a texture using shaders

Declarative programming language QML allows to connect the elements, their properties with universal variables in shader programs description. For these purposes there is such elements as ShaderEffectItem, for instance. Here, for example, we define a certain image image.jpg. And in the source property we set just that this image any will change in the image and further this property is set already in the fragment shader program description fragmentShader as uniform sampler2D source. qt_TexCoord0 defines initial coordinate a texture. We receive there gray color on all texture scalar product lowp float gray = dot (textureColor, vec4 (0.299, 0.587, 0.114, 0.0)); also we install color of a fragment in an output variable gl_FragColor.

....
Item {
id: main
Image {
id: img
source: "images/image.jpg"
}

id: effect
property real ratio: 1.0
sourceItem: img;
hideSource: true
}

"
varying highp vec2 qt_TexCoord0;
uniform sampler2D source;
uniform highp float ratio;
void main(void)
{
lowp vec4 textureColor = texture2D(source, qt_TexCoord0.st);
lowp float gray = dot(textureColor, vec4(0.299, 0.587, 0.114, 0.0));
gl_FragColor = vec4(gray * ratio + textureColor.r * (1.0 - ratio), gray * ratio + textureColor.g * (1.0 - ratio), gray * ratio + textureColor.b * (1.0 - ratio), textureColor.a);
}
"
}

SequentialAnimation on ratio {
id: ratioAnimation
running: true
loops: Animation.Infinite
NumberAnimation {
easing.type: Easing.Linear
to: 0.0
duration: 500
}
PauseAnimation {
duration: 500
}
NumberAnimation {
easing.type: Easing.Linear
to: 1.0
duration: 500
}
PauseAnimation {
duration: 500
}
}
}


After performance color of a texture (picture) gradually completely passes in gray, and all is then reverse also it is fulfilled in an infinite loop. Now:

A question actually here in what: and I can change somehow color of any definiteness of a part of a texture (my picture images/image.jpg), i.e. any certain sections. For example I will define in QML two variables xColor, yColor, we transfer it similarly ratio the shader description and then for example the texture will change only in a square with coordinates the left top corner [xColor - 10, yColor - 10] and [xColor + 10, yColor + 10] - bottom right corner. I want:

I know that it can be implemented. How it more optimally to make? In what direction to me to think? Whether there are any similar examples? It would be nice to add blending color (red to gray in this section).

• Was this translated automatically? I got the idea, thanks to the provided code and pictures, but I really had trouble understanding every sentence… I wonder whether the people upvoting this question actually read it :-) – sam hocevar Dec 6 '11 at 21:11
• Can you edit my question? – G-71 Dec 8 '11 at 20:22

I hope I understand the question correctly. What you want is tell the fragment shader to only apply your effect to a neighbourhood of (xColor,yColor).

First of all, you should learn about the GLSL mix() function (called lerp() in HLSL). This heavy calculation:

gl_FragColor = vec4(gray * ratio + textureColor.r * (1.0 - ratio),
gray * ratio + textureColor.g * (1.0 - ratio),
gray * ratio + textureColor.b * (1.0 - ratio),
textureColor.a);


Can be rewritten as:

gl_FragColor = mix(textureColor, gray, vec4(vec3(ratio), 0.0));


There is also the step() command, which tests whether a value is higher than another. This should work:

      varying highp vec2 qt_TexCoord0;
uniform sampler2D source;
uniform highp float ratio;
uniform highp vec2 pa, pb;
void main(void)
{
lowp vec4 textureColor = texture2D(source, qt_TexCoord0.st);
lowp float gray = dot(textureColor, vec4(0.299, 0.587, 0.114, 0.0));
lowp vec4 test = step(vec4(pa.xy, qt_TexCoord0.st),
vec4(qt_TexCoord0.st, pb.xy));
ratio *= (test[0] * test[1]) * (test[2] * test[3]);
gl_FragColor = mix(textureColor, gray, vec4(vec3(ratio), 0.0));
}


Finally, you just need to pass ((xColor - 10) / xTextureSize, (yColor - 10) / yTextureSize) in pa, and the same (with + 10) in pb. Merging pa and pb in one single vec4 uniform would be a lot better but maybe less readable.

You can create a mask using a new texture:

varying vec blend_ammount; // 0.0 to 1.0