locked
How to properly connect Android device orientation and application's CameraNode rotation? RRS feed

  • Question

  • User240348 posted

    Hello

    Does anybody know, how to properly send the device orientation data got from SensorManager.GetOrientation( ) to Urho Application Camera node's rotation ? In other words I want to control my application's camera (its node rotation) using the device's orientation sensor.

    The below does not work as expected:

    public void OnSensorChanged(SensorEvent e) {
        if (e.Sensor.Type == SensorType.GeomagneticRotationVector) {
            var rm = new float[9];
            SensorManager.GetRotationMatrixFromVector(rm, e.Values.ToArray());
            var ov = new float[3];
            SensorManager.GetOrientation(rm, ov);
            app.Pitch = (MathHelper.RadiansToDegrees(ov[0]) + 360) % 360;
            app.Yaw = (MathHelper.RadiansToDegrees(ov[1]) + 360) % 360;
            app.CameraNode.Rotation = new Quaternion(app.Pitch, app.Yaw, 0);
        }
    }
    
    Monday, May 7, 2018 2:40 PM

Answers

  • User240348 posted

    If anybody is interested, I solved it - here is the final version of OnSensorChanged method:

    // [app] is an instance of Urho.SimpleApplication
    public void OnSensorChanged(SensorEvent e) {
        if (e.Sensor.Type == SensorType.GeomagneticRotationVector) {
            var inR = new float[9];
            SensorManager.GetRotationMatrixFromVector(inR, e.Values.ToArray());
            var outR = new float[9];
            // we need to remap coordinate system, since the Y and Z axes will be swapped, when we pick up the device 
            if (SensorManager.RemapCoordinateSystem(inR, Android.Hardware.Axis.X, Android.Hardware.Axis.Z, outR)) {
                var ov = new float[3];
                SensorManager.GetOrientation(outR, ov);
                try {
                    app.Pitch = (MathHelper.RadiansToDegrees(ov[1]) + 360) % 360;
                    app.Yaw = (MathHelper.RadiansToDegrees(ov[0]) + 360) % 360;
                    app.CameraNode.Rotation = new Quaternion(app.Pitch, app.Yaw, 0);
                }
                catch (System.Exception ex) {
                    // while Urho.SimpleApplication is not fully started, the [app] properties are not available
                    System.Diagnostics.Trace.WriteLine(ex.Message);
                }
            }
        }
    }
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Tuesday, May 15, 2018 12:06 PM
  • User240348 posted

    Another possible solution using only quaternions:

    public void OnSensorChanged(SensorEvent e) {
        if (e.Sensor.Type == SensorType.GeomagneticRotationVector) {
            var qv = new float[4];
            SensorManager.GetQuaternionFromVector(qv, e.Values.ToArray());
            try {
                app.CameraNode.Rotation = new Quaternion(qv[1], -qv[3], qv[2], qv[0]);
                app.CameraNode.Pitch(90.0f);
                app.CameraNode.Roll(180.0f);
            }
            catch (System.Exception ex) {
            }
        }
    }
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Wednesday, May 16, 2018 2:07 PM

All replies

  • User240348 posted

    @EgorBo

    What I also tried is to use SensorManager.GetQuaternionFromVector() method and set the CameraNode.Rotation property directly using the quaternion data from method:

    public void OnSensorChanged(SensorEvent e) {
        if (e.Sensor.Type == SensorType.GeomagneticRotationVector) {
            // The quaternion QV is stored as [w, x, y, z]
            // w = QV[0], x = QV[1], y = QV[2], z = -QV[3]
            var QV = new float[4];
            SensorManager.GetQuaternionFromVector(QV, e.Values.ToArray());
            app.CameraNode.Rotation = new Quaternion(QV[1], QV[2], -QV[3], QV[0]);
        }
    }
    

    But unfortunately the camera rotation is again not as expected.

    Saturday, May 12, 2018 3:37 PM
  • User240348 posted

    If anybody is interested, I solved it - here is the final version of OnSensorChanged method:

    // [app] is an instance of Urho.SimpleApplication
    public void OnSensorChanged(SensorEvent e) {
        if (e.Sensor.Type == SensorType.GeomagneticRotationVector) {
            var inR = new float[9];
            SensorManager.GetRotationMatrixFromVector(inR, e.Values.ToArray());
            var outR = new float[9];
            // we need to remap coordinate system, since the Y and Z axes will be swapped, when we pick up the device 
            if (SensorManager.RemapCoordinateSystem(inR, Android.Hardware.Axis.X, Android.Hardware.Axis.Z, outR)) {
                var ov = new float[3];
                SensorManager.GetOrientation(outR, ov);
                try {
                    app.Pitch = (MathHelper.RadiansToDegrees(ov[1]) + 360) % 360;
                    app.Yaw = (MathHelper.RadiansToDegrees(ov[0]) + 360) % 360;
                    app.CameraNode.Rotation = new Quaternion(app.Pitch, app.Yaw, 0);
                }
                catch (System.Exception ex) {
                    // while Urho.SimpleApplication is not fully started, the [app] properties are not available
                    System.Diagnostics.Trace.WriteLine(ex.Message);
                }
            }
        }
    }
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Tuesday, May 15, 2018 12:06 PM
  • User240348 posted

    Another possible solution using only quaternions:

    public void OnSensorChanged(SensorEvent e) {
        if (e.Sensor.Type == SensorType.GeomagneticRotationVector) {
            var qv = new float[4];
            SensorManager.GetQuaternionFromVector(qv, e.Values.ToArray());
            try {
                app.CameraNode.Rotation = new Quaternion(qv[1], -qv[3], qv[2], qv[0]);
                app.CameraNode.Pitch(90.0f);
                app.CameraNode.Roll(180.0f);
            }
            catch (System.Exception ex) {
            }
        }
    }
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Wednesday, May 16, 2018 2:07 PM