基于Android设备方向的Xamarin.Android与UrhoSharp相机节点旋转

t9eec4r0  于 2023-11-15  发布在  Android
关注(0)|答案(3)|浏览(127)

在我的Xamarin.Android应用程序中,我从设备的地磁旋转矢量复合传感器获取X,Y,Z轴的方向数据,并使用SensorManager.GetOrientation( )方法进行处理。我想在CameraNode的Rotation属性上的UrhoSharp场景中应用此方向数据。换句话说,我想使用设备的“方向”传感器控制场景的相机。
到目前为止,我在SensorChanged事件处理程序中所做的是:

// app -> an instance of Urho.SimpleApplication
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 = (Urho.MathHelper.RadiansToDegrees(ov[0]) + 360) % 360;      // map [-Pi...+Pi] to [0...360]
        app.Yaw = (Urho.MathHelper.RadiansToDegrees(ov[1]) + 360) % 360;        // map [-Pi/2...+Pi/2] to [0...360]
        app.CameraNode.Rotation = new Urho.Quaternion(app.Pitch, app.Yaw, 0);
    }
}

字符串
但不幸的是,它并不像预期的那样工作,相机总是看向错误的方向。

更新:
最好的解决方案是使用带有方向传感器的旋转矩阵,并使OnSensorChanged方法尽可能短!

using System.Linq;
using System.Threading.Tasks;

// a global array
private float[] SensorData = null;

public void OnSensorChanged(SensorEvent? e) {
    SensorData = e.Values.ToArray();
}

// a task defined somewhere in the OnCreate async method
await Task.Run(async () => {
    var RM = new float[9];
    var outR = new float[9];
    var res = new float[3];
    var Azimuth = 0.0f;
    var Pitch = 0.0f;
    var Roll = 0.0f;

    while (true) {
        if (SensorData == null) return;

        SensorManager.GetRotationMatrixFromVector(RM, SensorData);
        var remap = SensorManager.RemapCoordinateSystem(RM, Android.Hardware.Axis.X, Android.Hardware.Axis.Z, outR);
        if (!remap) return;

        _ = SensorManager.GetOrientation(outR, res);
        Azimuth = (MathHelper.RadiansToDegrees(res[0]) + 360.0f) % 360.0f;  // azimuth
        Pitch = MathHelper.RadiansToDegrees(res[1]);                        // altitude
        Roll = MathHelper.RadiansToDegrees(-res[2]);

        try {
            // finally update our Camera Node's Rotation property 
            cn.Rotation = new Quaternion(Pitch, Azimuth, Roll);
        }
        catch {
            // On [Urho.Application.Stop] this exception occurs.
            // Break is also required to exit from while loop!
            break;
        }

        RunOnUiThread(() => {
            // update our TextViews
            tvAzm.Text = $"Azimuth: {Azimuth,7:F2}";
            tvPitch.Text = $"Pitch:   {Pitch,7:F2}";
            tvRoll.Text = $"Roll:    {Roll,7:F2}";
        });

        // let's wait to avoid to frequent RunOnUiThread calls
        await Task.Delay(50);
    }
});

pdkcd3nj

pdkcd3nj1#

OnSensorChanged应该是:

if (e.Sensor == mRotationSensor)
    {
        var rm = new float[9];
        SensorManager.GetRotationMatrixFromVector(rm, e.Values.ToArray());
        var ov = new float[3];
        SensorManager.GetOrientation(rm, ov);
        app.pitch = (Urho.MathHelper.RadiansToDegrees(ov[1]) + 360) % 360;      // map [-Pi...+Pi] to [0...360]
        app.yaw = (Urho.MathHelper.RadiansToDegrees(ov[0]) + 360) % 360;
        Log.Error("pitch=",app.pitch+"");
        Log.Error("yaw=", app.yaw + "");
        // map [-Pi/2...+Pi/2] to [0...360]
        app.cameraNode.Rotation = new Urho.Quaternion(app.pitch, app.yaw, 0);

    }

字符串
您需要在OnCreate方法中为SensorManager添加以下内容:

mSensorManager = (SensorManager)GetSystemService(Activity.SensorService);
 mRotationSensor = mSensorManager.GetDefaultSensor(SensorType.RotationVector);
 mSensorManager.RegisterListener(this, mRotationSensor, SensorDelay.Game);


并添加变量:

private SensorManager mSensorManager;
 private Sensor mRotationSensor;


最后不要忘记为你的Activity实现ISensorEventListener接口。
我在github上提供了一个演示

jvidinwx

jvidinwx2#

最后,我通过一些研究和@joe的帮助解决了这个问题。
下面是方法的最终版本:

// [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 cooridante 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);
            }
        }
    }
}

字符串

bihw5rsg

bihw5rsg3#

使用四元数的另一种可能的解决方案:

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) {
        }
    }
}

字符串

相关问题