【问题标题】:Why is this image not mirrored vertically?为什么这个图像没有垂直镜像?
【发布时间】:2016-10-30 16:55:55
【问题描述】:

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

  • 未指定原语;它可能会推断出GL_TRIANGLE
  • 因此,它会在世界空间中创建一个具有顶点(-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
})()

【问题讨论】:

  • "clip space," whatever that is,研究有那么难吗?您的大多数其他问题都是特定于框架的,与 WebGL API 无关。您得出结论 {u,v} = -{x,y} 是错误的。 U 和 X 都是从左到右,Y 是从下到上,而 V 是从上到下。
  • @LJᛃ 我看到用词定义的词来定义词......在搜索了很多关于剪辑空间的页面之后,我能推测的最好的结果是,就像 git 暂存区一样,稍后会有意义。
  • 另外,“你的前提是错误的”/“uv 到图像像素坐标的映射不是 GL 的一部分”听起来对我来说是一个很好的答案。我没有意识到采样器是由原始数据流构建的。
  • 让我改进我之前的陈述,因为它在技术上不正确,UV 坐标的工作方式与从左到右、从下到上的位置坐标 {u,v}={x,y} 相同。问题是纹理数据(正如您已经注意到的那样)直接映射到内存,以便从图像读取的第一行像素位于 V 坐标 0 处(或者如果有除 NEAREST 之外的任何采样,则精确到 .5 / height被使用)这就是为什么它们看起来是翻转的,为什么我说 V 从上到下。

标签: javascript webgl opengl-es-2.0 regl


【解决方案1】:

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

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

您的问题的简短答案是整个图像被翻转,因为

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

改成

gl_Position = vec4(position, 0, 1);

你会看到它是颠倒的

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

  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

如果我们相对于画布/屏幕/帧缓冲区绘制它,我们得到

蓝色区域是屏幕/画布

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

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

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

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

这有点难以解释,但是如果您查看this example,您会发现在屏幕外渲染到/从纹理渲染时不需要翻转。仅在渲染到画布/屏幕时。

如果您想看到大三角形,请将着色器更改为此

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

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

您可以在 regl 示例中看到它的渲染翻转

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

【讨论】:

  • 没有“世界空间”之类的东西 呵呵,到现在为止我还没有想到position只不过是一个用户定义的属性。 GL“转换管道”的许多描述都包括模型/视图转换,我没有意识到它是多么任意
  • 问题是 GL 曾经有一个固定的功能管道,而许多旧的教程和文献仍然会带来这些东西。自从着色器成为一种东西以来,其中大部分已经被弃用(并且在 WebGL 所基于的 GL 的 ES 分支中被完全删除,这是大多数移动设备中的内容)。所以现在GL is just a rasterization engine 和其他一切都是 100% 用户提供的。
猜你喜欢
  • 2016-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-10
  • 2015-12-28
  • 1970-01-01
相关资源
最近更新 更多