Simple shadows

Blitz3D Forums/Blitz3D Programming/Simple shadows

big10p(Posted 2004) [#1]
Hi

My game has a small, rectangular mesh level (22x13 units), and I'm doing simple 'blob' shadows by texturing the mesh with 512x512 shadow map.

This looks OK but the shadows still look a bit too blocky for my liking. I don't really want to use a bigger texture (is 512x512 too big even, for some cards?).

Anyone have any tips on getting better looking shadows?

I saw sswifts demo and his shadows seem to be of a much higher resolution. Wonder how he does that? I think he might be using quads for the separate shadows but I've no idea how he gets them to hug the geometry. :/

Unfortunately, I cant afford to get swwifts system at the mo, and not sure whether it would be suitable for my needs, anyway - my level has 135 'fruit' on them, all of which need a drop-shadow.

BTW, I only need shadows to be cast on the level mesh, not any other geo.

As always, any help most welcome. :)


Bot Builder(Posted 2004) [#2]
Yeah, sswifts shadow system works by hugging the geometry of the level mesh, then texturing the shadow triangles with the shadow. Many systems use a small camera render of the object to do this from the lights perspective.

In sswifts shadow system you can also use a texture from a file to avoid the lag of an extra render.


big10p(Posted 2004) [#3]

Many systems use a small camera render of the object to do this from the lights perspective.



I tried this method, also. Unfortunately, the required CopyRect KILLED the framerate on one of my machines - didn't realize CopyRect was THAT slow. :/

Also, because I'm using a 512x512 texture, I can't run my game in 640x480 mode as Blitz (or DX) won't let me render to a buffer with a dimension bigger than the screen res. Not to mention the prob of doing a black & white render for the shadow map. So I ditched that idea. :)


TartanTangerine (was Indiepath)(Posted 2004) [#4]
Have you looked in the code archives, there are lots of quick and dirty shadow systems there that do the job just great.


fredborg(Posted 2004) [#5]
Maybe this one will do: http://www.blitzbasic.com/codearcs/codearcs.php?code=1010

:)


jfk EO-11110(Posted 2004) [#6]
Contrary to popular belief, sswifts shadowsystem doesn't consume a lot of time with rendering or copyrect to textures, but the most of the time is used in the "huggin algorithms". I tried to comment out the renderworld and copyrect commands, and the framerate didn't increase remarkably.

It's a nice library, but if you want to use it for 135 individual shadow casters, then - forget about it. Sswifts shadow system will be slowed down by several factors: number of shadow casters, number of lights and size (polycount) of the shadow-receiver(s).

I am using his system in my FPS engine. I have a 15k Tris static Level that is the main Shadow Receiver. I had to work out a solution that will create an invisible copy of the near-camera Tris on the fly from time to time to be "hugged" by the shadowsystem, because the diffrence from 15kTris and 1kTris is about twice the framerate.

If you have 135 Fruits on a small area, you better use 1 or maybe a grid of renders for all of them instead of a render for each fruits shadow.


John Pickford(Posted 2004) [#7]
How is this 'hugging' achieved without Z fighting?


AntonyWells(Posted 2004) [#8]
You have a variable Z_polygon offset, no z-fighting.

I suggest getting it too, it works great, and is fast on my p-800 even casting shadows from 3 1000 poly+animated models+seperate guns casting shadow, all onto a full map..full game running too, and still runs at a playable rate.

plus for your situration it has static texture shadow casters(or something like that)..you can give it that oval thing in a texture map and it casts that.


John Pickford(Posted 2004) [#9]
You mean you place the polygons slighltly above the surface? Won't that go wrong at a distance?


big10p(Posted 2004) [#10]
Yeah, I've had a look at some shadow stuff in the archives but I don't think the methods are suitable for my situation. I need speed over quality. (Fredborg: I don't think your code is working on my machine because I just get a mass of swirling black and grey blobs. It's probably my old GeForce 256, on this machine. I'll have a look at the code and try and see what method you're using. Thanks.)

I just require simple 'blob' shadows to show directly underneath stuff as a visual aid to tell where stuff is in 3D-space. I'm simply converting entity coords into texture coords and using Oval to draw a blob at that point. I guess this is the method I'm going to have to stick with - they just look a bit blocky.

It's a nice library, but if you want to use it for 135 individual shadow casters, then - forget about it.

Ah, I did think it might not be suitable for my needs. Oh, well.

You mean you place the polygons slighltly above the surface? Won't that go wrong at a distance?


I'm actually using this method for something else in my game and find that I need to offset stuff by as much as .01 to stop z-fighting. I was a bit surprised that it needed to be this much, frankly.


Dreamora(Posted 2004) [#11]
For this situation, the Sswift shadow would perhaps work.
It has 3 different types of shadow casting

-Real shadow using shadow volumes
-using a premade shadow that is put onto a correctly aligned "covering" mesh
-static shadow, which are precalculated ( like calculating lightmap but using a mesh for the shadow which doesn't suffer in quality on large shadow receivers )


jfk EO-11110(Posted 2004) [#12]
As I said before, sswifts system uses a lot of power by aligning the quads to the normals of the receiver. Using static shadows won't make it much faster. Of course, it is a good library, I bought it too, and I highly respect its quality, especially since the "hugging" Algoritm was way beyond my horizon, but for this 135 fruits situation it may mot be the best solution, if you really need the shadows do be ONLY underneath the fruits.

Using the Oval Command is not so clever, since it's a slow command. Better draw an image that contains your Oval.

If the texture is smaller, then the oval will be blurred due to texture filtering, and it may look less blocky.

There is still the renderworld option to create your shadowmap. Think about to use an isometric CameraProjMode for this!

A further option would be to use a sprite or quad underneath each fruit, aligned to the ground.

Maybe you should post a screenie of the scene, so we see what it is about.


MSW(Posted 2004) [#13]
Why not just draw up a 32 by 32 (or even 64 by 64) texture with a darkened circle in the center...create a rectangle mesh from two polygons apply the "shadow" texture...and place it under each fruit aligned to the normal of the "ground" below it...If the fruits move around the level you can use a line pick from the fruit to the ground to find where to place the shadow (if the ground height varies like on a terrain) or just make the fruit a child of the shadow...then you can animate the fruit bounceing around and whatnot but keep the shadow under it without all the complexity of linepicks and such.


TeaVirus(Posted 2004) [#14]
What I've found works well is storing the pixels for your lightmap in an array. You then "draw" your shadows to the lightmap array, blur the pixels as many times as you need, then WPF the pixels to your texture. Here is the piece of code that I use to do this:

 
For n=0 To LMBlur	;number of blur operations to apply
	For y=1 To LMscrH-2		;height of lightmap array
		For x=1 To LMscrW-2		;width of lightmap array
			c=LMbuffer(x,y)
			If (c And $FFFFFF) > 0
				c1=LMbuffer(x-1,y)	
				c2=LMbuffer(x+1,y)
				c3=LMbuffer(x,y+1)
				c4=LMbuffer(x,y-1)
				r=c Shr 16 And $FF : g=c Shr 8 And $FF : b=c And $FF
				rl=c1 Shr 16 And $FF : gl=c1 Shr 8 And $FF : bl=c1 And $FF
				rr=c2 Shr 16 And $FF : gr=c2 Shr 8 And $FF : br=c2 And $FF
				rd=c3 Shr 16 And $FF : gd=c3 Shr 8 And $FF : bd=c3 And $FF
				ru=c4 Shr 16 And $FF : gu=c4 Shr 8 And $FF : bu=c4 And $FF
				rd=((r Shl 1)+(rl+rr+rd+ru) Shr 1)Shr 2
				gr=((g Shl 1)+(gl+gr+gd+gu) Shr 1)Shr 2
				bl=((b Shl 1)+(bl+br+bd+bu) Shr 1)Shr 2
				LMbuffer(x,y)=(((rd Shl 8)+gr) Shl 8)+bl
			EndIf
		Next
	Next
Next

buf=TextureBuffer(LMtex)
LockBuffer buf
For y=0 To LMscrH-1
	For x=0 To LMscrW-1
		xx=lmbox+x : yy=lmboy+y
		If xx<LMtexW And YY<LMtexH
			WritePixelFast lmbox+x,lmboy+y,LMbuffer(x,y),buf
		EndIf
	Next
Next
UnlockBuffer buf


I'm not sure that this is the best way but if I only update my lightmap every 2-3 frames and the texture isn't too big it's pretty fast even with a lot of blurring passes. Plus, it looks really nice!


Rob(Posted 2004) [#15]
it's horrendiously slow on my pc so therefore I use a towel mesh and just cast local shadows onto it.


big10p(Posted 2004) [#16]

Using the Oval Command is not so clever, since it's a slow command. Better draw an image that contains your Oval.

If the texture is smaller, then the oval will be blurred due to texture filtering, and it may look less blocky.

I'll give this a shot later, cheers.

There is still the renderworld option to create your shadowmap. Think about to use an isometric CameraProjMode for this!

As I mentioned in an above post, I've given this a try, also. I dumped the idea for the reasons above.

A further option would be to use a sprite or quad underneath each fruit, aligned to the ground.

This (same as what MSW is also suggesting, I think) would probably work for the fruit as they never move and are situated always on flat ground. However, the dynamic stuff (player, enemies, etc.) can go up and down hills - the level is terraced - so I would need a way to make the quad hug the level geo. :/

Maybe you should post a screenie of the scene, so we see what it is about.

OK, I'll do that later - I'm not on my home machine at the mo.

Tea virus: I think that method maybe too slow for my needs - I really need to update the shadow map every frame else the shadows will lag behind the entities.

Thanks for all the input, folks!

I'll get back to this when I get home. :)


sswift(Posted 2004) [#17]
"For this situation, the Sswift shadow would perhaps work.
It has 3 different types of shadow casting

-Real shadow using shadow volumes
-using a premade shadow that is put onto a correctly aligned "covering" mesh
-static shadow, which are precalculated ( like calculating lightmap but using a mesh for the shadow which doesn't suffer in quality on large shadow receivers )"


My system does not do "shadow volumes". The first mode, the dynamic shaodws, are created by rendering shadow textures using the entity casting the shadow. It does this only when the shadow changes enough to need to be updated, for speed.


"As I said before, sswifts system uses a lot of power by aligning the quads to the normals of the receiver. Using static shadows won't make it much faster."


If you are referring to textured shadows... an unchanging texture projected onto a surface dynamically... Then that will improve speed if your card is fill rate limited.

If however you are reffering to static shadows... Which in my system are shadows which are cast once, and never updated again, then you are wrong. Static shadows create a mesh, and a texture and then do not update them further. Obviously these only work when cast onto non moving goemetry like a level. But they're extremely fast, so long as you don't let a hundred of them get in view at once, as each is an entity.


jfk EO-11110(Posted 2004) [#18]
No, I meant textured shadows. I just checked the time it uses without rendering and copyrectangles and I saw that it's using the most of the time for other things, like parsing the receivers Polygons and caculate normals etc.

Fortunately it was pretty easy to clone the surrounding part of the level geometry and let your system parse it instead of the entire level mesh.
Btw. I had some problems with the Falloff parameters. It seems this is (receiver-)Vertex-based. With big Triangles this may produce artifacts. Isn't there a way to simply use the distance from the light to the shadow quad to set the opaqueness of the shadow quad, using the same tone for all 4 vertices of the quad?


big10p(Posted 2004) [#19]
OK, I tried using DrawImage to put the shadows onto the map instead of Oval/Rect but it seems to be slower! I also had to turn off flag 256 (VRAM) because DrawImage didn't work with it on - didn't get an error, just nothing gets drawn to the texture!? These are the FPS scores I got for the different tests:
- Using Oval/Rect with flag 256 set : 109
- Using Oval/Rect with flag 256 NOT set : 105
- Using DrawImage with flag 256 NOT set : 82
Why does Rect/Oval work with flag 256 but not DrawImage?

Anyway, here's a couple of screenies. Please note this is only test code so ignore the (lack of) models/textures! :P

This is going to be the game's default camera setting. It's so far away that the quality of the shadows isn't too apparent. However, I also plan to have an alternative camera mode that follows the player at a much closer range.


The red cone is the player; the pink ball is a player weapon to throw at enemies; the yellow dots are the 'fruit'; the brown cylinder is a log which can be rolled over enemies to squish them. :)



Trixx(Posted 2004) [#20]
Oh, no ! You are also working on a clone of "Do! Run Run" !
I started mine 4 months ago... Now I must hurry up to finish it first :)
In my version, which, by the way looks almost identical to yours, all shadows are part of one surface. When I add a shadow, I add a textured quad to shadow surface and remember vertex indexes for that shadow. Then, when players/enemies move, I manually update positions of vertices that belong to that shadow. This is the fastest solution. Only problem is sloped parts of the terrain, but slopes are always on fixed angle, so that is also not very hard to do.


jfk EO-11110(Posted 2004) [#21]

I tried using DrawImage to put the shadows onto the map instead of Oval/Rect but it seems to be slower!



Oops :)


sswift(Posted 2004) [#22]
"Isn't there a way to simply use the distance from the light to the shadow quad to set the opaqueness of the shadow quad, using the same tone for all 4 vertices of the quad?"

I'm not sure what exactly you're talking about and right now I am starving and can't think. But I did update the system quite a while ago to clip the polygons that fall in the shadow volume so the size of the tris that the shadow falls on should not affect its appearance any more. And the falloff... That's caluclated per vertex. And the shadows are not projected onto quads, they are projected onto arbitrary shapes that look like a quad from the view of the light source, but in actuality, are often no such thing.


big10p(Posted 2004) [#23]
Oh, no ! You are also working on a clone of "Do! Run Run" !

[extreme echo]
NOOOOOOOOOOoooooooooo!!!!!!!!!!!!
[/extreme echo]
lol. I don't believe it! I thought Do! Run Run was too obscure a game for anyone else to be doing. *sound of heart sinking* :)

I started mine 4 months ago... Now I must hurry up to finish it first :)

Heh, you've got a 4 month jump on me so I guess we'll being seeing yours first. ;) I haven't even started the game code yet; I'm still just doing test code to work out the best way to do things.

Have you done animated models of Mr. Do etc., yet? I'd love to see how yours is coming along - any chance of a screenie or even a demo?

In my version, which, by the way looks almost identical to yours, all shadows are part of one surface. When I add a shadow, I add a textured quad to shadow surface and remember vertex indexes for that shadow. Then, when players/enemies move, I manually update positions of vertices that belong to that shadow. This is the fastest solution. Only problem is sloped parts of the terrain, but slopes are always on fixed angle, so that is also not very hard to do.

I toyed with using this method also but figured it would be a pain when the shadow is half on a slope. i.e. in the second screenie above, the players shadow is half on the flat ground and half on the slope. How are you handling that?


sswift(Posted 2004) [#24]
A game like this, with overhad shaodws is how my own shadow system came about.

Imagine looking at the map from above.

Imagine a circle that defines your shadow. Now imagine a square that contains that circle.

Now find all triangles which intersect that square in the mesh. A quick dirty method is to simply discard all triangles which have all vertcies on one side of any one of the four lines that make up your square.

This will miss some tris... allow some outside the square to remain, but this is not a problem...

Now load your shaodw texture. Set it to have UV clamping and make sure the edges of the texture are white.

Now, project the vertcies of the triangle onto your square. Ie, if a vertex is near the top left corner of the square, it's texture cooridnate is 0,0. And if it is near the lower right, it's coordinates are 1,1. You will have to scale the world cooridnates of the verts down using the size of the square to get these 0..1 cooridnate for uv mapping.

Now you have your vertex UV cooridnates. Vertices outsite the square which are included for those triangle partly outside the square or mistakenly included will be outsidee this range. Normall this could cause the textue to tile. But the UV clamping prevents that, so these areas will appear transparent.

Finally, build a mesh that is slightly above the surface with all the tringles that were intersecting the square that you just computeed the texturee cooridnates for. Then set thismesh to multiply. And voila, one texture projected onto your mesh to make a shadow.

Or you can spend $20 and have all the work done for you by my shadow system. :-)


big10p(Posted 2004) [#25]
Interesting and thanks for sharing. Sounds like alot of work, though - is there much complex math involved?


John Pickford(Posted 2004) [#26]
'complex maths'

$20 is about 11 quid.

;-)


Trixx(Posted 2004) [#27]
Have you done animated models of Mr. Do etc., yet? I'd love to see how yours is coming along - any chance of a screenie or even a demo?

I have players and several creature models done, but they are not the same models as in the original game. I hope that I'll have a playable beta in a month or two :)

I toyed with using this method also but figured it would be a pain when the shadow is half on a slope. i.e. in the second screenie above, the players shadow is half on the flat ground and half on the slope. How are you handling that?

When the shadow is on the slope, I add another quad for the sloped part of the shadow, so the shadow at that time consist of two quads . Then I update the UV coords of each of the two parts , to split the shadow correctly. As I say, this is possible because all slopes are always on fixed angle, and this is not ideal solution but is very fast. But what sswift say, seems better and is more universal solution, so you can go that way too.
Anyway, good luck, and post some new screenies when you can !


sswift(Posted 2004) [#28]
"is there much complex math involved?"

Much less for lights casting straight down than for lights casting at any angle. I think you could do it. No vector stuff or anything like that. Just scaling coordinates and checking to see if a coordinate is greater or less than an X or Z value.

Ps:
No email questions please. :-)


big10p(Posted 2004) [#29]
$20 is about 11 quid.

OK, I get the message. :) I'd like to see if I can come up with a solution, first. Not to mention I am VERY broke at the moment. :/

Trixx: Cheers! I look forward to seeing the fruits of your labours, too. ;)

Ps:
No email questions please. :-)

Slam the door in my face, why dontcha!? Charming! :P


sswift(Posted 2004) [#30]
Big:
I didn't say don't ask questions on the forums. :-) But I get people emailing me and asking stuff all the time and a lot of the time I'd rather they ask on the forums, so that others might answer their question, or so that more than one person can benefit from the answer. :-)

Plus I don't feele entrapped into having to spend hours debugging your code if I don't feel like it. :-)


big10p(Posted 2004) [#31]
lol. I was only joking! I would use the forums for questions anyway as I know how time consuming (not to mention a little annoying) it can be answering peoples emails all the time. :)

Cheers!


John Pickford(Posted 2004) [#32]
I was kidding too of course. I'd rather figure things out for myself too. I'm sure Shawns code is excellent of course.