2017-01-15 37 views
6

Witam Udało mi się znaleźć odchylenie, skok i przechylenie z akceleratora i czujnika magnetycznego w mojej aplikacji na Androida. Teraz chcę obrócić cel kamery (min3d) wokół punktu w mojej scenie zgodnie z kątami. Rezultatem jest możliwość spojrzenia w scenę 3D poprzez przeniesienie urządzenia z Androidem. Próbowałem przez kilka dni prawie przeczytać wszystkie odpowiedzi w SO, ale po prostu nie mogę tego zrobić.Jak uzyskać RotationMatrix od odchylenia, skoku i przechylenia

Ruch, który otrzymuję, nie ma absolutnie żadnego sensu. Weryfikowałem, że moje odchylenie wynosi od 0 do 360 i jest poprawne, wysokość jest w zakresie od -90 do 90 i jest poprawna, a na końcu rolka ma wartość od -180 do 180 i jest stała.

Zasadniczo robię rotację macierzy i mnożenie przez mój cel i wektor w górę.

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; 

Początkowo mój cel wynosi (0,0,150), a mój wektor up to (0,1,0).

Dziękuję za pomoc.

+0

Znaleziono :) Zaktualizowano moją odpowiedź. – Sung

Odpowiedz

1

Po macierzy rolki, wektor docelowy musi być spójny, ponieważ cel tylko dąży do osi.

W rzeczywistości twój cel nie jest vec3 (0,150,150), cel jest rzeczywiście vec3 (0,0,150). Obracasz go, a następnie dodajesz vec3 (0,150,0). Pomyśl o tym, vec3 (0,0,150) jest zawsze vec3 (0,0,150), jeśli obrócisz oś Z.

Aktualizacja

Tak, rotateM() mnoży macierz przed ustawieniem i matrycę teraz ustawić, tak logicznie nie ma żadnego problemu.

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; 
    } 
} 

Ta funkcja rotateM android() jest połączona wersja tych trzech matryc poniżej

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

+0

Byłoby to prawdą, gdy ładowałem matrycę tożsamości po każdym obrocie, którego nie robiłem. –

+0

@ JawadLeWywadi Ok pomnóż macierz w func, rotateM(), której nie mogłem poznać. dwie rzeczy są dla mnie dziwne. 1. nigdy nie normalizujesz up i cel vectos. 2. Nie widzę, żebyś ustawił pozycję kamery. 3. po prostu zatrzymaj wektor bez mnożenia (może nie być to konieczne, ale nie wiem, co robisz w aparacie()) – Sung

+0

Pozycja się nie zmienia. I dlaczego miałbym normalizować te wektory? –

0

robisz źle podczas ustawiania wartości docelowych i upAxis. przypisujesz wartości kątów do celu i aktualizujesz do góry o tych samych wartościach docelowych. Jednak celem jest punkt x, y, z w środowisku 3d, a upAx mówi aparatowi, aby wziął ten wektor jako odniesienie (zmiana w góręAx wyrzuci kamerę). Oto moja implementacja za pomocą akceleratorów i magazynów zmotywowanych od ExampleAccelerometer.java

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; 

    } 
} 
+0

To nie działa, ponieważ gdy mamy rolkę i/lub skok, wektor kamery powinien się zmienić. –