- Home /
Object snapping to floor and other objects in VR
I want to snap objects to the floor, then lock them in place so the player can snap other objects neatly adjacent to the other objects without having to fiddle with rotating it just right. I was originally going to use VRTK snapping, but I want somewhat of a freeform room furniture placement system without having to place thousands of “snap drop zones” to account for the possibilities. Is there a snapping code that works in VR?
I looked around and found this code from a YT tut: https://youtu.be/n2fx9rkMMVU { Vector3 gridSnapPos(Vector3 originalPosition) { float granularity = .1f; Vector3 snappedPosition = new Vector3(Mathf.Floor(originalPosition.x / granularity) granularity, originalPosition.y, Mathf.Floor(originalPosition.z / granularity) granularity); return snappedPosition; }
public void Snap() { this.transform.position = gridSnapPos(this.transform.position);
} } The problem I have now is that it jitters and jumps too much when grabbing it, so I made it enable on untouch and disable after running 1 frame: { void OnEnable() { Snap(); enabled = false; } } and whenever it’s enabled now, sitting on the floor completely still, it will jump in the -x direction.
I want it to stay put where I place it, but still allow other objects to collide with it so I can place them neatly adjacent. (edited)
Also, I tried doing rotation snapping using the same code just replacing “vector” with “quaternion” and “position” with “rotation”, doesn’t really work.
I’m trying to use it in conjunction with Fuseman’s Force tutorial: https://youtu.be/uf4sz7YbF04 ForceGrab.cs : which goes on the controllers { using System.Collections; using System.Collections.Generic; using UnityEngine; using VRTK;
public class ForceGrab : MonoBehaviour {
private SteamVR_Controller.Device controller;
private LineRenderer lRender;
private Vector3[] positions;
private ForceGrabItem grabbable;
private Snapping snapIt;
private bool grabbed;
private Vector3 lastHandPos;
private Quaternion lastHandRot;
private VRTK_InteractableObject interactable;
// Use this for initialization
void Start () {
SteamVR_TrackedObject trackedObj = GetComponent<SteamVR_TrackedObject>();
controller = SteamVR_Controller.Input((int) trackedObj.index);
lRender = GetComponent<LineRenderer>();
positions = new Vector3[2];
}
// Update is called once per frame
void Update () {
if (!grabbed)
{
grabbable = RaycastForGrabbableObject();
if (!grabbable) return;
}
Vector3 currHandPos = transform.position;
Quaternion curHandRot = transform.rotation;
if (controller.GetPressDown(SteamVR_Controller.ButtonMask.Trigger))
{ // force grab
grabbed = true;
grabbable.Grab(true);
grabbable.SetMoveScale(transform.position);
lastHandPos = currHandPos;
lastHandRot = curHandRot;
DisplayLine(false, transform.position);
}
else if (controller.GetPress(SteamVR_Controller.ButtonMask.Trigger))
{ // force move
grabbable.Move(currHandPos, lastHandPos, curHandRot, lastHandRot);
}
else if (controller.GetPressUp(SteamVR_Controller.ButtonMask.Trigger))
{ // release
grabbed = false;
grabbable.Grab(false);
snapIt.Snap();
//GetComponent snapping enable disable
}
lastHandPos = currHandPos;
lastHandRot = curHandRot;
}
private ForceGrabItem RaycastForGrabbableObject()
{
RaycastHit hit;
Ray r = new Ray(transform.position, transform.forward);
// Debug.DrawRay(transform.position, transform.forward);
if (Physics.Raycast(r, out hit, Mathf.Infinity) && hit.collider.gameObject.GetComponent<ForceGrabItem>() != null)
{
if (hit.collider.gameObject.GetComponent<VRTK_InteractableObject>())
{
interactable = hit.collider.gameObject.GetComponent<VRTK_InteractableObject>();
interactable.ToggleHighlight(true);
interactable.StartTouching(gameObject);
}
DisplayLine(true, hit.point);
return hit.collider.gameObject.GetComponent<ForceGrabItem>();
// print("hit");
}
else
{
if (interactable != null)
{
interactable.ToggleHighlight(false);
interactable.StopTouching(gameObject);
interactable = null;
}
DisplayLine(false, transform.position);
return null;
// print("not hit");
}
}
void DisplayLine(bool display, Vector3 endpoint)
{
lRender.enabled = display;
positions[0] = transform.position;
positions[1] = endpoint;
lRender.SetPositions(positions);
}
} } ForceGrabItem.cs : which goes on the interactable object { using System.Collections; using System.Collections.Generic; using UnityEngine;
public class ForceGrabItem : MonoBehaviour {
private Rigidbody rBody;
private float moveScale;
// Use this for initialization
void Start () {
rBody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update () {
}
public void Grab(bool shouldGrab)
{
rBody.isKinematic = shouldGrab;
}
public void SetMoveScale(Vector3 handPosition)
{
Vector3 origin = GameObject.FindGameObjectWithTag("MainCamera").transform.position;
moveScale = Vector3.Magnitude(transform.position - origin) / Vector3.Magnitude(handPosition - origin);
}
public void Move(Vector3 curHandPos, Vector3 lastHandPos, Quaternion curHandRot, Quaternion lastHandRot)
{
rBody.MovePosition(rBody.position + (curHandPos - lastHandPos) * moveScale);
rBody.MoveRotation(Quaternion.RotateTowards(lastHandRot, curHandRot, Time.deltaTime));
}
} } And Snapping.cs : which goes on the interactable object { using System.Collections; using System.Collections.Generic; using UnityEngine;
public class Snapping : MonoBehaviour { void OnEnable() { Snap(); enabled = false; } //Position snap Vector3 gridSnapPos(Vector3 originalPosition) { float granularity = .1f; Vector3 snappedPosition = new Vector3(Mathf.Floor(originalPosition.x / granularity) granularity, originalPosition.y, Mathf.Floor(originalPosition.z / granularity) granularity); return snappedPosition; }
//Rotatation snap (is broken, makes object freak out) /Quaternion gridSnapRot(Quaternion originalRotation) { float granularity = .1f; Quaternion snappedRotation = Quaternion.Euler(Mathf.Floor(originalRotation.x / granularity) granularity, originalRotation.y, Mathf.Floor(originalRotation.z / granularity) granularity); return snappedRotation; }/
public void Snap()
{
this.transform.position = gridSnapPos(this.transform.position);
//this.transform.rotation = gridSnapRot(this.transform.rotation);
Debug.LogError("snap");
}
} } This is what it currently looks like: https://youtu.be/yGpmjgf2AYs
Help?
I'm also looking for a snapping solution, have you found a solid one? If not, i'll forward whatever i find.
Answer by kavanavak · May 20, 2017 at 08:46 AM
I'm also looking for a snapping solution, have you found a solid one? If not, i'll forward whatever i find.
I haven't worked on it in a while and I haven't found any answers. This seems like a basic common thing but apparently it isn't.
Your answer
Follow this Question
Related Questions
calculating looking angle between 2 transforms 0 Answers
Rotate player (rigidbody) towards his movement 2 Answers
Pose.ctor - create pose from vector3 and quaternion 1 Answer
Slerp look at direction not working... 3 Answers
Saving and applying an array of Vector3 velocities on an array of GameObjects 1 Answer