Jump to content

Rotate a point around another point using quaternion


photo

Recommended Posts

Posted (edited)

Good evening,

I wrote this code in unity to rotate a vec3 point around another vec3 point (with a bit of help from Deepseek):

    public static class QuaternionClass {
        public static Vector4 quatMul(Vector4 q1, Vector4 q2) {
            float w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
            float x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
            float y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x;
            float z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w;
            return new Vector4(x, y, z, w);
        }
        public static Vector4 angledAxis(float angle,Vector3 rotationAxis){
                Vector3 perpendicular = VectorManipulator.normalizeVector3(rotationAxis); 
                float halfAngle = angle * 0.5f * (Mathf.PI/180.0f);
                float sinHalfAngle = Mathf.Sin(halfAngle);
                float w = Mathf.Cos(halfAngle);
                float x = perpendicular.x * sinHalfAngle;
                float y = perpendicular.y * sinHalfAngle;
                float z = perpendicular.z * sinHalfAngle;
                return new Vector4(x,y,z,w);
        }
        public static Vector3 rotate(
            Vector3 origin, Vector3 point,Vector4 angledAxis
            ){
            Vector3 rotatedVec = origin;
            if (point != origin){
                Vector3 pointDirection = VectorManipulator.vectorDirections(origin,point);     
                Vector4 rotatingVector = new Vector4(pointDirection.x, pointDirection.y, pointDirection.z,0);
                Vector4 inverseQuat = new Vector4(-angledAxis.x,-angledAxis.y,-angledAxis.z,angledAxis.w);
                Vector4 rotatedQuaternion = quatMul(quatMul(angledAxis,rotatingVector), inverseQuat);

                rotatedVec = origin + new Vector3(
                        rotatedQuaternion.x,
                        rotatedQuaternion.y,
                        rotatedQuaternion.z
                        );
            }
            return rotatedVec;
        }
    }

I want to do it using your library, but I can't really seem to understand how to do it: https://developer.unigine.com/en/docs/latest/api/library/math/cs/quat?rlang=cpp&autotranslate=en

If I do something like this it only rotates the object around itself:

	ObjectMeshDynamic clone;

    public ObjectMeshDynamic createCube(vec3 size,vec3 position,int i){
        ObjectMeshDynamic cube = Primitives.CreateBox(size);
        cube.TriggerInteractionEnabled = true;
        cube.SetIntersection(true, 0);
        cube.SetIntersectionMask(1, 0);
        cube.SetCollision(true,0);
        cube.SetCollisionMask(1, 0);
        cube.WorldPosition = position;
        cube.Name = $"{i}";
        BodyRigid bodySphere = new BodyRigid(cube);
        new ShapeSphere(bodySphere, 2);
        bodySphere.ShapeBased = false;
        bodySphere.Mass = 1f;
        return cube;
    }
    private void Init(){
        Visualizer.Enabled = true;
        Unigine.Console.Onscreen = true;
        Physics.ShowShapes = Physics.SHOW_TYPE.SOLID;
        Physics.ShowJoints = true;
        Physics.ShowCollisionSurfaces = true;
        vec3 pos = new vec3(0,0,5);
        clone = createCube(new vec3(1,1,1),pos,1);
    }
    float count = 0;
    private void Update(){
        clone.SetWorldRotation(new quat(new vec3(0,0,1),count));
        count += 0.1f;
    }

How can I rotate a vec3 point around another vec3 point?

Edited by Sevdat
Posted
On 7/25/2024 at 1:06 PM, Sevdat said:

Good evening,

I wrote this code in unity to rotate a vec3 point around another vec3 point (with a bit of help from Deepseek):

    public static class QuaternionClass {
        public static Vector4 quatMul(Vector4 q1, Vector4 q2) {
            float w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
            float x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
            float y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x;
            float z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w;
            return new Vector4(x, y, z, w);
        }
        public static Vector4 angledAxis(float angle,Vector3 rotationAxis){
                Vector3 perpendicular = VectorManipulator.normalizeVector3(rotationAxis); 
                float halfAngle = angle * 0.5f * (Mathf.PI/180.0f);
                float sinHalfAngle = Mathf.Sin(halfAngle);
                float w = Mathf.Cos(halfAngle);
                float x = perpendicular.x * sinHalfAngle;
                float y = perpendicular.y * sinHalfAngle;
                float z = perpendicular.z * sinHalfAngle;
                return new Vector4(x,y,z,w);
        }
        public static Vector3 rotate(
            Vector3 origin, Vector3 point,Vector4 angledAxis
            ){
            Vector3 rotatedVec = origin;
            if (point != origin){
                Vector3 pointDirection = VectorManipulator.vectorDirections(origin,point);     
                Vector4 rotatingVector = new Vector4(pointDirection.x, pointDirection.y, pointDirection.z,0);
                Vector4 inverseQuat = new Vector4(-angledAxis.x,-angledAxis.y,-angledAxis.z,angledAxis.w);
                Vector4 rotatedQuaternion = quatMul(quatMul(angledAxis,rotatingVector), inverseQuat);

                rotatedVec = origin + new Vector3(
                        rotatedQuaternion.x,
                        rotatedQuaternion.y,
                        rotatedQuaternion.z
                        );
            }
            return rotatedVec;
        }
    }

