VR Expansion Plugin

You are using a physics based grip (the default one), Either increase the stiffness of the grip by a lot or change to a non physics grip type. Depending on the weight of the held object you might need a significantly higher grip stiffness than the default setting of 1500 to hold it steady.

wiki entry has the grip types listed (some of the naming is rather unfortunate, it made more sense when they were created): https://bitbucket.org//vrexpansionplugin/wiki/VRGrippableMotionController

Hey,

First of all, thank you for your plugin, very useful!

I have a suggestion for something I think is missing.
It would be nice if the Grippable Components had an Event Dispatcher On Grip and On Grip Release.

So for example if a handle is gripped, then it sends an event that can be used to put the Door itself in the player hand and then to release it, or that kind of things.

Hi , just a quick question
what’s the best way to skip ue encroachment checking when teleporting using your perform move action teleport?
in order words we would like to pass a bNocheck = true to TeleportTo function

thanks in advance

That is something that you can directly add to any component or actor yourself and is kind of overkill to provide as part of the grippables. Its easy enough to add a new delegate in the blueprint editor and OnGrip fire it off with whatever data you need.

For now? Add a custom one to use. Edit nvm

For the future (IE: when I am out of beta branch I am working in) I have some extra data room on the teleport to move action since I am only replicating Yaw, i’ll throw a bool into one of the unused floats and replicate it as a bool and add the encroachment option for the default node.

I’d like to avoid adding any more straight replicated vars to the move actions if possible.

Edit The change is already in my beta branch i’ll port it out, shouldn’t matter

Re-edit Master branch of both repositories has it live

it works like a charm, many thanks

Pushed a new commit to both repositories

Binaries won’t be built until later tonight, will edit when they are done

Plugin



Added bSkipEncroachmentCheck to the PerformMoveAction_Teleport function

Fixed some string property sizes in the OpenVRExpansionFunctionLibrary

Added OnPlayerStateReplicated bindable event to the VRCharacters, will fire off when the
player state has replicated over (every time it is changed, if you only want it once
then unbind after it is done). Useful for initial player set up on clients.

Corrected a fatal crash issue with how Epic is currently checking motion controllers
for IsLocallyOwned.

Fixed SecondaryGripTypes with the Retain option being broken in some situations when
using client authoritive grips.

Now only setting simulating server side on drop of a non client authority grip to avoid
a replication race condition.

Improved the network overhead of client authoritive grips by replacing some of the
RPC properties with GripIDs now that GripIDs are standard. Also am now using a seperate
drop function for client auth grips instead of re-using the modification one to save
on replication cost.

Moved the SetIsHeld call to before calling OnGrip so that there is a valid IsHeld during
operations in that event.

Added bSetOwnerOnGrip to AdvancedGripSettings, when true (default) gripping an actor
will automatically set its owner to the motion controllers owner (if it is a pawn).
(does not apply to component grips)

On grip release it DOES NOT RESET OWNER, keep  in mind


Added bAllowIgnoringAttachOnOwner to all Grippable *actor* types, when true (default)
the actor will ignore replicated attachment sends when the grippables GripMovementType
is set to Client_Authority or Client_Authority_NoRep,  is to prevent the replication
from interfering with client side control of attachment in these modes.

Overrode OnRep_ReplicateMovement to bypass them not setting the simulated state
if the movement replication had been off for awhile and the state had toggled in the meantime.


Added DropAndSocketGrip/Object functions to the grip controllers.  dedicated function
will drop a grip and attach it to the passed in scene component with the transform / socket
that was given.

Added bool bWasSocketed to the OnGripRelease and OnChildGripRelease events in the GripInterface.
When true the grip was dropped with a socketing function.

Added RequestsSocketing function to the interface, allows querying if the object wants to be socketed.
(On release / general queries), by default has no functionality, override it to return a value.


Template



Overhauled how the teleport controllers get the player state and set themselves up a bit.

Added socketing capability to the sample gun for the body component on the example pawn.

Added a socketing check to the VivePawnCharacter in the CallCorrectDropEvent area of the event graph (really simple).
More complex implementations could skip querying the object and check themselves, or do other things.


Uploaded the precompiled binaries

Hello . I downloaded your plugin in Februrary and been using it ever since. There was a problem, where Project/ Engine crashed when the garbage collection was done. I overrided it by basically disabling the garbage collection. Now I’m in the Engine 4.19.2 and remembered that. I changed value again to 61.Something (the original) and the crashing still happening. Is there still a engine bug or was there something in project that I still got? Thank you.

It was the engine, and it should be fixed now

Sometimes I got crash: check(PhysicsGrips.Num() <= (GrippedObjects.Num() + LocallyGrippedObjects.Num()));

What that causes? And why crash, not warning?

Its not a “crash” it is an ensure (quits out to debug in editor/debug builds, doesn’t in packaged shipping), and the latest version just throws a warning anyway (as of last week).

The cause is you deleting something when there is an active physics grip on it without dropping it first, its to promote good behavior.

Regardless I had gotten tired of people reporting so last week I made it a warning and added some additional auto cleanup of constraints that are left hanging.

You just ran into it at the wrong time (right after it was fixed but you are likely on the version before the fix).

Edit “fixed” btw, I don’t see it as having been a bug as it means incorrect behavior was being used, but there wasn’t a reason for it to be so harsh.

Did a small patch to fix FTransform 16 bit alignment in 32 bit builds from my latest changes.

Hey! :slight_smile:

I getting error and im not sure how to figure it out. Its when i do the package of the plugin.

ATHelper: Package Plugin Task (Windows): Picking the default remote server
UATHelper: Package Plugin Task (Windows): ERROR: Remote compiling requires a server name. Use the editor (Project Settings, IOS) to set up your remote compilation settings.
UATHelper: Package Plugin Task (Windows): Doing xcode-select --print-path
UATHelper: Package Plugin Task (Windows): ERROR: Failed to start local process for action (“A folyamat nem ind?that? el, mert nincs megadva f?jln?v.”): -o BatchMode=yes “${CURRENT_USER}@” “cd “/” && xcode-select --print-path”
UATHelper: Package Plugin Task (Windows): Took 1,4631563s to run UnrealBuildTool.exe, ExitCode=5
UATHelper: Package Plugin Task (Windows): ERROR: Command failed (Result:5): d:\Program Files\Epic Games\UE_4.19\Engine\Binaries\DotNET\UnrealBuildTool.exe UE4Game IOS Development -project=“D:\Unreal Projects\VRSword\VRExpansionPlugin\HostProject\HostProject.uproject” -iwyu -module=VRExpansionPlugin -receipt=“D:\Unreal Projects\VRSword\VRExpansionPlugin\HostP
roject\Plugins\VRExpansionPlugin\Binaries\IOS\UE4Game.target” -NoHotReload -ignorejunk. See logfile for details: ‘UnrealBuildTool-2018.06.03-13.54.59.txt’
UATHelper: Package Plugin Task (Windows): (see d:\Program Files\Epic Games\UE_4.19\Engine\Programs\AutomationTool\Saved\Logs\UAT_Log.txt for full exception trace)

UATHelper: Package Plugin Task (Windows): AutomationTool exiting with ExitCode=5 (5)
UATHelper: Package Plugin Task (Windows): BUILD FAILED
LogSlate: Window ‘Plugins’ being destroyed
LogSlate: Window ‘Plugins’ being destroyed
LogDirectoryWatcher: A directory notification for ‘…/…/…/Engine/Plugins/’ was aborted.
LogDirectoryWatcher: A directory notification for ‘…/…/…/…/…/…/Unreal Projects/VRSword/Plugins/’ was aborted.

I think its try to build the package for IOS, or something like that and thatswhy its always fail for me. I tryed a lot fix from google but its a dead end… atleast for me. Please help me if you know how to get rid of the IOS problem!!

How do you do snap turning with pitch?

Example case

Lets say every time the delta of the mouse Y axis over time is + or - 30, then apply a + or - 10 pitch offset to the vr replicated camera.
Note 1: Don’t rotate the characteror vr root, since rotates everyting (aka the whole character mesh and causing it to fly in the air)
Note 2: Since its VR the client should directly apply the rotation and the server may do it later and replicate to clients (except the client it started from)

If you are trying to directly control the cameras pitch you will need to either turn off LockToHMD (don’t do that), or modify where it gets the tracked data and add an offset.

Hey, quick question. Is there any way to disable non-slot gripping on an object? Basically, just deny gripping if you aren’t gripping at a slot?

Thanks.

Yeah LockToHMD won;t work, since will stop VR tracking.
I’m trying to do snap like you do with YAW on the seatedcharacter.
Basicly with some input (either a key presss or mouse moved past a certain value, then increment pitch on camara and/or yaw on character)
It’s to help people who can’t look up or down easily to still be able to look at something up high or down low (or behind them in case of yaw snap turning)

So on character tick get x / y mouse axis.
Determine if mouse move bigger then some value then call SetActorRotationVR to update yaw rotation for character and update pitch rotation for vr replicated camera.

The code below is what I came up with, its called with

NewRot.Pitch = VRReplicatedCamera->RelativeRotation.Pitch + Mouse Y Axis
NewRot.Yaw = GetActorRotationVR()->.Yaw + Mouse X Axis
NewRot.Roll = GetActorRotationVR()->.Roll
bUseYawOnly = false
bAccountForHMDRotation = true
bApplyPitchToCamera = true



     // Sets the actors rotation taking into account the HMD as a pivot point (also moves the actor), returns the location difference
    // bAccountForHMDRotation sets the rot to have the HMD face the given rot, if it is false it ignores the HMD rotation
    // bApplyPitchToCamera sets new rotation pitch to vr replicated camera instead of whole character root.
    UFUNCTION(BlueprintCallable, Category = "BaseVRCharacter|VRLocations")
    FVector SetActorRotationVR2(FRotator NewRot, bool bUseYawOnly = true, bool bAccountForHMDRotation = true, bool bApplyPitchToCamera = true)
    {
        AController* OwningController = GetController();

        FVector NewLocation;
        FRotator NewRotation;
        FVector OrigLocation = GetActorLocation();
        FVector PivotPoint = GetActorTransform().InverseTransformPosition(GetVRLocation());
        PivotPoint.Z = 0.0f;

        FRotator OrigRotation = bUseControllerRotationYaw && OwningController ? OwningController->GetControlRotation() : GetActorRotation();

        // Original rotation is always applied to the full character.
        //  means that when pitch is applied, the whole character body will rotate, which at 90 degrees for example will make most characters float unnaturally in the air.
        // Usually we just want to rotate the head (and possibly attached arms/hands in non vr) when pitching and ignore pitch rotation for the full body.
        // To do  I first copy back pitch from VRReplicatedCamera if bApplyPitchToCamera is set.
        // Note:    NewRot.Pitch value is based on a value of the VRReplicatedCamera->RelativeRotation.Pitch + Mouse Y axis offset.
        //            NewRot.Roll and NewRot.Yaw are based on GetActorRotationVR.
        if (bApplyPitchToCamera)
        {
            OrigRotation.Pitch = VRReplicatedCamera->RelativeRotation.Pitch;
        }

        if (bUseYawOnly)
        {
            // Zero out new supplied Pitch and Roll.
            NewRot.Pitch = 0.0f;
            NewRot.Roll = 0.0f;
        }

        if (bAccountForHMDRotation)
        {
            NewRotation = UVRExpansionFunctionLibrary::GetHMDPureYaw_I(VRReplicatedCamera->RelativeRotation);
            NewRotation = (NewRot.Quaternion() * NewRotation.Quaternion().Inverse()).Rotator();
        }
        else
        {
            NewRotation = NewRot;
        }

        NewLocation = OrigLocation + OrigRotation.RotateVector(PivotPoint);
        //NewRotation = NewRot;
        NewLocation -= NewRotation.RotateVector(PivotPoint);

        if (bUseControllerRotationYaw && OwningController) //&& IsLocallyControlled()
        {
            OwningController->SetControlRotation(NewRotation);
        }

        // Save new calculated pitch before nulling so that we can apply it to the vr camera later.
        float pitch = NewRotation.Pitch;

        // When char does not directly use controller pitch. (The bUseControllerRotationPitch should be on VRReplicatedCamera)
        if (bApplyPitchToCamera && !bUseControllerRotationPitch)
        {
            // Null out pitch (before applying location and rotation to root of character.)
            NewRotation.Pitch = 0.0f;
            // Note: The pitch should still be applied to Owning Controller in code above (so new pitch information can always be accessed with ControlRotation.Pitch)
        }

        // Also setting actor rot because the control rot transfers to it anyway eventually
        SetActorLocationAndRotation(NewLocation, NewRotation);

        // Apply pitch to camera after actor has been rotated.
        // Only do  when Root does not use controller pitch.
        // bUseYawOnly must be false (since we use pitch).
        if (bApplyPitchToCamera && !bUseControllerRotationPitch && !bUseYawOnly)
        {
            //FRotator camComRot = VRReplicatedCamera->GetComponentRotation();
            //camComRot.Pitch = pitch;
            //VRReplicatedCamera->SetWorldRotation(camComRot);
            FRotator rota = VRReplicatedCamera->RelativeRotation;
            rota.Pitch = pitch;
            VRReplicatedCamera->SetRelativeRotation(rota);
        }

        return NewLocation - OrigLocation;
    }

