Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Soft shadow
Started by horacebury Feb 05 2019 05:13 AM

4 replies to this topic
gfx2 shadow fade blur
[TOPIC CONTROLS]
This topic has been archived. This means that you cannot reply to this topic.
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

horacebury

[GLOBAL: userInfoPane.html]
horacebury
  • Corona Geek

  • 3,070 posts
  • Corona SDK

I have a really lovely shadow behind an interface element, generated using just a circle and a radial fill:

 

2019-02-05_1300.png

local shadow = display.newCircle( 100, 100, 50 )
shadow.alpha = .25

shadow.fill.effect = "generator.radialGradient"

shadow.fill.effect.color1 = { .5,.5,.5, 1 }
shadow.fill.effect.color2 = { 0,0,0, 0 }
shadow.fill.effect.center_and_radiuses  =  { 0.5, 0.5, 0.1, .5 }
shadow.fill.effect.aspectRatio  = 1

local circle = display.newCircle( 100, 100, 25 )

I'm trying to get the same effect for other shapes, but having no luck.

 

I figured putting a black rectangle in front of a large white rectangle, grabbing it with a capture and applying a blur would do it, but (at least on Windows) this is doing nothing at all.

local g = display.newGroup()
g.x, g.y = 400, 400
local back = display.newRoundedRect( g, 0, 0, 450, 450, 50 )
local front = display.newRoundedRect( g, 0, 0, 400, 400, 50 )
front.fill = {0,0,0}

timer.performWithDelay( 300, function()
local combined = display.newSnapshot( 500, 500 )
combined.group:insert( g )
combined.x, combined.y = 400, 400
combined:invalidate()
combined.fill.effect = "filter.blurGaussian"
 
combined.fill.effect.horizontal.blurSize = 20
combined.fill.effect.horizontal.sigma = 140
combined.fill.effect.vertical.blurSize = 20
combined.fill.effect.vertical.sigma = 140
end )

Has anyone had any luck with this sort of effect?



[TOPIC: post.html]
#2

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,373 posts
  • Corona SDK

 

I figured putting a black rectangle in front of a large white rectangle, grabbing it with a capture and applying a blur would do it

 

conceptually yes, and nearly there, but the foreground object doesn't belong in the blurred snapshot, fe (somewhat unconventional indentation used to help illustrate create vs modify portions):

-- for convenience:
local ACW, ACH = display.actualContentWidth, display.actualContentHeight
local CCX, CCY = display.contentCenterX, display.contentCenterY
local RECTWH, RECTR, BLURR = ACW/2, ACW/10, ACW/10

-- a background to "notice" the shadow against:
local bkgnd = display.newRect(CCX,CCY,ACW,ACH)
  bkgnd.fill.effect = "generator.linearGradient"
  bkgnd.fill.effect.color1 = { 0.1,0.2,0.3,1 }
  bkgnd.fill.effect.color2 = { 0.6,0.8,1.0,1 }

-- a black rect to use as basis for shadow blur
local shade = display.newRoundedRect(0,0,RECTWH,RECTWH,RECTR)
  shade:setFillColor(0,0,0)

-- a snapshot large enough to hold the black rect and its blur
local shadow = display.newSnapshot(RECTWH+BLURR*2,RECTWH+BLURR*2)
  shadow.group:insert(shade)
  shadow.fill.effect = "filter.blurGaussian"
  shadow.fill.effect.horizontal.blurSize = BLURR
  shadow.fill.effect.vertical.blurSize = BLURR

-- a foreground rect to cover up shadow's basis
local front = display.newRoundedRect(0,0,RECTWH,RECTWH,RECTR)
  front:setFillColor(1,0.9,0.8)

-- the whole set of things needed to accomplish the overall effect:
local combined = display.newGroup()
  combined:insert(shadow)
  combined:insert(front)
  combined:translate(CCX,CCY)



[TOPIC: post.html]
#3

horacebury

[GLOBAL: userInfoPane.html]
horacebury
  • Corona Geek

  • 3,070 posts
  • Corona SDK

So you're putting the black rectangle in the snapshot and blurring that. Nice.

 

My approach was assuming that the black portion needed an area to blur into, hence the white rectangle.

 

I've done this before but can't find the code and thought perhaps Windows didn't like the Gfx2.0 mechanism. (Don't have my usual mac here.)



[TOPIC: post.html]
#4

horacebury

[GLOBAL: userInfoPane.html]
horacebury
  • Corona Geek

  • 3,070 posts
  • Corona SDK

I've not tried your code yet, but this is what I've just worked out after reviewing a piece of my old code:


local g = display.newGroup()
g.x, g.y = display.actualCenterX, display.actualCenterY
display.newRect( g, 0, 0, 600, 600 )
display.newRoundedRect( g, 0, 0, 300, 300, 50 ).fill = {1,0,0}

local function blur( group, removeOriginal )
	local capture = display.capture( group, { saveToPhotoLibrary=false, captureOffscreenArea=false } )
	capture.x, capture.y = group.x, group.y
	capture.fill.effect = "filter.blurGaussian"
	capture.fill.effect.horizontal.blurSize = 512
	capture.fill.effect.horizontal.sigma = 512
	capture.fill.effect.vertical.blurSize = 512
	capture.fill.effect.vertical.sigma = 512
	if (removeOriginal) then group:removeSelf() end
	return capture
end

local function greyed( group, removeOriginal )
	local capture = display.capture( group, { saveToPhotoLibrary=false, captureOffscreenArea=false } )
	capture.x, capture.y = group.x, group.y
	capture.fill.effect = "filter.grayscale"
	if (removeOriginal) then group:removeSelf() end
	return capture
end

timer.performWithDelay( 500, function()
	local blurred = blur(g, true)
	blurred = blur(blurred, true)
	blurred = blur(blurred, true)
	blurred = blur(blurred, true)
	local greyed = greyed(blurred, true)
	greyed.alpha = .3
end, 1 )



[TOPIC: post.html]
#5

horacebury

[GLOBAL: userInfoPane.html]
horacebury
  • Corona Geek

  • 3,070 posts
  • Corona SDK

OK, bit of an improvement here. Some points of note:

 

1. a background is required to avoid distortions in the captures (as well as rendering the blur)

2. a timer delay does not appear to be required (but is wise regardless)

 

This code requires a display group to apply the shadow to because it will generate the shadow and insert it at the bottom of the group.

local lib = {}

--[[
	Shadow constructor. Takes a display group and optional colour match to the background.
	Renders a shadow
	Params:
		group: Requires that the object the shadow is generated for is a display group.
		backgroundColour: The colour that the shadow should be rendered to.
		spread: Amount the blur is rendered by to increase its spread.
		alpha: The alpha value of the blur. Default is 1.
		notgrey: True if the shadow should be coloured like the group. Default is false.
	Returns:
		The shadow which is inserted into the group is returned, but will have index 1 anyway.
]]
function lib.new( group, backgroundColour, spread, alpha, notgrey )
	local backed = lib.back(group, backgroundColour, spread)

	local blurred = lib.blur(backed, true, spread or 0)
	if (notgrey == nil or notgrey) then blurred = lib.greyed(blurred, true) end
	blurred.alpha = alpha or 1

	local x, y = lib.shadowLocation( group )
	group:insert( 1, blurred )
	blurred.x, blurred.y = x, y

	return blurred
end

--[[ SUPPORTING FUNCTIONS ]]

function lib.cap( group )
	local capture = display.capture( group, { saveToPhotoLibrary=false, captureOffscreenArea=true } )
	capture.x, capture.y = group.x, group.y
	return capture
end

function lib.shadowLocation( group )
	local x, y = (group.contentBounds.xMin+group.contentBounds.xMax)/2, (group.contentBounds.yMin+group.contentBounds.yMax)/2
	return group:contentToLocal( x, y )
end

function lib.back( group, colour, spread )
	local x, y = lib.shadowLocation( group )
	local rect = display.newRect( group, x, y, group.width+(150*(spread or 1)), group.height+(150*(spread or 1)) )
	rect:toBack()
	rect.fill = colour or {1,1,1}

	local c = lib.cap( group )

	rect:removeSelf()

	return c
end

function lib.blur( group, removeOriginal, count )
	local capture = lib.cap( group )
	capture.fill.effect = "filter.blurGaussian"
	capture.fill.effect.horizontal.blurSize = 512
	capture.fill.effect.horizontal.sigma = 512
	capture.fill.effect.vertical.blurSize = 512
	capture.fill.effect.vertical.sigma = 512
	if (count > 0) then
		capture = lib.blur( capture, true, count-1 )
	end
	if (removeOriginal) then group:removeSelf() end
	return capture
end

function lib.greyed( group, removeOriginal )
	local capture = lib.cap( group )
	capture.fill.effect = "filter.grayscale"
	if (removeOriginal) then group:removeSelf() end
	return capture
end

--[[ DEMO ]]

local a = display.newGroup()
a.x, a.y = display.actualCenterX, display.actualContentHeight*.25
display.newRoundedRect( a, 0, 0, 300, 300, 50 ).fill = {1,0,0}

local b = display.newGroup()
b.x, b.y = display.actualCenterX-150, display.actualContentHeight*.5-150
display.newRoundedRect( b, 150, 150, 300, 300, 50 ).fill = {0,0,1}

local d = display.newGroup()
d.x, d.y = display.actualCenterX+150, display.actualContentHeight*.75
display.newRoundedRect( d, -150, 0, 300, 300, 50 ).fill = {0,1,0}

local c = {.96}

lib.new( a, c, 2 )
lib.new( b, c, nil, nil, false )
lib.new( d, c, nil, 1 )

return lib




[topic_controls]
[/topic_controls]