VRML Tutorial
REMOVAL OF CRASH BUG FROM AVATAR STUDIO AVATARS

The blaxxun Contact plugin has almost always been known to crash once in a while. I say "almost" because there are those that can remember a time when it wasn't so ;-). At least that was what a friend and colleague told me when I presented this to him. He said it happened when Avatar Studio came. And though there probably are other bugs that can make Contact crash, this one is probably the biggest. I can not be 100% sure that this is the bug. But I'm pretty sure. And I will explain why after I have presented one of the ways to remove it.

If you find this convincing and you have online avatars which you share with other people, I'll recommend that you mark the avatars that you have applied this or similar fix to with the text: "Crash free". I also changed the color of the texturless avatar to yellow so it's easier to see who is using which type of avatar.


0. Content

  1. Patch for Avatar Studio 2
  2. How to fix existing avatars
  3. What is going wrong?


1. Patch for Avatar Studio 2

To add this patch you will need to locate the existing file "avatar.ASTmpl". It's located in the directory where you installed the program. The path is something like "c:\Program Files\Avatar Studio 2\Systeme\export\avatar.ASTmpl". I didn't install mine under the suggested path. And I think to remember a "canal plus" in that path somewhere. When you find the file simply replace it with this one.

I have used the file from Kidou's v3 patch which fixes other problems. But it will work whatever you have installed Kidou's path or not.

Size = 3.3KB
avatar_astmpl.zip

2. How to fix existing avatars