I want to do it using your library, but I can't really seem to understand how to do it: https://developer.unigine.com/en/docs/latest/api/library/math/cs/quat?rlang=cpp&autotranslate=en

If I do something like this it only rotates the object around itself:

	ObjectMeshDynamic clone;

    public ObjectMeshDynamic createCube(vec3 size,vec3 position,int i){
        ObjectMeshDynamic cube = Primitives.CreateBox(size);
        cube.TriggerInteractionEnabled = true;
        cube.SetIntersection(true, 0);
        cube.SetIntersectionMask(1, 0);
        cube.SetCollision(true,0);
        cube.SetCollisionMask(1, 0);
        cube.WorldPosition = position;
        cube.Name = $"{i}";
        BodyRigid bodySphere = new BodyRigid(cube);
        new ShapeSphere(bodySphere, 2);
        bodySphere.ShapeBased = false;
        bodySphere.Mass = 1f;
        return cube;
    }
    private void Init(){
        Visualizer.Enabled = true;
        Unigine.Console.Onscreen = true;
        Physics.ShowShapes = Physics.SHOW_TYPE.SOLID;
        Physics.ShowJoints = true;
        Physics.ShowCollisionSurfaces = true;
        vec3 pos = new vec3(0,0,5);
        clone = createCube(new vec3(1,1,1),pos,1);
    }
    float count = 0;
    private void Update(){
        clone.SetWorldRotation(new quat(new vec3(0,0,1),count));
        count += 0.1f;
    }

How can I rotate a vec3 point around another vec3 point?

Good evening,

I converted the code to unigine version:

	ObjectMeshDynamic clone;
    ObjectMeshDynamic clone2;
    float angle = 1;
    vec4 q;
    vec3 newVec;
    vec3 axis = new vec3(0,0,1);

    public ObjectMeshDynamic createCube(vec3 size,vec3 position,int i){
        ObjectMeshDynamic cube = Primitives.CreateBox(size);
        cube.TriggerInteractionEnabled = true;
        cube.SetIntersection(true, 0);
        cube.SetIntersectionMask(1, 0);
        cube.SetCollision(true,0);
        cube.SetCollisionMask(1, 0);
        cube.WorldPosition = position;
        cube.Name = $"{i}";
        BodyRigid bodySphere = new BodyRigid(cube);
        new ShapeSphere(bodySphere, 2);
        bodySphere.ShapeBased = false;
        bodySphere.Mass = 1f;
        bodySphere.Gravity = false;
        return cube;
    }

    public static vec4 quatMul(vec4 q1, vec4 q2) {
        float w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
        float x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
        float y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x;
        float z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w;
        return new vec4(x, y, z, w);
    }
    public static vec4 angledAxis(float angle,vec3 rotationAxis){
            vec3 perpendicular = rotationAxis.Normalized; 
            float halfAngle = angle * 0.5f * (MathLib.PI/180.0f);
            float sinHalfAngle = MathLib.Sin(halfAngle);
            float w = MathLib.Cos(halfAngle);
            float x = perpendicular.x * sinHalfAngle;
            float y = perpendicular.y * sinHalfAngle;
            float z = perpendicular.z * sinHalfAngle;
            return new vec4(x,y,z,w);
    }
    public static vec3 rotate(
        vec3 origin, vec3 point, vec4 angledAxis
        ){
        vec3 rotatedVec = origin;
        if (point != origin){
            vec3 pointDirection = point - origin;     
            vec4 rotatingVector = new vec4(pointDirection.x, pointDirection.y, pointDirection.z,0);
            vec4 inverseQuat = new vec4(-angledAxis.x,-angledAxis.y,-angledAxis.z,angledAxis.w);
            vec4 mul = quatMul(angledAxis,rotatingVector);
            Log.Message($"mul:{mul}\n");
            vec4 rotatedQuaternion = quatMul(mul, inverseQuat);
            Log.Message($"rotatedQuaternion:{rotatedQuaternion}\n");

            rotatedVec = origin + new vec3(
                    rotatedQuaternion.x,
                    rotatedQuaternion.y,
                    rotatedQuaternion.z
                    );
        }
        return rotatedVec;
    }
    private void Init(){
        Visualizer.Enabled = true;
        Unigine.Console.Onscreen = true;
        Physics.ShowShapes = Physics.SHOW_TYPE.SOLID;
        Physics.ShowJoints = true;
        Physics.ShowCollisionSurfaces = true;
        vec3 pos = new vec3(10,10,10);

        clone = createCube(new vec3(1,1,1),pos,1);
        clone2 = createCube(new vec3(1,1,1),pos + new vec3(0,5,10),1);
        q = angledAxis(angle,axis);
        newVec = rotate(clone.WorldPosition,clone2.WorldPosition,q);
        clone2.WorldPosition = newVec;
    }
    private void Update(){
         clone2.WorldPosition = rotate(clone.WorldPosition,clone2.WorldPosition,q);
    }

