This page will hopefully tell you enough to go and so that you can build your own world. The annotated code for the central.vr world. There is also some discussion about header files and how you connect to a multiuser world.
Standard Dive header as usual
#include "dive.vh"
Header that defined a doric style portal
#include "gateway.vh"
Standard floor sizes
#define FLOOR_SIZE (75)
#define TILE_SIZE (10)
#define pod_prop (0.05)
My own definition of a column so it has a texture.Almosti
dentical to the one in gateway.vh
#define marble_column(texture1, radius,height) \ name "Column" \ \ subs object { \ eulerxyz \ v -1.5707963 0.0 0.0 \ subs object { \ material "WHITE_M" \ texture texture1 \ nobackface on \ gouraud on \ view 0 { \ CYLINDER (1.5*radius) (1.5*radius) \ (pod_prop*height) \ } \ } \ subs object { \ material "WHITE_M" \ texture texture1 \ gouraud on \ view 0 { \ ELLIPSE (1.5*radius) (1.5*radius) \ } \ } \ subs object { \ material "WHITE_M" \ texture texture1 \ gouraud on \ translation \ v 0.0 0.0 (pod_prop*height) \ view 0 { \ ELLIPSE (1.5*radius) (1.5*radius) \ } \ } \ subs object { \ translation \ v 0.0 0.0 (pod_prop*height) \ gouraud on \ nobackface on \ material "WHITE_M" \ texture texture1 \ view 0 { \ CYLINDER radius radius \ (height-(2*pod_prop*height)) \ } \ } \ subs object { \ material "WHITE_M" \ texture texture1 \ gouraud on \ nobackface on \ translation \ v 0.0 0.0 \ (height-(pod_prop*height)) \ view 0 { \ CYLINDER (1.5*radius) (1.5*radius) \ (pod_prop*height) \ } \ } \ subs object { \ material "WHITE_M" \ texture texture1 \ gouraud on \ translation \ v 0.0 0.0 \ (height-(pod_prop*height)) \ view 0 { \ ELLIPSE (1.5*radius) (1.5*radius) \ } \ } \ subs object { \ material "WHITE_M" \ texture texture1 \ gouraud on \ translation \ v 0.0 0.0 height \ view 0 { \ ELLIPSE (1.5*radius) (1.5*radius) \ } \ } \ }
My own gateway. Uses the marble column above.
#define marble_gateway(dest_world, title, marb1, marb2, door_mat, text_mat, x_dest, y_dest, z_dest) \ material "WHITE_M" \ texture marb2 \ gouraud on \ view 0 { \ RBOX \ v -1.5 0.0 -0.5 \ v 1.5 0.25 0.5 \ } \ subs object { \ translation \ v -1.2 0.25 0.0 \ marble_column(marb1, 0.2, 2.5) \ } \ subs object { \ translation \ v 1.2 0.25 0.0 \ marble_column(marb1, 0.2, 2.5) \ } \ subs object { \ material "WHITE_M" \ texture marb2 \ gouraud on \ view 0 { \ RBOX \ v -1.5 2.75 -0.5 \ v 1.5 3.0 0.5 \ } \ } \ subs object { \ material door_mat \ gateway dest_world v x_dest y_dest z_dest \ gouraud on \ view 0 { \ N_POLY 4 \ v -0.9 0.5 0.0 \ v 0.9 0.5 0.0 \ v 0.9 2.3 0.0 \ v -0.9 2.3 0.0 \ } \ } \ subs object { \ material text_mat \ translation \ v 0.0 2.4 0.0 \ fixedxyz \ v 0.0 3.1415927 0.0 \ view 0 { \ CTEXT 0.25 title "ccp" \ } \ }
This is the start of the actual world definition. The world data structure for this world specifies:
The refence for these is here
world "Central UCL" {
start v 0.0 0 0
min v -1e+20 0.0 -1e+20
max v 1e+20 1e+20 1e+20
fog 0.10
background 0.15 0.3 0.5
}
The floor object. Just like any other dive object.
object { texture "http://www-dept.cs.ucl.ac.uk/research/vr/Dive/textures/o020.rgb" view 0 { N_M_POLY 1 4 (0+T_PER_VERTEX) N_POLY 4 v (0.5*FLOOR_SIZE) 0 (0.5*FLOOR_SIZE) t 0 0 v (0.5*FLOOR_SIZE) 0 (-0.5*FLOOR_SIZE) t 0 (FLOOR_SIZE/TILE_SIZE) v (-0.5*FLOOR_SIZE) 0 (-0.5*FLOOR_SIZE) t (FLOOR_SIZE/TILE_SIZE) (FLOOR_SIZE/TILE_SIZE) v (-0.5*FLOOR_SIZE) 0 (0.5*FLOOR_SIZE) t (FLOOR_SIZE/TILE_SIZE) 0 } }
Two gateways. Any object can have a gateway attribute, it just menas that collision with this object takes you to the world specified in the gateway field. Here we are using two macro, but the corresponding gateway lines specify the world and position so:
gateway "http://www-dept.cs.ucl.ac.uk/research/vr/Dive/worlds/games.vr" v 0 0 0
gateway "tutorial" v 0 0 0
object {
translation
v 0.0 0.0 25.0
cool_pos_gateway("tutorial","tutorial","GATEWAY_M","WHEAT_M",
"BOTTLE_GREEN_M", "GREEN_M", 0.0,0.0,0.0)
}
object {
translation
v 0.0 0.0 15.0
marble_gateway("http://www-dept.cs.ucl.ac.uk/research/vr/Dive/worlds/games.vr",
"games", "http://www-dept.cs.ucl.ac.uk/research/vr/Dive/textures/n066.rgb",
"http://www-dept.cs.ucl.ac.uk/research/vr/Dive/textures/n073.rgb",
"BOTTLE_GREEN_M", "GREEN_M", 0.0,0.0,0.0)
}
}
Setting up and sharing a multiuser world is easy in Dive, but which world is shared can be confusing.
Shared worlds can only exist because a diveserver is creating a shared database between applications. The applications using a diveserver can exist in different worlds though, if you watch diveserver it tells you the name of the worlds it supports and how many members are currently in each.
Worlds are shared when you access the world with the same name as one currently on the diveserver. When a person loads up a world the diveserver registers the name, so that anyone who loads up the same world gets a copy of the one already running. However the name is simply be the string that was entered load it.
Some repercusions:
A point to remember is that preprocessing on header files is only done with header files on your DIVEPATH. Bear in mind that other people DIVEPATHS may not be the same. This is especially true when loading via a URL. It does not download any required VH files as well, they are assumed to be on your own DIVEPATH.
This means you will have to do as I did for the central.vr world: any new macros that will be used in worlds used by other people must be defined in the same file. This also means that you will have to define the macro in every file that uses it.
Of course you can get around this my running all your .vr files through cpp before putting them up on the server. This was done on a couple of the UCL Example worlds.
Anthony Steed, A.Steed@cs.ucl.ac.uk