Quick Links: Gideros Home | Download Gideros | Developer Guide
Desaturate Sprite
  • totebototebo +1 -1
    Member
    Is there a way to desaturate a Sprite now when RenderTarget can access pixels?
    My Gideros games: www.totebo.com
  • n1cken1cke +1 -1 (+2 / -0 )
    Maintainer Accepted Answer
    --~~~~~~~~~~~~~~~~~~~~~~~~~software shading~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--
    -- 'render' is RenderTarget instance
    -- 'shader' is a soft-shader function (r, g, b, a, x, y, ...) -> r, g, b, a
    -- '...' is for constants which will be passed to 'shader' function
    -- NOTE: each color component should be an integer in 0..255 range
    local function applyShader(render, shader, ...)
    local w, h = render:getWidth(), render:getHeight()
    local pixels = render:getPixels(1, 1, w, h)
    for i = 1, #pixels, 4 do
    local n = (i - 1) / 4
    local y = math.floor(n / w) + 1
    local x = (n - y * w + w) + 1
    local r, g, b, a = pixels:byte(i, i+3)
    r, g, b, a = shader(r, g, b, a, x, y, ...)
    render:clear(r * 65536 + g * 256 + b, a / 255, x, y, 1, 1)
    end
    end
    --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--
     
    local texture = Texture.new "sample.png"
    local w, h = texture:getWidth(), texture:getHeight()
    local image = Bitmap.new(texture)
    local render = RenderTarget.new(w, h)
    render:draw(image)
    local bitmap = Bitmap.new(render)
    stage:addChild(bitmap)
     
    local function grayscale(r, g, b, a, x, y)
    local avr = math.floor((r + g + b) / 3)
    return avr, avr, avr, a
    end
     
    applyShader(render, grayscale)

    Likes: pie, totebo

  • n1cken1cke +1 -1
    Maintainer
    However `RenderTarget.clear` method is not effective (8 seconds to process 512x512 pixels image). Gideros needs C++ implementation of above applyShader method because Lua strings and tables have much slower access.
  • totebototebo +1 -1
    Member
    Cool, thanks! Shame about the performance, but will give it a whirl.
    My Gideros games: www.totebo.com
  • hgy29hgy29 +1 -1
    Maintainer
    BTW, a real shader would be more efficient. What is a desaturation ?
  • n1cken1cke +1 -1
    Maintainer
    Desaturation = reduction of colorfulness.
    Real shader is hard to write for beginners and it constantly consumes videocard resources. This one-shot soft-shader is useful for image processing and you can later save the result because I don't think `getPixel` will return modified texture if you apply real shader to it (need to check).
    If Lua-C API supports effective iteration over arrays with Lua function application (i.e. "map") this can be very fast processing too.
  • hgy29hgy29 +1 -1
    Maintainer
    n1cke said:

    ... and it constantly consumes videocard resources.


    No it doesn't, you can apply it once and release it afterwards, and yes getPixel() will return processed pixels, since applying a shader is the exact purpose of a RenderTarget, wether the shader aims is create graphics or image processing.

    However I agree on the fact that shaders are less easy to deal with than lua functions, but on all aother points they are more effective, because the GPU is designed to do just that task.
  • hgy29hgy29 +1 -1
    Maintainer
    So is it like turning an image to greyscale or is there some mathematical subtile difference ? If it is greyscale, then http://giderosmobile.com/forum/discussion/6442/turn-a-colour-bitmap-greyscale-at-runtime/p1 still applies :)
  • n1cken1cke +1 -1 (+1 / -0 )
    Maintainer
    @hgy29, that's awesome!
    Then we only need additional simplified API for pixel shaders.
    Nothing special, just a template with predefined `ps.glsl`, `vs.glsl` and `Shader.new`. String with pixel shader code could be inserted into `void main() {...}`.
    In the end a user should be able to write something like this:
    renderTarget:applyShader [[
    //convert to grayscale using NTSC conversion weights
    float gray = dot(gl_Color.rgb, vec3(0.299, 0.587, 0.114));
    gl_FragColor = vec4(gray, gray, gray, gl_Color.a);
    ]]

    I think it's much better for image processing than 3 files with shader description.

    Likes: totebo

  • n1cken1cke +1 -1
    Maintainer
    @hgy29, I checked and it doesn't work works. You cannot get modified pixels from rendertargets because each time pixel shader applies to source texture (not previously modified one).
    local pixels1 = render:getPixels(1, 1, w, h)
     
    local effect = Shader.new("vs","ps",0,
    {
    {name="g_MVPMatrix",type=Shader.CMATRIX,sys=Shader.SYS_WVP, vertex=true},
    {name="g_Color",type=Shader.CFLOAT4,mult=1,sys=Shader.SYS_COLOR},
    {name="lightPos",type=Shader.CFLOAT4,mult=1,vertex=false},
    {name="g_Texture",type=Shader.CTEXTURE,mult=1,vertex=false}
    },
    {
    {name="POSITION0",type=Shader.DFLOAT,mult=3,slot=0,offset=0},
    {name="vColor",type=Shader.DUBYTE,mult=0,slot=1,offset=0},
    {name="TEXCOORD0",type=Shader.DFLOAT,mult=2,slot=2,offset=0}
    })
     
    bitmap:setShader(effect)
     
    render:draw(bitmap) --> this was missing!
     
    local pixels2 = render:getPixels(1, 1, w, h)
     
    assert(pixels1 ~= pixels2)

  • totebototebo +1 -1
    Member
    Gah! I knew I had posted something similar before, but couldn't find it in the forum search.

    Would it be counterintuitive to create an abstracted Lua class with common uses, such as blur and desaturation? Shaders still scare me, so for me that would be very useful. I am working on a Sprite:setBlur method, but it's still a way off working as it should.
    My Gideros games: www.totebo.com
  • hgy29hgy29 +1 -1
    Maintainer
    I don't really understand what you mean. If you want to keep your rendertarget's unmodified after the first draw call, then just don't draw on it again ? And you can use the rendertarget as source texture for subsequent calls without applying the shader again.
  • hgy29hgy29 +1 -1 (+3 / -0 )
    Maintainer
    @totebo, yes that's a good idea. We plan to allow shader's to be loaded from lua string instead of files, that way we will be able to hide shader stuff inside .lua libraries, plus shader's could be customised at run time for even better efficiency.
  • n1cken1cke +1 -1
    Maintainer
    @hgy29, I mean with `getPixels` function you can't get pixels of rendertarget modified by `setShader` effect. I can't load images from disk, apply shader effect (like grayscale) and then save the result (grayscaled image) to disk.
  • hgy29hgy29 +1 -1 (+2 / -0 )
    Maintainer
    Yes you can, the same way you apply shaders for drawing.
    In your example you miss the
    render:draw(bitmap)
    call, no ?
  • SinisterSoftSinisterSoft +1 -1 (+1 / -0 )
    Maintainer
    @n1cke,

    1. load your source image texture, point a bitmap to it, apply the shader to the bitmap.

    2. make a rendertarget. draw the bitmap to the rendertarget (once)

    3. read the pixels from the rendertarget.

    Likes: antix

  • n1cken1cke +1 -1
    Maintainer
    @hgy29, yes, sorry, missed that call.
  • totebototebo +1 -1
    Member
    I have tried to do the greyscale with shaders, but I can't get it to work. All that happens is all sprites disappear for a frame. :)

    Could someone post actual code to make a sprite greyscale with shaders? I'm missing something and and actual compilable example would help a lot.
    My Gideros games: www.totebo.com
  • n1cken1cke +1 -1 (+1 / -0 )
    Maintainer Accepted Answer
    Open "Normal mapping" example and replace `ps.glsl` "void main {...}"-part with:
    void main()
    {
    highp vec4 color = texture2D(g_Texture, texCoord).rgba;
    highp float m = (color.r + color.g + color.b) / 3;
    gl_FragColor = vec4(m, m, m, color.a);
     
    }


    First line gives you 4 color components as vector (vec4). It also sets precision as 'high' for it (this affects performance).
    Second line does some maths to get greyscaled color.
    Third line creates new color vector and assigns it to texture coordinate.

    This template just returns unmodified color if you want to experiment further:
    highp vec4 color = texture2D(g_Texture, texCoord).rgba;
    gl_FragColor = vec4(color.r, color.g, color.b, color.a);

    Likes: chuz0

  • totebototebo +1 -1
    Member
    Awesome, got it. I hadn't dared look inside the ps.glsl file before. Thanks!
    My Gideros games: www.totebo.com
  • antixantix +1 -1
    Member
    Example project please :)
  • totebototebo +1 -1 (+1 / -0 )
    Member
    Will make one once I get this working. First attempt of plugging it into my game removed the sprite instead of making it grey scale, so next step is to make a minimal project and take it from there.
    My Gideros games: www.totebo.com
  • totebototebo +1 -1 (+4 / -0 )
    Member
    Project attached!
    ShaderGreyscaleTest.zip
    6K
    My Gideros games: www.totebo.com
  • SinisterSoftSinisterSoft +1 -1 (+1 / -0 )
    Maintainer
    Almost a year later. ;)

    Likes: totebo

  • antixantix +1 -1 (+2 / -0 )
    Member

    Almost a year later. ;)



    Better late than never? :D
  • totebototebo +1 -1
    Member
    I cheated and used Photoshop in the other game. Now I had a chance to get back to it. Patience is a virtue, guys! :)

    Still, shaders are a twilight zone of mystery, magic and infinite pain and suffering. So I'm not there often.
    My Gideros games: www.totebo.com

Howdy, Stranger!

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

Login with Facebook Sign In with Google Sign In with OpenID

In this Discussion

Top Posters