我有一个矩形网格,我在一个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)
{
/* ... */
}
我遇到的问题是计算平移,缩放和旋转矩阵。
我知道我可以通过以下方式计算矩形点:
但我不明白如何计算所需的旋转矩阵。显然,因为它被表示为一条线(两点和一个宽度)而不是一个矩形(位置和大小),我计算平移矩阵和比例矩阵的方式需要不同。
例如,如果我像现在一样计算平移和比例矩阵(通过从提供的位置和宽度推导出尺寸和位置点);如何计算旋转矩阵?
EDIT1
我按照建议尝试过,但屏幕上没有任何内容:
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();
}
给出了这个结果:
两个矩形“节点”的左上角是我想要绘制的线的两个点。我可以看到它的长度应该是沿着方向的两倍。
答案 0 :(得分:1)
我假设您想要用矩形表示线,使得p1和p2位于矩形的两个相对边的中间。此外,我假设您的绘图命令使用左上角(0,0)的1 x 1平方的顶点。
然后,像素坐标中屏幕上的位置将是
p1 + d * x + n * w * (y - 0.5)
d =(p2-p1),n =标准化(-d.y,d.x),宽度为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)
修改强>
矩阵包含两个错误:
两者都已在大矩阵中修复。
至于你的问题,我现在可以想到的两件事是: