Unity Object Scale Rotation Drag Control Frame (VR supported)

A long time ago, a VR project needed to use a handle to control object rotation, scaling and other functions, and required a control frame like MRTK. Briefly talk about my idea of displaying this box and calculating scaling and rotation.

Draw borders and control points

The generated control frame is divided into two parts, one is a line, and the other is a control point for dragging.

When the object is scaled or rotated, the actual size of the line and the control point will not change (that is, the physical size of the border will not change), and the posture will rotate with the object.

1. Obtain eight vertex coordinates

This is the extension instance method added to Bounds class. The method is bound.Get8CornerPositions

 /// <summary> ///Return the corner coordinates in clockwise order from top to bottom /// </summary> public static void Get8CornerPositions(this Bounds bounds,Transform transform,ref Vector3[] allPoints) { if(allPoints == null || allPoints. Length < 8) { allPoints = new Vector3[8]; } Vector3 center = bounds.center; Vector3 extents = bounds.extents; float cxx = center.x; float cyy = center.y; float czz = center.z; float xx = extents.x; float yy = extents.y; float zz = extents.z; Float lead=cxx - xx;//The X coordinate of the left line Float redge=cxx+xx;//X coordinate of the right line float backedge = czz + zz; float frontedge = czz - zz; float topedge = cyy + yy; float bottomedge = cyy - yy; allPoints[0] = transform. TransformPoint(ledge, topedge, backedge); allPoints[1] = transform. TransformPoint(redge, topedge, backedge); allPoints[2] = transform. TransformPoint(redge,  topedge, frontedge); allPoints[3] = transform. TransformPoint(ledge,  topedge, frontedge); allPoints[4] = transform. TransformPoint(ledge,  bottomedge, backedge); allPoints[5] = transform. TransformPoint(redge,  bottomedge, backedge); allPoints[6] = transform. TransformPoint(redge,  bottomedge, frontedge); allPoints[7] = transform. TransformPoint(ledge,  bottomedge, frontedge); }

We create Bound through BoxCollider data, and then call this extension method to get eight vertex coordinates:

 Bounds tt = new Bounds(m_collider.center, m_collider.size); tt.Get8CornerPositions(this.transform,  ref allCornerPoints);

2. Obtain the coordinates of the rotation control point

According to the corresponding relationship between points and edges, add and divide the coordinates of two points by 2 to get the center point of an edge.

3. Get the edge coordinates

This edge needs two points, and 12 edges can be taken from the 8 calculated vertices according to the corresponding relationship.

4. Generate control points and lines

Create a child object ctrlRoot under the object as the center of the control frame, and then create a line or control point under it.

Lines Use the Cube object or GPU to draw the Cube directly. Eight vertices generate a cube with collision bodies, and the control points of eight line centers use Sphere with collision bodies.

Control rotation

The principle of rotation is Rotate Control Point stay Specified rotation plane Follow the position of the handle until the projection of the handle on the rotation plane is in line with the rotation control point.

When a Rotate Control Point When being dragged (monitored by collision body events), assume that the origin of the control frame is Pos(o) , the control point coordinates are Pos(k) , handle position is Pos(a) , the coordinates are those under the world coordinate system.

according to Rotate Control Point Of Index We can get the Normal vector Normal(plane) , the normal vector is the normal vector under the local coordinate system.

 //Direction vector from handle to control frame center point Vector3 direct = Pos(a) - Pos(o); //Direct projection on the rotation plane Vector3 worldCtrlNormal = this.transform.TransformDirection(Normal(plane)); Vector3 k = Vector3.ProjectOnPlane(direct,worldCtrlNormal); //Find the angle (with direction) of two vectors on this rotation plane float angle = Vector3.SignedAngle(Pos(k) - Pos(o), k,worldCtrlNormal); //Rotate the specified angle if (Mathf. Abs(angle) > 0.01) { this.transform.rotation *= Quaternion.Euler(angle * Normal(plane)); }

When rotating, since our rootCtrl is a sub object, we do not need to consider resetting or adjusting the position of the control frame.

Control zoom

When scaling, the scaling direction is the direction vector P (A.pos – B.pos) calculated from two diagonal points A and B.

 Vector3 scaleDirect = A.position -B.position;

Drag point A to zoom, and modify the object scale so that in the P (A – B) direction, the coordinates of point A coincide with the projection of the handle position in this direction.

 float v2 = Vector3.Dot(Pos(a) - A.position, Vector3.Normalize(scaleDirect));// Projection of handle on this axis Float scaleNumber=v2/Vector3. Distance (A.pos, B.pos);//The multiple that needs to be scaled again on the current basis

Apply zoom:

 this.transform.localScale  *= scaleNumber;

To prevent the size of control points from changing, modify the rootCtrl to scale inversely:

 this.rigRoot.transform.localScale /= scaleNumber;

After adjusting the zoom, you need to adjust the position of control points and lines, obtain new coordinates according to the method of drawing borders and control points, and adjust the coordinates of control points and line zoom, no longer described.

Compatible with VR or mouse

If necessary, you can implement the monitoring event of the control point by yourself.

Zimiao haunting blog (azimiao. com) All rights reserved. Please note the link when reprinting: https://www.azimiao.com/7680.html
Welcome to the Zimiao haunting blog exchange group: three hundred and thirteen million seven hundred and thirty-two thousand

Comment

*

*

Comment area

  1. WeiCN 03-07 06:37 reply

    The blogger is really productive

  2. Excuse me, the source code is not very clear 😥