GLSL着色器 - 更改“相机”位置

时间:2015-10-23 19:29:09

标签: opengl camera glsl

我正在尝试使用OpenGL创建某种“相机”对象。通过更改其值,您可以放大/缩小,并移动相机。 (想象一下2d世界,你就在它之上)。这会产生变量center.xcenter.ycenter.z

attribute vec2 in_Position;
attribute vec4 in_Color;
attribute vec2 in_TexCoords;

uniform vec2 uf_Projection;
uniform vec3 center;

varying vec4 var_Color;
varying vec2 var_TexCoords;

void main() {
    var_Color = in_Color;
    var_TexCoords = in_TexCoords;
    gl_Position = vec4(in_Position.x /  uf_Projection.x - center.x,
                       in_Position.y / -uf_Projection.y + center.y,
                                         0, center.z);
}

我正在使用uniform vec3 center来操纵相机位置。 (我觉得它应该被称为attribute,但我不确定;我只知道如何操纵uniform值。)

uf_Projection的值为屏幕高度和宽度的一半。这已经是这种情况(分析某些代码),我只能假设它是为了确保gl_Position中的值是规范化的吗?

输入center.x的值确实可以正确改变相机角度。 但是,它与某些内容的呈现位置不匹配。

除了问题:代码有多糟糕?我实际上是在问这些具体问题:

  • in_Position应该是什么?我见过几个代码示例使用它,但没有人解释它。它没有明确定义;它需要哪些值?
  • gl_Position应该采用什么值? uf_Projection似乎规范化了值,但在center.x添加值(超过2000)时,它仍然有效(正确移动了屏幕)。
  • 这是创建一种“相机”效果的正确方法吗?或者,还有更好的方法? (想法是屏幕上没有的东西,不必渲染)

1 个答案:

答案 0 :(得分:1)

只有考虑到更大的情况,才能回答您提出的问题。在这种情况下,这意味着我们应该看看顶点着色器和用于渲染的典型坐标转换

顶点着色器的目的是为要绘制的对象的每个顶点计算剪辑空间位置。 在此上下文中,对象只是一系列几何图元,如点,线或三角形,每个都由一些顶点指定。

这些顶点通常指定一些完全由用户定义的coorinate参考框架的位置。这些顶点位置定义的空间通常称为对象空间

现在,顶点着色器的工作是使用一些数学或算法方法从对象空间转换到剪辑空间。通常,这些转换规则也隐含地或明确地包含一些虚拟相机",以便对象被转换为好像被所述相机观察到的那样。

但是,使用了哪些规则,如何描述它们以及需要哪些输入是完全免费的。

  

in_Position应该是什么?我已经看到几个代码示例使用它,但没有人解释它。它没有明确定义;它需要哪些值?

因此,在您的情况下in_Position只是一些属性(意味着它是一个指定每个顶点的值)。 "含义"该属性的选择仅取决于它的使用方式。由于您将其用作某些坐标转换的输入,我们可以将其解释为顶点的对象空间位置。在您的情况下,这是一个2D对象空间。它的值"采取"完全取决于你。

  

gl_Position应该采用什么值? uf_Projection似乎规范化了值,但是当在center.x中添加值(超过2000)时,它仍然有效(正确地移动了屏幕)。

gl_Position是顶点的剪辑空间位置。现在剪辑空间有点难以描述。 &#34;标准化&#34;你看到这里有一个事实,即有另一个空间,规范化设备坐标(NDC)。并且在GL中,NDC的惯例是观察体积由NDC中的-1 <= x,y,z <= 1立方体表示。

因此,如果x_ndc为-1,则对象将显示在视口的左边框,右边的边界为x = 1,底边的y = -1,依此类推。您还在z处进行裁剪,因此距离太远或太靠近假想相机位置的对象也将不可见。 (请注意,近剪裁平面也会排除观察者后面的所有内容。)

从剪辑空间转换为NDC的规则是将剪辑空间x,y和z vlaues除以剪辑空间w值。 其基本原理是剪辑空间代表所谓的projective space,剪辑空间坐标为homogenuous coordinates。在StackOverflow文章中解释这背后的理论还有很多。

但这意味着,通过将gl_Position.w设置为center.z,GL稍后会有效地将gl_Position.xyz除以center.z以达到NDC坐标。这样的划分基本上创造了透视效果,使得更远的点看起来更靠近在一起。

我不清楚这是否正是你想要的。您当前的解决方案具有增加center.z将增加映射到查看卷的对象空间范围的效果,因此它确实提供缩放效果。我们考虑x坐标:

x_ndc = (in_Position.x /  uf_Projection.x - center.x) / center.z
      = in_Position.x / (uf_Projection.x * center.z) - center.x / center.z

换句话说,您可以在屏幕上看到的对象空间x范围将是应用于x_ndc=-1x_ndc=1的逆转换:

x_obj = (x_ndc + center.x/center.z) * (uf_Projection.x * center.z)
      = x_ndc * uf_Projection.x * center.z + center.x * uf_Projection.x
      = uf_Projection.x * (x_ndc * center.z + center.x);

基本上,visibile对象空间范围为center.xy +- uf_Projection.xy * center.z

  

这是创建一种&#34;相机的正确方法吗?影响?或者,还有更好的方法? (这个想法是屏幕上没有的东西,不必渲染)

从概念上讲,步骤是正确的。通常,使用转换矩阵来定义必要的步骤。但在你的情况下,直接应用转换作为一些乘法和加法更有效(但不太灵活)。

  

我使用uniform vec3 center来操纵相机位置。 (我觉得它应该被称为属性,但我不确定。

实际上,使用制服是正确的做法。属性适用于每个顶点可以更改的值。制服用于在绘制调用期间保持不变的值(因此,对于它们所接收的所有着色器调用,它们是均匀的#34;)。对于要处理的每个顶点,您的相机规格应该相同。只有顶点位置确实在顶点之间变化,因此每个顶点将相对于一些固定的摄像机位置(和参数)结束在不同的点。