I am trying to allow the user of my VR game to move objects around using a pointer, then when holding down a button, snap to a grid and align to the highest surface, essentially replicating the Editor behaviour or holding down shift+control and moving around a transform gizmo. (Try it, it’s fun!)
I have the grid part down, but can’t wrap my head around how to do the surface snapping.
Here is the code I have so far. I would appreciate any and all help!
// offsetPos is where the VR pointer is.
Vector3 offsetPos = pointer.objectControlPoint.transform.position + cursorOffset;
Vector3 newPos;
if (isSnapping) // Snap to ground code.
{
// I read previously to do this up then down thing, but It's not working as expected
RaycastHit groundHit = new RaycastHit();
if (Physics.Raycast(selectedObject.transform.position, Vector3.down, out groundHit))
{
RaycastHit objectHit = new RaycastHit();
if (Physics.Raycast(groundHit.point, Vector3.up, out objectHit))
{
Vector3 snapDiff = groundHit.point - objectHit.point;
snapYPos = snapDiff.y + (selectedObject.collider.bounds.extents.y);
}
}
float gridPosX = Mathf.Floor(offsetPos.x / worldGrid.gridCellSize) * worldGrid.gridCellSize;
float gridPosZ = Mathf.Floor(offsetPos.z / worldGrid.gridCellSize) * worldGrid.gridCellSize;
newPos = new Vector3(gridPosX, snapYPos, gridPosZ); // Sets the target position to the nearest grid cell, with a Y of the snap position.
}
else // If not in snap mode, set target position to just the VR cursor.
{
newPos = new Vector3(offsetPos.x, offsetPos.y, offsetPos.z);
}
// I know lerp might not be the most efficient, but I like the smooth effect, and it looks good when snapping to the grid...
selectedObject.transform.position = Vector3.Lerp(selectedObject.transform.position, newPos, movementLerpSpeed * Time.deltaTime);
The objects I need to be snapping all are different sizes and have their origins in different places, but all do have appropriate box colliders.
You can use Physics.Raycast() to find what collider surface you are hitting, and you can optionally receive a RaycastHit object back from that to determine the orientation of the surface so you can orient your emplaced thing.
Thank you for the reply, I appreciate it. I don’t know if you saw the code I posted above, but that’s something I already tried, and it wasn’t working. The problem is I need to be able to set the X and Z values, then have the Y snap to whatever is underneath. Additionally, the origin isn’t at the bottom of the object (different objects have different origin locations), so it’s not as simple as setting the position to raycastHit.point.
I see you doing two raycasts within each other and I’m not really sure what’s going on there.
It should be one raycast from eye to ground, and that gives you a RaycastHit, and now you’re done with raycasting.
Now to emplace it: somewhere you need to store the position of what you consider the object anchor. You can force all your objects to have that at zero by redoing them, or else put an invisible GameObject into each things’ hierarchy and use that to “back out” the calculation. Somehow that data has to be stored.
To orient the object, either leave it how you want, or else use the .normal from the RaycastHit to tilt the object.
Generally don’t use “bounds” because that simply doesn’t necessarily map to anything visual in game.
For some context:
The objects are imported at runtime, so it’s not as simple as “redoing them.” I’m using collider.bounds because the objects each have box colliders that are sized appropriately. What I want to do is align the object so that the bottom face of the collider (i.e. The bottom of the object) rests on the surface to snap to. I’m not sure what calculations are necessary to do this.
Additionally, if I do that correctly, I want the object to raise itself to the top position. Meaning that if it snaps to the ground, then slide it left/right/forward/backward, I don’t want it to intersect any other objects on the ground, I want it to move up to end up on top of other objects on the ground as well. I hope that makes sense!
Thanks so much!
That does not get you out of doing the actual work of vertically positioning the object. You may need an additional UI step / state that lets the user fine-control in/out of the object.
Bounds are world-space aligned (see docs), so if you’re placing a cube at 45 degrees, the “bounds” are a larger world axis-aligned cube that fully encloses it. That’s where most people run into issues with Bounds.
Bounds isn’t intended for this use.
Trickier and trickier… those objects would each need to have their colliders considered in your raycast.
Remember raycasting comes in lots of flavors: raycasting, colliders, planes, Plane, etc:
Interesting. I will look into these a little more. Thank you for sharing the resources.
Until then, I think I will use a fixed joint to have the objects accurately collide with other objects in the scene.
Thanks again!