感觉走进死胡同了,请教下大佬们关于 glsl 里的矩阵与向量相乘 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ccraohng
V2EX    问与答

感觉走进死胡同了,请教下大佬们关于 glsl 里的矩阵与向量相乘

  •  a href="Javascript:" Onclick="downVoteTopic(783916);" class="vote">
  •   ccraohng 2021-06-17 11:17:13 +08:00 1920 次点击
    这是一个创建于 1644 天前的主题,其中的信息可能已经有所发展或是发生改变。

    环境是 webgl 。

    感觉是哪里错了,但是又很奇怪不知道错在哪里,关键字搜了 why transpose 之类的也是下结论之类的。 向大家请教,请喝杯咖啡。

    glsl 手册 56 页

    vec3 v, u; mat3 m; u = v * m; is equivalent to u.x = dot(v, m[0]); // m[0] is the left column of m u.y = dot(v, m[1]); // dot(a,b) is the inner (dot) product of a and b u.z = dot(v, m[2]); And u = m * v; is equivalent to u.x = m[0].x * v.x + m[1].x * v.y + m[2].x * v.z; u.y = m[0].y * v.x + m[1].y * v.y + m[2].y * v.z; u.z = m[0].z * v.x + m[1].z * v.y + m[2].z * v.z; 

    向量使用的是列向量吧,比如这时候有一个平移变换 T(tx, ty, tz)

    按照我的理解应该是

    [ 1, 0, 0, tx, 0, 1, 0, ty 0, 0, 1, tz, 0, 0, 0, 1 ] 

    但是在 gl-matrix 变换里 是这样:

    [ 1, 0, 0, 0, 0, 1, 0, 0 0, 0, 1, 0, tz, ty, tz, 1 ] 

    这时候在一个 shader (这是实际正确的) 里

     attribute vec4 aVertexPosition; uniform mat4 uModelMatrix; void main(void) { gl_Position = uModelMatrix * aVertexPosition; } 

    在上面的 shader 里,如果按照 gl-matrix 的写法,变成了

    M = [ 1, 0, 0, 0, 0, 1, 0, 0 0, 0, 1, 0, tz, ty, tz, 1 ] V = [x, y, z, 1]; gl_Position = M * V; 

    相乘后 tx, ty, tz 不能变换上去吧?

    但是 gl-matrix 是对的(我看的这篇教程 也是这样),请问这是为什么?

    3dwelcome
        1
    3dwelcome  
       2021-06-17 11:29:12 +08:00
    gl-matrix 是定死的,但是 shader 里却是灵活的。可以 Row-Major,也可以 Column-Major 。

    区别就是 M*v 和 v*M 的写法不一样。

    至于为什么 Shader 里要同时提供两种矩阵格式,那是微软年代的历史遗留问题。当年 GPU 弱鸡,为了性能优化,少几个 DP4 都是赚到的,具体可看 http://www.mvps.org/directx/articles/nontranspose.htm
    ccraohng
        2
    ccraohng  
    OP
       2021-06-17 11:56:02 +08:00
    @3dwelcome

    是我的表述问题。
    上面手册里定点向量实际为

    [x,
    y,
    z,
    1]

    它的平移变换矩阵,按照 `uModelMatrix * aVertexPosition` 的写法应该(我的理解)为

    ```
    [
    1, 0, 0, tx,
    0, 1, 0, ty
    0, 0, 1, tz,
    0, 0, 0, 1
    ]
    ```

    但是 gl-matrix 是这样的

    ```
    [
    1, 0, 0, 0,
    0, 1, 0, 0
    0, 0, 1, 0,
    tz, ty, tz, 1
    ]
    ```


    gl-matrix 写法是 T(tx, ty, tz) 的转置矩阵,按照我的理解在 shader 里位置应该调换一下

    ```
    gl_Position = aVertexPosition * uModelMatrix
    ```

    为啥
    ccraohng
        3
    ccraohng  
    OP
       2021-06-17 12:07:11 +08:00
    @ccraohng 说错了,不是转置矩阵。gl-matrix 的写法使用行优先,位置调换一下?
    3dwelcome
        4
    3dwelcome  
       2021-06-17 12:13:12 +08:00
    "但是 gl-matrix 是这样的"

    不是啊,https://github.com/toji/gl-matrix/blob/master/src/mat4.js 一开始注释里,就写着是 column-major 格式,也就是应该用 Matrix * V 的写法。
    3dwelcome
        5
    3dwelcome  
       2021-06-17 12:17:09 +08:00
    不是啊,github.com/toji/gl-matrix/blob/master/src/mat4.js 一开始注释里,就写着是 column-major 格式,也就是应该用 V * Matrix 的写法。

    上面打错了,汗。

    Matrix * V 是 row-major 的写法。
    ccraohng
        6
    ccraohng  
    OP
       2021-06-17 12:20:04 +08:00
    @3dwelcome 你看下 https://github.com/toji/gl-matrix/blob/master/src/mat4.js#L829 fromTranslation 函数, 变换值是写在 12 13 14 索引上的
    ccraohng
        7
    ccraohng  
    OP
       2021-06-17 12:26:13 +08:00
    @3dwelcome 抱歉是我举得例子有问题
    3dwelcome
        8
    3dwelcome  
       2021-06-17 12:34:48 +08:00
    @ccraohng 你说的对,那就是注释写错了。

    我看 mat4.js 里的 translate 函数,也证明内部结构 row-major,并不符合标准的 OpenGL Matrix 格式,也许是为了和一些 3D 软件相互兼容。

    那么 gl_Position = M * V;这样写就没错了。(可明明 V * M 更快)
    ccraohng
        9
    ccraohng  
    OP
       2021-06-17 13:22:31 +08:00
    https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/uniformMatrix

    这个方法假定矩阵是列优先。

    [
    1, 0, 0, tx,
    0, 1, 0, ty
    0, 0, 1, tz,
    0, 0, 0, 1
    ]

    会变成

    [
    1, 0, 0, 0,
    0, 1, 0, 0
    0, 0, 1, 0,
    tz, ty, tz, 1
    ]
    与正确结果相反,所以 gl-matrix 使用的是

    [
    1, 0, 0, 0,
    0, 1, 0, 0
    0, 0, 1, 0,
    tz, ty, tz, 1
    ]
    3dwelcome
        10
    3dwelcome  
       2021-06-17 14:13:15 +08:00
    好吧,我又来打脸了。gl-matrix 注释没错,矩阵是列优先。

    我去查看了 https://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays 里面的详细说明。

    这个矩阵
    [
    1, 0, 0, tx,
    0, 1, 0, ty
    0, 0, 1, tz,
    0, 0, 0, 1
    ]

    在连续内存里,真实排列就是:
    [1,0,0,0][0,1,0,0][0,0,1,0][tx,ty,tz,1]

    所以 fromTranslation 函数, 变换值是填在 12 13 14 索引上,是完全没问题的。

    所以不是 gl-matrix 写法问题,而是内存布局本来就是这样写的。
    sillydaddy
        11
    sillydaddy  
       2021-06-17 14:40:15 +08:00   2
    @ccraohng
    @3dwelcome
    这个行主序、列主序,确实挺绕脚的,今天看两位在这讨论,于是又去查了一下,

    下面这个解释应该是靠谱的:
    https://blog.lazybee.me/d3dopengl_matrix/
    意思就是,行主序和列主序,在实际程序里面,真正的内存布局都是一样的,都是 m[12] m[13] m[14]表示平移值,但是,2 者对于行和列的解释不一样,行主序主张第 i 行第 j 列的值存储在 a[i][j],即 m[i*4+j]中,列主序则主张第 i 行第 j 列的值存储在 a[j][i],即 m[j*4+i]中。
    那么这两种不同的主张,为什么会有相同的内存布局呢?这是因为,行主序主张把向量看作是“行”,坐标变换写作 v=v*M,而列主序主张把向量看作是“列”,于是 v=M*v 。这样的要求,导致按行主序(v*M)运算时,要从 M 中按列取,而按列主序(M*v)运算时则要按行取。而行主序对“行”的定义,并不是列主序对“行”的定义,反而恰恰是列主序对“列”的定义(如前所述的 a[i][j]和 a[j][i]),所以,内存布局就一样了。所以关键在于是 v*M 还是 M*v 。

    下面这个说明里面也解释了作者的无奈。
    https://glmatrix.net
    sillydaddy
        12
    sillydaddy  
       2021-06-17 14:42:46 +08:00
    @ccraohng
    所以,不用再担心需要矩阵转置啦,内存布局都是一样的。只需注意,行主序时,向量的变换要写成 v*M,把向量看作行;列主序则是 M*v,把向量看作列。
    sillydaddy
        13
    sillydaddy  
       2021-06-17 15:07:45 +08:00
    @sillydaddy
    上面解释的有点嗦,用一句话概括下:
    m[0],m[4],m[8],m[12],对于行主序矩阵来说,是其第一列。而对于列主序来说,是其第一行。
    所以行矩阵的 v*M[第一列],与列矩阵的 M[第一行]*v,是一样的。
    ccraohng
        14
    ccraohng  
    OP
       2021-06-17 17:09:04 +08:00
    @sillydaddy

    什么行列优先。

    我是奇怪 gl-matrix 的写法为何“反着”的,
    在 shader 里是
    [
    1, 0, 0, tx,
    0, 1, 0, ty
    0, 0, 1, tz,
    0, 0, 0, 1
    ] *
    [x,
    y,
    z,
    1]

    MDN 上说了 uniformMatrix 是以列优先录入值,即坐标 0 - 3 会被转成 m[0] ( m[0] is the left column of m )

    [
    1, 0, 0, 0,
    0, 1, 0, 0
    0, 0, 1, 0,
    tz, ty, tz, 1
    ] 刚好被 转成

    [
    1, 0, 0, tx,
    0, 1, 0, ty
    0, 0, 1, tz,
    0, 0, 0, 1
    ]
    ccraohng
        15
    ccraohng  
    OP
       2021-06-17 17:51:51 +08:00
    @sillydaddy 没有 “转成”这个概念,我错了。是你发的链接中的 不同解释,老哥可以的话加我 v cmhkaWFuamk=
    sillydaddy
        16
    sillydaddy  
       2021-06-17 18:13:57 +08:00
    @ccraohng
    哈哈。就不用啦。你发这个帖子也帮我把行列主序的概念理解清楚了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4641 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 05:39 PVG 13:39 LAX 21:39 JFK 00:39
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86