You will have to open the wrl file and edit it by hand. For this you will either need a VRML editor like VRMLpad or a program that can un-gZip the file and you can then edit it in Notepad and gZip it again. The code to add is in red. And the green text is a unique text to search for. I have here used an Avatar Studio 2 file.


   children [
    WorldInfo { info ["Avatar Studio","Copyright (c)2000 CANAL NUMEDIA. All Rights Reserved."]}
    DEF TOUCH TouchSensor{ touchTime IS touchTime, isOver IS isOver }
    DEF vis VisibilitySensor { size 1 2 1 center 0 1 0 }
#------------------------------------------------------
    Shape {
     appearance Appearance{ material Material{diffuseColor 0.56 0.56 0.22} texture ImageTexture{url "djelle.jpg" } }
     geometry IndexedFaceSet {
      solid FALSE
      creaseAngle 3.14
      coord DEF PointList Coordinate{
      point[-0.0976 -0.032 -0.0011,-0.0922 -0.033 -0.0301,-0.1128 -0.0866 -0.0337,-0.0589 -0.033 -0.0503,-0.059
-0.067 -0.0659,-0.1196 -0.0979 0.0019,0.0991 -0.032 -0.0011,0.1196 -0.0979 0.0019,0.1121 -0.0866 -0.0337,0.0914
In the above code you have to exchange the color code for the new yellow one. This is not nessarry for the fix to work though.


    DEF OI11_53 OrientationInterpolator{
     key[ 0,0.25,0.5,1]
     keyValue[ -0.0317 -0.9942 -0.0847 -0.0095,0 1 0 0,0 1 0 0,-0.0317 -0.9942 -0.0847 -0.0095]
    }
#------------------------------------------------------
    DEF Welder Script {
     directOutput TRUE
     eventOut SFBool isInit
     eventIn SFBool Watched
     eventIn SFFloat fooEvents
     eventIn SFTime G0 IS set_gesture1
     eventIn SFTime G1 IS set_gesture2
     eventIn SFTime G2 IS set_gesture3
     eventIn SFTime G3 IS set_gesture4
     eventIn SFTime G4 IS set_gesture5


m3=m3.multRight(m2);
m4.setTransform(P[58],R[58]);
m4=m4.multRight(m3);
for(i=989;i<990;i++){W[i]=m4.multVecMatrix(V[i]);}
       Vtx.point=W;
      }//VtxTransform
      function fooEvents(t){
       if(!isInit) return;
       if(mode==0)VtxTransform();
       else if(mode==1)Vtx.point.setByVertexTransform(V,vgroups,P,R);
      }
      function eventsProcessed(){
       if(!isInit) return;
       if(mode==2) Vtx.point.setByVertexTransform(V,vgroups,P,R);
      }
      function Gstart(g,t){
       if((!watched)||(g>=ts.length)||!isInit)return;
       if(currG==-1){nextG=g;Gend(FALSE,t);}
       else{ts[currG].enabled=FALSE;ts[currG].stopTime=t;currG=-1;nextG=g;Gend(FALSE,t);}
      }
      function Gend(b,t){
       if(b==false){
        currG=nextG;


        ver=Browser.getVersion();
        if(ver<4.1)mode=0; //no eventsProcess
        else if(ver<5.0)mode=1; //setByVertexTransform()
         else mode=2; //+eventsProcess ok
       }
       else mode=0;
       isInit=true;
       fooEvents();
      }
    "}#sript Welder
#------------------------------------------------------
    DEF TsWalk TimeSensor{cycleInterval 1}
    DEF PosIt PositionInterpolator{key [0,1] keyValue [0 0 0,0 0 0]}
    DEF TsIdle TimeSensor{cycleInterval 180}
#------------------------------------------------------
    DEF Walker Script {
     directOutput TRUE
     eventIn SFBool isInit
     eventIn SFVec3f setPos IS set_position
     eventIn SFRotation setRot IS rotation
     eventIn SFBool isPilot IS isPilot
     eventIn SFBool isActive
     eventIn SFFloat walk
     eventIn SFBool watched


      }
      function walk(v,t){
       if(watched){
        fWalk+=(v-vWalk)*k2Walk;
        vWalk=v;
        while(fWalk>=1)fWalk-=1;//mod!
        while(fWalk<0)fWalk+=1;//grr!
        if(!isInit) return;
        walkFrac=fWalk;
       }
      }
      function setRot(v,t){
       rot_changed=v;
       if(v[3]!=angle){
        angle=v[3];
        dir.x=Math.sin(angle);
        dir.z=Math.cos(angle);
       }
      }
      function setPos(v,t){
       d=v.subtract(curPos);
       if(d.length()==0){
        if(moving)stopw(t);
        return;
       }
       kWalk=d.dot(dir)*ooStep;
       if(isPilot){
        if(!moving)startw();
        if(kWalk>0.2)kWalk=0.2;
        fWalk+=kWalk;
        while(fWalk>=1)fWalk-=1;//mod!
        while(fWalk<0)fWalk+=1;//grr!
        if(!isInit) return;
        walkFrac=fWalk;
        pos_changed=v;
        return;
       }
       keyValues[1]=v;
       if (moving)newMove=true;
       else if(notFirst){startw();move(t);}


 ROUTE Walker.values_changed TO PosIt.set_keyValue
 ROUTE TsWalk.fraction_changed TO PosIt.set_fraction
 ROUTE TsWalk.fraction_changed TO Walker.walk
 ROUTE PosIt.value_changed TO WalkingAvatar.set_translation
 ROUTE TsWalk.isActive TO Walker.isActive
 ROUTE Walker.startMove TO TsWalk.set_startTime
 ROUTE TsIdle.isActive TO Walker.idle
 ROUTE Welder.isInit TO Walker.isInit
 ROUTE TS0.fraction_changed TO PI0_1.set_fraction
 ROUTE PI0_1.value_changed TO Welder.pos_Center
 ROUTE TS0.fraction_changed TO OI0_2.set_fraction
 ROUTE OI0_2.value_changed TO Welder.rot_sacroiliac
 ROUTE TS0.fraction_changed TO OI0_3.set_fraction
 ROUTE OI0_3.value_changed TO Welder.rot_vl5



2. What is going wrong?

I found the bug while disassembling the avatar code for the adult community Jewels of Indra where we wanted better avatars. I rewrote a lot of the code and had a new avatar code which did what I wanted. At least on my harddrive. It crashed when I tried the avatar in a world. And after almost a day of trial and error (read crashing) I found the bugger doing this.

There are actually two bugs doing this mess. One is the VRML command setByVertexTransform() which is the one crashing the browser immediatly when given an empty point list. The point list is set in the function initialize in the script Welder with this line of code: V=Vtx.point;. If you remark the line you can experience the crash. The function initialize is the first function to be run when the VRML file is opened. So normally this would not be a problem in these avatars. Except I forgot to make the initialize wait for the data to be ready. In my new code it don't have the data from the start, they are loaded afterwards. So I searched through the code to find the places to stop the script from doing the setByVertexTransform() command until it was properly initialized. But there are two scripts in such an avatar. The other is Walker. This script makes the avatar do the walk animation. And I noticed that it send it's data directly to the interpolators instead of sending them to Welder. This has a good reason. And as you probably know it works. Well sometimes that is. Sometimes when an avatar enters a world the Walker script thinks the avatar is moving and thus it starts sending data to the interpolators. Which again at a point triggers the function with the setByVertexTransform(). And this apparently happens before the initialization of the Welder is finished. And you then have Contact crashing. At this point I wasn't certain that this is what actually happens. So I didn't stop the Walker from sending it's data directly. And I carried on with my avatar project. I made new modifications and tried them online in worlds about twenty times when it happened. I suddenly got a bunch of error codes because functions in Welder was called before the initialization was finished. I tried the same avatar a couple of times more which didn't bring up any errors. And then I was sure. Or as sure as I can be on a random event such as this. These errors would probably also have shown up with a normal avatar except that the browser had already crashed and died.

I really do hope that this can make our virtual experience with VRML a lot less crashie :-)