I have some textures (.png) of different shape (for example, a ball, an airplain, a star) and I need to add shadows for them by coding, not by another texture. It’s important because the game textures can be rotated and their shadows must save the direction.
I’ve been searching the topic over the Internet for 3 days, but haven’t find the answer. Any help would be greatly appriciated.
@ghost8bit, you might want to take a look a the 2D shadow work that Rene Aye has done. He has created a 2D shadow library. Here are some resources on the topic.
@StarCrunch, sure, It must illustrate what I said about
As It shows, shadow affects the background.
“Save the direction” means that the light source doesn’t change it’s position, so if you rotate an image the shadow doesn’t change it’s direction (from the up-right to rhe down-left or somehow).
@Rob, I thought about it, but it cant help fully, I mean, it would help with creation of a filter, but you cant apply the filter to that shape along the image.
@Charles, Yea, It’s only the lib I could find when I looked for shadow creating but anfortunately it doesn’t suit (the images above shows my case).
Now I think about applying image-shaped mask to a gradient filled square, how’d you think can it cope with the problem?
Okay, I figured it might be something like that, or I’d have thrown Rene’s (terrific) stuff your way too.
No promises, but I’ve been considering decent multi-pass effects to show, if we have time, during the shader segment on Monday’s Corona Geek. I’m not very satisfied with my current example, so I might try this. I have an idea that would build on the technique horacebury used here: Create a drop shadow
\_W=display.contentWidth \_H=display.contentHeight local background = display.newRect(\_W/2,\_H/2,\_W, \_H) background:setFillColor(0.6, 0.6, 0.8) --object we want to be with shadow local ball = display.newImage('30\_3@2x.png', \_W/2, \_H/2) local size = 10 -- shadow object local ballshadow = display.newImage( '30\_3@2x.png', \_W/2 - size+5, \_H/2 + size-5) ballshadow:setFillColor(0)--it fills our obj with black colour not touching the background of the image --here's a trick for fill.effect, we just make shadow-image's canvas bigger local r = display.newRect( ballshadow.x, ballshadow.y, ballshadow.width\*2, ballshadow.height\*2 ) r:setFillColor(0, 0) --take black obj with extended canvas into the group local g = display.newGroup() g:insert(r) g:insert(ballshadow) --turn a groupObj into a displayObj local c = display.capture( g ) --apply blur filter and set alpha c.fill.effect = "filter.blurGaussian" c.fill.effect.horizontal.blurSize = 10 c.fill.effect.horizontal.sigma = 128 c.fill.effect.vertical.blurSize = 10 c.fill.effect.vertical.sigma = 128 c.alpha = 0.7 c.x = ballshadow.x c.y = ballshadow.y display.remove( ballshadow ) c:toBack() background:toBack()
BUT:
Corona windows simulator shows neither object nor it’s shadow
Android app shows only the object
Corona mac simulator shows everything perthectly
Xcode ios simulator shows only the object
I wanna ask Corona labs: What the heck is going on???
My best guess, if that’s your complete code, is that you’re falling afoul of the “Capture on Launch” issue, as described in the gotchas here: display.capture() Try putting all the code after you load your group into a timer, as done there.
Or maybe g is still in the way? I see you removed ballshadow instead…
That said, it’s looking pretty good so far! The main novelty I think I could introduce, where the shader would come in, would be a little directional steering.
The shadow breaks up a bit, which I think is fixable by averaging a few neighbors. As is, it would be worth making a talking point of that sort of thing anyway. (I tried rearranging the multi-pass order, since after all we are doing a blur, but got an error. It looks like filter.blurGaussian is already multi-pass itself and maybe there are some quirks!)
All I can say is, that the gaussian blur filter does not work with mobile devices in real time. I don’t know why, but the filter must be recalculated on every frame which slows everything down on mobile devices. On desktop the filter is working fine for me.
But as long as your sprites do fit on the screen, maybe you can capture the filtered sprite once, and then remove the filter.
@ René Out of curiosity, how recent are the devices you’re using? I’ve run into the same performance issues, but was unsure whether what I have isn’t just too old. I should have followed up on this and mentioned the second capture.
@ nasibullin Obviously just a basic shift in position is a pretty lame excuse for another shader, so I’ve thrown some color into my example too. But my purposes are intended for illustration, of course. Since you probably just need the shift, those calculations can of course all be done in Lua, say in an enterFrame handler.
I tested with a iPhone 5 not (5S). The FPS dropped that much, that I decided to not investigate into this technique. But since the desktop comnpilers are out now, the camera system might be interesting for desktop apps. Right now I’m on vacation any my internet connection is rather lame here. When I’m back home I can test it with an iPad Air 2, but I think the FPS will drop too. The docs also do not recommend to use the blur filter for realtime effects. So I think only workaround is to capture the blurred object into a new image and then kill the original gauss blur filter.
I tested with iPad Air 2 and the FPS drops too. Not that much like on an iPhone 5 but definitely too much to use the blur filter on a mobile device in realtime.
this is such a simple/basic effect, that if performance is a concern, then i’d suggest just resorting to an “old tech” solution, and forget about any real-time gaussian blurs and such via shaders.
just precreate a monochrome mask of your sprite, blurred by some R. then draw that under your sprite, offset by some XY, at partial transparency, possibly using multiply blend mode if normal doesn’t look right (tho just normal blend mode will probably look right if your shadow mask is truly mono black with alpha – use multiply if “faking it” with a grayscale-no-alpha bitmap).
now if you rotate them both synchronously, but keep the XY offset the same in global coords, it’ll preserve the illusion of a constant light source direction. plus photoshop preprocessed blur will probably look better than your real-time blur anyway AND cost no real-time cpu to generate, just a single additional bitmap to render underneath (which is “cheap” in relative performance terms).