solved uniform shadows to make your menu UI POP

Showcase your libraries, tools and other projects that help your fellow love users.
Post Reply
AxisAngles
Prole
Posts: 12
Joined: Mon Feb 22, 2016 9:02 am

solved uniform shadows to make your menu UI POP

Post by AxisAngles » Fri Mar 11, 2016 12:38 am

So I solved a little double integral to see how much light gets to a point, assuming you have a hemisphere of infinite size where light is coming in uniformly from all directions except the circular base, and a rectangle on a plane aligned with the base of that hemisphere. The result is pretty awesome.

demos are attached.
Image

code:

Code: Select all

--local r=rectshadow.new([height],[posx],[posy],[sizex],[sizey])
--You can set r.h, r.px, r.py, r.sx, r.sy
--In order to delete a rectangle shadow, just do r:remove()

--What do you have to do to add this?
--For each button, make a new rectangle shadow with its pixel dimensions and height.
--	DO NOT MAKE A NEW ONE EACH FRAME, ONLY HAVE AS MAKE RECTANGLE OBJECTS AS YOU HAVE BUTTONS OR WHATEVER

--Each time you change the position of a rectangle button or frame or whatever, set r.px and  r.py to change the position of the shadow thing.

--Draw all of your stuff to a canvas, for example lolcanvas, instead of the screen.

--Then when you want to finalize your UI (probably the last step in your render process)
--	call the rectshadow.draw(lolcanvas,outcanvas)
--	leave outcanvas to nil to have it draw directly to the screen

local rectshadow do
	rectshadow={}
	local setmt=setmetatable
	local unpack=unpack

	local getshader=love.graphics.getShader
	local getcanvas=love.graphics.getCanvas
	local setshader=love.graphics.setShader
	local setcanvas=love.graphics.setCanvas
	local draw=love.graphics.draw

	local nrects=0
	local rects={}
	local htab={}
	local ptab={}

	function rectshadow.new(h,px,py,sx,sy)
		local rect={
			update=true;
			i=0;
			h=h or 0;
			px=px or 0; py=py or 0;
			sx=sx or 0; sy=sy or 0;
		}

		local meta={}
		local funcs={}

		function meta:__newindex(i,v)
			rect[i]=v
			rect.update=true
		end
		meta.__index=rect

		local removed=false
		function funcs:remove()
			if not removed then
				removed=true
				local i=rect.i
				rects[nrects].i=i
				rects[i]=rects[nrects]
				htab[i]=htab[nrects]
				ptab[i]=ptab[nrects]
				nrects=nrects-1
			end
		end

		nrects=nrects+1
		rects[nrects]=rect
		htab[nrects]=h or 0
		ptab[nrects]={
			px or 0,py or 0,
			(px or 0)+(sx or 0),
			(py or 0)+(sy or 0)
		}
		rect.i=nrects

		return setmt(funcs,meta)
	end

	local uniformshadowshader=love.graphics.newShader([[
		extern number w;
		extern number h;
		//Must be sorted based on height from least to greatest
		extern float height[64];
		//Stores upper left corner in xy, lower right corner in zw
		extern vec4 pos[64];
		extern number n;

		//idk lol.
		float lightfromarea(in float x0,in float y0,in float x1,in float y1){
			float sx0=inversesqrt(1+x0*x0);
			float sy0=inversesqrt(1+y0*y0);
			float sx1=inversesqrt(1+x1*x1);
			float sy1=inversesqrt(1+y1*y1);
			float atx0=atan(sx0*y0)-atan(sx0*y1);
			float atx1=atan(sx1*y1)-atan(sx1*y0);
			float aty0=atan(sy0*x0)-atan(sy0*x1);
			float aty1=atan(sy1*x1)-atan(sy1*x0);
			return 0.15915494*(sx0*x0*atx0+sx1*x1*atx1+sy0*y0*aty0+sy1*y1*aty1);
		}

		//As long as stuff doesn't overlap, it's exactly correct.
		vec4 effect(vec4 colorin,Image texturein,vec2 posin, vec2 pixelin){
			float px=w*posin.x;
			float py=h*posin.y;

			float besth=0;

			for(int i=0;i<n;i++){
				if(
					besth<height[i]
					&&pos[i].x<=px
					&&pos[i].y<=py
					&&px<=pos[i].z
					&&py<=pos[i].w
				){
					besth=height[i];
				}
			}

			float br=1;

			for(int i=0;i<n;i++){
				float dheight=height[i]-besth;
				if(0<dheight){
					br-=lightfromarea(
						(pos[i].x-px)/dheight,
						(pos[i].y-py)/dheight,
						(pos[i].z-px)/dheight,
						(pos[i].w-py)/dheight
					);
				}
			}

			return max(0,br)*Texel(texturein,posin);
		}
	]])

	function rectshadow.draw(incanvas,outcanvas)
		uniformshadowshader:send("n",nrects)
		if 0<nrects then
			for i=1,nrects do
				local rect=rects[i]
				if rect.update then
					rect.update=false
					htab[i]=rect.h
					local p=ptab[i]
					p[1]=rect.px
					p[2]=rect.py
					p[3]=rect.px+rect.sx
					p[4]=rect.py+rect.sy
				end
			end
			--Is there a less shitty way of doing this?
			--I'd like to do :send("height[5]",x)
			uniformshadowshader:send("height",unpack(htab))
			uniformshadowshader:send("pos",unpack(ptab))
		end

		local w,h=incanvas:getDimensions()
		uniformshadowshader:send("w",w)
		uniformshadowshader:send("h",h)

		local lastshader=getshader()
		local lastcanvas=getcanvas()

		setshader(uniformshadowshader)
		setcanvas(outcanvas)
		draw(incanvas)

		setshader(lastshader)
		setcanvas(lastcanvas)
	end
