Answered by:
Dynamic Shadows! WOO!!
Question

hi guys! i just coded dynamic shadows in SB! looks really awesome! but its not done..
heres the import code: VMM615
move the lightsource with the arrow keys.
its still got some bugs, but i'll fix them.
i made that using the turtle cuz im too stupid to use trigonometry... i learned in school how to use it, but i forgot it... can someone tell me how to do this with trigonometry instead of using the turtle? it would run much better then..
i just need to find the point, where the shadow starts on the floor. for example: a "sunray" is coming from the lightsource and is going to the an edge of the Box. And going in that angle to the floor. and i need to find that point, where the "sunray" is touching the floor, so it can create a triangle with one edge on that point, one on one of the lower corners of the box and one on the top corner of the box.
i hope you guys understand what i need..
Live for nothing, OR CODE FOR SOMETHING! (Happy now vijaye?^^)
Answers

Try the following import CXM437 as an idea method, but the screen clearing may be an issue for any game. Its nothing other than the geometry shown above, just treating the various cases carefully, sun above, below, etc.
 Marked as answer by Dudeson Monday, October 19, 2009 9:29 PM
All replies


You don't need any trigonometric formula here. You simply need to use similarity.
B = b * (H/h)
C = a * (H/h)
You also must note there's two shadows if the sun is just over the house.
If the sun is below the top of the house, the shadow should be so :
In this case, you'll need a triangle + a rectangle.
Fremy  Developer in VB.NET, C# and JScript ...  Feel free to try my extension Proposed as answer by FremyCompany [MSFT] Friday, August 28, 2009 10:25 PM
 Marked as answer by litdevModerator Tuesday, September 15, 2009 8:43 PM
 Unmarked as answer by Dudeson Sunday, October 11, 2009 10:52 PM


You don't need any trigonometric formula here. You simply need to use similarity.
B = b * (H/h)
C = a * (H/h)
You also must note there's two shadows if the sun is just over the house.
If the sun is below the top of the house, the shadow should be so :
In this case, you'll need a triangle + a rectangle.
Fremy  Developer in VB.NET, C# and JScript ...  Feel free to try my extension
Live for nothing, OR CODE FOR SOMETHING! (Happy now vijaye?^^) 

I think Fremy's similar triangle formulae are right. Another way to work it out is with vectors.
The sun is at (Sx,Sy ) and a box corner is at (Bx,By ) and the shadow hits the ground at (Dx,Dy ).
A straight line is defined by y = A*x+B
The sun and the box top both lie on this line, so Sy = A*Sx+B and By = A*Bx+B
We can solve these for A and B by subtracting the second from the first.
SyBy = A*(SxBx) => A = (SyBy)/(SxBx) and therefore B = SyA*Sx
When we know A and B (from above) , we can find Dx, since we know this point must be on the same line and have Dy = gh, hence:
Dy = gh = A*Dx+B => Dx = (ghB)/A
Putting this together:
Dx = (gh(SyA*Sx))/A = (ghSy)/A+Sx => Dx= (ghSy)*(SxBx)/(SyBy)+Sx and Dy = gh
So if the sun is at (Sx,Sy) and a box corner is at (Bx,By), then the shadow will hit the ground at (Sx+(ghSy)*(SxBx)/(SyBy),gh ), assuming the sun is above the box.
We need to check two corners (Bx1,By) and (Bx2,By) and that Sy < By (the sun is above the box, remembering y increases down). Also we only get a left shadow when Sx > Bx1 and a right shadow when Sx < Bx2.
PS , using Fremy's picture: and the right side shadow:
Dx = Sx+B
h = BySy
H = gySy
b = BxSx
B = b*(H/h) = (BxSx)*(gySy)/(BySy)
Hence Dx= Sx+(BxSx)*(gySy)/(BySy) The same answer Edited by litdevModerator Saturday, August 29, 2009 9:17 AM Add PS



yay! i finally got it working!
man! it took me so long till i found out that the picture for the formula doesnt really fit to the formula you gave me..
H is as big as h in that picture... but h is actually just from the top of the rectangle, to the lightsource... and H is the Heigt... (from the bottom of the rectangle to the lightsource...
works really awesome so far!
heres the import code if you wanna check it out:
XHZ643
btw, i found some amazing 2d dynamic shadow engines! (too bad its not made in SB, but its still awesome)
here you go:
http://www.gamedev.net/reference/articles/article2032.asp
and here at the bottom:
http://forums.xna.com/forums/p/34665/219412.aspx
i think thats extremely awesome! looks so real and stuff!
but that "shadow maze" ,on image Image 9 in the first link, isnt possible to be done in small basic? or is it? (but it would be propably as slow as a slideshow...)
Live for nothing, OR CODE FOR SOMETHING! (Happy now vijaye?^^) 
yay! i finally got it working!
man! it took me so long till i found out that the picture for the formula doesnt really fit to the formula you gave me..
H is as big as h in that picture... but h is actually just from the top of the rectangle, to the lightsource... and H is the Heigt... (from the bottom of the rectangle to the lightsource...
works really awesome so far!
heres the import code if you wanna check it out:
XHZ643
btw, i found some amazing 2d dynamic shadow engines! (too bad its not made in SB, but its still awesome)
here you go:
http://www.gamedev.net/reference/articles/article2032.asp
and here at the bottom:
http://forums.xna.com/forums/p/34665/219412.aspx
i think thats extremely awesome! looks so real and stuff!
but that "shadow maze" ,on image Image 9 in the first link, isnt possible to be done in small basic? or is it? (but it would be propably as slow as a slideshow...)
Live for nothing, OR CODE FOR SOMETHING! (Happy now vijaye?^^)
It already works better.
Two remaining problems :
* It flashes (maybe you should use GraphicsWindow.DrawTriangle instead of AddTriangle, since you need the trianges only one time)
* If the sun is just on the top of the house, your program crash because you try to divide by 0. This is a special case because there's no triangle to show, just a rectangle.
Fremy  Developer in VB.NET, C# and JScript ...  Feel free to try my extension 


GraphicsWindow.FillTriangle(BoxX+50,BoxY,BoxX+50,BoxY+150 ,ShadowRight,BoxY+150 )
should be:
GraphicsWindow.FillTriangle(BoxX+50,BoxY,BoxX+50,BoxY+50 ,ShadowRight,BoxY+50 )
also for the left shadow.
Fixed in XHZ6432  Nice catch BTW!
Fremy  Developer in VB.NET, C# and JScript ...  Feel free to try my extension Edited by FremyCompany [MSFT] Saturday, August 29, 2009 12:21 PM Small bug fix

i know that! i wanted it like that, i was just testing something out!
im working on a new version now. and im gonna chech out your ppls stuff now.
btw, im now trying to do Top down view shadows now, not from the side...
and
filltriangle will have the same effect like addtriangle, but different. if you use filltriangle, the triangle is always under every other object. but if you use addtriangle, you can make other objects be in the shadow.. but having objects hidden in the shadow of an object looks really cool, but if you always see the top of every object, its more logic... im gonna do the version with filltriangle.
Live for nothing, OR CODE FOR SOMETHING! (Happy now vijaye?^^) 

DAMN! i cant GET IT TO WORK!!!!!!!!!! The shadow works really great when the lightsource is ABOVE the box.. but not when its under it... idk how i have to change the variables to work how it should...
heres the code:
PKD858
plz! someone help me!
(btw, the shadows are over the box, because the box is transparent. when the lightsource is above the box, it works great, so please dont change anything there...)
Live for nothing, OR CODE FOR SOMETHING! 

You don't need any trigonometric formula here. You simply need to use similarity.
B = b * (H/h)
C = a * (H/h)
You also must note there's two shadows if the sun is just over the house.
If the sun is below the top of the house, the shadow should be so :
In this case, you'll need a triangle + a rectangle.
Fremy  Developer in VB.NET, C# and JScript ...  Feel free to try my extension
Live for nothing, OR CODE FOR SOMETHING! 
I think Fremy's similar triangle formulae are right. Another way to work it out is with vectors.
The sun is at (Sx,Sy ) and a box corner is at (Bx,By ) and the shadow hits the ground at (Dx,Dy ).
A straight line is defined by y = A*x+B
The sun and the box top both lie on this line, so Sy = A*Sx+B and By = A*Bx+B
We can solve these for A and B by subtracting the second from the first.
SyBy = A*(SxBx) => A = (SyBy)/(SxBx) and therefore B = SyA*Sx
When we know A and B (from above) , we can find Dx, since we know this point must be on the same line and have Dy = gh, hence:
Dy = gh = A*Dx+B => Dx = (ghB)/A
Putting this together:
Dx = (gh(SyA*Sx))/A = (ghSy)/A+Sx => Dx= (ghSy)*(SxBx)/(SyBy)+Sx and Dy = gh
So if the sun is at (Sx,Sy) and a box corner is at (Bx,By), then the shadow will hit the ground at (Sx+(ghSy)*(SxBx)/(SyBy),gh ), assuming the sun is above the box.
We need to check two corners (Bx1,By) and (Bx2,By) and that Sy < By (the sun is above the box, remembering y increases down). Also we only get a left shadow when Sx > Bx1 and a right shadow when Sx < Bx2.
PS , using Fremy's picture: and the right side shadow:
Dx = Sx+B
h = BySy
H = gySy
b = BxSx
B = b*(H/h) = (BxSx)*(gySy)/(BySy)
Hence Dx= Sx+(BxSx)*(gySy)/(BySy) The same answer
im sorry, but this was to complicated for me, that i could use it... (also because of the high english...)
Live for nothing, OR CODE FOR SOMETHING! 
I think Fremy's similar triangle formulae are right. Another way to work it out is with vectors.
Whats A and B? and g!?!?
The sun is at (Sx,Sy ) and a box corner is at (Bx,By ) and the shadow hits the ground at (Dx,Dy ).
A straight line is defined by y = A*x+B
The sun and the box top both lie on this line, so Sy = A*Sx+B and By = A*Bx+B
We can solve these for A and B by subtracting the second from the first.
SyBy = A*(SxBx) => A = (SyBy)/(SxBx) and therefore B = SyA*Sx
When we know A and B (from above) , we can find Dx, since we know this point must be on the same line and have Dy = gh, hence:
Dy = gh = A*Dx+B => Dx = (ghB)/A
Putting this together:
Dx = (gh(SyA*Sx))/A = (ghSy)/A+Sx => Dx= (ghSy)*(SxBx)/(SyBy)+Sx and Dy = gh
So if the sun is at (Sx,Sy) and a box corner is at (Bx,By), then the shadow will hit the ground at (Sx+(ghSy)*(SxBx)/(SyBy),gh ), assuming the sun is above the box.
We need to check two corners (Bx1,By) and (Bx2,By) and that Sy < By (the sun is above the box, remembering y increases down). Also we only get a left shadow when Sx > Bx1 and a right shadow when Sx < Bx2.
PS , using Fremy's picture: and the right side shadow:
Dx = Sx+B
h = BySy
H = gySy
b = BxSx
B = b*(H/h) = (BxSx)*(gySy)/(BySy)
Hence Dx= Sx+(BxSx)*(gySy)/(BySy) The same answer
Live for nothing, OR CODE FOR SOMETHING!
Live for nothing, OR CODE FOR SOMETHING! 

A and B here are coeffcients in the equation of a line y = Ax+B, gh (mistyped as gy sometimes) is the Graphics Window height, i.e. ground level of the bottom of the box, hence for example H = ghSy, or gh = H+Sy.
sorry, i dont wanna sound mean but, those words are to high for me understand... but that formula is for the shadows just going to the "floor"? if yes, im trying to do a top down view version... (i coded a "collision engine" that works with every object..(rectangle))
Live for nothing, OR CODE FOR SOMETHING! 
The formula Dx= Sx+(BxSx)*(ghSy)/(BySy) calculates the x Coordinate(Dx) on the ground level y = gh, when the sun is at (Sx,Sy) and the top box corner is at (Bx,By). Therefore a ray of light passes from the sun (Sx,Sy), just passing the box top (Bx,By) and hits the ground at (Dx,Dy), where the y for ground is Dy=gh.
This is a straight line passing through the sun, box top and the ground. A straight line is any point (x,y) that satisfys the equation y = A*x+B, where A and B are constant numbers.
In this case A = (SyBy)/(SxBx) and B = SyA*Sx
So if the sun is at (100,50), and the box top is at (80,80), then A = (5080)/(10080) = 1.5 and B = 50(1.5*100) = 200
All points (x,y) on the ray satisfy y = 1.5x + 200
If the ground is at y=140, then the ray hits the ground at Dx = 100+(80100)*(14050)/(8050) = 40
Hits the ground at (40,140)
y = 1.5x + 200 (the equation of the ray) is true for the sun (50= 1.5*100+200), the box top (80 =1.5*80+200) and the ground (140 = 1.5*40+200)
Try drawing a diagram if unclear.


Another thought  all of this is for shadows seen from the side with the sun and object in view. More commonly this applies to light sources that are relatively close the the object. Everything we said so far is based on the original code you posted (side on view).
If you have a plan view (seen from above), where the sun is above the view (above and behind the viewer), then some of this may be easier, you mentioned top down view a couple of posts ago. For a plan view the sun may be assumed to be very far away and all objects will have the same direction shadow, proportional to their height. The shadows only change (for all objects in the same way) if the sun moves and not depending on where the objects are.
Perhaps if you draw picture of what you want it may be possible to suggest a different approach. 
You don't need any trigonometric formula here. You simply need to use similarity.
B = b * (H/h)
C = a * (H/h)
You also must note there's two shadows if the sun is just over the house.
If the sun is below the top of the house, the shadow should be so :
In this case, you'll need a triangle + a rectangle.
Fremy  Developer in VB.NET, C# and JScript ...  Feel free to try my extension
i didnt work on the dynamic shadows project for some time. but i need it again now.
it would be awesome if you could tell me what the formula would be like when the light source (tip of h) is under the box/house.. cuz im really stuck at doing upside down shadows...
Live for nothing, OR CODE FOR SOMETHING! 
You need to fill the two grey shadow shapes (one triangle and one box). Therefore you need the coordinates of their corners.
You know:
1] The top left corner of the box (BTLx,BTLy)
2] The width of the box (Bw)
3] The height of the box (Bh)
4] The window width (Wx)
5] The position of the sun (Sx,Sy)
Therefore the square shadow has corners (BTLx+Bw,BTLy) (Wx,BTLy) (Wx,BTLy+Bh) (BTLx+Bw,BTLy+Bh)
The bottom 2 corners of the triangle are also obvious (BTLx,BTLy) (Wx,BTLy)
Now the only nontrivial corner of the triangle:
It lies on a line from the sun, through the box corner, ending on the side of the window (x = Wx).
This line has an equation y = A.x+B, where A and B are constants. As before we can find A and B since they are satisfied by the sun and box corner coordinates:
Sy = A.Sx + B and BTLy = A.BTLx + B
Hence if we subtract the second equation from the first (the Bs cancel) we get (SyBTLy) = A.(SxBTLx) and therefore A = (SyBTLy)/(SxBTLx), as long as the sun is to the left of the box (Sx < BTLx) we are OK.
We can find B by substituting our value of A back into the first equation above and rearranging : B = Sy  A.Sx = Sy  (SyBTLy)/(SxBTLx).Sx
Now the top point of the triangle will have x = Wx.
Hence its y coordinate will be y = A.Wx + B = (SyBTLy)/(SxBTLx).Wx + Sy  (SyBTLy)/(SxBTLx).Sx = Sy + (SyBTLy)/(SxBTLx)(WxSx)
The triangle coordinates are: (BTLx,BTLy) (Wx,BTLy) (Wx,Sy + (SyBTLy)/(SxBTLx)(WxSx)) 
thx!
are you sure i need to do it with a box? because i also did it wich 2 triangles.. like this: FCT935 (i know, the shadows arent right, but this should just show off the idea..)
or is the version with the box easyer to do?
Live for nothing, OR CODE FOR SOMETHING! 
You can do it with triangles or with rectangles  I was just following the drawing you showed  the idea is always the same  calculate the corners of any shape you want to shade  their geometry just needs to be worked out  unfortunately there is no single formula for all cases, but the principal remains constant.

