Code archives/3D Graphics - Effects/basic directional shadows
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
I actually posted this in a forum a while ago... This it pretty much the basis of the ShaKAL shadow library I was working on ages ago. Hope it helps. | |||||
;Attempt at explaining directional shadows ;-Kevin Laherty (kalisme@hotmail.com) ;This is mearly a re-release of a pseudo-tutorial I released ages ago. ;I refur to this as a pseudo-tutorial because I'm actually quite ;concerned that this will seem like total utter jibberish ;since I'm horrible at explaining things... ;This is based off code that someone posted in a forum ;a few years ago (great learning material). ;I don't know his name, but if you know who I'm talking about ;please inform me, he deserves alot of credit. ;Anywho, this code casts a directional shadow from a caster entity ;onto a receiver entity. It may not be the most stunning style ;of casting shadows, but it's quite fast (when coded right) ;and seems to blend quite well into a blitz3d game engine. ;I hope I help at least one person and someone uses it to ;fancy-up a game n_n ;This was also the basis of my ShaKAL library I was working on ;a long time ago. (If anyone remembers it) Graphics3D 800,600 SetBuffer BackBuffer() AmbientLight 0,0,0 ;Ssize: ;the size of the shadows texture. ;(remember To use base 2... eg: 2 4 8 16 32 64 128 256 512) ;make sure it's smaller than the games resolution... ;eg: you can't render a 512x512 map on a 320x240 screen... Global ssize=64 Global shadow_tex=CreateTexture(ssize,ssize,16+32) ;create the shadow texture ;Xscale: ;lets say the default zoom the shadow camera is 1.(it's actually .06, but 1 sounds easyier :P ) ;so if Xscale = 1, the zoom = 1/Xscale# = 1 ;but if Xscale is smaller than 1 it will make the camera zoom in more. ;It's hard for me to explain... play with it, you'll get it in time. Global Xscale#=1*(.8/4) ;creating and setting up the shadow rendering camera. shadowcam=CreateCamera() CameraViewport shadowcam,0,0,ssize,ssize ;the viewport the shadows will be rendered through. CameraClsColor shadowcam,255,255,255 ;Yup, white background for shadow textures. CameraProjMode shadowcam,2 ;Orthographic view, sorry, I've only figured out very simple directional shadows. CameraZoom shadowcam,.06/xscale# ;though the function "shadow_test" does this every time it's used, here it is for you to see anyway. It's not needed here. CameraFogMode shadowcam,1 ;The fog is put on so it seems like everythings white... to make a caster visable to the camera, disable fogging to that object. CameraFogRange shadowcam,1,1 CameraFogColor shadowcam,255,255,255 HideEntity shadowcam ;we don't want it onscreen now. ;just setting up the scene======== camera=CreateCamera() ;<-the game camera PositionEntity camera,0,5,-15 scene=CreateSphere() ;<-later used as the receiver. ScaleEntity scene,20,1,20 caster=CreateCone() ;<-the object that shall cast a shadow. UpdateNormals caster EntityShininess caster, .2 EntityColor caster,200,0,0 RotateEntity caster,40,90,60 PositionEntity caster, 0,2,0 ScaleEntity caster, 1,2,1.5 light=CreateLight(2) ;<-the light source vis_light = CreateSphere(12,light) ;<-sphere used to make the light source visable. EntityColor vis_light,0,200,0 EntityFX vis_light,1 PositionEntity light,-20,8,-1 ;================================= ;placing the shadow texture onto the receiver... ;but If you make a shadow lib For a game, ;You'll probably want this in the actual function... not here. EntityTexture scene,shadow_tex ;Main loop============================================ While quit=0 Cls MoveEntity light,0,0,1:TurnEntity light,0,-5,0 ;A rotating light source. Much more intresting. TurnEntity caster,0,0,.5 RenderWorld UpdateWorld If KeyHit(1) Then quit=1 shadow_test(shadowcam,camera,light,caster,scene) ;<- our function. Text 500,10,"Xscale#: "+ Xscale# Text 500,20,"zoom: "+ .06/Xscale# Text 300,30,"hit ''<-'' & ''->'' to change the Xscale#." Flip If KeyHit(203) Then xscale#=Xscale#*.8 If KeyHit(205) Then xscale#=Xscale#*1.2 Wend End ;===================================================== ;shadow_test function: ;I made this to help explain the how the real magic is done. ;used like so: ;shadow_test(s_camera,g_camera,s_light,s_caster,s_receiver) ; ;>s_camera ; The shadow camera used to render the shadows. ; ;>g_camera ; The in game camera used to render the game. ; ;>s_light ; The light source. ; ;>s_caster ; The object that shadows are casted from. ; ;>s_receiver ; Where the shadows land onto. Function shadow_test(s_camera,g_camera,s_light,s_caster,s_receiver) CameraZoom s_camera,.06/xscale# ;<-setting up the zoom for the shadow rendering camera. cleartexture(shadow_tex) ;<- I added this because alot of graphics cards seem to render fog differant to mine.. Hopefully this fixes the blurring problem. HideEntity g_camera ;The in game camera must be hidden, ShowEntity s_camera ;and the shadow camera must become visable. EntityFX s_caster,1+8 ;<- setting up the caster: EntityColor s_caster,0,0,0 ;It needs to be black and unnefexted by fog and lights. ;The shadow rendering camera must be placed at ;the light source Then pointed at the caster. PositionEntity s_camera,EntityX(s_light,1),EntityY(s_light,1),EntityZ(s_light,1) PointEntity s_camera,s_caster ;Here we render the camera and convert it to a texture. RenderWorld() Color 255,255,255: Rect 0,0,ssize,ssize,0 ;<-this rectangle is used to cull anything that tries to poke outside of the textures boundry box. CopyRect 0,0,ssize,ssize,0,0,BackBuffer(),TextureBuffer(shadow_tex) ;The surface and verticy loop. ;This loops through every surface of the receiver mesh, ;Then every surfaces vertecies. ;Our main focus should be the ;"Tformpoint" And "vertextexcoords" commands. ;These commands actually paint the texture onto the ;receiver correctly. For s=1 To CountSurfaces(s_receiver) surf=GetSurface(s_receiver,s) For v=0 To CountVertices(surf)-1 TFormPoint VertexX(surf,v),VertexY(surf,v),VertexZ(surf,v),s_receiver,s_camera VertexTexCoords surf,v,(TFormedX()/Xscale#)/32+0.5,1-((TFormedY()/Xscale#)/32+.5) Next Next ;Here we just switch the attributes of the caster back to normal. ;In an actual game engine you might have to make this more complex. ;I suggest keeping the old attributes in tempory memory then ;calling them back at about this point. EntityFX s_caster,0 EntityColor s_caster,200,0,0 ;here we hide the shadow camera and bring back the game camera, ;ready to go back to the main game loop like nothing ever happend. ShowEntity g_camera HideEntity s_camera End Function ;This last little function holds no real importance, it just clears a texture and makes it white. ;I added this because when I first released this code I found alot of graphics cards don't make ;the fog as thick as mine (I'm guessing it's because my card it cheap), and the shadow texture ;Grabbed the old shadow texture off the ground and blurred with the new one... ;very annoying and unpretty.... Oh well... Hope this works much better. Function cleartexture(tex) SetBuffer TextureBuffer( tex ) Color 255,255,255 Rect 0,0,TextureWidth(tex)+1,TextureHeight(tex)+1 SetBuffer BackBuffer() End Function |
Comments
| ||
Yep I remmember it! Still have your previous shadow demos :) Nice work. Whenever I get to actaully make a game, one day, this is diffenitly what I want to use for the shadow system. Thanks! |
| ||
Pretty good. I tried this: ScaleEntity scene,20,10,20 TranslateEntity scene,0,-10,0 The shadow is still aligned correctly on the non-flat ground! |
| ||
It casts a shadow and a 'hidden' rectangle. It's hidden as you are casting onto a white surface. I naturally changed the scene's colour to 1,1,1 and was greeted by the rectangle grinning at me as it played with the shadow. The rectangle has to go - I don't like it. |
| ||
Puki: It casts the shadow texture (which happens to be a rectangle) onto a surface mesh and lines up the texture to come from the light source. The background is white because I use a blend mode that removes white in shaKAL. The white rectangle around the rendered shadow camera is just a safe-guard I guess, just incase the shadow object sorta pokes out of view of the camera... without the white rectangle culling the edges it creates ugly black lines. Well, that's my explanation, but of course you can change anything you want, its public domain now =D |
| ||
Puki is right..its really producing ugly rectangle...actually on any given color different than 255,255,255 .. it means for real purpose its not possible to use this system.. |
| ||
oh... now I think I understand. I just want to point out this is more reading material than a system that can be directly put into a game. I wouldn't recomend using it like that at all. I just wanted to give a brief explanation of the method I use so that I could help others program there own shadow system. I guess I should of pointed that out. Sorry guys. |
| ||
hey..Kalisme, this is nice piece of code buddy..I was just hoping that its ready for use immidiatelly, thats all ;) |
| ||
this a good method ;) I changed and optimized your system and post the new solution ;) |
| ||
The my version Type Shadow Field Obj Field ShwTexSize Field ShwTex Field ShwInit End Type Graphics3D 1024,768,32,2 SetBuffer BackBuffer() AmbientLight 0,0,0 Global Xscale#=1*(.8/2) shadowcam=CreateCamera() CameraProjMode shadowcam,2 CameraFogMode shadowcam,1 CameraFogRange shadowcam,1,1 CameraFogColor shadowcam,255,255,255 HideEntity shadowcam Local camera=CreateCamera() ;<-the game camera PositionEntity camera,0,5,-15 ;scene=CreateSphere() ;<-later used as the receiver. Local scene=CreateCube() ;<-later used as the receiver. ScaleEntity scene,20,1,20 PositionEntity scene,0,-1,0 Local IDScene.Shadow = SW_AddObject(scene) Local caster=CreateCone(32) ;<-the object that shall cast a shadow. PositionEntity caster, 0,3,0 RotateEntity caster,40,90,60 ScaleEntity caster, 1,2,1.5 UpdateNormals caster EntityColor caster,200,0,0 Local IDCaster.Shadow = SW_AddObject(caster) Local caster1=CreateSphere(32) ;<-the object that shall cast a shadow. PositionEntity caster1,0,1,0 EntityColor caster1,0,0,200 UpdateNormals caster1 Local IDCaster1.Shadow = SW_AddObject(caster1) Local light=CreateLight(2) ;<-the light source Local vis_light = CreateSphere(12,light) ;<-sphere used to make the light source visable. EntityColor vis_light,0,200,0 EntityFX vis_light,1 PositionEntity light,-20,8,-1 ;================================= While quit=0 ;===> If KeyHit(1) Then quit=1 If KeyHit(203) Then Xscale#=Xscale#*.9 If KeyHit(205) Then Xscale#=Xscale#*1.1 ;===> SW_ResetShadow(); ;===> MoveEntity light,0,0,0.25:TurnEntity light,0,-1.25,0 ;A rotating light source. Much more intresting. TurnEntity caster,0,0,.5 UpdateWorld shadow_test1(shadowcam,camera,light,IDCaster ,IDScene) ;<- our function. shadow_test1(shadowcam,camera,light,IDCaster1,IDScene) ;<- our function. shadow_test1(shadowcam,camera,light,IDCaster ,IDCaster1) ;<- our function. RenderWorld() ;===> Text 500,10,"Xscale#: "+ Xscale# Text 500,20,"zoom: "+ .06/Xscale# Text 300,30,"hit ''<-'' & ''->'' to change the Xscale#." Flip ;===> Wend End ;===================================================== Function shadow_test1( s_camera, g_camera, s_light, caster.Shadow, s_receiver.Shadow) ;===> ;Stop ;===> HideEntity g_camera ;The in game camera must be hidden, ShowEntity s_camera ;and the shadow camera must become visable. ;===> If s_receiver\ShwInit=True Then CameraClsMode s_camera, False, True Else CameraClsMode s_camera, True, True s_receiver\ShwInit = True EndIf ;===> Local TSize = s_receiver\ShwTexSize ;===> CameraClsColor s_camera,255,255,255 CameraZoom s_camera,.06/Xscale# ;<-setting up the zoom for the shadow rendering camera. CameraViewport s_camera,0,0,TSize,TSize ;the viewport the shadows will be rendered through. CameraProjMode s_camera,2 ;Orthographic view, sorry, I've only figured out very simple directional shadows. ;===> SW_HideObject() ;===> Local s_caster=CopyEntity( caster\Obj ) EntityFX s_caster,1+8 ;<- setting up the caster: EntityColor s_caster,0,0,0 ;It needs to be black and unnefexted by fog and lights. ShowEntity s_caster ;===> PositionEntity s_camera,EntityX(s_light,True),EntityY(s_light,True),EntityZ(s_light,True) PointEntity s_camera,s_receiver\Obj RenderWorld() ;===> CopyRect 0,0,TSize,TSize,0,0,BackBuffer(),TextureBuffer(s_receiver\ShwTex) ;===> Local CurObj = s_receiver\Obj For s=1 To CountSurfaces(CurObj) Local surf=GetSurface(CurObj,s) For v=0 To CountVertices(surf)-1 TFormPoint VertexX(surf,v), VertexY(surf,v), VertexZ(surf,v), CurObj, s_camera VertexTexCoords surf,v,(TFormedX()/Xscale#)/32+0.5,1-((TFormedY()/Xscale#)/32+.5) Next Next ;===> SW_ShowObject() ;===> ShowEntity g_camera HideEntity s_camera FreeEntity s_caster ;===> End Function Function SW_AddObject.Shadow( Obj) Local SW_Size = 512 Local CurModel.Shadow = New Shadow CurModel\Obj = Obj CurModel\ShwInit = False CurModel\ShwTex = CreateTexture( SW_Size, SW_Size, 16+32) CurModel\ShwTexSize = SW_Size EntityTexture CurModel\Obj,CurModel\ShwTex ;===> SetBuffer(TextureBuffer(CurModel\ShwTex)) ClsColor 255,64,255 Cls SetBuffer(BackBuffer()) ;===> Return CurModel End Function Function SW_ResetShadow() Local CurModel.Shadow For CurModel=Each Shadow CurModel\ShwInit = False Next End Function Function SW_HideObject() Local CurModel.Shadow For CurModel=Each Shadow HideEntity CurModel\Obj Next End Function Function SW_ShowObject() Local CurModel.Shadow For CurModel=Each Shadow ShowEntity CurModel\Obj Next End Function |
| ||
nice |
| ||
ughh im dizzy now |
| ||
I changed and optimized your system and post the new solution ;) "DareDevils'" one is slower than a slug dragging its feet. Try again. I want one like the first one, but without the rectangle - I don't like the rectangle. |
| ||
Also - and quite frankly, I should not have to point this out. Just what the jolly-badger is going on with the segments? Do I have to do everything myself? How the hell is increasing those optimizing anything? I really won't stand for this. EDIT: I'll edit the resolution and depth myself - might as well do everything. |
| ||
Right, the results are as follows: Graphics3D 800,600,16,1 Get rid of this: ;Local caster1=CreateSphere() ;<-the object that shall cast a shadow. ;PositionEntity caster1,0,1,0 ;EntityColor caster1,0,0,200 ;UpdateNormals caster1 ;Local IDCaster1.Shadow = SW_AddObject(caster1) and its Satan offspring: ;shadow_test1shadowcam,camera,light,IDCaster1,IDScene) ;<- our function. ;shadow_test1shadowcam,camera,light,IDCaster ,IDCaster1) ;<- our function. Then, for the Love of Large, remove: ;EntityColor vis_light,0,200,0 |
| ||
I thought that rendering it easier it would have been useful to all |
| ||
.actually I have now same rectangle and some weird lines over plane surface and whole thing is slower..I dont know what is your optimization about... |
| ||
The my optimization is multi shadow for object and organization for use in application game, the slow speed is the generate for dettail texture shadow. bye |
| ||
But your optimisation honked up the resolution and screen depth (potentially) and then honked up the segments, then added another chuffing caster. You also made the same shocking error to add a green - I repeat, green - vis light. The first thing I did with the original one was sort that shocker out. |
| ||
Puki, just what are you talking about? What do you mean "segments"? And who cares if the entity for the light source is green? |
| ||
He increased the segments on the primitives. How many people are seriously going to leave in a green caster when the light is not green? Might just be me, but I always make the caster and the light the same colour. |
| ||
is spectacular, especially to learn things ... thanks man. |
Code Archives Forum