Steps
to building BrahmsVE applications and other information
Index:
A)
3D Modeling and animation in preparation for supporting
the Brahms Output

Figure 1: a collage of gestures from
the EVA prep scenario
A large number
of animations must be produced to support a BrahmsVE application
(as shown in figure 1 above).
1) A Primer
on the Methodology used to associate objects with agents
(we refer to as Avatars) in a 3D scene

Figure
2: the canonical Bill and his Coffee scneario
In
our canonical example of Bill and the coffee cup "take
a drink", Brahms gives a single command but this
causes a cascade of animations and object actions when
that Brahms command is ingested into the VE core and its
JavaScript parser and scheduler. First the JavaScript
("the script") causes the cup to disappear from
the table, then the cup that is built into the Bill avatar
appears on his hand and is therefore able to move along
with agent, permitting an arm gesture to allow Bill to
seem like he is drinking or reheating his coffee (as in
Figure 2 above). Lastly for Bill to put down the cup,
the script tells the cup to disappear inside the avatar,
then the other cup appears in the world again on the table.
So you need two models of the cofee cup to make this happen.
2) Development
of the 3D component models
i) Worlds
Worlds (the
background scene, in this case the FMARS HMP habitat)
are developed in the Atmosphere Builder and exported to
the .AER format along with Javascript files and other
referenced files (textures and Viewpoint Objects, see
below).
Once
this world scene is created, walkthroughs with the Brahms
modeler must occur to set the named anchor points (areas)
which represent pathways and destinations for objects
and avatars in the ultimate BrahmsVE application. Automatic
wayfinding is obviously a better long term solution and
this was recently developed in test for the MER
prototyping efforts.
Timing:
a world itself can take anywhere from a week to 2 weeks
or more again depending on the complexity.
ii)
Objects
We will first
look into the MTX (metastream viewpoint) structure of
an object used in an Atmosphere scene in BrahmsVE:
Example
object for study (backpack)
Next
we will look into a larger and more sophisticated 3D viewpoint
object, an Avatar representing an agent in the scene:
Example
avatar (Bill Clancey Avatar)
Steps
and Tools used to create 3D objects (excluding world):
A
whole series of steps and tools are needed to create and
animate the 3D viewpoint objects.
1.
Model is created in 3D Studio Max (3dsmax)
2. Model is then textured in 3dmax
3. Model is then exported to 3ds format
4. Model is then imported into Poser
5. Model then has bones applied
6. Other accessory objects that are needed are imported
following above steps to be applied to the master object
(ie: coffee cup for Bill's avatar).
7. Accessory objects are processed and then bones have
to be applied as well
8. Next the animations are created frame by frame for
each object (see Key Framing of Animations below).
9. Test animations to be sure they run aand then tweeked,
that is triggering the cluster of animations set off by
a Brahms output gesture
10. Once we are happy with the animations we then export
to viewpoint
11. We then test in viewpoint
12. We then imported the viewpoint objects into Atmosphere
and turn them into agents
13. We test in Atmosphere and correct any mistakes by
going back to just when annimations are applied.
Key
Framing of Animations
1.
Load object (human figure) into the frame editor in Poser
2. Start with frame 1 (say have the avatar seated) Poser
has a large library of typical positions but we cannot
use them as they are too generic and often not detailed
enough
3. Next move to the 50'th frame and then have the figure
standing
4. Poser would fill in the blanks between frame 1 and
50
5. Go back and tweek in each frame to get it the way you
want because Poser doesn't always do it correctly, this
can be a time consuming process.
Timing:
8 hours to create a typical model and texture it and iteration
for a week or so.
Reusability:
Cutting and pasting of animations from one avatar to next.
So far we have not created anything generic as we have been
following a script.
Definition:
Bones
Bones are pivot points in avatar or objects. skin (mesh)
has to be attached to the bones in the right area. You have
to attach multiple parts of the mesh to the bones. Textures
are applied prior to the application of the bones. Once
bones are completed then the animations can be applied.
B) Development and and testing of a
Brahms VE application: the Brahms Modeler's Side of the
story
The Brahms model
must be developed in close cooperation with the VE 3D scenegraph
modeling team. Brahms modelers must choreograph the action
through the world, and help the 3D designers and JavaScript
Core VE engine developer understand the sequencing, naming
of areas and gestures and other animations, and engage in
constant iterative testing.
1) The Brahms
modeler's tasks
- The Brahms
model is developed, named gestures and areas in the 3D
world are built right into the Brahms model itself.
- The Brahms
Modeler must specify the appearance and layout of the
3D world, pathways and named areas, the objects and avatars
(agents) that must be in the world, starting clock, timing
of actions and animations, any built in delays, and the
textual reporting that will help the end user understand
the model. Important from this process is the production
of an inventory of objects, avatars, labels of areas in
the world for motion of agents, and gestural sequences
and how the mapping of a Brahms label for a gesture is
satisfied by the cluster of local animations built into
the 3D model.
- The Brahms
Oworld export must be generated along with a parallel
human readable script for the 3D modeling team. Often
this is accompanied by overhead storyboards, as showin
in Figure 3 below.

