c++ - 具有缩放拉伸(stretch)纵横比的 glm 旋转

标签 c++ opengl rotation scaling glm-math

我正在尝试使用 glm 旋转纹理图像,但输出看起来拉伸(stretch)或没有沿 z 轴正确旋转。这个可能的解决方案是什么。
enter image description here

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));
enter image description here
一些建议与 glm::ortho 相乘,但它给出方形
glm::mat4 projection(1.0f);    
projection = glm::ortho(
              -imgAspectRatio,             
              imgAspectRatio,              
              -1.0f,      
              1.0f,       
              -1.0f,              
              1.0f                
      );

最佳答案

如果您有一个方形窗口,您当前拥有的代码实际上可以工作。
通过将图像纵横比缩放和 View 纵横比缩放结合到一个步骤中,您当前的操作顺序基本上如下:

  • 按图像纵横比缩放图像平面。
  • 按 View 纵横比缩放场景中的所有 xy 坐标。
  • 旋转图像平面。
  • 平移图像平面。

  • 但是,您真的想在最后按 View 纵横比进行缩放。一个简单的练习来帮助可视化原因:想象你有一个完美的方形窗口,在其中渲染一个 xy 坐标为 (-1, -1), (1, -1), (0, 1) 的三角形。现在假设您的窗口高度增加了一倍,但您希望形状保持不变:显然,您只需将每个 y 坐标乘以 1/2。现在假设您要将三角形逆时针旋转 90 度,但仍保持形状相同。您是否先旋转然后按 View 纵横比缩放?或相反亦然?通过运行这两个选项,很明显您必须最后按 View 纵横比进行缩放。
    换句话说,您需要以下顺序:
  • 按图像纵横比缩放图像平面。
  • 旋转图像平面。
  • 平移图像平面。
  • 按 View 纵横比缩放场景中的所有 xy 坐标。

  • 这是通过看起来像这样的代码实现的:
        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));
    
    与您的示例一样,前四行假设 View 和图像宽度都大于各自的高度。如果反过来为真,您可能需要添加一些逻辑来改变这一点。
    更新:
    根据您想要实现的翻译效果,您可能需要移动 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(...) 设置为第一行代码。这就是 Nile Qor 想要的。在这种情况下,代码的最后几行变为:
        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));
    
    有关更多上下文,您可以在此答案的评论部分查看讨论。

    关于c++ - 具有缩放拉伸(stretch)纵横比的 glm 旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63261779/

    相关文章:

    C++更改dll中的类,其中指向该类的指针返回给其他dll

    c++ - Qt 在 Linux 中无法正确读取字符串

    c++ - 使用土壤从带有opengl的纹理图集中获取区域

    c++ - 正交投影矩阵 - 错误位置的三角形

    c++ - 在列表初始化中缩小转换为 bool - 奇怪的行为

    c++ - std::packaged_task 编译错误 w/gcc 4.6

    c - opengl交错vbo不渲染到屏幕

    math - 四元数 (0,0,0,0) 表示什么

    xamarin.ios - 尝试使用 Transform 在 MonoTouch 中旋转 UIView

    ios - 使用 CGAffineTransformTranslate 旋转后将图像移动到其原始维度空间