Note: Currently it doesn’t work and it seems the mouse Y change affects the character roll and not the pitch of the camera.
I have a feeling the VR replicated camera (or the whole character) is always rotated 90 degrees, causing strange issue.

Edit:
I also tried just updating the pitch with a keypress like , but it didnt work:

Final Edit:

I got it working. I had to change the pitch of the ‘Net Smoother’, not the VRReplicated camera which is a child of Net Smoother.
The example in the link allows the user to change pitch rotation with a key press.
allows multiple functions:

  1. Apply a ‘snap’ for pitch (& roll / yaw) to the first person (vr replicated) camera without directly affecting the character mesh.
  2. Changing the netsmoother also rotates it child components, so in non vr you can use it to rotate the hands (since they are attached to it).

In case anyone is interested.

Changing pitch of the netsmoother is incorrect, it will result in an offset capsule and moves everything from the center of the tracked space.

You should be taking the cameras transform and setting it to My_Offset_As_A_Transform * CameraTransform, that applies the pitch adjustment PRIOR to the cameras rotations, if you just ADD pitch to the hmds rotation the resulting final rotation will be incorrect depending on how they are holding their head.

You also don’t want to do it in SetActorRotation, you want to do it in the camera itself (get camera view). The character ignores the cameras pitch for its standing capsule location and only takes yaw.

One thing to consider, is that to do it correctly you would want the HMDs neck / eye offset transform taken into account.

I thought NetSmoother is inside the VRRootReference, so it will only affect the components that are its children, so the VR Replicated Camera and motion controls.
So I thought should be fine for both non vr users (since it would update the camera and attached motion controlls which allows the user to click on various thhings up in the air)
For VR users the update in pitch would affect motion controls, but it looks like they ignore the net smoother pitch, since they update their own rotation.


Anyway I tried implementing it as you suggested and tried various ways, but it seems that after the pitch is updated it is auto resets back.

All changes below are made in
void UReplicatedVRCameraComponent::GetCameraView(float DeltaTime, FMinimalViewInfo& DesiredView)

First I tried to update the pitch after


if (XRCamera->UpdatePlayerCamera(Orientation, Position))

But I realized that would not work for non-vr because bLockToHmd would be false.
These changes are in the code bellow as commented out lines.

