Vector3 question: How to know right axis when using pinch punch gestures to scale object in virtual reality?
I have an object that can be scaled in virtual reality using Vive touch controllers. The issue: the pinch punch gestures for scaling relate to the world, but the object to scale is already rotated. How do I know along which axis the user is intending to scale?
Here's a sample video of how it should work, with the sample code to achieve this below: https://www.youtube.com/watch?v=bJwgtoyedcI
As it shows, only one axis (the biggest stretch) is meant to be scaled a time. However, in this video example the cube was carefully rotated for the code to work. Rotated anyway else, and the wrong scaling axis will be applied. How would I go about this? And to clarify, I would like to only change the localScale, not permanently apply the scaling to a parent transform. Thanks for any help!
// had been trying eulerAngles as well as localEulerAngles
Vector3 originalAngles = (Vector3)transformToHandle.eulerAngles;
// trying to reset object's rotation
transformToHandle.Rotate(-originalAngles);
/*
// (an alternative was to rotate the pinch punch points along their center)
Vector3 centerToBePivot = Vector3.Lerp(startPos1, startPos2, 0.5f);
Vector3 anglesToRotate = -Universe.lastTransformHandled.eulerAngles;
startPos1 = RotatePointAroundPivot(startPos1, centerToBePivot, anglesToRotate);
endPos1 = RotatePointAroundPivot(endPos1, centerToBePivot, anglesToRotate);
startPos2 = RotatePointAroundPivot(startPos2, centerToBePivot, anglesToRotate);
endPos2 = RotatePointAroundPivot(endPos2, centerToBePivot, anglesToRotate);
*/
// preparing some values
Vector3 scale = transformToHandle.localScale;
Vector3 startPos1 = positionEmptyClickStarted;
Vector3 endPos1 = transform.position;
Vector3 startPos2 = otherDotScript.positionEmptyClickStarted;
Vector3 endPos2 = otherDot.transform.position;
float leftRightDistanceStart = Vector3.Distance(startPos1, startPos2);
float leftRightDistanceEnd = Vector3.Distance(endPos1, endPos2);
float growth = leftRightDistanceEnd - leftRightDistanceStart;
// along which axis do we want to stretch? Pick biggest
float xStretch = Mathf.Abs(startPos1.x - endPos1.x) + Mathf.Abs(startPos2.x - endPos2.x);
float yStretch = Mathf.Abs(startPos1.y - endPos1.y) + Mathf.Abs(startPos2.y - endPos2.y);
float zStretch = Mathf.Abs(startPos1.z - endPos1.z) + Mathf.Abs(startPos2.z - endPos2.z);
// apply the scaling now
if ( xStretch >= yStretch && xStretch >= zStretch ) {
scale.x = scaleAtStart.x + growth;
}
else if ( yStretch >= xStretch && yStretch >= zStretch ) {
scale.y = scaleAtStart.y + growth;
}
else if ( zStretch >= xStretch && zStretch >= yStretch ) {
scale.z = scaleAtStart.z + growth;
}
// ensuring scaling won't go into negative or too small
float min = 0.01f;
if (scale.x < min) { scale.x = min; }
if (scale.y < min) { scale.y = min; }
if (scale.z < min) { scale.z = min; }
// reapply scale and rotate back to how it was
transformToHandle.localScale = scale;
transformToHandle.eulerAngles = originalAngles;
Edit: Apologies, have now seen the note at the top of your last question.
Did you try editing the code I gave you from 2D to 3D? It involves removing 1 line, changing 3 and replacing the 2D method with the 3D method I wrote. Code here.
Thanks. That code uses WorldToScreenPoint, but I'm working in virtual reality, where there is actual e.g. depth in a true 3D space (so moving my hand into the depth would not change a screen point, but it does change the depth point). Have you seen above video? The cube is meant to be localScaled in any of the 3 dimensions (and as opposed to the last question, with 2 hands for$$anonymous$$g a line). Thanks again for any help!
You can still edit my code to use 3D, simply by removing the casting into Screen-space:
Vector3[] vecs = new Vector3[3];
Vector2 pos = trans.position;
vecs[0] = trans.right;
vecs[1] = trans.up;
vecs[2] = trans.forward;
and use Influence3D
This will depend on whether you want to decide the direction by the starting proximity of the hands to a side, or to decide the axis based on the movement of the hands away or towards each other or some combination of the both?
It should work like this (you can hear the sound of the click when the hand is pressed): https://www.youtube.com/watch?v=bJwgtoyedcI
$$anonymous$$g. if I'm moving my hand left and right outwards, it should grow along the left right axis. The video shows the example code I pasted above in action and it all works with one big exception... as soon as the transform is already rotated, it will apply the scaling along the wrong axis...
Sorry, I got it now using Quaternion.Inverse! I will post an answer soon. Thanks for trying to help, it is appreciated! I wish I knew as much about this stuff as you!
Answer by JPhilipp · May 01, 2016 at 07:32 PM
So it turns out the problem in above code was that for the alternative, outcommented try, this
Vector3 anglesToRotate = -transformToHandle.eulerAngles;
... needed to be this ...
Quaternion inverse = Quaternion.Inverse(transformToHandle.rotation);
Vector3 anglesToRotate = inverse.eulerAngles;
Then it all works.
Your answer
Follow this Question
Related Questions
Vector3.Angle is wrong 1 Answer
XR Device Simulator doesn't react 2 Answers
Trouble With Free Movement & Camera in Oculus 0 Answers
For the HTC Vive How Can I change the SteamVR overlay Menu 0 Answers
Place a UI element in the x and z direction of the user's gaze, keeping y value "straight ahead" 1 Answer