[英]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
我已尝试按照建议进行操作,但屏幕上没有任何显示:
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)
编辑
该矩阵包含两个错误:
两者都已固定在大型矩阵中。
关于您的问题,我目前能想到的两件事是:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.