繁体   English   中英

使用比例+旋转矩阵在OpenGL中的两个点之间绘制一个矩形

[英]Drawing a rectangle between two points in OpenGL using scale + rotation matrix

我有一个矩形网格物体,与其他类用来绘制自身的flyweight类型对象共享。 绘图代码如下所示:

void Draw(const glm::ivec2 position, const glm::ivec2 size)
{
    /* do some binding ...*/

    glm::vec2 s(m_screenDimensions.x,m_screenDimensions.y);
    glm::vec2 p(position.x,position.y);
    glm::vec2 d(size.x,size.y);
    glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0f),glm::vec3(-1.0f+p.x/s.x*2.0f+(d.x/s.x),1.0f-p.y/s.y*2.0f-(d.y/s.y),0.0f));
    glm::mat4 scaleMatrix = glm::scale(glm::mat4(1.0f),glm::vec3(d.x/s.x,d.y/s.y,1.0f));
    m_program.SetUniform(m_modelMatrixLocation,translationMatrix * scaleMatrix * glm::mat4(1.0f));

    /* dispatch draw calls ... */
}

这很容易在所需的位置和大小处绘制一个矩形。 但是,我现在想使用相同的矩形flyweight绘制线。 所以基本上:

void Draw(const glm::ivec2 position1, const glm::ivec2 position2, const unsigned int width)
{
    /* ... */
}

我遇到的问题是计算平移,缩放和旋转矩阵。

我了解可以通过以下方式计算矩形点:

  1. 在两个位置之间获取向量
  2. 获取垂直向量
  3. 将四个中的每个放置在沿此垂直向量移动的位置周围

但是我不明白如何计算所需的旋转矩阵。 显然,因为它是用一条线(两个点和一条宽度)而不是矩形(位置和大小)表示的,所以我计算翻译矩阵和比例矩阵的方式必须与此不同。

例如,如果我像现在那样计算平移和比例矩阵(通过从提供的位置和宽度中推导出大小和位置点); 如何计算旋转矩阵?

编辑1

我已尝试按照建议进行操作,但屏幕上没有任何显示:

void RectColoured::Draw(const glm::ivec2 position1, const glm::ivec2 position2, const int width) const
{
    m_program.Bind();
    m_program.SetUniform(m_colorUniformLocation,m_color);
    m_program.SetUniform(m_useTextureUniformLocation,false);

 /*   glm::vec2 s(m_screenDimensions.x,m_screenDimensions.y);
    glm::vec2 p(position1.x,position1.y);
    glm::vec2 d(position2.x-position1.x+10,position2.y-position1.y+10);
    glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0f),glm::vec3(-1.0f+p.x/s.x*2.0f+(d.x/s.x),1.0f-p.y/s.y*2.0f-(d.y/s.y),0.0f));
    glm::mat4 scaleMatrix = glm::scale(glm::mat4(1.0f),glm::vec3(d.x/s.x,d.y/s.y,1.0f));
    m_program.SetUniform(m_modelMatrixLocation,translationMatrix * scaleMatrix * glm::mat4(1.0f));
*/
    glm::vec2 s(m_screenDimensions.x,m_screenDimensions.y);
    glm::vec2 d = position2-position1;
    glm::vec2 n = glm::normalize(d);
    auto p1 = position1;
    float w = width;
    float m[] = {
            2*d.x/s.x,  2*n.x/s.x*w,    0,  2*(p1.x-0.5*n.x)/s.x-1.0,
            2*d.y/s.y,  2*n.y/s.y*w,    0,  2*(p1.y-0.5*n.y)/s.y-1.0,
            0,          0,              0,  0,
            0,          0,              0,  1
    };
    glm::mat4 matrix = glm::make_mat4(m);
    m_program.SetUniform(m_modelMatrixLocation,matrix);

    m_quad.BindAndDraw();
}

编辑2不太在那里:

void RectColoured::Draw(const glm::ivec2 position1, const glm::ivec2 position2, const int width) const
{
    m_program.Bind();
    m_program.SetUniform(m_colorUniformLocation,m_color);
    m_program.SetUniform(m_useTextureUniformLocation,false);

    glm::vec2 s = m_screenDimensions;
    glm::vec2 d = position2-position1;
    glm::vec2 n = glm::normalize(glm::vec2(d.y,-d.x));
    auto p1 = position1;
    float w = width;
    float m[] = {
        2.0f*d.x/s.x,                       -2.0f*d.y/s.y,                      0.0f, 0.0f,
        2.0f*n.x/s.x*w,                     -2.0f*n.y/s.y*w,                    0.0f, 0.0f,
        0.0f,                               0.0f,                               0.0f, 0.0f,
        2.0f*(p1.x-0.5f*n.x*w)/s.x-1.0f,    -2.0f*(p1.y-0.5f*n.y*w)/s.y+1.0f,   0.0f, 1.0f
    };
    glm::mat4 matrix = glm::make_mat4(m);
    m_program.SetUniform(m_modelMatrixLocation,matrix);

    m_quad.BindAndDraw();
}

给出以下结果:

在此处输入图片说明

两个矩形“节点”的左上角是我要绘制的直线的两个点。 我可以看到它的长度大约是方向的两倍。

我假设您要用矩形表示线,以使p1和p2位于矩形的两个相对边缘的中间。 此外,我假设您的绘制命令使用的左上角为(0,0)的1 x 1正方形的顶点。

那么屏幕在像素坐标中的位置将是

p1 + d * x + n * w * (y - 0.5)

其中d =(p2-p1),n = normalize(-dy,dx)且w为宽度。 然后通过将opengl -1转换为1范围,我们得到

vec2(-1.0, -1.0) + 2/s * (p1 + d * x + n  * w * (y - 0.5))

用于屏幕尺寸。 这导致以下转换矩阵

2 * d.x / s.x | 2 * n.x / s.x * w | 0.0 | 2 * (p1.x - 0.5 * n.x * w) / s.x - 1.0
-----------------------------------------------------------------
-2 * d.y / s.y | -2 * n.y / s.y * w | 0.0 | -2 * (p1.y - 0.5 * n.y * w) / s.y + 1.0
-----------------------------------------------------------------
0.0       | 0.0                   | 0.0 | 0.0
-----------------------------------------------------------------
0.0       | 0.0                   | 0.0 | 1.0

(或转置取决于您要向左乘还是向右乘)。 该矩阵在示例中已经可以用于统一。

要将其拆分为平移/旋转/缩放矩阵,实际上您需要2个缩放矩阵,因为非均匀缩放通常不会随旋转而变化。 我们可以分为以下4个步骤:

scale by (length(p2 - p1), width)
rotation by rotation matrix with columns (normalize(d), n)
scale by (2/s.x, 2/s.y)
translate by (see last column in the big matrix)

编辑

该矩阵包含两个错误:

  • 我错过了在翻译部分乘以w
  • 第二行需要乘以-1,以确保(0,0)是左上角,而不是左下角。

两者都已固定在大型矩阵中。

关于您的问题,我目前能想到的两件事是:

  • OpenGL矩阵默认情况下是列优先的,而数组中的矩阵是行主要的。 您可能需要转置矩阵(即在行和列之间切换)。
  • 使用背面剔除时,变换可能会从正方形开始按顺时针方向形成三角形。 要解决此问题,请尝试将法线从normalize(-dy,dx)更改为normalize(dy,-dx),即对其进行镜像(或更改矩阵中所有n出现的符号等)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM