javascript - 为什么这个图像不是垂直镜像的?

标签 javascript webgl opengl-es-2.0 regl

我发现自己在 webGl 中使用的许多符号和域约定中有点迷失。查看this regl example (它显示狒狒测试图像)。这是我对它的理解:

  • 未指定原语;它可能会推断出 GL_TRIANGLE
  • 因此,它创建了一个三 Angular 形曲面,其顶点为 (-2, 0)(0, -2)(2, 2) 在世界空间中。在纸上画出来,看起来这是专门选择的,因为它包含区域 [0,1] x [0,1]
  • uv 从世界空间获取它的值,包括这个 [0,1] x [0,1] 区域(这是 texture2d)。如果我理解正确的话,惯例是 +u 指向图像的右边缘+v 指向顶部.
  • gl_Position设置为1 - 2*uv,让图片占据[-1,1] x [-1,1], z =0 在“剪辑空间”中,不管它是什么。
  • 更重要的是,这也意味着+{u,v}方向对应-{x,y}!<
  • 显示的图像,,实际上是水平镜像!! ( compare to this ) 但它不是垂直镜像。 在最终与屏幕像素坐标之间的转换过程中,肯定有其他因素抵消了 y 中的负因子。
  • 但是,Google 搜索没有提供任何证据表明 gl_Position 以任何方式相对于屏幕进行镜像。我看到有人讨论说它是左撇子,但这只是根据相对于世界坐标取反 z 的结果。 (e.g. this question here)

简而言之,在我看来,该图像也应该垂直镜像。

我错过了什么?


为了后代,代码转载如下:(MIT licensed)

const regl = require('regl')()
const baboon = require('baboon-image')

regl({
  frag: `
  precision mediump float;
  uniform sampler2D texture;
  varying vec2 uv;
  void main () {
    gl_FragColor = texture2D(texture, uv);
  }`,

  vert: `
  precision mediump float;
  attribute vec2 position;
  varying vec2 uv;
  void main () {
    uv = position;
    gl_Position = vec4(1.0 - 2.0 * position, 0, 1);
  }`,

  attributes: {
    position: [
      -2, 0,
      0, -2,
      2, 2]
  },

  uniforms: {
    texture: regl.texture(baboon)
  },

  count: 3
})()

最佳答案

WebGL 和您上面的示例中都没有“世界空间”这样的东西。 WebGL 只关心剪辑空间或(规范化设备坐标)。世界空间是应用程序/框架/库处理并提供着色器以最终提供 WebGL 剪辑空间(或规范化设备坐标)的东西

正如 LJ 所指出的,上面的代码不是 webgl,而是 regl,一些库。所以它要做的是那个库而不是 webgl。例如,它可能会翻转它加载的所有纹理,我们怎么知道?也就是说,很容易猜到它会做什么。

对你的问题的简短回答是整个图像被翻转是因为

gl_Position = vec4(1.0 - 2.0 * position, 0, 1);

改成

gl_Position = vec4(position, 0, 1);

你会看到它是颠倒的

它正在绘制一个巨大的三 Angular 形。输入值是

  position: [
      -2, 0,
      0, -2,
      2, 2]
  },

还有这一行

gl_Position = vec4(1.0 - 2.0 * position, 0, 1);

表示写入gl_Position的值是

1 - 2 * -2, 1 - 2 *  0
1 - 2 *  0, 1 - 2 * -2
1 - 2 *  2, 1 - 2 *  2

这是

 5,  1
 1,  5
-3, -3

如果我们绘制相对于我们得到的 Canvas /屏幕/帧缓冲区

triangle-diagram

蓝色区域是屏幕/ Canvas

至于翻转,重要的是要注意纹理没有“向上”的概念。更重要的是要记住纹理坐标 0,0 引用纹理中的第一个像素,1,1 引用纹理中的最后一个像素。

这是应用于该三 Angular 形的纹理坐标

enter image description here

其中纹理中的红点代表纹理坐标中的 0,0。

将 0,0 视为纹理的起点(而不是底部)的原因是,当您渲染到纹理(通过帧缓冲区)时,您不需要进行任何翻转。只有当你最终渲染到屏幕上时,翻转才会起作用,因为 WebGL 在绘制到屏幕时恰好将 -1,-1 放在左下角。

这有点难以解释,但如果您查看 this example您会看到在向/从纹理渲染离屏时不需要翻转。仅当渲染到 Canvas /屏幕时。

如果你想看到大三 Angular 形,把shader改成这个

gl_Position = vec4((1.0 - 2.0 * position) * 0.2, 0, 1);

验证纹理是否翻转here's the original

enter image description here

你可以看到它在 regl 示例中呈现翻转

enter image description here

关于学习WebGL和裁剪空间I'd recommend these tutorials

关于javascript - 为什么这个图像不是垂直镜像的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40331405/

相关文章:

javascript - 如何获取div内部html对象的值

javascript - preserveDrawingBuffer false - 值得付出努力吗?

javascript - Three.js 曲线路径动画

linux - OpenGL ES 2 控制台帧缓冲区光标

opengl-es-2.0 - 在 OpenGL ES 2.0 中使用 PBO 将像素直接复制到 GPU 内存中

Javascript 检查在 IE7 中不起作用

javascript - 刷新列表时 Hook useCallback 继续使用旧值

ios - 使用 OpenGL ES 平滑改变线宽

javascript - 使用 lodash 压缩不同大小的数组

javascript - WebGL 片段着色器构造函数错误 - 参数太多