如何从偏航,俯仰和滚动中获得RotationMatrix

时间:2017-01-15 01:15:19

标签: java android matrix opengl-es android-sensors

您好我在我的Android应用程序中找到了来自加速器和磁传感器的偏航,俯仰和滚动。我现在想根据角度来旋转我的场景中的一个点周围的相机目标(min3d)。结果是能够通过移动Android设备来查看3d场景。我已经尝试了好几天几乎在SO中阅读所有相关的答案,但我无法让它发挥作用。

我得到的运动绝对没有感觉。我确认我的偏航在0-360之间并且是正确的,音高在-90到90之间并且是正确的,最后滚动在-180和180之间并且是一致的。

基本上我正在通过目标和向上矢量进行矩阵旋转和乘法。

float[] rotation = new float[16];   
Matrix.setIdentityM(rotation, 0);
Matrix.rotateM(rotation, 0, (float) Math.toDegrees(roll), 0, 0, 1);         
Matrix.rotateM(rotation, 0, (float) Math.toDegrees(pitch)+90f, 1, 0, 0);        
Matrix.rotateM(rotation, 0, (float) Math.toDegrees(-azimut), 0, 1, 0);      

float[] target = new float[4];
float[] source = new float[]{0,0,150,0};    
Matrix.multiplyMV(target, 0,rotation, 0, source, 0);
float targetX = target[0] + 0;
float targetY = target[1] + 150;
float targetZ = -target[2] + 0;

target = new float[4];
source = new float[]{0,1,0,0};
Matrix.multiplyMV(target, 0,rotation, 0, source, 0);
float upX = target[0];
float upY = target[1];
float upZ = target[2];

scene.camera().target.x = targetX;              
scene.camera().target.y = targetY;
scene.camera().target.z = targetZ;      
scene.camera().upAxis.x = upX;
scene.camera().upAxis.y = upY;
scene.camera().upAxis.z = upZ;

最初我的目标是(0,0,150),我的向上是(0,1,0)。

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

在滚动矩阵之后,目标矢量必须一致,因为目标仅针对目标轴。

实际上,你的目标不是vec3(0,150,150),目标确实是vec3(0,0,150)。你旋转它,然后添加vec3(0,150,0)。所以考虑一下,如果你旋转z轴,vec3(0,0,150)总是vec3(0,0,150)。

更新