but I still can't do it using your library. I tried something like this, but it doesn't work.

        vec3 pos = new vec3(10,10,2);
        clone = createCube(new vec3(1,1,1),pos,1);
        clone2 = createCube(new vec3(1,1,1),pos + new vec3(0,5,0),1);
        q = new quat(pos + new vec3(0,5,0),count);
        vec3 o = clone2.WorldPosition;
        vec3 f = q*o*(-q);
        Log.Message($"{f}\n");

 

Posted (edited)
On 7/27/2024 at 8:23 AM, Sevdat said:

Good evening,

I converted the code to unigine version:

	ObjectMeshDynamic clone;
    ObjectMeshDynamic clone2;
    float angle = 1;
    vec4 q;
    vec3 newVec;
    vec3 axis = new vec3(0,0,1);

    public ObjectMeshDynamic createCube(vec3 size,vec3 position,int i){
        ObjectMeshDynamic cube = Primitives.CreateBox(size);
        cube.TriggerInteractionEnabled = true;
        cube.SetIntersection(true, 0);
        cube.SetIntersectionMask(1, 0);
        cube.SetCollision(true,0);
        cube.SetCollisionMask(1, 0);
        cube.WorldPosition = position;
        cube.Name = $"{i}";
        BodyRigid bodySphere = new BodyRigid(cube);
        new ShapeSphere(bodySphere, 2);
        bodySphere.ShapeBased = false;
        bodySphere.Mass = 1f;
        bodySphere.Gravity = false;
        return cube;
    }

    public static vec4 quatMul(vec4 q1, vec4 q2) {
        float w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
        float x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
        float y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x;
        float z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w;
        return new vec4(x, y, z, w);
    }
    public static vec4 angledAxis(float angle,vec3 rotationAxis){
            vec3 perpendicular = rotationAxis.Normalized; 
            float halfAngle = angle * 0.5f * (MathLib.PI/180.0f);
            float sinHalfAngle = MathLib.Sin(halfAngle);
            float w = MathLib.Cos(halfAngle);
            float x = perpendicular.x * sinHalfAngle;
            float y = perpendicular.y * sinHalfAngle;
            float z = perpendicular.z * sinHalfAngle;
            return new vec4(x,y,z,w);
    }
    public static vec3 rotate(
        vec3 origin, vec3 point, vec4 angledAxis
        ){
        vec3 rotatedVec = origin;
        if (point != origin){
            vec3 pointDirection = point - origin;     
            vec4 rotatingVector = new vec4(pointDirection.x, pointDirection.y, pointDirection.z,0);
            vec4 inverseQuat = new vec4(-angledAxis.x,-angledAxis.y,-angledAxis.z,angledAxis.w);
            vec4 mul = quatMul(angledAxis,rotatingVector);
            Log.Message($"mul:{mul}\n");
            vec4 rotatedQuaternion = quatMul(mul, inverseQuat);
            Log.Message($"rotatedQuaternion:{rotatedQuaternion}\n");

            rotatedVec = origin + new vec3(
                    rotatedQuaternion.x,
                    rotatedQuaternion.y,
                    rotatedQuaternion.z
                    );
        }
        return rotatedVec;
    }
    private void Init(){
        Visualizer.Enabled = true;
        Unigine.Console.Onscreen = true;
        Physics.ShowShapes = Physics.SHOW_TYPE.SOLID;
        Physics.ShowJoints = true;
        Physics.ShowCollisionSurfaces = true;
        vec3 pos = new vec3(10,10,10);

        clone = createCube(new vec3(1,1,1),pos,1);
        clone2 = createCube(new vec3(1,1,1),pos + new vec3(0,5,10),1);
        q = angledAxis(angle,axis);
        newVec = rotate(clone.WorldPosition,clone2.WorldPosition,q);
        clone2.WorldPosition = newVec;
    }
    private void Update(){
         clone2.WorldPosition = rotate(clone.WorldPosition,clone2.WorldPosition,q);
    }

but I still can't do it using your library. I tried something like this, but it doesn't work.

        vec3 pos = new vec3(10,10,2);
        clone = createCube(new vec3(1,1,1),pos,1);
        clone2 = createCube(new vec3(1,1,1),pos + new vec3(0,5,0),1);
        q = new quat(pos + new vec3(0,5,0),count);
        vec3 o = clone2.WorldPosition;
        vec3 f = q*o*(-q);
        Log.Message($"{f}\n");

 

Good morning,

I wrote it using your library, but noticed that rotating by 1 degrees works like rotating 0.5 degrees.

Rotating 360 degrees is a bit off too.

image.png.4d6287e958f373f9443e1a4cd662cd7b.png

Is everything working as intended?

    float angle = 1f;
    vec3 rotationAxis = new vec3(0, 0, 1);
    ObjectMeshDynamic origin;
    ObjectMeshDynamic point;
    float time = 0;
    float count;

    public ObjectMeshDynamic createCube(vec3 size,vec3 position,int i){
        ObjectMeshDynamic cube = Primitives.CreateBox(size);
        cube.TriggerInteractionEnabled = true;
        cube.SetIntersection(true, 0);
        cube.SetIntersectionMask(1, 0);
        cube.SetCollision(true,0);
        cube.SetCollisionMask(1, 0);
        cube.WorldPosition = position;
        cube.Name = $"{i}";
        BodyRigid bodySphere = new BodyRigid(cube);
        new ShapeSphere(bodySphere, 2);
        bodySphere.ShapeBased = false;
        bodySphere.Mass = 1f;
        bodySphere.Gravity = false;
        return cube;
    }
    public quat angledAxis(float angle, vec3 rotationAxis){
        return new quat(rotationAxis, angle);
    }
    public vec3 rotate(vec3 origin, vec3 point, quat angledAxis){
        quat q = angledAxis;
        vec3 v = point - origin;
        vec3 rotatedOffset = q * v * new quat(new float[] { -q.x, -q.y, -q.z, q.w });
        return origin + rotatedOffset;
    }
    
    private void Init(){
        Visualizer.Enabled = true;
        Unigine.Console.Onscreen = true;
        Physics.ShowShapes = Physics.SHOW_TYPE.SOLID;
        Physics.ShowJoints = true;
        Physics.ShowCollisionSurfaces = true;

        vec3 pivotPosition = new vec3(10, 10, 2);
        vec3 rotatingPosition = pivotPosition + new vec3(0, 5, 0);
        origin = createCube(new vec3(1, 1, 1), pivotPosition, 1);
        point = createCube(new vec3(1, 1, 1), rotatingPosition, 1);
    }

    private void Update(){
        if (time>0.05){
            point.WorldPosition = rotate(
                    origin.WorldPosition,
                    point.WorldPosition,
                    angledAxis(angle,rotationAxis)
                );
            time = 0;
            count++;
            if (count>360) count = 0;
            Log.Message($"{count}\n");
        } else time += Game.IFps;
    }

When rotating a mesh do I need to multiply each vertex with a quaternion or is there a more efficient way of rotating them?

Edited by Sevdat
  • Like 1
Posted (edited)

Good evening,

As user karpych11 stated:

The code above had the mistake in:

vec3 rotatedOffset = q * v * new quat(new float[] { -q.x, -q.y, -q.z, q.w });

v is a vector not a quat. It should have been transformed into a quat:

quat pureImaginaryQuaternion = new quat();
	pureImaginaryQuaternion.x = v.x;
	pureImaginaryQuaternion.y = v.y;
	pureImaginaryQuaternion.z = v.z;
	pureImaginaryQuaternion.w = 0.0f;

then it would have been correct. In order to use it the vector way:

    public quat angledAxis(float angle, vec3 rotationAxis){
        return new quat(rotationAxis, angle);
    }
    public vec3 rotate(vec3 origin, vec3 point, quat angledAxis){
        quat q = angledAxis;
        vec3 v = point - origin;
        vec3 rotatedOffset = q * v;
        return origin + rotatedOffset;
    }

in order to access the math library directly:

vec3 rotatedOffset = MathLib.Mul(angledAxis, v);
Edited by Sevdat
×
×
  • Create New...