Avatar Introduction
Any valid VRML code has the potential ability to act as a user's avatar,
but to add extra features and
options like gestures, movement behaviour and exploiting chat text
strings special code is required.
Blaxxun avatars will not be accepted for the Deep Matrix network. Standard
Avatar Studio2 output avatars
with the Script work-around "vrmlmatrix" js object do not work
well in Instant Player. Their gestures
lower the fps in Instant Player to an unreasonable degree and in some
cases cause it to crash.
However if these avatars are first converted to HAnim animation by
Seamless3D at: http://www.seamless3d.com/
and then hand edited with the addition of Deep Matrix Scripts, fields
and Protos they can be used in Deep Matrix.
Instructions for this conversion are here: Avatar
Studio2 Conversion
Since Seamless is open source I hope in the near future to modify its
source code to output Deep Matrix ready
HAnim avatars. In the meantime they have to created by hand editing.
Avatars are located in the client_application/worlds/Avatars folder,
feel free to look at their code and learn.
Here is the Proto header for a Deep Matrix avatar, I have annotated its various features with a "#" sign:
PROTO Avatar[
exposedField MFString gestures ["Hello","Laughing","Frowns","Agrees","NG_no_lod","NG_humanoid"]
# gestures field carries the expression choices that will be listed
in pull down menu of the Java client GUI.
# There are six strings in the field, but only those that are
not prefixed with "NG_" will show up as expression choices.
# There MUST be one expression string for each "eventIn SFBool
gesture" described below.
# The "NG_" prefixed strings are to instruct the Java application
that the avatar is to have certain features during loading.
# "NG_no_lod" tells the application to skip the built in LOD
generally given to all avatars and backback objects.
# "NG_humanoid" tells the application to look for humanoid behaviour
fields. It is mandatory for humaniod avatars in general and
# avatars converted from AvatarStudio2 in particular.
eventIn SFBool gesture1
eventIn SFBool gesture2
eventIn SFBool gesture3
eventIn SFBool gesture4
# The basic gesture inputs. Notice in this example there are four eventInSFBool
gesture and four strings in the gestures field without the "NG_" prefix.
# Notice too they are SFBool rather than SFTime as in blaxxun avatars.
exposedField SFString inMotionBehaviour "walkBehaviour"
exposedField SFString notInMotionBehaviour "standBehaviour"
# inMotionBehaviour and notInMotionBehaviour are fields looked
for when the "NG_humanoid" tag is used in the gestures field.
# Not having them will result in the avatar not loading.
walkBehaviour and standBehaviour
eventIn SFBool walkBehaviour
eventIn SFBool standBehaviour
eventIn SFVec3f set_position
eventIn SFRotation set_orientation
eventIn SFInt32 set_proxy
eventIn SFBool set_UserAvatar
eventOut SFBool isOver
eventIn SFBool set_HUD_anim
# The above five eventIns are mandatory for avatars with the "NG_humanoid" tag
exposedField MFString imageTexture_url ["http://www.sevenemeraldtablets.net/Delores/delores.jpg","delores.jpg"]
exposedField SFBool dmAvatarStudio TRUE
# The bottom two fields are for Avatar Studio2 avatar conversions and
necessary
for them to function correctly.
# The "NG_humanoid" gestures tag is also mandatory Avatar Studio2 avatar
conversions.
eventIn SFString set_name
# Optional field to deliver the user's name to the avatar.
eventIn MFString talker_text
# Optional field to deliver the chat text from the network to the avatar.
eventOut MFString to_local_chat
# Optional field to deliver the text from the avatar to the immediate
user's chat display.
eventOut MFString to_network_chat
# Optional field to deliver the text from the avatar to the network
for all the world's users to see.
]
{
How to Convert an Avatar Studio2
Avatar for Deep MatrixIP9 Use
Special Note on Avatar Positioning
1. First convert the avatar to H-Anim using Seamless3D
Open Seemless3D then choose:
file -> import bxx studio and open your avatar
then choose:
scene tree -> scene
In the new scene window check your desired option boxes and make SURE
the "genHAnimNodes" box is checked AND "genContactSBVT" box is unchecked.
If you are going to use NotePad as an editor you will want to make
sure the "outputGZipped" box is unchecked as well,
otherwise the code will look like gibberish because it is compressed!
then click the "output" button at the top.
2. Back up your newly generated avatar and do the modifications from
a copy!
3. Now open the avatar file copy in a text editor -perferably VrmlPad,
but NotePad will work as long the file is not g-zipped!
A. Using the "Find" feature go to instances of the word "PAnim"
in the file.
For example:
DEF TS1 PAnim{
period 2.0005
children [
Replace the word "PAnim" with "TimeSensor", replace the word "period"
with "cycleInterval"
After the numerical decimal value put in a left facing curly bracket
i.e. "}"
like this:
DEF TS1 TimeSensor { cycleInterval 2.0005 }
Press enter and on the next line add "Group {" directly above "children ["
The final modification looks like this:
DEF TS1 TimeSensor { cycleInterval 2.0005 }
Group {
children [
You'll have to do this twelve times for each "PAnim" instance.
At DEF TS11 change the cycleInterval floating decimal value to .3:
DEF TS11 TimeSensor { cycleInterval .3 }
When you get to the bottom "DEF TS12" the TimeSensor code MUST include
"enable FALSE and loop true"
Like so:
DEF TS12 TimeSensor { cycleInterval 1.5267 enabled FALSE loop TRUE }
Using the "Find" feature search the file for the word: "startTime"
and delete all twelve lines of "startTime IS gesture1" through
"startTime IS gesture12".
Generally speaking you can do this easily when you replace TimeSensor
for PAnim, because "startTime IS..."
will be found right above the DEF TS code. However the last "startTime
IS gesture12" you will have to use
the "Find" feature to locate.
In the ROUTE portion at the bottom of the file replace the word "slider"
with "fraction_changed".
For example:
ROUTE TS1.slider TO ....
becomes:
ROUTE TS1.fraction_changed TO...
B. Next find line starting with "geometry IndexedFaceSet" from the top
of the file and select -
delete the top part of the file starting with the left curly
bracket "}"
to directly below up but not including
the line "#generated by Seamless3d....":
Then below the line "#generated by Seamless3d...." copy and paste in
the following code between the rows of "#" signs
#####################################################################
PROTO Avatar["
eventIn SFBool gesture1
eventIn SFBool gesture2
eventIn SFBool gesture3
eventIn SFBool gesture4
eventIn SFBool gesture5
eventIn SFBool gesture6
eventIn SFBool gesture7
eventIn SFBool gesture8
eventIn SFBool gesture9
eventIn SFBool gesture10
eventIn SFBool walkBehaviour
eventIn SFBool standBehaviour
eventIn SFVec3f set_position
eventIn SFRotation set_orientation
exposedField SFString inMotionBehaviour "walkBehaviour"
exposedField SFString notInMotionBehaviour "standBehaviour"
exposedField MFString gestures ["Hello","Laughing","Frowns","Agrees","Smiles","Disagrees","Rejects","Upset","Good_bye","Super_zen"]
eventIn SFInt32 set_proxy
eventIn SFBool set_UserAvatar
exposedField SFBool dmAvatarStudio TRUE
exposedField MFString imageTexture_url [""]
eventOut SFBool isOver
eventIn SFBool set_HUD_anim
]
{
Group {
children [
Collision {
collide FALSE
children [
DEF Ts TouchSensor { isOver IS isOver }
DEF vis VisibilitySensor { size 1 2 1 center 0 1 0 enabled FALSE
}
DEF Sw Switch {
whichChoice 0
choice [
Group {
children
Shape {
appearance NULL
geometry IndexedFaceSet {
coord Coordinate {
point [ -0.17 .7 0.125,
-0.17 -.98 0.125,
0.17 .7 0.125,
0.17 -.98 0.125,
0.17 .7 -0.125,
0.17 -.98 -0.125,
-0.17 .7 -0.125,
-0.17 -.98 -0.125 ]
}
coordIndex [ 0, 1, 3, 2, -1, 4,
5, 7,
6, -1,
6, 7, 1, 0, -1, 2,
3, 5,
4, -1, 6, 0, 2, 4,
-1, 1,
7, 5, 3, -1 ]
color Color { color [ .3 .3 .3, .3 .3 .3, .3 .3 .3, .3 .3 .3, .3 .3 .3,
.3 .3 .3, .3 .3 .3, .3 .3 .3 ]}
}}
}
Group {
children [
HAnimHumanoid{
skin Shape{
appearance Appearance{
material Material{
}
texture ImageTexture{
url IS imageTexture_url
}
}
###################################################################################
C. Use the Find function to locate the following code near the top
of the file:
exposedField MFString imageTexture_url [""]
and put in the address or addresses of your avatar's .jpg file
It should have the same name as your avatar file i.e. "lili.wrl" has
"lili.jpg"
between the square brackets like this:
exposedField MFString imageTexture_url ["lili.jpg"]
for more than one address seperate the addresses with a comma:
exposedField MFString imageTexture_url ["http://www.mysite.com/html/myavatars/lili.jpg",lili.jpg"]
D. Next using the Find function again locate the code "exposedField MFString gestures" near the top of the file:
exposedField MFString gestures ["Hello","Laughing","Frowns","Agrees","Smiles","Disagrees","Rejects","Upset","Good_bye","Super_zen"]
and add at the very end of the list of gesture expressions the following
two words seperated with commas: "NG_no_lod" and "NG_humanoid".
The result should look like this:
...."Upset","Good_bye","Super_zen","NG_no_lod","NG_humanoid"]
E. Go the bottom of the file that is right above the ROUTE section
and paste the following code between the rows of "#" signs above the
ROUTE listings:
###################################################################################
DEF InitTimer TimeSensor { loop TRUE cycleInterval .1 }
DEF DMsc Script {
eventIn SFVec3f set_position IS set_position
eventIn SFRotation set_orientation IS set_orientation
eventIn SFTime initTime
eventIn SFBool isActive
eventIn SFBool watched
eventIn SFBool gesture1 IS gesture1
eventIn SFBool gesture2 IS gesture2
eventIn SFBool gesture3 IS gesture3
eventIn SFBool gesture4 IS gesture4
eventIn SFBool gesture5 IS gesture5
eventIn SFBool gesture6 IS gesture6
eventIn SFBool gesture7 IS gesture7
eventIn SFBool gesture8 IS gesture8
eventIn SFBool gesture9 IS gesture9
eventIn SFBool gesture10 IS gesture10
eventIn SFBool gesture11 IS standBehaviour
eventIn SFBool gesture12 IS walkBehaviour
eventIn SFBool set_UserAvatar IS set_UserAvatar
eventIn SFInt32 set_proxy IS set_proxy
eventIn SFBool set_HUD_anim IS set_HUD_anim
field SFNode Sw USE Sw
field SFBool bUserAvatar FALSE
field SFBool bWatched FALSE
directOutput TRUE
field SFNode InitTimer USE InitTimer
field SFNode vis USE vis
field MFNode MFN [ USE TS1 USE TS2 USE TS3 USE TS4 USE TS5 USE TS6
USE TS7 USE TS8 USE TS9 USE TS10 USE TS11 USE TS12 ]
url "javascript:
function shutdown(){
for( var a = 0; a<MFN.length; a += 1){
MFN[a].enabled = false;
}
vis.enabled = false;
}
function initTime(v,ts){ if(v){ MFN[10].startTime = ts;
InitTimer.loop = false; }}
function set_UserAvatar(v){
if(v){ bUserAvatar = v;
vis.enabled = false;
}}
function set_HUD_anim(v,ts){
if(bUserAvatar){ MFN[11].enabled = v; }
}
function set_proxy(v,ts){
if(v==0){
vis.enabled = false; bWatched = false;
}
else {
vis.enabled = true; bWatched = true;
MFN[11].enabled = false;
}
Sw.whichChoice = v;
}
function isActive(v,ts){ if(!v){ MFN[10].startTime = ts;}}
function watched(v){ bWatched = v;}
function set_position(v,ts){ if(bWatched&&!MFN[11].enabled){
MFN[11].enabled = true; }}
function set_orientation(v,ts){ if(bWatched&&!MFN[11].enabled){
MFN[11].enabled = true; }}
function gesture1(v,ts){ if(v&&bWatched){ MFN[0].startTime
= ts; }}
function gesture2(v,ts){ if(v&&bWatched){ MFN[1].startTime
= ts; }}
function gesture3(v,ts){ if(v&&bWatched){ MFN[2].startTime
= ts; }}
function gesture4(v,ts){ if(v&&bWatched){ MFN[3].startTime
= ts; }}
function gesture5(v,ts){ if(v&&bWatched){ MFN[4].startTime
= ts; }}
function gesture6(v,ts){ if(v&&bWatched){ MFN[5].startTime
= ts; }}
function gesture7(v,ts){ if(v&&bWatched){ MFN[6].startTime
= ts; }}
function gesture8(v,ts){ if(v&&bWatched){ MFN[7].startTime
= ts; }}
function gesture9(v,ts){ if(v&&bWatched){ MFN[8].startTime
= ts; }}
function gesture10(v,ts){ if(v&&bWatched){ MFN[9].startTime
= ts; }}
function gesture11(v,ts){
if(v){ if(MFN[11].enabled){ MFN[11].enabled = false; }
else { MFN[10].startTime = ts; }}
}
function gesture12(v,ts){ if(v&&bWatched){ MFN[11].enabled
= true;}}
"
}
]}
]}
]}
]}
ROUTE Ts.isActive TO DMsc.gesture1
ROUTE TS11.isActive TO DMsc.activeTest
ROUTE InitTimer.cycleTime TO DMsc.initTime
ROUTE vis.isActive TO DMsc.watched
ROUTE TS12.isActive TO DMsc.isActive
ROUTE TS1.isActive TO DMsc.isActive
ROUTE TS2.isActive TO DMsc.isActive
ROUTE TS3.isActive TO DMsc.isActive
ROUTE TS4.isActive TO DMsc.isActive
ROUTE TS5.isActive TO DMsc.isActive
ROUTE TS6.isActive TO DMsc.isActive
ROUTE TS7.isActive TO DMsc.isActive
ROUTE TS8.isActive TO DMsc.isActive
ROUTE TS9.isActive TO DMsc.isActive
ROUTE TS10.isActive TO DMsc.isActive
####################################################################################
The ROUTE area code should look something like this before and after:
F. Save the file, load it in Instant Player and open Instant Player's
console to check for errors that will be in red letters.
You can ignore the error statement: "FATAL Avalon Create non
nav type" As I stated before Instant Player is still in beta development
and alot of times prints errors that are meaningless to the end-user.
You will want to run the your avatar through Chisel or VrmlPad publish
feature to reduce the length of decimal placement values.
G. Test your avatar on the Deep Matrix client before
using!
Experience has show that the Seamless conversion sometimes puts avatars
at different positions on the Y axis!
Generally with female avatar conversions need to be lowered on
the Y axis by -.27 meter.
Using the "Find" feature simply replace the Group Node parenting of
the HAnimHumanoid with a Transform and a translation field
like this:
Before:
Group {
children [
HAnimHumanoid{
After:
Transform {
translation 0 -.27 0
children [
HAnimHumanoid{
But please note it also has been found that some conversions (both male
and female) need to be lowered -.4 on the Y axis using the code given
above.
Shared Objects
As stated else where Shared Objects are only in a demo state at the
moment and restricted to load and unload in the world they
are found in.
Like Avatars, any code can function as a Shared Object that will appear
in the Objects list of the Java EAI client.
However to add features like shared events and text to chat and visa
versa the special Shared Object Proto is needed.
Some hand coding and scripting experience is necessary to get your
Shared Object working properly.
Here is the Shared Object Proto with all exposedFields, eventIns and
eventOuts features that are available.
All of these are options and none are mandatory. You can add exposedFields,
eventOut and Ins as desired.
In fact you have to if you want to use any shared events.
PROTO SharedObject [
# states_changed -Holds all instances of shared event Protos, both
persistent storage and lock type shared events may be used.
exposedField MFNode states_changed [ ]
# from_network_chat -Delivers incoming chat strings from the network
eventIn MFString from_network_chat
# set_local_chat -Sends messages to the local chat of the user.
eventOut MFString set_local_chat
# set_network_chat -Sends messages to the entire network.
eventOut MFString set_network_chat
]
{
# your code here.........
}
The following shared event example is taken from the Mobius Strip file:
#VRML V2.0 utf8
# A. At the top of your file you will first need list Share Event Protos
to be used.
# In this case a SFRotation lock shared event:
PROTO CtrlNetworkSFRotation [
eventIn SFString set_lock
eventIn SFString set_name
eventOut SFString lock_changed
eventIn SFTime set_control
eventOut SFString name_changed
eventOut SFTime control_time
eventIn SFRotation set_value
eventOut SFRotation value_changed
eventIn SFRotation value_fromnet
eventOut SFRotation value_tonet
exposedField SFString tag
""
field SFBool localCopy TRUE
exposedField SFBool echo
TRUE
exposedField SFBool cont
FALSE
]
{Group { children [ ...]} }
# End of Proto CtrlNetworkSFRotation definition
# B. Next the Shared Object Proto.
# Notice how the Proto header has been modifed to meet the needs of
its instance.
# Please View the Mobius4 file in the Avatars folder for the full code.
PROTO SharedObject [ exposedField MFNode states_changed [ ]
eventOut SFRotation rotation_changed
exposedField SFRotation set_rotation 0 1 0 0
eventOut SFTime active_changed
eventIn SFString set_lock
eventIn SFString set_name
eventOut MFString set_local_chat
eventOut MFString set_network_chat
]
{ Group { children [
# Mobius code and Scripts go here.
]}
}
# End of SharedObject definition
# C. Now the Proto instance.
# The state_changed exposedField holds the SharedEvent instance:
DEF SO SharedObject { states_changed [ DEF MR2 CtrlNetworkSFRotation
{ tag "SR_F" cont TRUE localCopy FALSE echo TRUE } ]}
# D. The ROUTES are listed last.
# Notice the ROUTES going to and from the DEF SO SharedObject instance
and the DEF MR2 shared event instance:
ROUTE SO.rotation_changed TO MR2.set_value
ROUTE MR2.value_changed TO SO.set_rotation
ROUTE SO.active_changed TO MR2.set_control
ROUTE MR2.lock_changed TO SO.set_lock
ROUTE MR2.name_changed TO SO.set_name