This tutorial will show how to get the most out of your .b3d scene exported from 3D World Studio. Map geometry is only the most basic kind of information stored in a 3D World Studio scene. There's much more useful information besides just triangles and vertex positions. By accessing this data in the loaded .b3d mesh, we can add particle emitters, start positions, water, visibility culling, and just about anything else you can think of.
Files
AdvancedSceneLoadingInBlitz3D.zip
LoadWorld()
When loading a .b3d scene, we are going to replace LoadMesh() with a new command, LoadWorld(), which we will write right now. We start by loading the .b3d, and returning if the scene fails to load. We use LoadAnimMesh() instead of LoadMesh() because LoadMesh() would collapse all objects into a single mesh, which we don't want:
Now we create a world pivot, with a number of child pivots and meshes. Each child is going to contain a certain type of object.
-The meshes entity will be parent to all map meshes found in the scene.
-The renderbrushes entity will be a collapsed mesh used for drawing all brush objects.
-The collisionbrushes entity will be a parent to all brush objects, and will be used for collision and picking. Since the renderbrushes entity is used to draw all the brush objects, the collisionbrushes entity will not be drawn. Blitz3D renders faster with single surfaces, which the renderbrushes object creates. However, separate objects are faster to run collision on, because Blitz3D performs a box test on each object. By storing the render and collision brush objects separately, our game will be most optimized for Blitz3D.
-The solidentities entity is parent to all solid entities. Solid entities are brushes or meshes that have a special classname. They can be used to create a trigger field the player steps into, an area filled with water, and lots of other things. Here, we will use a solid entity to create an invisible collision object.
-The pointentities entity is parent to all point entities in the scene. Point entities are placed in the editor, and can be lights, sound emitters, particle emitters, enemies, or just about anything else you can imagine. Here, we will use a point entity called a "playerstart" to tell our program where the camera should start out.
Now we are going to go through the scene limbs and load each limb according to what type of object it is. Each limb in the scene has properties stored in the entity name. The properties are stored as a keyname and a keyvalue, like this:
classname=light
range=800
color=255 255 255
By using the KeyValue() function, we can return a keyvalue for any entity, for whatever keyname we indicate:
keyvalue$=KeyValue$( entity, "classname" )
By selecting each entity "classname" we can determine what type of object each node in the scene is. Mesh objects will be parented to the meshes entity. Brush objects will be added to the renderbrushes entity for drawing, then parented to the collisionbrushes entity for collision:
Finally, we load our point and solid entities. We are only going to create one point and one solid entity. You will want to expand this to handle all types of entities in your engine:
We finish off the function by exiting the Next loop, freeing the original loaded mesh, and returning the world pivot:
Seeing it in Action
Open the example.3dw scene in 3D World Studio. Select the large box covering the map meshes and open the properties editor. You will see that this brush has a classname of field_hit. It also has two parameters, CastMeshShadows and CastBrushShadows, each set to 0. This will prevent the brush from casting a shadow when lights are calculated.
http://www.leadwerks.com/developer/images/c/cc/Blitz3dentities01.jpg?
There are three point entities in the scene. Two are lights, and one is a playerstart entity. The angles property indicates the orientation of the camera:
http://www.leadwerks.com/developer/images/6/68/Blitz3dentities02.jpg?
Open the LoadWorld.bb program and run it. The camera will start at the position and orientation of the "playerstart" entity. The camera will collide with the brush walls, and with an invisible collision brush covering the meshes. Collision will not be run on the more complex mesh objects.
What Other Entities Are There?
Whatever you want! This tutorial has shown you how to place entities in the editor and load them in Blitz3D. It's up to you to decide what "kinds" of objects your engine will handle. Add a particle emitter, a monster or a block of water. Use the KeyValue() function to return any parameters you want to set in the editor. Your imagination is the only limit.
Files
AdvancedSceneLoadingInBlitz3D.zip
LoadWorld()
When loading a .b3d scene, we are going to replace LoadMesh() with a new command, LoadWorld(), which we will write right now. We start by loading the .b3d, and returning if the scene fails to load. We use LoadAnimMesh() instead of LoadMesh() because LoadMesh() would collapse all objects into a single mesh, which we don't want:
Function LoadWorld(file$) map=LoadAnimMesh(file) If Not map Return
Now we create a world pivot, with a number of child pivots and meshes. Each child is going to contain a certain type of object.
-The meshes entity will be parent to all map meshes found in the scene.
-The renderbrushes entity will be a collapsed mesh used for drawing all brush objects.
-The collisionbrushes entity will be a parent to all brush objects, and will be used for collision and picking. Since the renderbrushes entity is used to draw all the brush objects, the collisionbrushes entity will not be drawn. Blitz3D renders faster with single surfaces, which the renderbrushes object creates. However, separate objects are faster to run collision on, because Blitz3D performs a box test on each object. By storing the render and collision brush objects separately, our game will be most optimized for Blitz3D.
-The solidentities entity is parent to all solid entities. Solid entities are brushes or meshes that have a special classname. They can be used to create a trigger field the player steps into, an area filled with water, and lots of other things. Here, we will use a solid entity to create an invisible collision object.
-The pointentities entity is parent to all point entities in the scene. Point entities are placed in the editor, and can be lights, sound emitters, particle emitters, enemies, or just about anything else you can imagine. Here, we will use a point entity called a "playerstart" to tell our program where the camera should start out.
world=CreatePivot() meshes=CreatePivot(world) renderbrushes=CreateMesh(world) collisionbrushes=CreatePivot(world) pointentities=CreatePivot(world) solidentities=CreatePivot(world) EntityType collisionbrushes,COLLISIONTYPE_BRUSH
Now we are going to go through the scene limbs and load each limb according to what type of object it is. Each limb in the scene has properties stored in the entity name. The properties are stored as a keyname and a keyvalue, like this:
classname=light
range=800
color=255 255 255
By using the KeyValue() function, we can return a keyvalue for any entity, for whatever keyname we indicate:
keyvalue$=KeyValue$( entity, "classname" )
By selecting each entity "classname" we can determine what type of object each node in the scene is. Mesh objects will be parented to the meshes entity. Brush objects will be added to the renderbrushes entity for drawing, then parented to the collisionbrushes entity for collision:
For c=1 To CountChildren(map) node=GetChild(map,c) classname$=Lower(KeyValue(node,"classname")) DebugLog "Loading "+Chr(34)+classname+Chr(34)+"..." Select classname Case "mesh" EntityParent node,meshes c=c-1 EntityType node,COLLISIONTYPE_MESH Case "brush" AddMesh node,renderbrushes EntityType node,COLLISIONTYPE_BRUSH EntityAlpha node,0 EntityParent node,collisionbrushes c=c-1
Finally, we load our point and solid entities. We are only going to create one point and one solid entity. You will want to expand this to handle all types of entities in your engine:
;Invisible collision brush Case "field_hit" EntityParent node,collisionbrushes EntityType node,COLLISIONTYPE_BRUSH EntityAlpha node,0 c=c-1 ;Camera start position point entity Case "playerstart" angles$=keyvalue(node,"angles","0 0 0") pitch#=piece(angles,1," ") yaw#=piece(angles,2," ") roll#=piece(angles,3," ") If cam PositionEntity cam,EntityX(node),EntityY(node),EntityZ(node) RotateEntity cam,pitch,yaw,roll EndIf
We finish off the function by exiting the Next loop, freeing the original loaded mesh, and returning the world pivot:
End Select Next FreeEntity map Return world End Function
Seeing it in Action
Open the example.3dw scene in 3D World Studio. Select the large box covering the map meshes and open the properties editor. You will see that this brush has a classname of field_hit. It also has two parameters, CastMeshShadows and CastBrushShadows, each set to 0. This will prevent the brush from casting a shadow when lights are calculated.
http://www.leadwerks.com/developer/images/c/cc/Blitz3dentities01.jpg?
There are three point entities in the scene. Two are lights, and one is a playerstart entity. The angles property indicates the orientation of the camera:
http://www.leadwerks.com/developer/images/6/68/Blitz3dentities02.jpg?
Open the LoadWorld.bb program and run it. The camera will start at the position and orientation of the "playerstart" entity. The camera will collide with the brush walls, and with an invisible collision brush covering the meshes. Collision will not be run on the more complex mesh objects.
What Other Entities Are There?
Whatever you want! This tutorial has shown you how to place entities in the editor and load them in Blitz3D. It's up to you to decide what "kinds" of objects your engine will handle. Add a particle emitter, a monster or a block of water. Use the KeyValue() function to return any parameters you want to set in the editor. Your imagination is the only limit.