Nil*_*Qor 1 c++ opengl scaling rotation glm-math
我正在尝试使用 glm 旋转纹理图像,但输出看起来被拉伸或未沿 z 轴正确旋转。对于这个问题,可能的解决方案是什么?
float imgAspectRatio = imageWidth / (float) imageHeight;
float viewAspectRatio = viewWidth / (float) viewHeight;
if (imgAspectRatio > viewAspectRatio) {
yScale = viewAspectRatio / imgAspectRatio;
} else {
xScale = imgAspectRatio / viewAspectRatio;
}
glm::mat4 model(1.0f);
model = glm::translate(model, glm::vec3(0, 0, 0));
model = glm::rotate(model, glm::radians(angle),
glm::vec3(0, 0, 1));
model = glm::scale(model, glm::vec3(xScale, yScale, 1.0f));
Run Code Online (Sandbox Code Playgroud)
有些人建议与 glm::ortho 相乘,但它给出的是正方形
glm::mat4 projection(1.0f);
projection = glm::ortho(
-imgAspectRatio,
imgAspectRatio,
-1.0f,
1.0f,
-1.0f,
1.0f
);
Run Code Online (Sandbox Code Playgroud)
如果您有一个方形窗口,您当前拥有的代码实际上可以工作。
通过将图像纵横比缩放和视图纵横比缩放合并为一个步骤,您当前的操作顺序基本上如下:
但是,您确实希望在最后按视图纵横比进行缩放。一个简单的练习可以帮助形象化原因:假设您有一个完美的方形窗口,在其中渲染一个 xy 坐标为 (-1, -1), (1, -1), (0, 1) 的三角形。现在假设您的窗口高度加倍,但您希望形状保持不变:显然,您只需将每个 y 坐标乘以 1/2 即可。现在假设您想要将三角形逆时针旋转 90 度,但仍保持形状不变。您是否先旋转,然后按视图纵横比缩放?或相反亦然?通过运行这两个选项,很明显您必须最后按视图纵横比进行缩放。
换句话说,您需要以下顺序:
这是通过如下代码实现的:
float xScaleImg = 1.0f;
float yScaleImg = xScaleImg / imgAspectRatio;
float xScaleView = 1.0f;
float yScaleView = viewAspectRatio;
glm::mat4 model(1.0f);
model = glm::scale(model, glm::vec3(xScaleView, yScaleView, 1.0f));
model = glm::translate(model, glm::vec3(0, 0, 0));
model = glm::rotate(model, glm::radians(angle), glm::vec3(0, 0, 1));
model = glm::scale(model, glm::vec3(xScaleImg, yScaleImg, 1.0f));
Run Code Online (Sandbox Code Playgroud)
前四行假设(如示例中的情况)视图和图像宽度都大于各自的高度。如果情况相反,您可能需要添加一些逻辑来改变这种情况。
更新:
根据您想要实现的翻译效果,您可能需要将glm::translate(...)命令向上移动一行。我在原始答案中给出的顺序使平移单位以像素为单位相等。例如,如果您传入glm::vec3(1.0f, 1.0f, 0.0f),并且窗口的宽度为 1280 像素,则图像将向左平移 640 像素,向上平移 640 像素。但是,您可能希望在两个轴上保持 OpenGL [-1, 1] 范围。也就是说,当您传递平移时glm::vec3(1.0f, 1.0f, 0.0f),您可能希望将图像向右平移窗口宽度的一半,向上平移窗口高度的一半。在这种情况下,您需要将翻译作为对图像执行的最后一个操作,这是通过编写glm::translate(...)第一行代码来完成的。这就是尼罗·科尔想要的。在这种情况下,代码的最后几行变成如下所示:
glm::mat4 model(1.0f);
model = glm::translate(model, glm::vec3(1.0f, 1.0f, 0));
model = glm::scale(model, glm::vec3(xScaleView, yScaleView, 1.0f));
model = glm::rotate(model, glm::radians(angle), glm::vec3(0, 0, 1));
model = glm::scale(model, glm::vec3(xScaleImg, yScaleImg, 1.0f));
Run Code Online (Sandbox Code Playgroud)
有关更多上下文,您可以查看此答案的评论部分中的讨论。