4
\$\begingroup\$

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"
      }

    ShaderEffectItem {
       id: effect
       property real ratio: 1.0
        property variant source: ShaderEffectSource {            
             sourceItem: img;
             hideSource: true
        }

        fragmentShader:
          "
          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:

enter image description here

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:

enter image description here

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).

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 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 :-) \$\endgroup\$ Commented Dec 6, 2011 at 21:11
  • \$\begingroup\$ Can you edit my question? \$\endgroup\$
    – G-71
    Commented Dec 8, 2011 at 20:22

2 Answers 2

3
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

You can create a mask using a new texture:

mask image

And use the colour at each point as the ratio to GLSL mix() with your textureColor from your original image in your shader and your grey value.

You can also multiply the ratio by a blend ammount.

Something like

varying vec blend_ammount; // 0.0 to 1.0
lowp vec4 textureColor = texture2D(source, qt_TexCoord0.st);
lowp vec4 maskcolor = texture2D(mask, qt_TexCoord0.st);
lowp float gray = dot(textureColor, vec4(0.299, 0.587, 0.114, 0.0));
vec4 color = mix(textureColor, gray, maskcolor * blend_ammount);
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .