【问题标题】:OpenGL move object and keep transformationOpenGL移动对象并保持变换
【发布时间】:2018-03-20 09:36:22
【问题描述】:

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

我知道 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();

【问题讨论】:

  • 请参阅Understanding 4x4 homogenous transform matrices,这样您就可以将相机矩阵和模型矩阵分开......并且仅在渲染之前组合......看看那里最后一个链接中的示例。顺便说一句,您的图像没有多大意义,因为所需结果和当前结果之间的差异并不明显。你想沿着相机局部轴或物体局部轴或世界全局轴移动?
  • 你能给我们一些代码吗,你是如何应用你不同的转换的。
  • @DraykoonD 我添加了一些代码
  • 您知道透视投影在物体移动时会改变物体的轮廓,对吗?如果您不想进行这些更改,请使用正交投影
  • 您可以在投影矩阵上预乘一个平移矩阵,从而产生应用透视后移动对象的效果。从概念上讲,这将导致不对称的平截头体(这与投影仪的镜头移位实现的原理相同)。但是,如果您的场景中有多个对象,并且您希望对每个对象应用不同的此类变换,则必须小心(如果您只在 x 和 y 中平移,它应该仍然可以很好地工作,但如果您还搞砸了深度测试修改 z)。

标签: opengl matrix 3d camera projection


【解决方案1】:

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

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 )


注意,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 )


答案的扩展:

透视投影矩阵如下所示:

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

【讨论】:

  • 感谢您非常详细的回答,但这并没有给我想要的结果。它给了我一个不同的结果(显然),但不是想要的结果。问题不在于操作的顺序,我认为问题在于投影矩阵。 - 我需要以某种方式平移截锥体,因此消失点不在 [0, 0] 处,而是在平移四边形的中心位置。
  • 基本上你的扩展答案是有效的,你是一个数学魔术师。唯一的问题是:我如何使用像素单位(或我通常在 3D 空间中移动对象的单位)移动它? - 如果我用 0.5 移动它,它的移动真的很多。
  • 哦,是的,它正在工作!你真是一头野兽!不幸的是,我的“gluProject”方法无法识别这一点并返回值,就好像投影矩阵不会移动一样。是否有一个快速简单的解决方法,或者是将 xy 移位值添加到返回的顶点的唯一解决方法? - “gluProject”方法是我自己写的:i.imgur.com/YafMMgO.png
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-15
  • 2018-12-17
  • 2018-07-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多