在我的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);
}
});
型
3条答案
按热度按时间pdkcd3nj1#
OnSensorChanged
应该是:字符串
您需要在
OnCreate
方法中为SensorManager
添加以下内容:型
并添加变量:
型
最后不要忘记为你的Activity实现
ISensorEventListener
接口。我在github上提供了一个演示
jvidinwx2#
最后,我通过一些研究和@joe的帮助解决了这个问题。
下面是方法的最终版本:
字符串
bihw5rsg3#
使用四元数的另一种可能的解决方案:
字符串