Try the following import CXM437 as an idea method, but the screen clearing may be an issue for any game. Its nothing other than the geometry shown above, just treating the various cases carefully, sun above, below, etc.
 Marked as answer by Dudeson Monday, October 19, 2009 9:29 PM


As you can see from the code I used 3 triangles.
GraphicsWindow.FillTriangle(C1x,C1y,C2x,C2y,(D1x+D2x)/2,(D1y+D2y)/2)
GraphicsWindow.FillTriangle(C1x,C1y,D1x,D1y,D2x,D2y)
GraphicsWindow.FillTriangle(C2x,C2y,D1x,D1y,D2x,D2y)
From the drawing (after finding the two box corners to use (C1 and C2) and the window face to project onto) the triangles are:
(C1,D1,D2) (C2,D1,D2) and (C1,C2,(D1+D2)/2), the last triangle using the midpoint of D1 and D2 is needed for some cases where the first 2 triangles leave a 'hole' in the shadow. Try commenting out this triangle to see what I mean.


Good persistence  looking at it more carefully I think you are right and just using (C1,C2,D1) and (C2,D1,D2) as you tried works, we could also use (C1,C2,D2 ) and (C1 ,D1,D2), but not (C1,C2,D1 ) and (C1 ,D1,D2) or (C1,C2,D2 ) and (C2 ,D1,D2)  Import NPW879. There should be no fine joining line using a GraphicsWindow.PenWidth=0.