end
Attachments
uniformshadows e ix demo.love
(2.42 KiB) Downloaded 120 times
uniformshadows click demo.love
(2.6 KiB) Downloaded 124 times

User avatar
ivan
Party member
Posts: 1328
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: solved uniform shadows to make your menu UI POP

Post by ivan » Fri Mar 11, 2016 7:16 am

Runs very slow on my old 64-bit Core2 Duo laptop.
Looks pretty good though I think this sort of effect
could be achieved using a couple of transparent textures and setColor.
Here my ugly 36-line version without the shaders and tweening.
Attachments
colorpicker.love
(551 Bytes) Downloaded 103 times

AxisAngles
Prole
Posts: 12
Joined: Mon Feb 22, 2016 9:02 am

Re: solved uniform shadows to make your menu UI POP

Post by AxisAngles » Fri Mar 11, 2016 8:01 am

Okay yeah, it is a bit ridiculous to be running approximately 512 atans and 256 inversesqrts per pixel per frame.

Image

Of course, it could be worse. I could be integrating over the pixel

Image

I'll work on making it faster.

User avatar
Nuthen224
Citizen
Posts: 50
Joined: Sun Jul 28, 2013 9:40 pm

Re: solved uniform shadows to make your menu UI POP

Post by Nuthen224 » Sat Mar 12, 2016 4:42 pm

It looks very cool!

User avatar
DanielPower
Citizen
Posts: 50
Joined: Wed Apr 29, 2015 5:28 pm

Re: solved uniform shadows to make your menu UI POP

Post by DanielPower » Thu Mar 17, 2016 9:09 pm

It looks cool, but is extremely inefficient. Runs at about 1 frame every 5 seconds with integrated graphics on a core i7. Whether or not it runs at an acceptable frame rate on dedicated graphics, I cannot say. But to put such a strain on the hardware for a simple effect is wasteful.

Will test on my gaming rig later.

User avatar
zorg
Party member
Posts: 2379
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: solved uniform shadows to make your menu UI POP

Post by zorg » Thu Mar 17, 2016 9:17 pm

It does run decently on my rig, GTX 960.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.

AxisAngles
Prole
Posts: 12
Joined: Mon Feb 22, 2016 9:02 am

Re: solved uniform shadows to make your menu UI POP

Post by AxisAngles » Thu Aug 30, 2018 12:48 am

Just realized it uses 70% of my GTX1080Ti running at 240fps. I had no idea.

Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests