Attach Character Collision Capsule to HMD (SteamVR)

I’m using an HTC Vive in SteamVR. I have managed to set up an empty character component with movement mapped to the motion controller thumbpads and a camera locked to the HMD, but I can’t seem to get the collision capsule to follow the HMD since it is the blueprint root; it always stays in the center of the chaperone space. I’ve now rigged up a second collision capsule, as suggested here, and I am updating its position and half-height on each tick so that it stretches from the floor to the HMD location. This works well for interactions with physics objects (I can now push things around by walking into them), but my collision with the floor is still dictated by the original capsule in the center of my play space. This means that in order to walk off of a ledge, I have to be moving using the thumbstick; if I physically walk off the ledge I will hang in mid air. When walking up a ramp, my body capsule will just overlap the floor. I’ve attempted to disable collision on the root capsule, but this causes me to immediately fall through the floor… as far as I can tell this is happening because my body capsule is teleporting on each tick, and it’s impossible to move a non-root component via sweep. Is there any way to attach the root capsule to the HMD in order to make interactions with the floor a bit more natural?

The problem is that the camera is moving relative to the Actor (thus your actor doesn’t move in World Space because the camera is inside the play space. Play space is effectively your Actor). Walking in the play space is moving the “Camera” and not the pawn / actor. That is how the Lock To HMD checkbox works, the engine is doing a very simple Query orientation and pose from an HMD if it is attached and that option is true. The collision capsule knows nothing of this. Sorry I don’t have a better answer for you, this is actually making me wonder what happens when we go between Vive / Oculus.

One option is to always be moving the actor to keep you in the center of the play space but there are most likely a bunch of “gotchas” with that technique.

I currently have a mechanism set up so that the character root is moved towards the camera component each tick (via the standard character movement input), and then the scene root is changed to center the playspace on a given static point. This works, but there is a subtle shaking that occurs because of the constant movement of the root object that makes me sick pretty fast. Also, having the static point makes thumbstick movement a bit awkward because it doesn’t respond to physics quite right. I reckon if I were to capture the current playspace center at the beginning of a tick, add movement vectors, then adjust the scene root after physics are applied and before rendering occurs, it would fix both the shaking issue and the thumbstick movement. getting a hook for that second tick is proving tricky, however; I’m attempting to implement what is described here but I am a noob and it’s not terribly straightforward

Any fix or potential update to this?

The basic idea of the solution I came up with is to move the character on each tick towards the camera (or rather, a scene marker that is attached to the camera that is approximately where my neck is) and then update the VR origin scene component to keep the camera stationary. It’s a bit tricky to set up, but works well.

Here is how I’m moving the character:

It is important to update the VR origin immediately after movement and before rendering, or you will get a lot of nauseating shaking. To do this I’ve bound a function to OnCharacterMovementUpdated like this:

UpdateSceneOffset looks like this:

For thumbstick movement, I’m just moving the VR origin in the direction I want to move. I’m basically just adding a vector to the world position of the scene, then clamping it within ~30 cm (this is an arbitrary number but it needs to be greater than 0) of the location that would cause the camera to always be stuck to the capsule. This prevents you from walking through walls. This vector is calculated like this:

And then moved like this, accounting for rotation because MoveComponentTo uses relative locations and physics sometimes causes the character to rotate and we don’t want the camera to be affected:

I’m using MoveComponentTo because simply updating the location causes choppiness. Speed is controlled by a scalar applied to the thumbstick and (more critically) the delta on MoveComponentTo.

Update: Due to performance issues I moved this to C++. The relevant class can be found [here.][6]

Update2: has a plugin available [here][7] that offers a much more robust solution to this problem.

see my answer

Hey SlimeQ,

Do you happen to have a sample character BP of this available anywhere to download so I could take a look at it? I’d really be interested in testing it out. Thanks!

No, it’s unfortunately very tied up with the rest of my character and I don’t really want to release that for reasons. Also I’ve been experiencing some performance issues so I’ve been switching it over to C++ for optimization. I guess I could just throw the class up on github when I’m done? Unless you really want it in blueprint for some reason

I tried building out your approach as posted, and I got some pretty bad stuttering on the updates of the capsule. I ended up going back to updating my capsule, mesh, and root via the SetWorldTransform function. It’s pretty smooth, and I haven’t gotten any stuttering this way.

Sterilized and uploaded to github. All you’ll need to do is create a blueprint derived from this class.

I got that too. I’ve since migrated all the functionality over to C++, you can find it here

Did that fix the stuttering? It felt more like it had to do with the delay caused by running the update on character movement for the capsule

It fixed it on my machine. Theoretically there should be no delay as long as the update happens between movement and rendering within the acceptable framerate. You might also be interested in [this guy’s plug in][1]. He accomplished the same goal by different means that allow for standard movement inputs to be used. It works very well
[1]: VR Expansion Plugin - XR Development - Unreal Engine Forums

You can have an dummy character for take place and update collision with the world . The dummy is follow the camera vr then keep the contrains between them like fixed distance or vector. You move in real world → camera do offset → then dummy follow → if the dummy has collid and stop → check the fix distance or the fix vector → make the camera revert offset. It work for me.

Is this still the best solution, as far as you’re aware of?

i’d recommend using 's VRExpansionPlugin https://bitbucket.org//vrexpansionplugin

Oh yeah, I’ve seen it. Great stuff. I’m just trying to roll my own over here though :slight_smile:

i’ve basically just hacked it to pieces to fit my needs. good luck!

edit: it’s worth noting that the plugin has received a ton of updates since october, it’s really pretty good

Assuming you have this setup where the camera follows your HMD (note the scene node parenting your HMD camera)

136803-componenthierarchyforhmdtrack.png

The simplest method I know to get what you’re looking is to use something like this function in you character BP (open image in a new tab to see full resolution)

We sample the camera relative location, null out the Z axis and get the delta with its old position. We add that delta vector to the collision position and subtract the same delta from the camera offset. Finally we update the old camera position as “OldPosition” member variable. That’s it.

Here’s the bp pastebin: Sync Character Collision to HMD with Rotation Fix posted by anonymous | blueprintUE | PasteBin For Unreal Engine 4

You’ll should be able to walk off ledges and push things around as expected.

Edit: updated to fix rotation, this is done by rotating our DeltaPos by the collision rotation (should only be yaw) but only when added to the collision component, don’t rotate the delta for the camera offset.

1 Like

Event Tick should be sufficient. Depending on what you do, you may need to change the tick group, but by default it should just work on the regular tick interval.