It looks like the fine line is still there, but you can only see it clearly if the shadow colour is fairly dark compared to the lit background e.g. black on lightblue. In this case you could also draw a shadow coloured line over the fine line e.g.
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(0,0,gw,gh)
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillTriangle(C1x,C1y,C2x,C2y,D1x,D1y)
GraphicsWindow.FillTriangle(C2x,C2y,D1x,D1y,D2x,D2y)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 2
GraphicsWindow.DrawLine(C2x,C2y,D1x,D1y) 
i knew it!
but, cant you see the end points of the line sticking out a little bit of the shadow? (i also tried this with the lines some times, but it never worked very well...)
well, i want those shadows to suck the smallest amount of performance as possible.. cuz this would be very useful for some little games..
btw, do shapes made with shapes.addrectangle suck more performance than graphicswindow.fillrectangle even when its not being moved around? because if it would suck the same amount of performance, we could, to remove the shadow flicker when the shadows are redrawn, add the shadow and then add the new one and then delete the old one, like you did for the animations in my game..
Live for nothing, OR CODE FOR SOMETHING! 
With regard to performance  try it and see with a test program  my guess is that there won't be too much in it if you don't move the shape, but this is just a guess  its often not good to guess at how something is internally implemented so I would certainly test this performance first.
The shapes idea could solve the flicker and perhaps the small line bit sticking out since the shapes can have Pen borders as well as Brush filling  again prototype to see.
The main issue I see using shapes rather than painting to the background is that the shadows will be on top of all other shapes, whereas the GraphicsWindow.FillRectangle paints to the background and all shapes remain visible on top (e.g. the blue box in the shadows demo is always present on top of the shadows we draw).
The following (replacing all the current clearing and drawing code) shows the possible advantages and disadvantages of shapes (no indication of performance issues  need more dedicated tests for this). Also, some playing with PenWidth or a Shapes.AddLine may improve the sticking out bit.
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 2
Shadow1 = Shapes.AddTriangle(C1x,C1y,C2x,C2y,D1x,D1y)
Shadow2 = Shapes.AddTriangle(C2x,C2y,D1x,D1y,D2x,D2y)
Shapes.Remove(Shadow1Old)
Shapes.Remove(Shadow2Old)
Shadow1Old = Shadow1
Shadow2Old = Shadow2

