OpenGL移动对象并保持转换

时间:2017-10-09 08:33:37

标签: opengl matrix 3d camera projection

我有一个物体,它是变形的(在Y轴上以45度旋转)。 目标是在x和y轴上移动(平移)对象并保持转换效果。 很难解释,所以我拍了一张照片:
desired result

我知道opengl中相机的概念,我知道我不能真正移动相机,但实际上一切都在相机周围移动。有人真的知道如何实现这个目标吗?

我的代码:

//set mvp
matrixProj = new PerspectiveProjectionMatrix(fovy, aspect, near, far);
matrixView = new ModelMatrix();
matrixView.LookAtTarget(new Vertex3f(0, 0, 2), new Vertex3f(0, 0, 0), new Vertex3f(0, 1, 0));
matrixModel = new ModelMatrix();
matrixModel.SetIdentity();
matrixModel.RotateY(45);
matrixModel.Translate(-2, -2, 0);
Matrix4x4 mvp = matrixProj * matrixView * matrixModel;
Gl.UniformMatrix4(Gl.GetUniformLocation(shaderProgram, "MVP"), 1, false, mvp.ToArray());

//draw quad
Gl.Begin(PrimitiveType.Quads);
Gl.Vertex3(-2, 2, 0);
Gl.Vertex3(2, 2, 0);
Gl.Vertex3(2, -2, 0);
Gl.Vertex3(-2, -2, 0);
Gl.End();

1 个答案:

答案 0 :(得分:3)

您必须更改说明的顺序。通过将对象的平移矩阵乘以旋转矩阵,执行围绕对象的轴的旋转。 这意味着您必须先进行平移,然后进行旋转。

matrixModel = new ModelMatrix();
matrixModel.SetIdentity();
matrixModel.Translate(-2, -2, 0);
matrixModel.RotateY(45);

注意,翻译矩阵如下所示:

Matrix4x4 translate;

translate[0] : ( 1,  0,  0,  0 )
translate[1] : ( 0,  1,  0,  0 )
translate[2] : ( 0,  0,  1,  0 )
translate[3] : ( tx, ty, tz, 1 )

围绕Y轴的旋转矩阵如下所示:

Matrix4x4  rotate;
float      angle;

rotate[0] : ( cos(angle),  0, sin(angle), 0 )
rotate[1] : ( 0,           1, 0,          0 )
rotate[2] : ( -sin(angle), 0, cos(angle), 0 )
rotate[3] : ( 0,           0, 0,          1 ) 

矩阵乘法的工作原理如下:

Matrix4x4 A, B, C;

// C = A * B
for ( int k = 0; k < 4; ++ k )
    for ( int l = 0; l < 4; ++ l )
        C[k][l] = A[0][l] * B[k][0] + A[1][l] * B[k][1] + A[2][l] * B[k][2] +  A[3][l] * B[k][3];


translate * rotate的结果是:

model[0] : ( cos(angle),  0,  sin(angle), 0 )
model[1] : ( 0,           1,  0,          0 )
model[2] : ( -sin(angle), 0,  cos(angle), 0 )
model[3] : ( tx,          ty, tz,         1 )

translate * rotate


请注意,rotate * translate的结果为:

model[0] : ( cos(angle),                     0,   sin(angle),                     0 )
model[1] : ( 0,                              1,   0,                              0 )
model[2] : ( -sin(angle),                    0,   cos(angle),                     0 )
model[3] : ( cos(angle)*tx - sin(angle)*tx,  ty,  sin(angle)*tz + cos(angle)*tz,  1 )

rotate * translate


答案的延伸:

透视投影矩阵如下所示:

r = right, l = left, b = bottom, t = top, n = near, f = far

2*n/(r-l)      0              0                0
0              2*n/(t-b)      0                0
(r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1    
0              0              -2*f*n/(f-n)     0

其中:

r  = w / h
ta = tan( fov_y / 2 );

2*n / (r-l) = 1 / (ta*a)    --->  1/(r-l) = 1/(ta*a) * 1/(2*n)
2*n / (t-b) = 1 / ta        --->  1/(t-b) = 1/ta * 1/(2*n)

如果您想通过偏移(xy)取代视野,那么您必须这样做:

x_disp = 1/(ta*a) * x/(2*n)
y_disp = 1/ta * y/(2*n)

1/(ta*a)  0       0               0
0         1/t     0               0
x_disp    y_disp  -(f+n)/(f-n)   -1    
0         0       - 2*f*n/(f-n)   0

设置透视投影矩阵,如下所示:

float x = ...;
float y = ...;

matrixProj = new PerspectiveProjectionMatrix(fovy, aspect, near, far);
matrixProj[2][0] = x * matrixProj[0][0] / (2.0 * near); 
matrixProj[2][1] = y * matrixProj[1][1] / (2.0 * near); 

glFrustum,像素偏移量可以像这样应用:

float x_pixel = .....;
float y_pixel = .....;

float x_dipl = (right - left) * x_pixel / width_pixel;
float y_dipl = (top - bottom) * y_pixel / height_pixel;
glFrustum( left + x_dipl, right + x_dipl, top + y_dipl, bottom + y_dipl, near, far);