Blend animation replication.

The best and quickest support by a group of top-notch editing specialists, guaranteed!

Moderator: Forum Guards

Blend animation replication.

Postby han » Thu Sep 25, 14 9:52 am

DX uses blend animation for all kinds of stuff like lipsynch, head turning or hands waving during conversation, and it turns out to be a pain in the ass to handle scriptedpawns blendanimations clientside (i somehow can't reset the head after a conversation yet (which i can probably fix somehow), however i'm not sure if running simulated code other playerpawns is possible in a direct way (however having an own actor which controlls these animation would probably work).

However.. now i started evaluating the possibility of adding replication for blend animations. Native replication can probably be used for replicating variables of base classes, so the blend animation relevant variables could be replicated like those of the "normal" animations. However i have not found yet sth. useful to read about animation replication - it somehow happens magically. My current assumption is that this happens in PreNetReceive() / PostNetReceive() as AActor::PreNetReceive() saves the SimAnim variable.

On how to do native (variable only) replication, check the ut2004 script source/Onslaught.cpp.

My 2 cents for now..

/edit: Okay some blend animations variables seem to get actually replicated.

/edit2: Okay it's getting weired, those animation variables only get replicated if is less then ROLE_SimulatedProxy (despite other checks). So how the fuck does animation replication actually work?

/edit3: I should look more carefully before posting:
Actor.uc
Code: Select all
   // Animation.
   unreliable if( DrawType==DT_Mesh && ((RemoteRole<=ROLE_SimulatedProxy && (!bNetOwner || !bClientAnim)) || bDemoRecording) )
      AnimSequence, BlendAnimSequence;                  // blended anims added - DEUS_EX CNN
   unreliable if( DrawType==DT_Mesh && (RemoteRole==ROLE_SimulatedProxy))
      bAnimNotify;
   unreliable if( DrawType==DT_Mesh && (RemoteRole<ROLE_SimulatedProxy))
      SimAnim, AnimMinRate, SimBlendAnim, BlendAnimMinRate;   // blended anims added - DEUS_EX CNN

So guess i have to find out where this animsequence lands, but some corrosponding bBlendAnimNotify seems missing.

/edit4:
Unreal Gold: So the last line makes more sense, here. maybe the replication statement shown in DX uc code is wrong?
Code: Select all
   // Animation.
   unreliable if( DrawType==DT_Mesh && (RemoteRole<=ROLE_SimulatedProxy) )
      AnimSequence;
   unreliable if( DrawType==DT_Mesh && (RemoteRole==ROLE_SimulatedProxy) )
      bAnimNotify;
   unreliable if( DrawType==DT_Mesh && (RemoteRole<ROLE_AutonomousProxy) )
      SimAnim, AnimMinRate;
Last edited by han on Thu Sep 25, 14 11:51 am, edited 1 time in total.
han
Newbie
 
Posts: 15
Joined: Thu Nov 29, 12 10:47 pm

Re: Blend animation replication.

Postby han » Thu Sep 25, 14 11:48 am

Not sure if this is right, but thats what i've found out so far. I should probably add the same for blend anims and give it a try. However this bAnimNotify bugs me.
Code: Select all
FPlane      PreSimAnim;

void AActor::PreNetReceive()
{
   guard( AActor::PreNetReceive );

   // [..]

   PreSimAnim               = SimAnim;

   // [..]

   unguard;
}

void AActor::PostNetReceive()
{
   guard( AActor::PostNetReceive );

   // [..]

   if ( SimAnim != PreSimAnim )
   {
      AnimFrame   = SimAnim.X * 0.0001;
      AnimRate   = SimAnim.Y * 0.0002;
      TweenRate = SimAnim.Z * 0.001;
      AnimLast   = SimAnim.W * 0.0001;

      if ( AnimLast < 0.0 )
      {
         AnimLast *= -1.0;

         bAnimLoop = 1;

         if ( IsA( APawn::StaticClass() )
         {
            if ( AnimMinRate < 0.5 )
               AnimMinRate = 0.5;
         }
      }
      else
      {
         bAnimLoop = 0;
      }
   }

   // [..]

   unguard;
}


/edit:
Those values these values get multiplied with are probably just because of how FPlane replication works to achieve a greater accuracy.
han
Newbie
 
Posts: 15
Joined: Thu Nov 29, 12 10:47 pm

Re: Blend animation replication.

Postby han » Sat Sep 27, 14 10:45 am

Okay, my code so far. For head turning this seems to work fine, but for eye blinking and mouth animations this does not work very well. I guess it's the animations are to fast for replication and/or the scaling values are to low which results in a too low accuracy. However these rates are hardcoded. However they could be skaled by hooking PlayBlendAnim() / TweenBlendAnim(), maybe this would result better results. Another bugs seems to be that eyes are kept shut until StopBlendAnim() is called. However i was just interessted in having the head turning replicated, As all the lipsynch stuff needs is having bIsTalking set on client, though i might run into the mouth stays open after conversation bug again.

Here is the code:
Code: Select all
// Out of ut2004scripts3369\Onslaught\Src\Onslaught.cpp
static inline UBOOL NEQ(BITFIELD A,BITFIELD B,UPackageMap* Map) {return A!=B;}
static inline UBOOL NEQ(BYTE A,BYTE B,UPackageMap* Map) {return A!=B;}
static inline UBOOL NEQ(INT A,INT B,UPackageMap* Map) {return A!=B;}
static inline UBOOL NEQ(FLOAT& A,FLOAT& B,UPackageMap* Map) {return *(INT*)&A!=*(INT*)&B;}
static inline UBOOL NEQ(FVector& A,FVector& B,UPackageMap* Map) {return ((INT*)&A)[0]!=((INT*)&B)[0] || ((INT*)&A)[1]!=((INT*)&B)[1] || ((INT*)&A)[2]!=((INT*)&B)[2];}
static inline UBOOL NEQ(FRotator& A,FRotator& B,UPackageMap* Map) {return A.Pitch!=B.Pitch || A.Yaw!=B.Yaw || A.Roll!=B.Roll;}
//static inline UBOOL NEQ(UObject* A,UObject* B,UPackageMap* Map) {if( Map->CanSerializeObject(A) )return A!=B; Channel->bActorMustStayDirty = true; /* debugf(TEXT("%s Must stay dirty because of %s"),Channel->Actor->GetName(),A->GetName()); */ return (B!=NULL);}
static inline UBOOL NEQ(FName& A,FName B,UPackageMap* Map) {return *(INT*)&A!=*(INT*)&B;}
static inline UBOOL NEQ(FColor& A,FColor& B,UPackageMap* Map) {return *(INT*)&A!=*(INT*)&B;}
static inline UBOOL NEQ(FPlane& A,FPlane& B,UPackageMap* Map) {return ((INT*)&A)[0]!=((INT*)&B)[0] || ((INT*)&A)[1]!=((INT*)&B)[1] || ((INT*)&A)[2]!=((INT*)&B)[2] || ((INT*)&A)[3]!=((INT*)&B)[3]; }
static inline UBOOL NEQ(const FString& A,const FString& B,UPackageMap* Map) {return A!=B;}

#define DOREP(c,v) \
   if( NEQ(v,((A##c*)Recent)->v,Map) ) \
   { \
      static UProperty* sp##v = FindObjectChecked<UProperty>(A##c::StaticClass(),TEXT(#v)); \
      *Ptr++ = sp##v->RepIndex; \
   }

#define DOREPARRAY(c,v) \
   {static UProperty* sp##v = FindObjectChecked<UProperty>(A##c::StaticClass(),TEXT(#v)); \
   for( INT i=0; i<ARRAY_COUNT(v); i++ ) \
      if( NEQ(v[i],((A##c*)Recent)->v[i],Map) ) \
            *Ptr++ = sp##v->RepIndex+i;}

/*-----------------------------------------------------------------------------
   GetOptimizedRepList()
-----------------------------------------------------------------------------*/

INT* AHXScriptedPawn::GetOptimizedRepList( BYTE* Recent, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map )
{
   guard( AHXScriptedPawn::GetOptimizedRepList );

   Ptr = Super::GetOptimizedRepList( Recent, Retire, Ptr, Map );

   if( DrawType==DT_Mesh && ((RemoteRole<=ROLE_SimulatedProxy && (!bNetOwner || !bClientAnim)) || bDemoRecording) )
   {
      DOREPARRAY( Actor, BlendAnimSequence );
      DOREPARRAY( Actor, SimBlendAnim );
      DOREPARRAY( Actor, BlendAnimMinRate );
   }

   return Ptr;

   unguard;
}

/*-----------------------------------------------------------------------------
   PreNetReceive()
-----------------------------------------------------------------------------*/

FPlane PreSimBlendAnim[4];

void AHXScriptedPawn::PreNetReceive()
{
   guard( AHXScriptedPawn::PreNetReceive );

   Super::PreNetReceive();

   for ( INT i = 0; i < 4; i++ )
   {
      PreSimBlendAnim[i] = SimBlendAnim[i];
   }

   unguard;
}

/*-----------------------------------------------------------------------------
   PostNetReceive()
-----------------------------------------------------------------------------*/

void AHXScriptedPawn::PostNetReceive()
{
   guard( AHXScriptedPawn::PostNetReceive );

   Super::PostNetReceive();

   for ( INT i = 0; i < 4; i++ )
   {
      if ( SimBlendAnim[i] != PreSimBlendAnim[i] )
      {
         BlendAnimFrame[i] = SimBlendAnim[i].X * 0.0001;
         BlendAnimRate[i]  = SimBlendAnim[i].Y * 0.0001; // execPlayBlendAnim() / execTweenBlendAnim use this scaling value
         BlendTweenRate[i] = SimBlendAnim[i].Z * 0.001;
         BlendAnimLast[i]  = SimBlendAnim[i].W * 0.0001;

         if ( BlendAnimLast[i] < 0.0 )
         {
            BlendAnimLast[i] *= -1.0;

            //bAnimLoop = 1;

            if ( IsA( APawn::StaticClass() ) )
            {
               if ( BlendAnimMinRate[i] < 0.5 )
                  BlendAnimMinRate[i] = 0.5;
            }
         }
         else
         {
            //bAnimLoop = 0;
         }
      }
   }

   unguard;
}
han
Newbie
 
Posts: 15
Joined: Thu Nov 29, 12 10:47 pm


Return to Editing issues

Who is online

Users browsing this forum: No registered users and 10 guests
cron