Figure 3: Storyboard to aid the VE modeling
team
Many iterations
must take place between the Brahms team, 3D modeler and
JS developer to achieve the desired results.
2) Sample
Brahms Output
The
following is the record format of the "Oworld"
exported action output of Brahms from the start of the Planning
Meeting (Scenario 1).
activity|primitive|0|57|projects.fmarsvre.RZ|AnnouncingStartOfPlanning|
activity|primitive|57|58|projects.fmarsvre.RZ|RequestingGeneratorStatus|
activity|primitive|58|114|projects.fmarsvre.RZ|OrderingToRefuelGenerator|
activity|primitive|114|171|projects.fmarsvre.RZ|RequestingWeatherReport|
activity|primitive|171|176|projects.fmarsvre.RZ|Getup|
The above exported
actions can be placed into the VE model by cut and paste
or by inclusion in a web interface (text buffer) which the
JS for the VE has access to. The VE core then parses these
commands. More is described in the section following on
the BrahmsVE Core. In future these actions will be sent
live via a connection (SOAP or another means). Figure 3
below shows our vision for the real time communications
between Brahms and the VE.

Figure 4: the proposed real time communications between
Brahms and the VE
C) Overview of the BrahmsVE Core
Figure 5 below
shows the major components of the "VE Core" which
is the Javascript library that is embedded into each Atmosphere
scenegraph. Currently each VE Core contains both generic
elements (threading, scheduling, triggering) and scripts
that are custom built for the particular application (custom
groupings of clusters of small animations to create one
addressible gesture, such as "drink coffee").

