Javascript 尝试使用WebGL(regl)的正交投影在屏幕空间坐标中绘制形状

Javascript 尝试使用WebGL(regl)的正交投影在屏幕空间坐标中绘制形状,javascript,matrix,webgl,regl,Javascript,Matrix,Webgl,Regl,使用regl,我试图实现一个非常简单的drawRect()函数,它最终能够在屏幕空间中传递x、y、width和height(原点0,0位于屏幕左上角) 以下是我目前掌握的情况: 目前,它绘制了一个空白屏幕(我猜是由于投影矩阵剪辑或将所有内容移出视口)。如果从顶点着色器中删除投影,或在“投影”属性中使用标识矩阵,则它将再次渲染蓝色正方形 因此,我的问题是: 我做错了什么?为什么我的正交投影不起作用 我将来如何调试它,以便“看到”结果坐标以及它们是如何错误的 我读过一些SO问题、OpenGL书籍和

使用regl,我试图实现一个非常简单的
drawRect()
函数,它最终能够在屏幕空间中传递x、y、width和height(原点0,0位于屏幕左上角)

以下是我目前掌握的情况:

目前,它绘制了一个空白屏幕(我猜是由于投影矩阵剪辑或将所有内容移出视口)。如果从顶点着色器中删除投影,或在“投影”属性中使用标识矩阵,则它将再次渲染蓝色正方形

