Announcement

Collapse
No announcement yet.

True First Person / Weld camera to bone or socket / Body Awareness

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    True First Person / Weld camera to bone or socket / Body Awareness

    In the UDK Editor, add an eye socket to your model.
    Make sure the Relative Rotation is correct.
    X = Forward
    Y = Right
    Z = Up



    Add to your pawns variable list:
    Code:
    var name EyeSocket;
    Add to your pawns default properties:
    Code:
        EyeSocket=Eyes
    Add these functions:
    Code:
    /*
    CalcCamera
    
    Called from UTPlayerController::GetPlayerViewPoint(), 
    which is called by the current camera.
    */
    simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
    {
        local bool bCameraCalc;
        
        // if we are the local player, make sure our head is normal size.
        // This will make it visible again in third person views and give us the correct bone positions later.
        // NOTE: A better way to do this is to make sure the head is a separate mesh/component and stop it being rendered to the owner.
        if (WorldInfo.NetMode != NM_DedicatedServer && IsHumanControlled() && IsLocallyControlled() && (HeadScale != 1.0f))
        {
            SetHeadScale(1.0f);
    
            // since we've just un-shrunk the head, force the skeleton to update, just in case
            Mesh.ForceSkelUpdate();
        }
        
        // Call the proper CalcCamera function and remember the result
        bCameraCalc = Super.CalcCamera(fDeltaTime, out_CamLoc, out_CamRot, out_FOV);
    
        // now that we've run the proper calcs, shrink the head again,
        // but only if we're the local player and in a first person view
        if (WorldInfo.NetMode != NM_DedicatedServer && IsHumanControlled() && IsLocallyControlled() && IsFirstPerson() && !bFixedView)
        {
            SetHeadScale(0.0f);
    
            // force the skeleton to update, just in case
            Mesh.ForceSkelUpdate();
        }
    
        // send the result back to UTPlayerController::GetPlayerViewPoint()...
        return bCameraCalc;
    }
    
    /*
    GetPawnViewLocation
    
    Someone wants the position of our eyes - lets give it to them.
    Its probably CalcCamera() anyway (see above).
    */
    simulated event Vector GetPawnViewLocation()
    {
        local vector viewLoc;
    
        // no eye socket? No way I can tell you a location based on this socket then...
        if (EyeSocket == '')
            return Location + BaseEyeHeight * vect(0,0,1);
    
        // HACK - force the first person weapon and arm models to hide
        // NOTE: You should remove all first person only weapon/arm meshes instead.
        SetWeaponVisibility(false);
        
        // HACK - force the world model and attachments to be visible
        // NOTE: You should make sure the mesh/attachments are always rendered.
        SetMeshVisibility(true);
    
        Mesh.GetSocketWorldLocationAndRotation(EyeSocket, viewLoc);
    
        return viewLoc;
    }
    
    /*
    Dying
    
    Instead of switching to a third person view, 
    match the camera to the location and rotation of the eye socket.
    */
    simulated State Dying
    {
        // skip UTPawn's fancy damage/third person views
        simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
        {
            return Global.CalcCamera(fDeltaTime, out_CamLoc, out_CamRot, out_FOV);
        }
    
        simulated event rotator GetViewRotation()
        {
            local vector out_Loc;
            local rotator out_Rot;
    
            // no eye socket? No way I can tell you a rotation based on this socket then...
            if (EyeSocket == '')
                return Global.GetViewRotation(); // non-state version please
            
            Mesh.GetSocketWorldLocationAndRotation(EyeSocket, out_Loc, out_Rot);
    
            return out_Rot;
        }
    }
    If you want to always match the camera to the rotation of the eye socket,
    use a similar piece of code as the dying state:
    Code:
    /*
    GetViewRotation
    */
    simulated event rotator GetViewRotation()
    {
        local vector out_Loc;
        local rotator out_Rot;
    
        // no eye socket? No way I can tell you a rotation based on this socket then...
        if (EyeSocket == '')
            return Super.GetViewRotation();
            
        Mesh.GetSocketWorldLocationAndRotation(EyeSocket, out_Loc, out_Rot);
    
        return out_Rot;
    }
    Copy-paste job from my current pawn with added comments and a few other minor adjustments.
    I haven't tested it with a pawn based on UTPawn lately, so let me know if it has any problems.

    #2
    Please note the Relative Location of the eye socket is up to you.

    Matching it exactly to the location of the models eyes the obvious idea.

    A different one (which I use) is to match it to a special 'camera bone' that is linked to the root of your model.
    This allows you to smooth out the camera movements, as well as slightly adjust its location during different animations for better peripheral vision.

    In the end, it is totally up to you.

    Comment


      #3
      THANK YOU for this tutorial! I have been waiting for something like this for ages!

      Comment


        #4
        Nice one.

        Maybe one could also specify a bone name like "b_head" as fallback for the missing socket.
        And some interpolation between the old and new location of the socket based on a config variable, so that the player can define how much view shaking he gets and save him from motion sickness.

        Comment


          #5
          I get an error in line 67. UFrontEnd thinks there's meant to be a missing semicolon after the word "mesh".

          Comment


            #6
            Originally posted by iLikeTheUDK View Post
            I get an error in line 67. UFrontEnd thinks there's meant to be a missing semicolon after the word "mesh".
            Fixed.

            "SetMeshVisibility(true)" to "SetMeshVisibility(true);"

            Originally posted by Crusha K. Rool View Post
            Nice one.

            Maybe one could also specify a bone name like "b_head" as fallback for the missing socket.
            And some interpolation between the old and new location of the socket based on a config variable, so that the player can define how much view shaking he gets and save him from motion sickness.
            Could do. I should really change it just to produce an error, forcing you to update the mesh and add the socket. Falling back allows for all sorts of issues to creep in.

            Smoothing via interpolating was originally the plan, but I found just matching the camera location to the socket removes quite a bit. I am switching to a separate camera bone now. This will allow for some 'fudging' to occur during certain actions, helped along by the animator, as well as further smoothing the view.

            Stairs cause some jerkiness issues, but with a little bit of coding, you can smooth that out a lot. It doesn't even require messing with foot placement / IK, though that would be the ultimate goal, aesthetically and view wise.

            Either way, I'll definitely have to to update it at some point.

            Comment


              #7
              This is more or less what we did with our racing game; included a socket to attach the camera to. Made things much easier in the long run and isn't difficult to implement at all

              Comment


                #8
                Thanks for this. This better than using bones, since sockets can be moved when needed. Sweet.

                Comment


                  #9
                  this looks awesome thanks man

                  Comment


                    #10
                    Thank you Jusko for the awesome tutorial!

                    I have some issues but I don't want to annoy you so I will post my problems only in case I'm not able to work out a solution in the following weeks.

                    Once again thank you

                    EDIT: Ok, I hate to contradict myself, but could someone post the original GetActorEyesViewPoint event from the Pawn class (I've messe a little with it, my bad)?

                    Comment


                      #11
                      It gives me this error:
                      Error, CalCamera conflicts with funcion UTGame.UTPawn: 'CalcCamera'

                      Comment


                        #12
                        Originally posted by julianbraso View Post
                        It gives me this error:
                        Error, CalCamera conflicts with funcion UTGame.UTPawn: 'CalcCamera'
                        See =>
                        Originally posted by slowJusko View Post
                        ... a pawn based on UTPawn ...
                        By the sounds of it, you're modifying UTPawn directly.
                        If this is the case, you'll need to adjust the actual CalcCamera function.

                        Comment


                          #13
                          Ohhh, sorry i read it wrong, so i have to make a class based on UTPawn, but then where do i have to put it so the game uses it?

                          Comment


                            #15
                            i somehow knew someone would redirect me to that haha, thanks blade i'm getting to it right now

                            Comment

                            Working...
                            X