UE4 & OpenGL坐标系
UE4
使用左手系(DX
),OpenGL
固定管线使用右手系,可以通过可编程的管线在OpenGL
渲染管线中使用和UE4
一样的左手系。
三维空间的坐标系
- 局部空间(
Local Space
,或者称为物体空间(Object Space
)) - 世界空间(
World Space
) - 观察空间(
View Space
,或者称为视觉空间(Eye Space
)) 或是视图坐标系 - 裁剪空间(
Clip Space
) 或是投影坐标系 - 屏幕空间(
Screen Space
)
左右手坐标系变换在裁剪空间和观察空间进行。
投影坐标系
正射投影矩阵
右手系-正射投影矩阵
template
GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_NO(T left, T right, T bottom, T top, T zNear, T zFar)
{
mat<4, 4, T, defaultp> Result(1);
Result[0][0] = static_cast(2) / (right - left);
Result[1][1] = static_cast(2) / (top - bottom);
Result[2][2] = - static_cast(2) / (zFar - zNear);
Result[3][0] = - (right + left) / (right - left);
Result[3][1] = - (top + bottom) / (top - bottom);
Result[3][2] = - (zFar + zNear) / (zFar - zNear);
return Result;
}
左手系-正射投影矩阵
template
GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_ZO(T left, T right, T bottom, T top, T zNear, T zFar)
{
mat<4, 4, T, defaultp> Result(1);
Result[0][0] = static_cast(2) / (right - left);
Result[1][1] = static_cast(2) / (top - bottom);
Result[2][2] = static_cast(1) / (zFar - zNear);
Result[3][0] = - (right + left) / (right - left);
Result[3][1] = - (top + bottom) / (top - bottom);
Result[3][2] = - zNear / (zFar - zNear);
return Result;
}
透视投影
右手系-透视投影
emplate
GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_NO(T fovy, T aspect, T zNear, T zFar)
{
assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0));
T const tanHalfFovy = tan(fovy / static_cast(2));
mat<4, 4, T, defaultp> Result(static_cast(0));
Result[0][0] = static_cast(1) / (aspect * tanHalfFovy);
Result[1][1] = static_cast(1) / (tanHalfFovy);
Result[2][2] = - (zFar + zNear) / (zFar - zNear);
Result[2][3] = - static_cast(1);
Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear);
return Result;
}
左手系-透视投影
template
GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_ZO(T fovy, T aspect, T zNear, T zFar)
{
assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0));
T const tanHalfFovy = tan(fovy / static_cast(2));
mat<4, 4, T, defaultp> Result(static_cast(0));
Result[0][0] = static_cast(1) / (aspect * tanHalfFovy);
Result[1][1] = static_cast(1) / (tanHalfFovy);
Result[2][2] = zFar / (zFar - zNear);
Result[2][3] = static_cast(1);
Result[3][2] = -(zFar * zNear) / (zFar - zNear);
return Result;
}
视图坐标系
//右手系
template
GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtRH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)
{
//forward:W
vec<3, T, Q> const f(normalize(center - eye));
//right:V
vec<3, T, Q> const s(normalize(cross(f, up)));
//up:U
vec<3, T, Q> const u(cross(s, f));
mat<4, 4, T, Q> Result(1);
Result[0][0] = s.x;
Result[1][0] = s.y;
Result[2][0] = s.z;
Result[0][1] = u.x;
Result[1][1] = u.y;
Result[2][1] = u.z;
Result[0][2] =-f.x;
Result[1][2] =-f.y;
Result[2][2] =-f.z;
Result[3][0] =-dot(s, eye);
Result[3][1] =-dot(u, eye);
Result[3][2] = dot(f, eye);
return Result;
}
//左手系
template
GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtLH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)
{
vec<3, T, Q> const f(normalize(center - eye));
vec<3, T, Q> const s(normalize(cross(up, f)));
vec<3, T, Q> const u(cross(f, s));
mat<4, 4, T, Q> Result(1);
Result[0][0] = s.x;
Result[1][0] = s.y;
Result[2][0] = s.z;
Result[0][1] = u.x;
Result[1][1] = u.y;
Result[2][1] = u.z;
Result[0][2] = f.x;
Result[1][2] = f.y;
Result[2][2] = f.z;
Result[3][0] = -dot(s, eye);
Result[3][1] = -dot(u, eye);
Result[3][2] = -dot(f, eye);
return Result;
}
参考文章
- 投影矩阵推导过程
- UE4 & OpenGL坐标系