damn!
i totally forgot that shapes are always over drawn things... it would be really useful (not just for this) if you could set the layer for each object in the next version....
i'll analyze your code as soon as i have time!
Live for nothing, OR CODE FOR SOMETHING! 
Yes, this has been mentioned before I think as a possible enhancement  I think it would need some thought as to how it was implemented with the SmallBasic purpose in mind (simplicity as an educational teaching language).
A first time programmer isn't going to want to decide on Z (layer value) attributes to simply draw a circle. So the best bet to me may be to introduce another Shapes property, say Shapes.Depth defaulted to 0.
If you want to see this feature then post in the Bugs and Suggestions (v0.6 to 0.7) thread with some description and any ideas you have on what it should do and some thinking on how it would work with the SmallBasic objectives in mind, then see what other people think. 

i just quickly made a 2 shadow version: ZSD244
but theres one problem.. i dont know how to make the background being repainted just once, instead of 2 times for each box... i hope you know what i mean..
but you will understand as soon as you test the code..
Live for nothing, OR CODE FOR SOMETHING! 
If we clear the screen once every time before both sets of shadows are created then both shadows work. We need to only do this when there has been some movement of the sun or box.
The flicker really need to use shapes and therefore the Z layer index option to be added.
Import ZSD2441 
wow! nice solution!
its so awesome! now we can add as many objects as we want!
is this finished now? i guess..
can i add this to my example project compilation? (will be released soon) for sure i would credit you.
Live for nothing, OR CODE FOR SOMETHING! 
