Help with Swift Shadow system
Blitz3D Forums/Blitz3D Programming/Help with Swift Shadow system
| ||
Hi all I recently bought the swift shadow system and I have a problem with animated characters. I tried to run the demo using the Mario animated mesh (from the castle demo of blitz). If I use LoadMesh the shadow works perfectly, buy if I use LoadAnimMesh the shadow doesn't appear... Help, please... :) Thank you in advance -Banky |
| ||
LoadAnimMesh attaches a structure to the model, and the first level of that structure is a null pivot, not your model. Find the name of the main model in your modeller ( or there is a B3d hierarchy viewer in the code archives ) and then get the handle of that with the FindChild() command. You can then set *this* as the shadowcaster. |
| ||
Thanks for the answer Sybixsus, but my problem is that I can't use the name of the main model. To make the shadows work I have to set as a shadowcaster every part of the model (for example, right arm, left arm, left leg...) and this way the system is sooooo slow. (19 frames in a Athlon XP+ 2600 with a Geforce FX 5600) Is this the only way to make it work with animated meshes? Help, please... :) Thank you in advance -Banky |
| ||
Generally you would use a single model which was animated with skeletal animation, thus only needing one shadow casting object. You could probably get around this problem by creating a cube which is just big enough to envelop the entire character, then parent the character to the cube and set the cube as the shadow casting object. If you need the player to be parented for something else, just parent it to the cube directly before calling Update_Shadows() and then immediately afer, parent it back to whatever else you want it parented to. |
| ||
Banky: Your post convinced me to take another look at the possiblity of adding the ability to cast shadows from compound objects made of multiple entities. I think I can do it in a manner which would work well enough for animated characters, but I need a demo to test with. If you could send me a simple program with your segmented model animating onscreen with a lightsource and something set for it to cast shadows on, then that would be helpful. Set the shadow to cast from it's head or something and I will change it to the pivot myself. That way you can tell it's set up right before you send it. |
| ||
I think I've fixed the problem... jsut need a demo from you to test with. :-) |
| ||
sswift use the markio demo from the blitz3d folder and substitute the terrain for a mesh terrain, i think that is the model he is using anyways |
| ||
Mmm, I just bought "sswifty's" shadow system. Hope I get an updated one. |
| ||
Hi, Sswift This is my piece of code... Just a modification of the demo code with an animated character and a gile[s] level. I hope it will be useful to you... Thanks for the answers, - Banky --- Type emitter Field parent,rate#,time# Field texture,blend Field speed#,spread#,life#,size#,growth#,gravity# End Type Type particle Field sprite Field x#,y#,z# Field sx#,sy#,sz# Field life#,lifespan#,size#,growth#,gravity# End Type Type flare Field sprite Field texture Field alpha#,talpha# End Type ;#Region Program Setup Global Terminate = False ; Set this to True anywhere to terminate the program. ; Setup the screen dimensions Global ScreenWidth = 1024 Global ScreenHeight = 768 Global ScreenDepth = 16 Global ScreenMode = 2 ; Create the screen. Graphics3D ScreenWidth,ScreenHeight,ScreenDepth,ScreenMode SetBuffer BackBuffer() ; Switch to Back Buffer for Double Buffered drawing. ; Setup the lighting... AmbientLight 200,200,200 ;#End Region ;#Region Declarations ; Setup the camera. ;Global MainCamera = CreateCamera() ;#End Region Include "Swift Shadow System - 097.bb" Include "ParseB3D.bb" Global info1$="Swift Shadow System Demo" Global info2$="Please note that this is a STRESS TEST!" Global info3$="There are 48 pairs of casting/receiving objects in this scene." Global info4$="And double that number when you add a second light!" Include "start.bb" ; Stuff for the normal calculation function: Dim Face_NX#(32768) Dim Face_NY#(32768) Dim Face_NZ#(32768) Dim Vertex_ConnectedTris(32768) Dim Vertex_TriList(32768, 16) ; Stuff for the HSV to RGB function. Global HSV_R Global HSV_G Global HSV_B .Main ; Removes all the default flags when you load a texture. ; Required because shadow maps cannot be mipmapped or the UV clamping will cause artifacts, ; and blitz by default has mipmapping enabled for all textures loaded. ClearTextureFilters ; Load a texture for our fake shadows. ; Note the flags: ; Texture must have UV clamping enabled, and no mipmapping! Global TEX_Fake_Shadow = LoadTexture("TEX-003.jpg", 16+32) ; Create a camera and move it back from 0,0,0 Camera = CreateCamera() CameraRange Camera, 0.1, 65536 ;PositionEntity Camera, 0, 200, -800 Camera_Pivot = CreatePivot() EntityParent Camera, Camera_Pivot, True ; Set up the lights. Gosub Setup_Lights Gosub Create_Objects Shadow_Resolution = 256 ; Set the amount to nudge the shadows by to combat z fighting. Shadow_Nudge# = 0.75 Animated_Casters(caster_2) ; Remember that we're drawing rendered shadows by default. Cast_Rendered_Shadows = True ; Specify what objects should receive shadows. ; It's not a good idea to have too many objects receiving shadows. Receive_Shadow(Receiver_1) ; Specify the lights which cast shadows, and set their range. Cast_Light(Light_1, 2000) Time_Old = MilliSecs() Time_Of_Next_Event = Time_Old + 2000 While Not KeyDown(1) Time_New = MilliSecs() Time_Delta = Time_New - Time_Old Time_Delta_Sec# = Float(Time_Delta)/1000.0 Time_Old = Time_New If KeyHit(88) Then SaveScreenshot() If KeyHit(2) ; Stop the objects from casting shadows. ; Note: ; You only need to call this once per object casting shadows, ; even if it casts shadows onto more than one reciever. Delete_Shadow_Caster(Caster_2) ; Fighter ; If we're currenty casting rendered shadows... If Cast_Rendered_Shadows = True ; Make the objects cast fake shadows. ; The value of the resolution parameter doesn't matter because you created the texture. Cast_Textured_Shadow(caster_2, TEX_Fake_Shadow) ; Fighter Cast_Rendered_Shadows = False Else ; Make the objects cast rendered shadows. ; We don't need a texture parameter because the function will create a unique texture ; for each shadow itself. Cast_Shadow(caster_2, Shadow_Resolution) ; Fighter Cast_Rendered_Shadows = True EndIf EndIf If KeyHit(3) If Shadow_Resolution = 128 Shadow_Resolution = 256 Else If Shadow_Resolution = 256 Shadow_Resolution = 512 Else If Shadow_Resolution = 512 Shadow_Resolution = 128 EndIf EndIf EndIf ; If we're currenty casting rendered shadows... If Cast_Rendered_Shadows = True ; Stop the objects from casting shadows. ; Note: ; You only need to call this once per object casting shadows, ; even if it casts shadows onto more than one reciever. Delete_Shadow_Caster(caster_2) ; Fighter ; Make the objects cast rendered shadows. ; We don't need a texture parameter because the function will create a unique texture ; for each shadow itself. Cast_Shadow(caster_2, Shadow_Resolution) ; Fighter ; EndIf EndIf If KeyHit(4) Delay 5000 EndIf If KeyHit(5) FormatC = Not FormatC EndIf If KeyHit(6) Second_Light = Not Second_Light If Second_Light = True Cast_Light(Light_2, 2000) ShowEntity Light_2 Else Delete_Light_Caster(Light_2) HideEntity Light_2 EndIf EndIf If KeyHit(57) Show_Shadow_Map = Not Show_Shadow_Map EndIf ;TurnEntity Caster_1, 1, 1, 1 TurnEntity Caster_2, 1, 0.5, 0 ;TurnEntity Caster_3, 0, 1, 0.5 TurnEntity Light_Pivot, 0.25, 0.5, 1 Update_Shadows(camera) UpdateWorld If Show_Shadow_Map = False Then RenderWorld Select Event Case 0 Info$ = "-- Swift Shadow System - Created by Shawm C. Swift --" Case 1 Info$ = "-- Press 1 to toggle rendered/fake shadows! --" Case 2 Info$ = "-- Press 2 to toggle shadow resolution between 128, 256, and 512! --" Case 3 Info$ = "-- Press 3 to crash your pc! --" Case 4 Info$ = "-- Press 4 to FORMAT C: drive! ---" Case 5 Info$ = "-- Press 5 to kill your framerate... I mean add a second light to the scene. --" End Select Text GraphicsWidth()/2, 16*1, Info$, True, False If (Time_Delta > 0) Frames_Per_Second = Int(Floor(1000.0/Float(Time_Delta))) Text GraphicsWidth()/2, 16*2, "FPS: " + Str$(Frames_Per_Second), True, False EndIf Select (Event Mod 3) Case 0 Text GraphicsWidth()/2, 16*3, "Shadow Resolution: " + Str$(Shadow_Resolution), True, False Case 1 Text GraphicsWidth()/2, 16*3, "Shadow Polys: " + Str$(Shadow_Poly_Count), True, False Case 2 Text GraphicsWidth()/2, 16*3, "Scene Polys: " + Str$(TrisRendered()), True, False End Select If FormatC = True Text GraphicsWidth()/2, GraphicsHeight()/2, "Formatting C:\ ... Please wait.", True, True EndIf Flip False Wend End ; ------------------------------------------------------------------------------------------------------------------- .Setup_Lights ; Tell the shadow system what the ambient light level is. (Blitz doesn't have a command to retreive that info.) Shadow_Ambient_Light_R = 80 Shadow_Ambient_Light_G = 80 Shadow_Ambient_Light_B = 128 AmbientLight Shadow_Ambient_Light_R, Shadow_Ambient_Light_G, Shadow_Ambient_Light_B ; Create three point light sources. Light_1 = CreateLight(2) Light_2 = CreateLight(2) ; Set the color of the lights. LightColor Light_1, 255, 255, 240 LightColor Light_2, 255, 255, 240 ; Set the radius of the lights. LightRange Light_1, 2000 LightRange Light_2, 2000 ; Create a pivot to rotate the light sources around. Light_Pivot = CreatePivot() PositionEntity Light_Pivot, 0, 800, 0 ; Attach the light sources to the pivot. EntityParent Light_1, Light_Pivot EntityParent Light_2, Light_Pivot ; Position the light sources around the pivot. PositionEntity Light_1, 400, 0, 0 PositionEntity Light_2, 0, 0, 400 ; Create entities to show the positions of the light sources in the world. TEX_04 = LoadTexture("TEX-004.bmp", 8) Light_Sprite_1 = CreateSprite(Light_1) ScaleSprite Light_Sprite_1, 100, 100 EntityFX Light_Sprite_1, 1 EntityBlend Light_Sprite_1, 3 EntityTexture Light_Sprite_1, TEX_04 Light_Sprite_2 = CopyEntity(Light_1, Light_2) HideEntity Light_2 Return ; ------------------------------------------------------------------------------------------------------------------- ; This subroutine creates and textures the meshes we will use to cast and recieve the shadows. ; ------------------------------------------------------------------------------------------------------------------- .Create_Objects ; We have to set the mipmap flag manually because we turned that off so we could create ; shadow textures without mipmapping. TEX_01 = LoadTexture("TEX-001.jpg", 8) TEX_02 = LoadTexture("TEX-002.jpg", 8) TEX_05 = LoadTexture("TEX-005.jpg", 8) Receiver_1 = LoadMesh("level\romanbath.b3d") ParseB3D(receiver_1) Calculate_Normals(Receiver_1) ; Make pillars Temp1 = CreateCylinder(12, False) ScaleMesh Temp1, 40, 100, 40 UpdateNormals(Temp1) Temp2 = CreateCube() ScaleMesh Temp2, 50, 10, 50 Calculate_Normals(Temp2) PositionMesh Temp2, 0, 100, 0 Temp3 = CreateSphere(8) ScaleMesh Temp3, 40, 40, 40 UpdateNormals(Temp3) PositionMesh Temp3, 0, 150, 0 Caster_2 = LoadAnimMesh("mario.3ds") Animate CASTER_2, 1, 1 PositionEntity Caster_2, 0, 7, 50, True Return ; ------------------------------------------------------------------------------------------------------------------- ; This function adds a bit of noise to a mesh so that it's more interesting. ; ------------------------------------------------------------------------------------------------------------------- Function Randomize_Mesh(ThisMesh) Offset = 25 ; Loop through all surfaces of the mesh. Surfaces = CountSurfaces(ThisMesh) For LOOP_Surface = 1 To Surfaces Surface_Handle = GetSurface(ThisMesh, LOOP_Surface) ; Loop through all triangles in this surface of the mesh. Verts = CountVertices(Surface_Handle) For LOOP_Verts = 0 To Verts-1 Vx# = VertexX#(Surface_Handle, LOOP_Verts) Vy# = VertexY#(Surface_Handle, LOOP_Verts) Vz# = VertexZ#(Surface_Handle, LOOP_Verts) VertexCoords Surface_Handle, LOOP_Verts, Vx#, Vy#+Rnd(-Offset,Offset), Vz# Next Next End Function ; ------------------------------------------------------------------------------------------------------------------- ; This function takes a screenshot of whatever is on the screen and saves it in the current directory. ; ------------------------------------------------------------------------------------------------------------------- Function SaveScreenshot() iFileNumber% = 0 Repeat iFileNumber = iFileNumber + 1 sFileName$ = "Screenshot" + String$("0", 3 - Len(Str$(iFileNumber))) + iFileNumber + ".bmp" Until Not(FileType(sFileName$)) SaveBuffer FrontBuffer(), sFileName$ End Function ; ------------------------------------------------------------------------------------------------------------------- ; This function calculates and sets the normals for a mesh. ; ; This is diffrent from Blitz's function in that it does not smooth across edges which do not share vertices. ; In my opinion, that is the best way to calculate the normals for a mesh. Blitz on the other hand assumes that ; vertices which lie at the same point in space should be smoothed across. This works well for ; ; Should probably update this so that it can recursively loop through all of an entities children as well. ; ------------------------------------------------------------------------------------------------------------------- Function Calculate_Normals(ThisMesh) ; Loop through all surfaces of the mesh. Surfaces = CountSurfaces(ThisMesh) For LOOP_Surface = 1 To Surfaces Surface_Handle = GetSurface(ThisMesh, LOOP_Surface) ; Reset the number of connected polygons for each vertex. For LoopV = 0 To 32767 Vertex_ConnectedTris(LoopV) = 0 Next ; Loop through all triangles in this surface of the mesh. Tris = CountTriangles(Surface_Handle) For LOOP_Tris = 0 To Tris-1 ; Get the vertices that make up this triangle. Vertex_0 = TriangleVertex(Surface_Handle, LOOP_Tris, 0) Vertex_1 = TriangleVertex(Surface_Handle, LOOP_Tris, 1) Vertex_2 = TriangleVertex(Surface_Handle, LOOP_Tris, 2) ; Adjust the number of triangles each vertex is connected to and ; store this triangle in each vertex's list of triangles it is connected to. ConnectedTris = Vertex_ConnectedTris(Vertex_0) Vertex_TriList(Vertex_0, ConnectedTris) = LOOP_Tris Vertex_ConnectedTris(Vertex_0) = ConnectedTris + 1 ConnectedTris = Vertex_ConnectedTris(Vertex_1) Vertex_TriList(Vertex_1, ConnectedTris) = LOOP_Tris Vertex_ConnectedTris(Vertex_1) = ConnectedTris + 1 ConnectedTris = Vertex_ConnectedTris(Vertex_2) Vertex_TriList(Vertex_2, ConnectedTris) = LOOP_Tris Vertex_ConnectedTris(Vertex_2) = ConnectedTris + 1 ; Calculate the normal for this face. ; Get the corners of this face: Ax# = VertexX#(Surface_Handle, Vertex_0) Ay# = VertexY#(Surface_Handle, Vertex_0) Az# = VertexZ#(Surface_Handle, Vertex_0) Bx# = VertexX#(Surface_Handle, Vertex_1) By# = VertexY#(Surface_Handle, Vertex_1) Bz# = VertexZ#(Surface_Handle, Vertex_1) Cx# = VertexX#(Surface_Handle, Vertex_2) Cy# = VertexY#(Surface_Handle, Vertex_2) Cz# = VertexZ#(Surface_Handle, Vertex_2) ; Triangle 1 ; Get the vectors for two edges of the triangle. Px# = Ax#-Bx# Py# = Ay#-By# Pz# = Az#-Bz# Qx# = Bx#-Cx# Qy# = By#-Cy# Qz# = Bz#-Cz# ; Compute their cross product. Nx# = Py#*Qz# - Pz#*Qy# Ny# = Pz#*Qx# - Px#*Qz# Nz# = Px#*Qy# - Py#*Qx# ; Store the face normal. Face_NX#(LOOP_Tris) = Nx# Face_NY#(LOOP_Tris) = Ny# Face_NZ#(LOOP_Tris) = Nz# Next ; Now that all the face normals for this surface have been calculated, calculate the vertex normals. Vertices = CountVertices(Surface_Handle) For LOOP_Vertices = 0 To Vertices-1 ; Reset this normal. Nx# = 0 Ny# = 0 Nz# = 0 ; Add the normals of all polygons which are connected to this vertex. Polys = Vertex_ConnectedTris(LOOP_Vertices) For LOOP_Polys = 0 To Polys-1 ThisPoly = Vertex_TriList(LOOP_Vertices, LOOP_Polys) Nx# = Nx# + Face_NX#(ThisPoly) Ny# = Ny# + Face_NY#(ThisPoly) Nz# = Nz# + Face_NZ#(ThisPoly) Next ; Normalize the new vertex normal. ; (Normalizing is scaling the vertex normal down so that it's length = 1) Nl# = Sqr(Nx#^2 + Ny#^2 + Nz#^2) ; Avoid a divide by zero error if by some freak accident, the vectors add up to 0. ; If Nl# = 0 Then Nl# = 0.1 Nx# = Nx# / Nl# Ny# = Ny# / Nl# Nz# = Nz# / Nl# ; Set the vertex normal. VertexNormal Surface_Handle, LOOP_Vertices, Nx#, Ny#, Nz# ;VertexColor Surface_Handle, LOOP_Vertices, polys*127, polys*127, polys*127 Next Next End Function ; ------------------------------------------------------------------------------------------------------------------- ; This function takes a color in HSV format and returns a color in RGB format. ; ------------------------------------------------------------------------------------------------------------------- Function HSV_to_RGB(h#, s#, v#) If s = 0 Then r# = g# = b# = v ;grey Else h = h / 60 i = Floor(h) f# = h - i p# = v * (1 - s) q# = v * (1 - s * f) t# = v * (1 - s * (1 - f)) Select i Case 0 r# = v g# = t b# = p Case 1 r# = q g# = v b# = p Case 2 r# = p g# = v b# = t Case 3 r# = p g# = q b# = v Case 4 r# = t g# = p b# = v Default r# = v g# = p b# = q End Select EndIf HSV_R = r# * 255 HSV_G = g# * 255 HSV_B = b# * 255 End Function Function Animated_Casters(caster_2) Shadow_Resolution = 256 If CountChildren(Caster_2) > 0 For childcount = 1 To CountChildren(Caster_2) child = GetChild(caster_2, childcount) Animated_Casters(child) Next Else Cast_Shadow(caster_2, Shadow_Resolution) ; Fighter EndIf End Function |
| ||
I need the level and the character. I think the character is markio? Email them to me. My email address is in my profile. |
| ||
Just so those following the thread know, The problem with casting shadows from groups of entities parented to one another is now fixed. You can now load an animated mesh comprised of a group of entities that are connected to one another, and have them cast a single shadow. |
| ||
Can you post a PICTURE to see how it looks? |
| ||
6 year old thread, dude. |
| ||
Heh my thoughts exactly LineOf7s.... PS: that "dude" was priceless. |