Figure 5: the full vision for the BrahmsVE
Core engine
There are a few
ways we have used to get the data to the VE core. The first
way, from around the time of the first coffee sequence,
involved manually translating the input lines into function
calls, one function call per line. Basically I was performing
the role of the parser. Those function calls were tagged
on at the end of the script and called after everything
else was set up. You can probably recognize them at the
bottom of the coffee sequence script.
2)
VE Core Parsing and Execution Steps (by Rolu)
Once
the Brahms output has been parsed a series of function calls
are generated. The following lines below correspond to the
function calls for the Planning Meeting Brahms output. These
lines are executed when the Sequence button is pressed in
the Controls interface:
this.ctrl.handleLine("activity|primitive|0|45|projects.fmarsvre.RZ|AnnouncingStartOfPlanning|");
this.ctrl.handleLine("activity|primitive|45|46|projects.fmarsvre.RZ|RequestingGeneratorStatus|");
this.ctrl.handleLine("activity|primitive|46|97|projects.fmarsvre.RZ|OrderingToRefuelGenerator|");
this.ctrl.handleLine("activity|primitive|97|153|projects.fmarsvre.RZ|RequestingWeatherReport|");
this.ctrl.handleLine("activity|primitive|153|156|projects.fmarsvre.RZ|Getup|");
However, as long as the lines are fed to the parser it doesn't
matter where they come from. Having them hardcoded like
in the above example is convenient, especially during testing
and demoing (and therefore still in use), but not necessary.
The third option is the webpage where you can paste the
lines directly into a html form, after which they get parsed
and executed by the script (running in the plugin). Since
there is no preprocessing at all necessary this way it forms
an almost direct link with Brahms. All you have to do is
copy the lines from the generated text file and paste them
in the web form.
The script that drives the Atmosphere scene contains three
important parts. The first is the VE core. This contains
all base functionality without regard to the simulation.
It contains the parser, the generic code for agents and
objects and everything else every simulation needs. The
second part is the simulation-specific part, which contains
the code for the used actions, agents and objects. The third
part is the initialization part, it is where stuff like
the above example function calls for this.ctrl.handleLine
lines belong, and it initializes the whole simulation (the
first two parts are basically just libraries, the initialization
part connects them in the right way).
The script knows about all involved entities (agents, objects,
places). Each of those entities is represented in the script
(their specific code is in the simulation-specific part,
which is based on generic code from the core, and they are
initialized in the initialization part). The specific code
for agents for example defines what aer and viewpoint objects
are used for the agent, what animations it has access to,
and details like how fast it's walking animation goes in
order to correctly synchronize the walk animation with horizontal
movement. The specific code for objects depends on what
they can do - specific code for a door for example would
contain open/close animations. Not all objects need specific
code, the laptop as used in sc1 for example is completely
inanimate and therefore does not appear in the script. Place
entities, which form the mapping between something like
projects.fmarsvre.GalleyArea and the position/orientation,
do not have specific code since they are all very similar,
those are all initialized in the initialization part and
taken care of in the core directly.
The initialization part of the script contains, as said,
the code that links up the libraries in the correct way.
It starts with initializing the core - creating the controller
object, for example. At this time it is a completely generic
VE environment. Then it sets up the simulation-specific
part. It creates and sets up objects for all entities involved.
In case of the sc1 script for exmple it creates an object
for every agent (there is some customized specific code
for every person in the simulation-specific part of the
script). It also sets up all the area's. There are no objects
in use in sc1 at this time that require special code. Then
it sends commands to the agent objects that make them be
seated around the table. When that all is finished it's
ready to accept Brahms output. It should be noted that every
piece of the simulation-specific part of the initialization
is now hardcoded, but can also (eventually) be triggered
by sending the right commands to the parser. In fact part
of the initialization is already done that way, and the
rest can easily be adapted. This makes it possible to have
a world with the VE core and a big set of simulation-specific
libraries, so you can make it display any simulation that
uses elements from the libraries, simply by placing some
initialization commands in front of the Brahms output and
sending all of it to the world.
3)
Simulation Specific Code
As you probably understand by now, the capabilities of a
script based on the VE core depend mostly on the simulation-specific
code. There must be specific code for every used agent (you
can have code around for agents that are not used in the
simulation that you are currently running, that does not
matter). There must be code for all actions the agents can
perform (those are the "action scripts", they
are more or less separate entities and can be shared by
agents). There must be code for all objects. However, once
the simulation-specific code is there you can combine it
in pretty much any way you want. With a little improvisation
you could model a game of musical chairs with the current
sc1 script without touching one single line of it, simply
by sending it a different Brahms output. All necessary scripting
is there - getting up, sitting down and walking around.
Adding agents or actions however involves writing action
scripts and modifying or creating the specific code for
agents, possibly changing or adding objects, and creating
the models and animations themselves. This requires specialistic
knowledge on the areas of (among others) Atmosphere, Atmosphere
javascripting, aer modelling, viewpoint objects and poser.
4)
Journey of an action output
To
get back to the original question - what happens when a
line enters the script? In a nutshell, it first gets passed
to the controller object, which runs it through the parser.
This results in either an error message or a collection
of information that's useful to the script. The agent object
that will handle the line further is looked up, and the
information is passed to it. The agent object will now queue
the information to until it's time to play the action. When
that time arrives the agent object looks up the corresponding
action script and hands over control. The action script
will do what's necessary and return control to the agent
when it's done. Along the way there are several points where
special actions can be performed, you could for example
send a request for status information to one of the agents.
This would be passed on to the agent, but not be queued
but processed immediately.
5)
Issues with the current approach
There
was another question - on the problems with the current
script. There are several, but basically they all come down
to the "pioneer" character of the current work.
Atmosphere is still a very new platform and as such there
is a lack of experience on many area's - things like, what
programming techniques work best? What is the best way to
control several viewpoint objects at the same time? How
can you interface with the outside world (that was basically
impossible at the start of the project)? There are several
programming techniques that work and are fairly standard
in the typical small scale projects but don't scale very
well to this level. To give an example, let's look at the
standard way to perform simple animations in Atmosphere.
In Atmosphere, every time before a frame is rendered the
scripts in the world get a chance to update the world. The
intervals between two of such events (called "timesteps")
is directly depending on your framerate and can vary a lot.
To make this easier the scripts get to know the total amount
of seconds elapsed since the world was entered and the amount
of seconds elapsed since the last timestep.
So, when your animation starts (say we are moving a box
from A to B in 8 seconds) you remember the current time.
You usually know how long your animation is going to take
(8 seconds this time), so you can calculate at what time
your animation should end - you remember that too. Finally
you place your box at A. The next timestep you first check
if the current time is past the time the animation should
end - if so you place the cube at B and stop. If not, you
check the time elapsed since the last timestep and use that
to calculate where the box should be now, (elapsedtime/totaltime)th
of the way between A and B.
We used this recipe in the VE scripts too. Most action scripts
have a variation of it as their core. It worked fine at
first. But later on it became more and more complicated.
A standard animation like above needs a fixed duration to
work. However, the actions we currently use have variable
lengths, and in some cases no real length at all (since
the end time is not known when the action starts). Furthermore
we now have simulation time seperated from real time. However,
the viewpoint animations still play in real time. They have
to be sped up or slowed down according to a combination
of the simulation time multiplier, a multiplier that results
from stretching or shrinking the action and a multiplier
that can be used to fix speed problems with the viewpoint
animations (necessary in some cases). All of that can be
done, however it gets overly complicated. Furthermore control
over the agent object is in hands of the action scripts,
which return it when they feel like. One bug in an action
script can wreck havoc with the schedule. It's not possible
to jump to a certain time in the simulation at once since
most action scripts never return control in the same timestep
as they got it. Finally, it's impossible to run the simulation
backwards.
5)
Future approaches
Instead we want to try an alternative approach where the
concept of time "flowing" is abandoned, and the
whole simulation is more stateless as far as time is concerned.
Every timestep the controller object will determine the
current time, depending on user input, the clock and Brahms
output, and will simply tell every agent to evaluate themselves
towards that time. Similarly, the agents will figure out
what action script that time falls in (they will remember
their whole queue since the start of the simulation) and
will tell the action script to evaluate itself towards somewhere
between 0 (start) and 1 (end). If the current action script
is another one than the one used last timestep that one
and all action scripts inbetween will have to be evaluated
to 1 (if going forward) or 0 (if going backward) to keep
everything consistent. This way you can go both forward
and backward in time at any arbitrary speed (and hence jump
to any time), while the agents will stay in control of themselves.
Since viewpoint animations can be told to evaluate towards
a certain time in the same way, handling is much easier
for action scripts, and the rest of the code can stay cleaner
(and therefore easier to build/maintain) too.
|