note 1: I had to figure out how quaternions worked, since initially I was working in the vr part. Therefore the code contains both quaternion and frotate calculations for the new pitch.



        // New q = Transform based on quad multiplication.
        // New R = Transform based on fRotator
        //FTransform origCameraTransform = CameraTransform
        //UE_LOG(LogBaseVRCharacter, Log, TEXT("ReplicatedVRCameraComponent::GetCameraView [Original] Transform: %s"), *origCameraTransform.ToString());

        //FQuat pitchQuat(FVector::RightVector, FMath::DegreesToRadians(bAdditionalPitch));
        //FQuat newOrientation = Orientation * pitchQuat;
        //UE_LOG(LogBaseVRCharacter, Log, TEXT("ReplicatedVRCameraComponent::GetCameraView [New Q] Orientation: %s"), *newOrientation.ToString());

        // Clamp pitch -88 to 88 degrees using FRotator (I guess there is also a quaternion way to do ).
        //FRotator rotClamp = FRotator(newOrientation);
        //rotClamp.Pitch = FMath::Clamp(rotClamp.Pitch, -88.0f, 88.0f);
        //newOrientation = rotClamp.Quaternion();
        //UE_LOG(LogBaseVRCharacter, Log, TEXT("ReplicatedVRCameraComponent::GetCameraView [New Q] Orientation clamp: %s"), *newOrientation.ToString());

        //CameraTransform = FTransform(newOrientation, Position);
        //UE_LOG(LogBaseVRCharacter, Log, TEXT("ReplicatedVRCameraComponent::GetCameraView [New Q] Transform w clamp: %s"), *CameraTransform.ToString());

        // Try the same calculation using fRotation instead of quaternion.
        //FRotator rot = FRotator(bAdditionalPitch, 0, 0);
        //origCameraTransform.ConcatenateRotation(rot.Quaternion());
        //UE_LOG(LogBaseVRCharacter, Log, TEXT("ReplicatedVRCameraComponent::GetCameraView [New R] Transform no clamp: %s"), *origCameraTransform.ToString());

        // Clamp it again
        //FRotator newRot = origCameraTransform.Rotator();
        //newRot.Pitch = FMath::Clamp(newRot.Pitch, -88.0f, 88.0f);
        //origCameraTransform.SetRotation(newRot.Quaternion());
        //UE_LOG(LogBaseVRCharacter, Log, TEXT("ReplicatedVRCameraComponent::GetCameraView [New R] Transform w clamp:: %s"), *origCameraTransform.ToString());
        CameraTransform = origCameraTransform

So then I tried to just update the DesiredView.Rotation.

Now for both solutions it seems the pitch does get properly applied, however directly after it the view gets reset to original viewpoint (I don’t know where).
At first I though was because I reset the bAdditionalPitch value after it was applied, but even not resetting the value to 0 didn’t work.
Then I thought it might not have replicated properly, but that also didn’t seem like that case…

note 2: bAdditionalPitch = 10.0f or -10.0f
note 3: bUsePawnControlRotation = false for both VR and non VR pawns in VR Replicated camera.



///************REFERENCE POINT***********
 if (bUseAdditiveOffset)
    {
        FTransform OffsetCamToBaseCam = AdditiveOffset;
        FTransform BaseCamToWorld = GetComponentToWorld();
        FTransform OffsetCamToWorld = OffsetCamToBaseCam * BaseCamToWorld;

        DesiredView.Location = OffsetCamToWorld.GetLocation();
        DesiredView.Rotation = OffsetCamToWorld.Rotator();
    }
    else
    {
        DesiredView.Location = GetComponentLocation();
        DesiredView.Rotation = GetComponentRotation();
    }

    // ************CHANGES START HERE *********
    if (bAdditionalPitch != 0)
    {
        UE_LOG(LogBaseVRCharacter, Log, TEXT("ReplicatedVRCameraComponent::GetCameraView [Original] DesiredRotation: %s"), *DesiredView.Rotation.ToString());
        DesiredView.Rotation.Pitch = FMath::Clamp(DesiredView.Rotation.Pitch + bAdditionalPitch, -88.0f, 88.0f);
        UE_LOG(LogBaseVRCharacter, Log, TEXT("ReplicatedVRCameraComponent::GetCameraView [Original] New DesiredRotation: %s"), *DesiredView.Rotation.ToString());

        //bAdditionalPitch = 0;
    }

Can you give me an example on how to do it?

final note: I also saw flag: bUseAdditiveOffset, should perhaps be used?