因此,我的问题是:

  • 我做错了什么?为什么我的正交投影不起作用
  • 我将来如何调试它,以便“看到”结果坐标以及它们是如何错误的
  • 我读过一些SO问题、OpenGL书籍和博客,但我被困在这里,因为这似乎应该行得通

    相关资源:


    编辑:固定视口宽度在正交投影中使用两次。这修复了一个空白屏幕,但是原点现在是左下角而不是左上角。切换正交投影的参数会导致再次出现空白屏幕。

    投影矩阵描述了从场景的三维点到视口的二维点的映射。投影矩阵从视图空间变换到剪辑空间。通过与剪辑坐标的
    w
    分量相除,剪辑空间中的坐标转换为(-1,-1,-1)至(1,1,1)范围内的归一化设备坐标(NDC)

    在正交投影时,视图空间中的坐标线性映射到剪辑空间坐标,剪辑空间坐标等于标准化设备坐标,因为
    w
    分量为1(对于笛卡尔输入坐标)。

    “左”、“右”、“下”、“上”、“近”和“远”的值定义了一个框。长方体体积内的所有几何体都在视口中“可见”

    最后,标准化设备坐标将线性映射到视口

    如下所示设置正交投影时:

    var m = mat4.ortho([], 0, viewportWidth, 0, viewportHeight, 0.1, 100.0);
    
    viewport: {x: 0, y: 0, width: window.innerWidth, height: window.innerHeight}
    
    position: [[-1, -1], [1, 1], [-1, 1], [-1, -1], [1, -1], [1, 1] ]
    
    { offset: [0, 0], scale: [0.5, 0.5], color: [0.2, 0.2, 1, 1] }
    
    r = right, l = left, b = bottom, t = top, n = near, f = far 
    
    2/(r-l)         0               0               0
    0               2/(t-b)         0               0
    0               0               -2/(f-n)        0
    -(r+l)/(r-l)    -(t+b)/(t-b)    -(f+n)/(f-n)    1
    
    然后,左下角(0,0)和右上角(viewportWidth,viewportHeight)的矩形从(-1,-1)映射到NDC(1,1)

    设置如下视口时:

    var m = mat4.ortho([], 0, viewportWidth, 0, viewportHeight, 0.1, 100.0);
    
    viewport: {x: 0, y: 0, width: window.innerWidth, height: window.innerHeight}
    
    position: [[-1, -1], [1, 1], [-1, 1], [-1, -1], [1, -1], [1, 1] ]
    
    { offset: [0, 0], scale: [0.5, 0.5], color: [0.2, 0.2, 1, 1] }
    
    r = right, l = left, b = bottom, t = top, n = near, f = far 
    
    2/(r-l)         0               0               0
    0               2/(t-b)         0               0
    0               0               -2/(f-n)        0
    -(r+l)/(r-l)    -(t+b)/(t-b)    -(f+n)/(f-n)    1
    
    然后NDC映射到具有左下角(0,0)和右上角(viewportWidth,viewportHeight)的视口矩形

    这意味着,(0,0,window.innerWidth,window.innerHeight)中的视图坐标将映射到视口矩形(0,0,window.innerWidth,window.innerHeight)。因此,您是在“窗口”(像素)坐标中绘制的

    如果有这样定义的几何图形:

    var m = mat4.ortho([], 0, viewportWidth, 0, viewportHeight, 0.1, 100.0);
    
    viewport: {x: 0, y: 0, width: window.innerWidth, height: window.innerHeight}
    
    position: [[-1, -1], [1, 1], [-1, 1], [-1, -1], [1, -1], [1, 1] ]
    
    { offset: [0, 0], scale: [0.5, 0.5], color: [0.2, 0.2, 1, 1] }
    
    r = right, l = left, b = bottom, t = top, n = near, f = far 
    
    2/(r-l)         0               0               0
    0               2/(t-b)         0               0
    0               0               -2/(f-n)        0
    -(r+l)/(r-l)    -(t+b)/(t-b)    -(f+n)/(f-n)    1
    
    然后,该几何体的大小是视口上的1*1像素-一个从(-1,-1)到(1,1)的矩形,比例为(0.5,0.5)

    增加比例(例如,
    比例:[100100]
    )以解决您的问题


    此外,几何体必须位于近平面和远平面之间,才能位于视图体积内

    在您的情况下,几何体的z坐标为0,如顶点着色器中所指定:

    gl_Position = projection * vec4(position.xy * scale, 0, 1);
    
    但根据正交投影中的规定,近平面为0.1,远平面为100.0:

    var m = mat4.ortho([], 0, viewportWidth, 0, viewportHeight, 0.1, 100.0);
    
    这会导致几何体被近平面剪裁,因为z坐标小于近平面

    更改近平面,以解决此问题:

    var m = mat4.ortho([], 0, viewportWidth, 0, viewportHeight, -100.0, 100.0);
    

    正交投影矩阵如下所示:

    var m = mat4.ortho([], 0, viewportWidth, 0, viewportHeight, 0.1, 100.0);
    
    viewport: {x: 0, y: 0, width: window.innerWidth, height: window.innerHeight}
    
    position: [[-1, -1], [1, 1], [-1, 1], [-1, -1], [1, -1], [1, 1] ]
    
    { offset: [0, 0], scale: [0.5, 0.5], color: [0.2, 0.2, 1, 1] }
    
    r = right, l = left, b = bottom, t = top, n = near, f = far 
    
    2/(r-l)         0               0               0
    0               2/(t-b)         0               0
    0               0               -2/(f-n)        0
    -(r+l)/(r-l)    -(t+b)/(t-b)    -(f+n)/(f-n)    1
    
    根据评论:

    对于mat4.ortho,左上角原点应为
    mat4.ortho([],0,视口宽度,视口高度,0,-1,1)
    ,但投影后屏幕上不会再次显示任何内容

    如果
    top
    为0且
    bottom
    为正值,则y轴将变为负值,因为
    2/(top-bottom)

    要解决此问题,可以手动反转y轴:

    var m = mat4.ortho([], 0, viewportWidth, -viewportHeight, 0, -1, 1);
    
    在这种情况下,必须反转偏移,因为视图的右上角为(0,0),左下角为(viewportWidth,-viewportHeight)

    e、 g

    如果你愿意

    var m = mat4.ortho([], 0, viewportWidth, viewportHeight, 0, -1, 1);
    
    然后必须反转y比例

    e、 g


    设置正交投影时,将带有
    (0,视口宽度,0,视口高度)
    的矩形投影到视口。这意味着您正在以像素坐标绘制。但是矩形的大小只有0.5像素(
    offset:[0,0],scale:[0.5,0.5],color:[0.2,0.2,1,1]
    )-试试类似于
    scale:[100100]
    @rabbi76的东西,我也想到了这一点!:-)那么至少我在正确的轨道上?哈哈。我想我把代码沙盒搞砸了,因为它没有保存。我在某一点将第三次drawRect调用设置为[50,50]比例,但屏幕上仍然没有绘制任何图形。除此之外,视口的规格中存在打字错误<代码>视口宽度为两倍。几何体由近平面剪裁。使用
    var m=mat4.ortho([],0,视口宽度,0,视口高度,-100.0,100.0)这很有道理,谢谢!近平面剪裁与固定双
    视口宽度相结合,在屏幕上显示了一些内容!但是,
    mat4.ortho([],0,viewportWidth,0,viewportHeight,-1,1)
    似乎使原点位于左下角而不是左上角。查看for mat4.ortho,左上角原点应为
    mat4.ortho([],0,视口宽度,视口高度,0,-1,1)
    ,但在该投影下,屏幕上不会再次显示任何内容。@Jonathandumain是的,因为在这种情况下y轴是负数的(从
    0
    -viewportHeight
    )。您必须使用反转y刻度:例如,
    刻度:[100,-100],