【问题标题】:OpenGL ES 2D Matrix setupOpenGL ES 2D 矩阵设置
【发布时间】:2014-12-26 20:39:32
【问题描述】:

我使用 OpenGL ES 2.0 仅渲染 2D 形状,因为它是 OpenGL ES 2.0,我必须创建自己的转换矩阵。

仅作为 2D 形状,我想将我的所有矩阵保持为 3x3,而我的向量只有 2 个坐标。

我还需要一个投影矩阵,因为我想将我的坐标映射到屏幕上,我不想从 [-1.0; 指定位置; 1.0]。

据我所知,人们仍然使用 4x4 矩阵来表示 2D 和 z 设置为 1 的向量,以及正交投影矩阵。

我的问题是:如何仅使用 3x3 矩阵进行所有转换和投影?我已经设置了投影矩阵,但翻译不起作用。

到目前为止,我已经完成了这样的翻译矩阵:

m[0][0] = 1;  m[0][1] = 0;  m[0][2] = tx;
m[1][0] = 0;  m[1][2] = 1;  m[1][2] = ty;
m[2][0] = 0;  m[2][3] = 0;  m[2][2] = 1;

据我所知,即使使用 NDC 坐标,这应该可以工作,当乘以向量时,它应该会导致

x+tx y+ty 1.0

但是当我尝试用 tx = 2f 平移这个从 -1 到 1 的三角形时,它会被压扁并且不会移动。

翻译前:

翻译后:

这里是我如何绘制三角形的参考:

    GLES20.glUniformMatrix3fv(shader.GetUniform("u_transform_mat"), 1, false, Transform.GetTransformationMatrix().ToFloatBuffer()); 

    GLES20.glEnableVertexAttribArray(shader.GetAttribute("a_vert_position"));
    GLES20.glEnableVertexAttribArray(shader.GetAttribute("a_vert_color"));

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, VBO[0]);

    GLES20.glVertexAttribPointer(shader.GetAttribute("a_vert_position"), 2, GLES20.GL_FLOAT, false, Vertex.SIZE, 0);
    GLES20.glVertexAttribPointer(shader.GetAttribute("a_vert_color"), 4, GLES20.GL_FLOAT, false, Vertex.SIZE, Vertex.POS_SIZE);

    GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, IBO[0]);    

    GLES20.glDrawElements(primitive, size, GLES20.GL_UNSIGNED_INT, 0);      

    GLES20.glDisableVertexAttribArray(shader.GetAttribute("a_vert_color"));
    GLES20.glDisableVertexAttribArray(shader.GetAttribute("a_vert_position"));

还有我的顶点着色器

uniform mat3 u_transform_mat;   

attribute vec3 a_vert_position;  
attribute vec4 a_vert_color;     

varying vec4 v_vert_color;       

void main()                 
{                           
   v_vert_color = a_vert_color;       

   gl_Position = vec4(u_transform_mat * a_vert_position, 1.0);
}                                 

【问题讨论】:

    标签: matrix vector opengl-es transformation projection


    【解决方案1】:

    您当然可以使用 3x3 矩阵在 2D 中应用仿射变换。您只需要注意自己的一致性即可。

    从您发布的代码片段来看,有两件事看起来有问题:

    矩阵需要是主要列

    OpenGL 期望矩阵按列主要顺序存储。从您构建矩阵的方式来看:

    m[0][0] = 1;  m[0][1] = 0;  m[0][2] = tx;
    m[1][0] = 0;  m[1][2] = 1;  m[1][2] = ty;
    m[2][0] = 0;  m[2][3] = 0;  m[2][2] = 1;
    

    这会将翻译组件放置在它们必须用于行主矩阵的位置。它还分配了两次m[1][2],并分配了m[2][3],这超出了3x3矩阵的范围。反过来,它从不分配 m[1][1] 和 m[2][1]。

    如果您想继续以这种方式编写矩阵(我同意这种方式更具可读性),您可以交换索引:

    m[0][0] = 1;  m[1][0] = 0;  m[2][0] = tx;
    m[0][1] = 0;  m[1][1] = 1;  m[2][1] = ty;
    m[0][2] = 0;  m[1][2] = 0;  m[2][2] = 1;
    

    第三个向量分量需要为 1.0

    您为顶点位置属性指定了两个组件,这是有道理的:

    GLES20.glVertexAttribPointer(shader.GetAttribute("a_vert_position"), 2,
                                 GLES20.GL_FLOAT, false, Vertex.SIZE, 0);
    

    但是在着色器中,你有这个:

    attribute vec3 a_vert_position;
    

    声明属性变量大于传递给着色器的组件数量是完全合法的。对于组件y 和z,未指定的组件填充为0.0,对于w,填充为1.0。因此,在您的着色器代码中,a_vert_position.z 将填充 0.0。如果然后将其与 3x3 变换矩阵相乘:

    u_transform_mat * a_vert_position
    

    这意味着翻译部分不会被应用。就像将 4x4 矩阵应用于 4 个分量向量以在 3D 空间中进行仿射变换时第 4 个分量需要为 1.0,当将 3x3 矩阵应用于 3 个分量向量以在 2D 空间中进行仿射变换时,第 3 个分量需要为 1.0。

    解决此问题的最简单方法是将属性声明为vec2,并在应用变换矩阵时添加 1.0 作为第三个组件:

    attribute vec2 a_vert_position;
    ...
       gl_Position = vec4(u_transform_mat * vec3(a_vert_position, 1.0), 1.0);
    

    【讨论】:

    • 谢谢,这解决了我最初的翻译问题。我还注意到我的旋转矩阵无法正常工作。这有点难以解释,但在旋转时,三角形会变形。这是我的旋转矩阵:puu.sh/dKzU7/b6bf14b332.png 我组合所有矩阵的顺序并不重要,因为它仅在使用旋转时发生,但我正在做平移缩放旋转
    • 上面的旋转矩阵少了一个符号 抱歉:puu.sh/dKArX/41e25f63ad.png (这是评论的编辑问题,它仍然变形)还有我可以对投影做些什么?没有投影,我必须在 [-1.0; 中指定点; 1.0]。到目前为止我看到的所有投影矩阵都是 4x4 矩阵
    • 抱歉,我的矩阵索引完全搞砸了。现在一切都解决了。剩下的就是投影问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-07
    相关资源
    最近更新 更多