Hinge Uses Object Center, Not Pivot

This is kind of hard to explain, so I attached a diagram.

I’m trying to rotate an object by attaching a hinge joint. I have a “dragger” object with a hinge joint, and I set its connected body to the object to be dragged. Then I move the dragger around the object, and the object rotates to follow.

This works great, except that the object rotates around its center point, not it’s pivot point. Doesn’t seem to matter how the anchor or connected anchor or anything is set. How can I get the object to rotate around its pivot point and not its center?

1721403--108582--pivot.jpg

Here’s the code that sets up the hinge joint. The targetTransform is the object being dragged, and draggerObj has the hinge joint and is being moved under program control.

    var tt = targetTransform.gameObject.AddComponent("Rigidbody");
    targetTransform.position.y += 0.002;  // lift slightly off surface
    targetTransform.rigidbody.isKinematic = false; 
    targetTransform.rigidbody.useGravity = false;
    targetTransform.rigidbody.constraints = RigidbodyConstraints.FreezeAll;
    targetTransform.rigidbody.constraints &= ~RigidbodyConstraints.FreezeRotationY;  // can only rotate on Y axis
 
    draggerHingeJoint.connectedBody = targetTransform.rigidbody;
         
    draggerHingeJoint.autoConfigureConnectedAnchor = false;     
    draggerHingeJoint.connectedAnchor = Vector3.zero;         
    draggerHingeJoint.anchor = Vector3.zero;

I’ve tried every possible setting and combination of settings in those last 3 lines, but the dragged object always rotates around its center point.

1 Like

Edit the Anchor values? :0

As I said, I’ve tried every possible value for anchor and connected anchor (see my code). Could you be more specific?

Just to be clear, I’ve tried setting both to Vector3.zero (should be local coordinates, which should be the pivot point of the dragged object), I can see the dot in the scene view that shows the anchor at the pivot point, where I believe it should be. I’ve tried setting anchor and letting it auto configure the connected anchor. I’ve tried setting the connected anchor and not setting the anchor. I’ve tried setting them to values other than zero, from the target position to random numbers. I’ve tried creating a new object at the pivot point and setting the anchor to its coordinates. I can’t find any settings for the anchor values that make any difference. The dragged object always rotates around its center. Which seems odd, since there is nothing at that point. No object has the coordinates of the center of the dragged object, so where is it getting that point from?

It also doesn’t matter the size of the object. I can change its scale each time before I rotate it, and it always adjusts to rotate around the center of the resized object.

Looks like freezing the position is the problem. If I get rid of all the RB constraints (comment out lines 6-7 in the sample), it rotates around the pivot point. Of course without position frozen, it jumps all over the place. So it looks like it will only rotate around the pivot point if I don’t freeze position, but without position frozen it moves around while it rotates. I’m stumped.

1 Like

Try different constraints at runtime, and maybe make the rotation axis diagnal. o;

I’ve tried every combination of constraints. If I freeze X, Y and/or Z position, it rotates around the center. The rotation axis is what it is. I have to rotate the object horizontally, which is around the Y axis, so X and Z rotation must be frozen (or it wobbles). I even tried changing the center of mass.

If you’re talking about the hinge joint axis, it doesn’t matter what I set that to, it makes no difference. Which doesn’t seem right.

There must be a way to do this, I’m just doing something wrong.

One more thing: I tried simply adding torque instead of using a dragger and hinge joint. It still rotates around the center of the object, not the pivot point. Must have something to do with the way I’ve attached the rigidbody to the object.

If I rotate the object:

targetTransform.Rotate(Vector3(0.0, tAngle, 0.0));

It rotates around the pivot point. But if I add a torque, it rotates around the center.

targetTransform.rigidbody.AddRelativeTorque(Vector3(0.0, tAngle, 0.0), ForceMode.Impulse);

Try resetting the force that you’re adding to 0 on the axis’ that you’re constraining.

The problem seems to have something to do with the parent object not having its own collider. Sort of. If I add a collider, in addition to adding a rigidbody, the object rotates around the pivot point (with both a hinge or with adding torque). But only if the collider is big enough. A very large collider works, but anything smaller, and it rotates around the center again. Only problem, with such a big collider, it’s impossible to rotate an object without hitting something else. So it’s not a solution, but some additional information.

I’d think setting the RB’s center of mass to Vector3.zero (the object’s pivot point?) in addition to adding the collider, it should force it to use that point to rotate around, but it doesn’t.

Maybe I’m asking the wrong questions. This seems like a very common, simple thing to do. I can drag an object around with a spring joint and it works great, stopping when it hits an obstacle. I just want to do the same when rotating the object. I’ve tried so many different approaches to this, I’ve lost track. What’s the secret to rotating an object under program control and having it stop when it hits an object?

I’ll test around, expect a reply soon.

Using raycast.
Here you go, you don’t need joints for this.
Please let me know if this is what you wanted.

using UnityEngine;
using System.Collections;

public class DragObject : MonoBehaviour
{
    //Select all layers except for the pickup one.
    public LayerMask ignorePickupLayer;

