Help me understand how to create an XR Poke Button

I am struggling to understand how to create an XR Poke Button from scratch, and what the best practices are.

I’ve tried copying from the existing poke button in the HandsDemoScene included in the MR template, and replacing the visuals with my own mesh, but it appears as if I change anything, it breaks and doesn’t work as expected: Poking in the wrong direction, finger gets sucked into the button (how?), button presses in too deeply, etc.

The most frustrating part is I’ve been able to successfully create a button that behaves the way I want… but then if I wanted to rotate it so it’s oriented in a different direction, it doesn’t work as expected.

So, I want to take a step back and go through the basics: What are the steps that need to be followed to create a poke button from scratch? Trying to copy from an existing example doesn’t work if I don’t even understand what I’m doing or how to set it up.

Questions:

  1. What is the minimum number of required components?
  2. Does the hierarchy need to be set up in a specific way? Does the collider need to be on its own game object?
  3. I assume the mesh needs to be its own game object (right?). Does it need to be a child of a child game object so that the first child is at scale (1,1,1) and the mesh itself can then be scaled differently?
  4. How do you control how far down the button presses?
  5. Poke direction in the poke filter controls the poke direction right? Is this local to the mesh, or local to the prefab root, or totally world space?
  6. Do the interactable, mesh (or mesh parent), and collider all need to be in the same space? And/or same scale?
  7. Why am I able to poke from any direction even though “Enable poke angle threshold” is enabled?
  8. Does the collider need to be at (0,0,0) local position, and offset using the collider center? How do I rotate it then?

I probably have other questions but at this point I am super confused. I’ve filed a bug report with a sample project but I expect whichever QA guy reads it will be just as confused :slight_smile:

Bottom line: I want a button using a triangle mesh, and when pressed, it presses in by 0.01 where it then stops and registers as a select event.

I’d also like to be able to add it to a prefab, where the prefab itself potentially could be re-scaled to something slightly smaller (for wrist UI) or slightly larger (for a console panel). Is this an unreasonable expectation?

Here’s a screenshot of the setup:

Video of how it actually behaves in practice:

PokeButtonIssues

Here’s the most maddening issue: The down button performs exactly how I want it to perform. I don’t even know how I managed to set it up so the button only presses in that far and no more than that.

But if the button is cloned and rotated for the up button, it doesn’t behave the same.

Yet the button in this project is set up exactly the same way as the other project. Why is the behaviour so different?

PokeButtonIssues2

EDIT:

Just to clarify, yes I’m aware the Y axis in the above videos is pointed in a different direction from the buttons. Here’s what the button’s Y direction looks like. This means the poke direction should be negative Y, right?

2 Likes

OK so… I spent the whole day yesterday looking at the pre-made poke button in the HandsDemoScene, and I’ve been able to get a triangle poke button that appears to work in all orientations, so I’ll share my findings here.

Note that there’s still a lot of assumptions and guesswork here because this is pretty poorly documented about how it actually works behind the scenes. I’d greatly appreciate it if anyone could correct me on some of these assumptions.

First, here’s a side view of the anatomy of the button:

  1. Assumption: The collider’s bounding box determines the default poke depth. That means the depth/height of the collider must be at least twice as long as the button’s height or desired poke depth.

  2. Assumption: Do not modify the collider’s center or size. Leave them as (0,0,0) and (1,1,1). Use the transform instead to move/resize the collider. I highly recommend avoiding rotating the collider if you can. I couldn’t get any good results otherwise. Rotate the mesh instead.

  3. Assumption: The button’s position must be on the edge of the collider. Otherwise your finger will sink into the button visual before the button begins moving, as shown in the following screenshot

  4. This is why it’s better to have the mesh as a child of the button game object. Then you’re freely able to offset, resize, and/or rotate it, etc.

  5. BUT! There’s an important gotcha here: You can’t actually move the button itself. If you change the Max Distance value in the XR Poke Follow Affordance, that will move the button. I have no idea what it means to leave this zero as I couldn’t make sense of the button behaviour when it’s zero. Also, don’t forget to turn on Clamp to Max Distance.

  6. AND! This is likely a bug, but the max distance value is in unscaled world space. It’s going to move the button by this amount in world space regardless of what scale(s) the button’s parents are. In other words, if you attach this button to a parent or prefab, you need to manually figure out the button’s lossy scale value and apply it to max distance.

  7. Read the last part of #6 again because that’s how important it is. You’re in for a world of hurt if you try to work around it otherwise.

  8. Poke direction is in the button’s space. Here we see the Y axis is pointing up when the button is selected, so we want poke direction to be negative Y.

I think that’s pretty much the bare minimum of what it takes to have a working poke button with predictable results.

This is all super confusing and is still built on a foundation of assumptions so it’d be super helpful if someone at Unity could check my work.

Better yet, it’d be super helpful to be able to just slap on a PokeButton component where you can just set the poke depth and you’re done. I suspect I’ll have to build that myself because it’s so fragile otherwise setting up a poke button.

End result:

PokeyArrows

1 Like