是的,rotateM()将您之前设置的矩阵和您现在设置的矩阵相乘,所以逻辑上没有问题。

 public static void rotateM(float[] rm, int rmOffset,
        float[] m, int mOffset,
        float a, float x, float y, float z) {
    synchronized(sTemp) {
        setRotateM(sTemp, 0, a, x, y, z);
        multiplyMM(rm, rmOffset, m, mOffset, sTemp, 0);
    }

public static void setRotateM(float[] rm, int rmOffset,
        float a, float x, float y, float z) {
    rm[rmOffset + 3] = 0;
    rm[rmOffset + 7] = 0;
    rm[rmOffset + 11]= 0;
    rm[rmOffset + 12]= 0;
    rm[rmOffset + 13]= 0;
    rm[rmOffset + 14]= 0;
    rm[rmOffset + 15]= 1;
    a *= (float) (Math.PI / 180.0f);
    float s = (float) Math.sin(a);
    float c = (float) Math.cos(a);
    if (1.0f == x && 0.0f == y && 0.0f == z) {
        rm[rmOffset + 5] = c;   rm[rmOffset + 10]= c;
        rm[rmOffset + 6] = s;   rm[rmOffset + 9] = -s;
        rm[rmOffset + 1] = 0;   rm[rmOffset + 2] = 0;
        rm[rmOffset + 4] = 0;   rm[rmOffset + 8] = 0;
        rm[rmOffset + 0] = 1;
    } else if (0.0f == x && 1.0f == y && 0.0f == z) {
        rm[rmOffset + 0] = c;   rm[rmOffset + 10]= c;
        rm[rmOffset + 8] = s;   rm[rmOffset + 2] = -s;
        rm[rmOffset + 1] = 0;   rm[rmOffset + 4] = 0;
        rm[rmOffset + 6] = 0;   rm[rmOffset + 9] = 0;
        rm[rmOffset + 5] = 1;
    } else if (0.0f == x && 0.0f == y && 1.0f == z) {
        rm[rmOffset + 0] = c;   rm[rmOffset + 5] = c;
        rm[rmOffset + 1] = s;   rm[rmOffset + 4] = -s;
        rm[rmOffset + 2] = 0;   rm[rmOffset + 6] = 0;
        rm[rmOffset + 8] = 0;   rm[rmOffset + 9] = 0;
        rm[rmOffset + 10]= 1;
    } else {
        float len = length(x, y, z);
        if (1.0f != len) {
            float recipLen = 1.0f / len;
            x *= recipLen;
            y *= recipLen;
            z *= recipLen;
        }
        float nc = 1.0f - c;
        float xy = x * y;
        float yz = y * z;
        float zx = z * x;
        float xs = x * s;
        float ys = y * s;
        float zs = z * s;
        rm[rmOffset +  0] = x*x*nc +  c;
        rm[rmOffset +  4] =  xy*nc - zs;
        rm[rmOffset +  8] =  zx*nc + ys;
        rm[rmOffset +  1] =  xy*nc + zs;
        rm[rmOffset +  5] = y*y*nc +  c;
        rm[rmOffset +  9] =  yz*nc - xs;
        rm[rmOffset +  2] =  zx*nc - ys;
        rm[rmOffset +  6] =  yz*nc + xs;
        rm[rmOffset + 10] = z*z*nc +  c;
    }
}

这个android函数rotateM()是这三个矩阵的组合版本

void Matrix_Rotation_X(Matrix   &out_M,const float angle)
{
    float COS = (float)cos(angle);
    float SIN = (float)sin(angle);
    out_M.s[_0x0_]=  1.f;       out_M.s[_0x1_]= 0.f;    out_M.s[_0x2_]= 0.f;    out_M.s[_0x3_]= 0.f;
    out_M.s[_1x0_]=  0.f;       out_M.s[_1x1_]= COS;    out_M.s[_1x2_]= SIN;    out_M.s[_1x3_]= 0.f;
    out_M.s[_2x0_]=  0.f;       out_M.s[_2x1_]=-SIN;    out_M.s[_2x2_]= COS;    out_M.s[_2x3_]= 0.f;
    out_M.s[_3x0_]=  0.f;       out_M.s[_3x1_]= 0.f;    out_M.s[_3x2_]= 0.f;    out_M.s[_3x3_]= 1.f;

}

void Matrix_Rotation_Y(Matrix   &out_M, const float angle)
{
    float COS = (float)cos(angle);
    float SIN = (float)sin(angle);
    out_M.s[_0x0_]=  COS;       out_M.s[_0x1_]= 0.f;    out_M.s[_0x2_]=-SIN;    out_M.s[_0x3_]= 0.f;
    out_M.s[_1x0_]=  0.f;       out_M.s[_1x1_]= 1.f;    out_M.s[_1x2_]= 0.f;    out_M.s[_1x3_]= 0.f;
    out_M.s[_2x0_]=  SIN;       out_M.s[_2x1_]= 0.f;    out_M.s[_2x2_]= COS;    out_M.s[_2x3_]= 0.f;
    out_M.s[_3x0_]=  0.f;       out_M.s[_3x1_]= 0.f;    out_M.s[_3x2_]= 0.f;    out_M.s[_3x3_]= 1.f;
}

void Matrix_Rotation_Z( Matrix  &out_M, const float angle)
{
    float COS = (float)cos(angle);
    float SIN = (float)sin(angle);
    out_M.s[_0x0_]=  COS;       out_M.s[_0x1_]= SIN;    out_M.s[_0x2_]= 0.f;    out_M.s[_0x3_]= 0.f;
    out_M.s[_1x0_]=  -SIN;      out_M.s[_1x1_]= COS;    out_M.s[_1x2_]= 0.f;    out_M.s[_1x3_]= 0.f;
    out_M.s[_2x0_]=  0.f;       out_M.s[_2x1_]= 0.f;    out_M.s[_2x2_]= 1.f;    out_M.s[_2x3_]= 0.f;
    out_M.s[_3x0_]=  0.f;       out_M.s[_3x1_]= 0.f;    out_M.s[_3x2_]= 0.f;    out_M.s[_3x3_]= 1.f;
}

https://github.com/sunglab/StarEngine/blob/master/math/Matrix.cpp

答案 1 :(得分:0)

设置target和upAxis值时出错。您要为目标指定角度值并使用相同的目标值更新upAxis。然而,目标是3d环境中的x,y,z点,upAxis告诉摄像机将此向上矢量作为参考(更改upAxis滚动摄像机)。这是我通过ExampleAccelerometer.java

激励的accels和mags实现的
public class ExampleAccelerometer extends RendererActivity implements SensorEventListener {

private SkyBox mSkyBox;
private final float[] mAccelerometerReading = new float[3];
private final float[] mMagnetometerReading = new float[3];

private final float[] mRotationMatrix = new float[16];
private final float[] mOrientation = new float[3];
private SensorManager mSensorManager;
private Sensor mAccel, mMag;
public Number3d upAxis;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    mAccel = mSensorManager.getDefaultSensor(
            Sensor.TYPE_ACCELEROMETER);
    mMag = mSensorManager.getDefaultSensor(
            Sensor.TYPE_MAGNETIC_FIELD);
    Matrix.setIdentityM(mRotationMatrix, 0);

}

public void initScene()
{
    scene.lights().add(new Light());

    mSkyBox = new SkyBox(5.0f, 2);
    mSkyBox.addTexture(SkyBox.Face.North,   R.drawable.wood_back,   "north");
    mSkyBox.addTexture(SkyBox.Face.East,    R.drawable.wood_right,  "east");
    mSkyBox.addTexture(SkyBox.Face.South,   R.drawable.wood_back,   "south");
    mSkyBox.addTexture(SkyBox.Face.West,    R.drawable.wood_left,   "west");
    mSkyBox.addTexture(SkyBox.Face.Up,      R.drawable.ceiling,     "up");
    mSkyBox.addTexture(SkyBox.Face.Down,    R.drawable.floor,       "down");
    mSkyBox.scale().y = 0.8f;
    mSkyBox.scale().z = 2.0f;
    scene.addChild(mSkyBox);

    //Initial upAxis vector
    upAxis = new Number3d(-1,0,0);
    scene.camera().upAxis = upAxis;

    mSensorManager.registerListener(this, mAccel, SensorManager.SENSOR_DELAY_UI);
    mSensorManager.registerListener(this, mMag,SensorManager.SENSOR_DELAY_UI);
}

@Override
protected void onDestroy() {
    super.onDestroy();

    // Don't receive any more updates from either sensor.
    mSensorManager.unregisterListener(this);
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
    // TODO Auto-generated method stub
}

@Override
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        System.arraycopy(event.values, 0, mAccelerometerReading,
                0, mAccelerometerReading.length);
    }
    else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
        System.arraycopy(event.values, 0, mMagnetometerReading,
                0, mMagnetometerReading.length);
    }

    SensorManager.getRotationMatrix(mRotationMatrix, null,
            mAccelerometerReading, mMagnetometerReading);

    SensorManager.getOrientation(mRotationMatrix, mOrientation);

    //Camera Position
    scene.camera().position.x = 0;
    scene.camera().position.y = 0;
    scene.camera().position.z = 0;

    //Camera target position (where camera looks at i.e. position of interest)
    scene.camera().target.x = 0;
        scene.camera().target.y = 0;
        scene.camera().target.z = 50;

        //To multiply target with rotation create a temp vector with 4 parameter
        float[] p = new float[4];
        p[0] = scene.camera().target.x;
        p[1] = scene.camera().target.y;
        p[2] = scene.camera().target.z;
        p[3] = 1;

        //Rotate target according to the rotation matrix derived via accel and mag sensor
        float[] target = new float[4];
        Matrix.multiplyMV(target, 0, mRotationMatrix, 0, p, 0);

//      set rotated camera target (this creates 2d rotation with roll and pitch)
        scene.camera().target.x = target[0];
        scene.camera().target.y = target[1];
        scene.camera().target.z = target[2];

//      change up axis for rolling with yaw parameter
        upAxis.x = (float)(Math.cos(mOrientation[0]));
        upAxis.y = (float) (Math.sin(mOrientation[0]));
        upAxis.z = 0;
        scene.camera().upAxis = upAxis;

    }
}