    //The distance at which the object will float in front of you.
    public float carryDistance  = 1.8f;
    //Them minimum distance you have to be away from an object to pick it up.
    public float reachDistance  = 2.4f;
    //The force at which the object moves towards the carry-point.
    public float movePower      = 6.0f;
    //The multiplier for the lerp deltaTime input.
    public float lerpSpeed      = 9.8f;

    //The multiplier for the target's rotation speed.
    public float rotateSpeed    = 3.8f;

    //Self explenatory
    bool carryingObject;
    Transform target;

    void Update()
    {
        //variable to store the raycast information in.
        RaycastHit hit;
        if (!carryingObject)
        {
            if (Input.GetMouseButtonDown(0))
            {
                //Checks if there's an object in front of you.
                if (Physics.Raycast(transform.position, transform.forward, out hit, reachDistance))
                {
                    //Checks whether you can pick the object up(Layer)
                    if (hit.transform.gameObject.layer == LayerMask.NameToLayer("Pickup"))
                    {
                        carryingObject = true;
                        target = hit.transform;
                        target.rigidbody.useGravity = false;
                        target.rigidbody.angularDrag = 0.5f;

                        Debug.Log("Picked up " + target.name);
                    }
                }
            }
        }
        else
        {
            //Direction that the object needs to move towrads.
            Vector3 direction;
            //Distance between the carryPoint and the targetObject.
            float distance;
            //Target velocity that it'll transition towards.
            Vector3 newVelocity;

            if (Physics.Raycast(transform.position, transform.forward, out hit, reachDistance, ignorePickupLayer))
            {
                //Debug.Log("Wall has been hit!");

                direction   = (hit.point - target.position).normalized;
                distance    = Vector3.Distance(target.position, hit.point);

                newVelocity = direction * movePower * distance;
            }
            else
            {
                //Debug.Log("Moving To ReachPoint!");
                Vector3 carryPoint = transform.position + transform.forward * carryDistance;

                direction   = (carryPoint - target.position).normalized;
                distance    = Vector3.Distance(carryPoint, target.position);

                newVelocity = direction * movePower * distance;
            }

            //Enable rotate when holding 'R' Key
            //NOTE: Disable the camera rotation script when this is happening!
            if(Input.GetKey(KeyCode.R))
            {
                //Mouse Input to rotate the object
                float x = Input.GetAxis("Mouse X");
                float y = Input.GetAxis("Mouse Y");

                //New rotation velocity for the targetObject.
                Vector3 newAngularVelocity = transform.TransformDirection(new Vector3(y, -x, 0) * rotateSpeed);

                target.rigidbody.angularVelocity = newAngularVelocity;
            }

            //Lerps towards the new velocity.
            target.rigidbody.velocity = Vector3.Lerp(target.rigidbody.velocity, newVelocity, Time.deltaTime * lerpSpeed);

            //Checks if you want to let go of the object
            if (Input.GetMouseButtonUp(0))
            {
                //Reset values
                Debug.Log("Dropped " + target.name);
                carryingObject = false;
                target.rigidbody.useGravity = true;
                target.rigidbody.angularDrag = 0.05f;
            }
        }
    }

}

I’d recommend you to use a slippery physics material when dragging an object :'P
The joint messes up the rotation, so I chose to not use one at all for the script o:
I hope you’re okay with that :s

https://dl.dropboxusercontent.com/u/53389053/Magii%20Games/Object_Pickup_n_Rotate/Object_Pickup_n_Rotate.html

Thanks. But I’m not sure that would work for me. The objects in my scene are all different sizes and shapes. One raycast isn’t sufficient to detect an obstacle (if I understand your code correctly). I had that same problem when moving an object down and trying to determine if anything was underneath it. I ended up having to cast multiple rays depending on the size and shape of the moving object, otherwise it would miss an obstacle only partially blocking its path. It’s not perfect (sometimes an edge or corner goes undetected), but combined with collision detection, works reliably.

I think my best solution is to NOT use joints or physics for rotating objects (I’ll do that for dragging). The best solution I’ve found so far is to use MoveRotation, which produces collisions (but does NOT stop as the docs says it does). When a collision occurs while rotating, I stop the object’s rotation and move it back a bit in the direction it came from. Of the MANY things I’ve tried so far, this works the best.

Hmm, The raycast is to prevent the object from adding too much force, which will result into spastic movements.
But it isn’t such a big deal, it happens in amnesia too, and no-one seems to be bothered by it.
Please try it out before drawing a conclusion :slight_smile:

Wow, this post is old as f$^ck but I can help you out. Your problem, is not to be fixed by code. But by moving the joint origin from the inspector in Unity

Hi, can you please specify how you move the joint origin from the inspector? Thanks. I encountered the exact same problem.

Ok I think I figured it out: The problem is that the rigidbody’s center of mass is not well-defined. By default, the COM is “calculated automatically from all colliders attached to the rigidbody” (https://docs.unity3d.com/ScriptReference/Rigidbody-centerOfMass.html). In order to set COM to the joint, simply find the position p1 of the joint in the world coordinate, and initialize COM as:
YourObject.GetComponent<Rigidbody>().centerOfMass = p1 - YourObject.transform.position;

Hi, if anyone is still having issue with this, here is what was my problem: my gameobject holding the hinge joint was a child of a transform on which I had changed the scale. The rotating axis was off and taking the child object out of this hierarchy fixed it.