Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
basic view range/ lighting effect — Gideros Forum

basic view range/ lighting effect

piepie Member
edited July 2015 in General questions
Hi, after understanding that I can't achieve this with existing blending modes I have some questions:

my goal would be a "viewing range" effect.
I thought to take a texture with an alpha/color gradient, add it to (actually maybe it's better to say subtract it from ) the alpha values of an existing "black" sprite above my scene, and apply the alpha/color values to the black sprite, so that I can show the scene through a nice gradient.

see the attachment, either if it's rough it should give an idea of what I have in mind..

What are my options?

From what I understood shaders could do this, but I am worried that since I need to update this continuously it won't be the best option (am I wrong?) I have a "big" tilemap which can be zoomed in/out and dragged around, and various things that can "create lights".
Assuming that I could succeed in writing an "alpha shader", of which I am not sure, would this be "heavy"?

Looking at Bird Animation 2 example (the one with cos transform) I can see that the output is rendered with renderTarget every now and then, and I fear that it will become too slow in my setup.

Any suggestion? Do I have to forget this? :D

Thank you
shaderoutcome.png
401 x 705 - 30K

Comments

  • totebototebo Member
    Don't forget it! I'd go with a dirty but relatively fast solution:

    - Create the mask circle as a bitmap with opaque edges
    - Create shapes at runtime to cover top/right/bottom/left sides
    - Pop all this in a sprite and make it stick to the character

    The trick is to make the shapes as small as possible but big enough to cover the screen. application:getDeviceWidth() and application:getDeviceHeight() would work if the character is moving around a lot, if the character is static you could almost halve it.

    Niclas

    Likes: pie

    My Gideros games: www.totebo.com
    +1 -1 (+1 / -0 )Share on Facebook
  • Did you want to create something like this :


    :-\"
    +1 -1 (+2 / -0 )Share on Facebook
  • @tkhnoman Your game is the best particle and effect on Gideros games i've ever seen! :D
    Coming soon
  • @vitalitymobile Thanks..
    I'm using TNT particle Engine for that game.
    http://www.tntparticlesengine.com/?page_id=58

    I used RenderTarget for the dark effect, but i'm using small area of RenderTarget and scaled them big afterward. The scale is quite high (32). That way i won't slow my game.
  • hgy29hgy29 Maintainer
    @pie, sorry if I mislead you, but you can do that with multiply blend mode too: see picture attached. Of course it be the same as using transparent instead of white in the 'spotlight' and leave blending mode is default 'alpha blending'.

    I think the drawback with all of the techniques decribed here is that it actually involves rendering the scene, then masking it with a black and white or black and transparent mask, thus masked pixels are drawn twice.

    If, by any chance, your background happens to be a single sprite with no sub-sprites, then you could use a specific shader to have him been drawn only where it should. I'll try to write one for you to show how this could be done.
    c9f27c15bbf37dce4cfa80a9776c9b.png
    401 x 705 - 40K
  • SinisterSoftSinisterSoft Maintainer
    edited July 2015
    @tkhnoman What did you do for that effect? I mean the torch light effect...

    (I have a few ideas, but I'd like to know your method)

    One of my ideas would be to draw as normal - then have a predrawn overlay that masked out everything apart from where the torch light was.

    A second way would be to clear a render target with black, then draw 'transparent' pixels on it, then draw this on the main screen scaled up.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • tkhnomantkhnoman Member
    edited July 2015
    @SinisterSoft Hmm.. I just used one more layer with blend mode multiply on top of it. This layer contain black-white RenderTarget image that keep updated each frame.

    The scale is used to reduce CPU usage.
  • SinisterSoftSinisterSoft Maintainer
    Thanks. :)
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • SinisterSoftSinisterSoft Maintainer
    edited July 2015
    I wonder if the alpha draw method would be faster? I mean when merging with the main screen.

    @hgy29 any idea?
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • piepie Member
    Thank you guys!
    @tkhnoman the "torch like effect" is really cool but I missed one thing: what area do you render with renderTarget and then scale x32?

    I actually think that my previous mockup mislead a bit on my game: I put it together quickly to explain the effect I'd like to achieve, but my game is not a platform so I think I can't do as @totebo suggested (I don't have a player fixed in the center of the screen, but it's on a tilemap which can be zoomed in/out and dragged around).
    I think I can use this workaround, but since I have "many" lights, I don't know how to handle texture overlapping and drawing a shape that keeps all the textures together in a "black frame".

    Here is a "real" mocked up screenshot: please don't mind the graphics which is under development :)

    In image 1 there is a tilemap, which is a sprite composed by different layers/sprites.

    Image 2 is a mockup of what I think should be the light casted by objects that have this property (I am guessing on "how": I suppose there will be a gradient texture applied "over" each object with "lighting property")

    Image 3 is what I'd like to achieve "mixing" image 1 and image 2: since the player can move, and that he can "turn lights on", I need these to be "movable" and that they could "merge" with each other.
    This is why I thought to "cut" alpha from a plain black layer placed above the tilemap: if alpha of a pixel reach 0, then the pixel would be transparent, otherwise it would be a half-transparent black, generating the gradient on the tilemap; while gideros has to blend just between black pixels and their alpha without thinking about pixels with no "light texture" overlapping.

    Image 4 is what I have so far: a "tile based lighting", which is a bit "ugly" compared to texture based gradients, and heavy on mobile devices: for each movement I have to set every alpha back to 1, update the alpha of every tile based on its distance from the light source (player is considered a light source), check if at least one tile of each light source is seen by player (so that I know it is in viewing range), and if it is, set the alpha of the adiacent tiles... works well on laptop but android devices get a bit of lag.

    @hgy29 if you have some time I'd really like to see a shader managing alpha per pixel, I would also try to use it as a base to "fix" the antialiasing on tiles we talked about here:
    http://giderosmobile.com/forum/discussion/comment/42735#Comment_42758


    Thank you very much for all your help :)
  • SinisterSoftSinisterSoft Maintainer
    edited July 2015
    I've just added the effect to Dungeons, I have a render target that is 1/4 the screen size, I then have alpha sprites that are 16x scaled up for the render target. In the game I scale the screen up/down quite a lot, it seems to look ok...

    @pie I have parts where the lights mix, is that what you mean?

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • piepie Member
    @SinisterSoft :-? I don't see why your approach wouldn't work with my game: but apparently I am still missing what you're doing :)

    Please correct me if I am wrong and fill in the blanks :D
    you have a texture with a "circle" with smooth edges to mimic "light" for each character.
    Which colors are you using for your gradient? do you have transparent pixels on that texture?
    What are you rendering with renderTarget? I think that this is what I am not getting here: do you have an overlapping black sprite or it's just the not multiplied pixels that remain black? (if you're using multiply)

    I didn't try using renderTarget because I didn't understand "where" to use it :) can you please enlight me?

    Thank you very much
  • SinisterSoftSinisterSoft Maintainer
    edited July 2015
    @pie , no problem, here you go...

    1) I create a texture and add it to the stage, the texture is set to it draws using 'multiply'.

    2) Every frame I clear the texture solid black, no transparency (test it drawn over your stage, it should be black)

    3) Then I draw white orb like sprites on the solid black texture with the middle solid white gradually fading to full alpha on the edges. They can overlap as the edges are full alpha.

    Because the rendertexture is a multiply with the screen then any areas that are still black will remain black, but any areas that are full white will show the image underneath. Anything inbetween (the edges of the circles will be a colour mix of black and the image underneath.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • piepie Member
    edited July 2015
    Thank you @SinisterSoft. :)
    I am feeling stupid, but I still have a couple of questions:
    I made an example with a tilemap (attached): is it expected to have the whole tilemap sprite "multiplied" (pic attached)?
    The only reason I found to use renderTarget is to avoid multiplying the tilemap layers between each other (actually using it like a "flatten image" on a sprite). Is there another way to "lock" them? I feel that renderTarget is a bit heavy and if I scale to 1/4 my graphics it will look much different.

    Thank you

    P.s.
    for reference in attachment:
    main-basic.lua = main.lua - just multiplying the tilemap
    mainRT.lua -this one using renderTarget to "flatten" layers

    transparentTilesMultiplied.png
    398 x 357 - 88K
    zip
    zip
    Isometric-Tilemap-shades.zip
    54K
  • SinisterSoftSinisterSoft Maintainer
    No only scale the rendertarget (the black bit with light shining through) and the actual white bits that go on the render target. The render targets is also the only thing you draw with the multiply. Leave everything else as is. You graphics underneath will shine through.

    See my video above.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • piepie Member
    Allright, I was doing the "opposite": :)
    I was trying to multiply the tilemap as in hgy29 suggestion, but I can't get this working as I expect, either if I renderTarget the multiplied light bits as you suggested.

    I don't get why my solid white in center gradient looks like in this attachment :-O :
    image

    I am losing my mind: I can almost see it, but I think I am still missing something: maybe I don't know how to draw the texture right?

    thank you :)

    for reference in attached project:

    main.lua - renderTarget on the "fog of war"
    main-basic.lua = main.lua - just multiplying the tilemap
    mainRT.lua -this one using renderTarget to "flatten" layers
    -plus, various gradients textures, each one wrong I suppose ;)
    stillIssues.png
    767 x 479 - 184K
    zip
    zip
    Isometric-Tilemap-shades2.zip
    215K
  • SinisterSoftSinisterSoft Maintainer
    here is the draw order for my program:

    everything to do with the actual game added to stage - eg layers of maps, sprites, etc

    a black render target - with white bits 'cut out' of it, set to multiply, added to stage.

    the game score panel, etc - anything above the game, added to stage.

    :)
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • SinisterSoftSinisterSoft Maintainer
    every frame `i move the bits 'below' the black render target. I then clear the rendertarget with black and draw the white bits on it afterwards.

    Normally this would take a while, but I have the black rendertarget set to 1/4 of the screen size and set the scale to 2. I also scale up the white bits with scale(16) and let the hardware do the alias work.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • piepie Member
    Ok, it's a curse... no matter what I do :)
    do you see something wrong here?

    Thank you
    --load tilemap
    local tilemap = load("iso-test-vertexz.lua")
    tilemap:setPosition(application:getLogicalHeight()/2,application:getLogicalWidth()/2)
     
    --render target
    local rt = RenderTarget.new(tilemap:getWidth(), tilemap:getHeight())
     
    --bitmap with rendertarget as texture
    local scene = Bitmap.new(rt)
    scene:setBlendMode("multiply") 
     
    -- Load the mask 
    local mask = Bitmap.new(Texture.new("light8.png"))
    mask:setAnchorPoint(0.5, 0.5)
    mask:setScale(4)
    mask:setPosition(application:getLogicalHeight()/2,application:getLogicalWidth()/2)
     
     
    --place objects on stage
    stage:addChild(tilemap)
    stage:addChild(mask)
    stage:addChild(scene)
     
    rt:draw(scene)
     
    -- Set the background color of the stage to black
    stage:setBackgroundColor(0, 0, 0.0)
     
    local dragging, startx, starty
     
    local function onMouseDown(event)
    	dragging = true
    	startx = event.x
    	starty = event.y
     
    	local xp,yp = event.x,event.y
    	mask:setPosition(xp,yp)
     
    end
     
    local function onMouseMove(event)
    	if dragging then
    		local dx = event.x - startx
    		local dy = event.y - starty
    		tilemap:setX(tilemap:getX() + dx)
    		tilemap:setY(tilemap:getY() + dy)
    		startx = event.x
    		starty = event.y
    	end
     
     
    end
     
    local function onMouseUp(event)
    	dragging = false
    end
     
    stage:addEventListener(Event.MOUSE_DOWN, onMouseDown)
    stage:addEventListener(Event.MOUSE_MOVE, onMouseMove)
    stage:addEventListener(Event.MOUSE_UP, onMouseUp)
     
    --Define the onEnterFrame event function. This deals with the positioning of the mask
    function onEnterFrame(event)
    	rt:clear(0x000000,1)
    	rt:draw(scene)
    end
     
    -- Register an enterFrame event handler function
    stage:addEventListener(Event.ENTER_FRAME,onEnterFrame)
  • SinisterSoftSinisterSoft Maintainer
    Accepted Answer
    yes - you are over doing things, it should be more like this (not tested):
    --load tilemap
    local tilemap = load("iso-test-vertexz.lua")
    tilemap:setPosition(application:getLogicalHeight()/2,application:getLogicalWidth()/2)
     
    --render target
    local rt = RenderTarget.new(application:getContentWidth(), application:getContentHeight())
     
    --bitmap with rendertarget as texture
    local dark = Bitmap.new(rt)
    dark:setBlendMode("multiply") 
     
    -- Load the mask 
    local light = Bitmap.new(Texture.new("light8.png"))
    light:setAnchorPoint(0.5, 0.5)
    light:setScale(4)
    light:setPosition(rt:getWidth()/2,rt:getHeight()/2)
     
    --place objects on stage
    stage:addChild(tilemap)
    stage:addChild(dark)
     
     
    -- Set the background color of the stage to black
    stage:setBackgroundColor(0, 0, 0.0)
     
    local dragging, startx, starty
     
    local function onMouseDown(event)
    	dragging = true
    	startx = event.x
    	starty = event.y
     
    	local xp,yp = event.x,event.y
    	tilemap:setPosition(xp,yp)
     
    end
     
    local function onMouseMove(event)
    	if dragging then
    		local dx = event.x - startx
    		local dy = event.y - starty
    		tilemap:setX(tilemap:getX() + dx)
    		tilemap:setY(tilemap:getY() + dy)
    		startx = event.x
    		starty = event.y
    	end
     
     
    end
     
    local function onMouseUp(event)
    	dragging = false
    end
     
    stage:addEventListener(Event.MOUSE_DOWN, onMouseDown)
    stage:addEventListener(Event.MOUSE_MOVE, onMouseMove)
    stage:addEventListener(Event.MOUSE_UP, onMouseUp)
     
    --Define the onEnterFrame event function. This deals with the positioning of the mask
    function onEnterFrame(event)
    	rt:clear(0x000000,1)
    	rt:draw(light)
    end
     
    -- Register an enterFrame event handler function
    stage:addEventListener(Event.ENTER_FRAME,onEnterFrame)

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • piepie Member
    AH! allright! I was rendering the wrong thing L-) (scene instead of mask in my setup). Thank you @SinisterSoft.
    :)

    Likes: SinisterSoft

    +1 -1 (+1 / -0 )Share on Facebook
  • SinisterSoftSinisterSoft Maintainer
    Is it sorted now?

    Plus you had the rt set to the size of the map, huge! It only had to be the size of the screen.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • SinisterSoftSinisterSoft Maintainer
    I've added setColourTransform to mine, so you see the colour tint to the magic weapon colour...
    wizard.png
    1489 x 800 - 747K
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • piepie Member
    wow cool color effect! I didn't think about that! Thanks for the additional tip

    I still didn't had the time to implement the black render target in my game, I hope I will do it today and see the real impact on its performance :)

    However, I am still wondering if there is a "better way" to achieve the same result without having to rely on renderTarget:
    either if we're rendering a small portion of the screen it has to be rendered and scaled every frame or so. It's a good workaround but I don't feel like it's a "best practice" :D

    I believe that multiplying the tilemap as @hgy29 suggested some posts ago would still be the best option; but there is the problem of multiply blending mode passed on to all the Sprite children, as in the project attached here in main-basic.lua. Maybe this would work only on single layered tilemaps with no overlapping objects, it's a pity though :)

  • SinisterSoftSinisterSoft Maintainer
    Best way is to keep things outside of lua and in the api side, much faster than lua.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
Sign In or Register to comment.