渲染时如何让SDL2 0,0定位在window的中心?
How to make SDL2 0,0 position the center of the window when rendering?
我们是 "porting/updating" 一个使用 SDL 渲染的旧项目,我们正在更改代码以使用矩阵变换等。
主要问题是SDL坐标系是左上角(0,0),我们希望它是window的中心。
我们正在使用它来渲染:
const auto modelMatrix = (Matrix3::translation(tr.position) * Matrix3::rotation(Magnum::Deg(tr.rotation))) * Matrix3::scaling(tr.scale);
const auto mvpMatrix = viewProjectionMatrix * modelMatrix;
SDL_SetRenderDrawColor(renderer, 0xFF, 0x0, 0x0, 0xFF);
Magnum::Vector2i winSize;
SDL_GetWindowSize(window, &winSize.x(), &winSize.y());
SDL_RenderDrawPointF(renderer, mvpMatrix.translation().x() + (winSize.x() /2), mvpMatrix.translation().y() + (winSize.y() /2));
这就是我们尝试过的并且似乎 "work",因为当我们在 mvpMatrix.translation() 中有正确的世界位置时,我们用 (winSize / 2) 偏移它让 SDL 渲染它到屏幕中央。
我们对这个解决方案不满意,我们不确定它是否适用于所有情况。还有另一种方法可以使它起作用吗?修改投影矩阵?
我们结束了这次转换:
(重要:我们在这里也反转了 Y 轴)!
Magnum::Vector2 convertHomogenousCoordsToSDL(SDL_Window* window, const Matrix3& MVP, Magnum::Vector2 vertex) {
// get vertex in homogenous coords
vertex = MVP.transformPoint(vertex);
// now convert from homogenous coords 0,0 center and y-axis up to SDL screen coords
Vector2i winSize;
SDL_GetWindowSize(window, &winSize.x(), &winSize.y());
auto winSizeHalf = Vector2(winSize) / 2.f;
auto matrixChangeCoords = Matrix3::translation(winSizeHalf) * Matrix3::scaling({ winSizeHalf.x(), -winSizeHalf.y() });
vertex = matrixChangeCoords.transformPoint(vertex);
return vertex;
}
现在我们可以将 space 中的任何点转换为 SDL window space,如下所示:
const auto modelMatrix = (Matrix3::translation(tr.position) * Matrix3::rotation(Magnum::Deg(tr.rotation))) * Matrix3::scaling(tr.scale);
const auto mvpMatrix = viewProjectionMatrix * modelMatrix;
SDL_SetRenderDrawColor(renderer, 0xFF, 0x0, 0x0, 0xFF);
const auto vertexPosition = helpers::convertHomogenousCoordsToSDL(window, mvpMatrix, { 0,0 });
SDL_RenderDrawPointF(renderer, vertexPosition.x(), vertexPosition.y());
我不会接受这个答案,看看这里是否可以改进!
(编辑)
封装它并在 ProjectionMatrix 中设置转换,就像@keltar 在评论中所说的那样
Magnum::Vector2i framebufferSize(SDL_Window* window) {
Vector2i winSize;
SDL_GetWindowSize(window, &winSize.x(), &winSize.y());
return winSize;
}
Magnum::Matrix3 projectionMatrixToSDLSpace(SDL_Window* window, const Vector2& cameraSize) {
const Vector2 winSizeHalf = Vector2(framebufferSize(window)) / 2.f;
return Matrix3::translation(winSizeHalf) * Matrix3::scaling({ winSizeHalf.x(), -winSizeHalf.y() }) * Magnum::Matrix3::projection(cameraSize);
}
我们是 "porting/updating" 一个使用 SDL 渲染的旧项目,我们正在更改代码以使用矩阵变换等。
主要问题是SDL坐标系是左上角(0,0),我们希望它是window的中心。
我们正在使用它来渲染:
const auto modelMatrix = (Matrix3::translation(tr.position) * Matrix3::rotation(Magnum::Deg(tr.rotation))) * Matrix3::scaling(tr.scale);
const auto mvpMatrix = viewProjectionMatrix * modelMatrix;
SDL_SetRenderDrawColor(renderer, 0xFF, 0x0, 0x0, 0xFF);
Magnum::Vector2i winSize;
SDL_GetWindowSize(window, &winSize.x(), &winSize.y());
SDL_RenderDrawPointF(renderer, mvpMatrix.translation().x() + (winSize.x() /2), mvpMatrix.translation().y() + (winSize.y() /2));
这就是我们尝试过的并且似乎 "work",因为当我们在 mvpMatrix.translation() 中有正确的世界位置时,我们用 (winSize / 2) 偏移它让 SDL 渲染它到屏幕中央。
我们对这个解决方案不满意,我们不确定它是否适用于所有情况。还有另一种方法可以使它起作用吗?修改投影矩阵?
我们结束了这次转换:
(重要:我们在这里也反转了 Y 轴)!
Magnum::Vector2 convertHomogenousCoordsToSDL(SDL_Window* window, const Matrix3& MVP, Magnum::Vector2 vertex) {
// get vertex in homogenous coords
vertex = MVP.transformPoint(vertex);
// now convert from homogenous coords 0,0 center and y-axis up to SDL screen coords
Vector2i winSize;
SDL_GetWindowSize(window, &winSize.x(), &winSize.y());
auto winSizeHalf = Vector2(winSize) / 2.f;
auto matrixChangeCoords = Matrix3::translation(winSizeHalf) * Matrix3::scaling({ winSizeHalf.x(), -winSizeHalf.y() });
vertex = matrixChangeCoords.transformPoint(vertex);
return vertex;
}
现在我们可以将 space 中的任何点转换为 SDL window space,如下所示:
const auto modelMatrix = (Matrix3::translation(tr.position) * Matrix3::rotation(Magnum::Deg(tr.rotation))) * Matrix3::scaling(tr.scale);
const auto mvpMatrix = viewProjectionMatrix * modelMatrix;
SDL_SetRenderDrawColor(renderer, 0xFF, 0x0, 0x0, 0xFF);
const auto vertexPosition = helpers::convertHomogenousCoordsToSDL(window, mvpMatrix, { 0,0 });
SDL_RenderDrawPointF(renderer, vertexPosition.x(), vertexPosition.y());
我不会接受这个答案,看看这里是否可以改进!
(编辑) 封装它并在 ProjectionMatrix 中设置转换,就像@keltar 在评论中所说的那样
Magnum::Vector2i framebufferSize(SDL_Window* window) {
Vector2i winSize;
SDL_GetWindowSize(window, &winSize.x(), &winSize.y());
return winSize;
}
Magnum::Matrix3 projectionMatrixToSDLSpace(SDL_Window* window, const Vector2& cameraSize) {
const Vector2 winSizeHalf = Vector2(framebufferSize(window)) / 2.f;
return Matrix3::translation(winSizeHalf) * Matrix3::scaling({ winSizeHalf.x(), -winSizeHalf.y() }) * Magnum::Matrix3::projection(cameraSize);
}