[英]Translation after rotation
我正在使用OpenGL ES 2.0 for Android。 我正在使用觸摸屏翻譯和旋轉模型。 我的翻譯僅在(x,y)平面上,我的旋轉僅在z軸附近。 想象一下,直接向下看桌面上的地圖並移動到地圖上的各種坐標,並能夠圍繞您正在看的點旋轉地圖。
問題是,在旋轉之后,我的后續翻譯將更長時間與屏幕上指針的運動匹配,軸是不同的。
我嘗試的一切都給了我兩種行為中的一種,一種相當於:
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, Xposition, Yposition, 0.0f);
Matrix.rotateM(mModelMatrix, 0, rotationAngle, 0.0f, 0.0f, 1.0f);
這允許我按預期進行平移(無論旋轉如何,屏幕上/下移動模型上下移動,左/右移動模型左右)。 問題是旋轉是圍繞物體的中心,我需要旋轉大約是我正在看的點,這與物體的中心不同。
我能得到的其他行為相當於:
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.rotateM(mModelMatrix, 0, rotationAngle, 0.0f, 0.0f, 1.0f);
Matrix.translateM(mModelMatrix, 0, Xposition, Yposition, 0.0f);
這給了我想要的旋轉,總是關於我正在看的點。 問題是在輪換后,翻譯是錯誤的。 屏幕上的左/右沿着旋轉的軸以不同的角度平移對象。
我需要一些方法來同時獲得這兩種行為。 它需要圍繞我正在看的點旋轉, 並沿着手指在屏幕上移動的方向平移。
這甚至可能嗎? 我是否基本上試圖將量子力學與牛頓物理學相協調,注定要失敗?
我不想列出我嘗試過的所有技巧,因為我想以全新的視角考慮所有可能性。
編輯:我仍然完全堅持這一點。
我有一個從世界坐標中的(0,0,0)開始的對象。 我的視圖是俯視對象的z軸,我想限制平移到x / y平面。 我還想僅圍繞z軸旋轉對象。 旋轉中心必須始終是屏幕的中心。
我正在用觸摸屏控制平移,所以無論旋轉方式如何,我都需要手指以相同的方式移動物體。
旋轉后,我的所有翻譯都會在旋轉的坐標系上開始,這意味着對象不會隨着指針在屏幕上移動。 我試圖按照休費舍推薦的那樣進行第二次翻譯,但我無法弄清楚如何計算第二次翻譯。 還有另外一種方法嗎?
我有同樣的問題。 但是我使用C#和OpenGL(SharpGL)並使用旋轉矩陣。
需要旋轉后的平移以將旋轉點保持在屏幕的中心。 作為CAD類型的應用程序。 問題是旋轉后鼠標翻譯並不總是與屏幕平行。
我在這里找到了解決辦法。
(Xposition, Yposition) = (Xposition, Yposition) + mRotation.transposed() * (XIncr, YIncr)
要么
NewTranslationPosition = oldTranslationPosition + rotationMatrix.Transposed * UserTranslationIncrement.
很多感謝reto.koradi(在OpenGL上)!
所以我大致用3D編碼:
double gXposition = 0;
double gYposition = 0;
double gZposition = 0;
double gXincr = 0;
double gYincr = 0;
double gZincr = 0;
float[] rotMatrix = new float[16]; //Rotational matrix
private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e)
{
OpenGL gl = openGLControl.OpenGL;
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
gl.LoadIdentity();
gl.MultMatrix(rotMatrix); //This is my rotation, using a rotation matrix
gl.Translate(gXposition, gYposition, gZposition); //translate second to keep rotation at center of screen
DrawCube(ref gl);
}
private void buttonTransLeft_Click(object sender, EventArgs e)
{
double tX = -0.1;
double tY = 0;
double tZ = 0;
TransposeRotMatrixFindPoint(ref tX, ref tY, ref tZ);
gXposition = gXposition + tX;
gYposition = gYposition + tY;
gZposition = gZposition + tZ;
}
private void buttonTransRight_Click(object sender, EventArgs e)
{
double tX = 0.1;
double tY = 0;
double tZ = 0;
TransposeRotMatrixFindPoint(ref tX, ref tY, ref tZ);
gXposition = gXposition + tX;
gYposition = gYposition + tY;
gZposition = gZposition + tZ;
}
public void TransposeRotMatrixFindPoint(ref double x, ref double y, ref double z)
{
//Multiply [x,y,z] by Transpose Rotation matrix to generate new [x,y,z]
double Xt = 0; //Tempoary variable
double Yt = 0; //Tempoary variable
Xt = (x * rotMatrix[0, 0]) + (y * rotMatrix[0, 1]) + (z * rotMatrix[0, 2]);
Yt = (x * rotMatrix[1, 0]) + (y * rotMatrix[1, 1]) + (z * rotMatrix[1, 2]);
z = (x * rotMatrix[2, 0]) + (y * rotMatrix[2, 1]) + (z * rotMatrix[2, 2]);
//or try this
//Xt = (x * rotMatrix[0, 0]) + (y * rotMatrix[1, 0]) + (z * rotMatrix[2, 0]);
//Yt = (x * rotMatrix[0, 1]) + (y * rotMatrix[1, 1]) + (z * rotMatrix[2, 1]);
//z = (x * rotMatrix[0, 2]) + (y * rotMatrix[1, 2]) + (z * rotMatrix[2, 2]);
x = Xt;
y = Yt;
}
這是一篇很老的帖子,但我發布的解決方案最適合后人。
解決方案是保留一個單獨的模型矩陣,在發生轉換時累積轉換,並在onDrawFrame()方法中將每個轉換乘以此矩陣。
//Initialize the model matrix for the current transformation
Matrix.setIdentityM(mModelMatrixCurrent, 0);
//Apply the current transformations
Matrix.translateM(mModelMatrixCurrent, 0, cameraX, cameraY, cameraZ);
Matrix.rotateM(mModelMatrixCurrent, 0, mAngle, 0.0f, 0.0f, 1.0f);
//Multiply the accumulated transformations by the current transformations
Matrix.multiplyMM(mTempMatrix, 0, mModelMatrixCurrent, 0, mModelMatrixAccumulated, 0);
System.arraycopy(mTempMatrix, 0, mModelMatrixAccumulated, 0, 16);
然后累積的矩陣用於定位對象。
以下是我對翻譯和旋轉的看法:您沒有移動對象,而是移動坐標系的原點。 以這種方式思考,你需要額外翻譯你的第一個行為。
手指運動是一個應該與屏幕的XY軸對齊的平移,所以你應該在旋轉之前完成。 然后進行旋轉,圍繞該點旋轉對象的坐標系。 如果您希望將對象繪制在相對於該點的其他位置,則需要先進行另一次轉換以將原點移動到那里。
所以我認為你的最終序列應該是這樣的
translate(dx,dy); 旋轉(A); 翻譯(cx,cy); 畫()
其中cx和cy是地圖中心和被觀察點之間的距離。 (可以簡化為-dx,-dy)
希望這可以幫助。
你應該使用你的第一種方法,雖然數學上第二種方法更有意義。 OpenGL和Android存儲矩陣之間存在差異。 畢竟它們是數組,但前4個值是行還是列?
這就是它“倒退”的原因。 請查看此信息以獲取更多信息,或閱讀有關行主要與列主要矩陣操作的信息。
我注意到第一種方法“向后”按預期工作。
數學:
假設您想圍繞一個點(x1,y1,z1)旋轉。 你的對象的起源是(Ox,Oy,Oz)。
設定原產地:
Matrix.setIdentityM(mModelMatrix, 0);
然后將要旋轉的點移動到原點:
Matrix.translateM(mModelMatrix, 0, -x1, -y1, -z1);
然后是Matrix.rotateM(mModelMatrix,0,rotationAngle,0.0f,0.0f,1.0f);
然后將其移回:
Matrix.translateM(mModelMatrix, 0, x1, y1, z1);
然后將其移動到您想要的位置:
Matrix.translateM(mModelMatrix, 0, x, y, z);
但是,在反思中,你會以相反的順序進行。
嘗試:設置原點:
Matrix.setIdentityM(mModelMatrix, 0);
然后以相反的順序執行操作:
Matrix.translateM(mModelMatrix, 0, x, y, z);
Matrix.translateM(mModelMatrix, 0, x1, y1, z1);
Matrix.rotateM(mModelMatrix, 0, rotationAngle, 0.0f, 0.0f, 1.0f);
Matrix.translateM(mModelMatrix, 0, -x1, -y1, -z1);
我希望這有幫助。
編輯
我可能錯過了解這個問題:這對我有用的是:
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, x1, y1, z1);
Matrix.rotateM(mModelMatrix, 0, rotationAngle, 0.0f, 0.0f, 1.0f);
Matrix.Multiply(mViewProjection, 0, mProjection, 0, mCameraView, 0); //something like this, but do you have the right order?
在我的Shader中,我有mViewProjection * mModelMatrix * a_Position;
您是否使用頂點着色器進行最終乘法?
嘗試進行靜態平移/旋轉(使用常量值),而不是使用觸摸屏控制平移。 如果它工作正常,可能你在其他地方有一個bug
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.