A VR application is a 3D game, just without the game-like objectives-dynamics.
Since there is a lot more work done in games then their is in VR, and I know a lot more about games, I am just going to talk about games.
My goal in teaching you guys is to get you all working in some kind of 3d world, so that each of you feels comfortable doing something.
I will explain some of the architecture used in many game engines and graphical packages, and explain some detail about the different systems used in those engines.
Primarily I am trying to get people to work with this stuff, and not just hear about it, so I'll include nice demos of everything that I expect people to try.
1) An internal representation models different aspects of reality, including as how things move and interact.
2) An external representation displays the information from the internal model to the user.
This involves just the external representation, as this object will have no actual interaction with the game universe.
Load up the game and type:
sel /game/vis | moves to the root of the scenegraph |
new n3dnode asteroid | creates a new n3dnode named asteroid as a child of the current node |
sel asteroid | selects the asteroid making it the current node |
gen_mesh lib/asteroid/data/asteriod.n3d | creates a nmeshnode that contains the mesh (set of polygons). |
gen_tex lib/asteroid/data/asteroid.bmp | creates a ntexarraynode that contains the texture |
gen_shader simple | creates a simple shader for this object |
save | saves this object to a file named asteroid.n for later use. |
For ambience type
gen_skybox stars | creates a skybox, using images from the directory "stars" |
It created a little tree composed of 4 nodes.
Since this tree is placed inside /game/vis (which is the root of the scenegraph) it gets displayed to the screen.
Instantiations of most classes live somewhere in the NOH, or named object hierarchy.
Think of it as naming an object every time you new them, and then putting those names in a big tree.
Soon you have something very similar to a directory tree, where all the objects are easily accessible.
The part of the tree we created looks like
game vis asteroid tex mesh shaderThis tree has a whole bunch of uses
All of this will make a lot of sense after working with it a little bit.
We created 4 classes, each doing its part towards drawing the object on the screen.
n3DNode contains the location of the object, and forms the root of the tree for each node.
nTexArrayNode holds an array of textures - the array is neccessary for multitexturing
nMeshNode holds a mesh - a set of polygons that define the object.
nShaderNode is a huge class with tons of options that controls how the object is drawn to the screen.
How do you keep track of all the objects you want to draw to the screen? The first way is just using a list, each object exists in the list and the list is walked each frame.
The best way to do it is using a scenegraph, which is the logical extension of this list.
Since many objects are hierarchical, i.e. a car & wheels, so we can use a tree to better represent things.
In this tree transformations at each node of the tree are passed down to children. The car contains the location of the car, the wheel just know their offset from the base of the car. As the car moves so do the wheels, even though the position contained in the wheel does not change. Using a list each wheel would have to continually determine the location of the car and place itself accordingly.
The SceneTree becomes a SceneGraph when we begin to reuse information. It is wasteful to keep 4 wheels, when the only difference between them is their transformation. By using a simpler class containing just this transformation, and making the entire wheel the children of several transformations we can be more effecient.
This is implemented with a matrix stack. Each node has a very simple algorithm to draw itself
Okay after much explanation we have created something, and explained how it is getting drawn.
The next step is to look at the internal representation.
Objects in the game are represented by entities living under /game/ent.
Each of these entities keeps a link to its corresponding node in the scenegraph that lives under /game/vis
That node looks just like the node we created before.
The entity however is very different as it has to act and interact with the world and not just get displayed.
sel /game/vis | we want the asteroid to be loaded into the vis tree |
get asteroid.n | loads the asteroid from the file we saved before |
sel /game/ent | moves to the entity tree |
sn nentity asteroid | is a combination of sel and new. It creates and selects an object |
setvis /game/vis/asteroid | tells the entity where its visnode is, in our case the asteroid we created before. |
sv pos 0 2 0 | sets the variable pos (position) attached to that entity to 0 2 0 |
var | displays all the information about the selected entity |
Each entity class is designed as a wrapper to hold data, it also connects to the vis node, and handles a few miscellanous things. Too add interesting behaviors we add classes called aspects as children of it in the NOH.
The result is a kind of powerful dynamic multipleinheritence, whereby game objects can gain modular methods and characteristics on the fly.
This seems much more complicated then it really is, so we'll skip over any further explanation for now.
new nphysics physics | This will add a rigid body physics model to the object |
sv torque 0 0 10 | Applies a torque to the object around the z axis. |
var | Shows all the new variables associated with the object since we attached the physics model |
The asteroid should spin around the z axis for a while and then come to a rest.
It comes to a rest because the default physics settings include drag.
To get it to behave more like an asteroid in space lets change that.
sv rfriction .01 | reduces the rotational friction so the asteroids looses 1% of its velocity every second. |
sv torque 1 3 5 | applies torques around all 3 axis's, to get a more natural spin. |
For stabilities stake we still maintain some rotation friction, but it should spin virtually indefinitely this time.
Now Lets give it a push, and see how it moves
sv friction .01 | reduces the linear friction so it looses 1% of its velocity every second. |
sv force 0 0 10 | applies a force along the z axis. |
Now it should move forward slowly at a nice even pace, to keep it from getting away lets set it so that its position will wrap around.
new nAreaWrapAround wraparound | wraps its position around a specified area. |
To get much further we need to move from using the console to scripts, as typing it into the console quickly becomes tedious.
Instead of just typing everything into giant initialization files, a unifed system for storing entities, aspects, and all their data.
Functions can then be used in initialization scripts to create the game world.
In nebula/data/lib there is a folder for every kind of entity.
Information about each entity is stored there, and the gen_ent function is used to create them.
I included a directory for this asteroid, as we can just start using it.
gen_ent asteroid | creates an entity/vis node of type asteroid pair out of the library. |
nebula/data/scripts (refered to as scripts from now on) contains all the scripts.
go.tcl is the main script called when the engine is loaded, at the end of it just before game.start add:
gen_ent asteroidThen run the game, now it should load up automatically.
loadscript asteroids.tcl
Run it again and it should load a bunch of asteroids.
Go into asteroids.tcl, and uncomment (remove the #) the two lines.Now it should create a whole bunch of asteroids, each moving around at random speeds.
in data/lib/asteroid.ent.tcl (before the sel..) add: new ncollisionnode collision cs collissionshape asteroid cs collisiontype object
This file contains all the aspects and variable settings for the asteroid entity, by adding the collisionnode we give asteroids the ability to collide.
Rerun it, and this time the asteroids should bump into each other and bounce around.
If you are feeling brave you can try to import my aircraft model (platform) from my research project and try to fly it around and avoid the asteroids.
set ent [gen_ent platform] | creates a platform entity and stores its name into ent |
/game/camera.sref attachedto $ent | sets the camera to follow the ent created above |
/ui.ss selected $ent | sets the interface to move the platform, instead of the camera. |
new nareawraparound $ent/wraparound | forces the plane to wrap around too |