GLSL 着色器 - 更改 'camera' 位置

GLSL Shader - change 'camera' position

我正在尝试使用 OpenGL 创建某种 'camera' 对象。通过更改其值,您可以缩放 in/out 并移动相机。 (想象一个 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 确实会正确更改相机角度。 但是,它与渲染某些东西的位置不匹配。

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

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

顶点着色器的目的是为要绘制的对象的每个顶点计算一个clip space位置。 在这种情况下,一个对象只是一系列几何图元,如点、线或三角形,每个由一些顶点指定。

这些顶点通常指定相对于一些完全由用户定义的参考坐标系的一些位置。 space 定义的顶点位置通常称为 对象 space.

现在顶点着色器的工作是使用某种数学或算法方式将对象space转换到剪辑space。通常,这些变换规则也隐含地或明确地由一些"virtual camera"组成,因此对象被变换,就好像被所述相机观察到的那样。

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

What is in_Position supposed to be? I've seen several code examples use it, but no-one explains it. It's not explicitly defined either; which values does it take?

所以 in_Position 在你的例子中只是一些属性(意味着它是一个指定的值 per vertex)。此属性的 "meaning" 完全取决于它的使用方式。由于您将其用作某些坐标变换的输入,我们可以将其解释为表示顶点 的对象space 位置。在您的情况下,这是一个二维对象 space.The 值 "takes" 完全取决于您。

What values is gl_Position supposed to take? uf_Projection seems to normalize the values, but when adding values (more than 2000) at center.x, it still works (correctly moved the screen).

gl_Position是顶点的剪辑space位置。现在 clip space 有点难以描述。您在这里看到的 "normalization" 与另一个 space,即 标准化设备坐标 (NDC) 这一事实有关。在 GL 中,NDC 的惯例是,观看体积由 NDC 中的 -1 <= x,y,z <=1 立方体表示。

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

从剪辑 space 转换为 NDC 的规则是将剪辑 space x、y 和 z vlaues 除以剪辑 space w 值。 这样做的理由是剪辑 space 代表所谓的 projective space, and the clip space coordinates are homogenuous coordinates。在 Whosebug 文章中解释这背后的理论是远远不够的。

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

我不清楚这是否正是您想要的。您当前的解决方案的效果是增加 center.z 会增加映射到查看体积的对象 space 范围,因此它确实会产生缩放效果。让我们考虑 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

换句话说,您在屏幕上看到的对象 space 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);

所以基本上,可见对象 space 范围将是 center.xy +- uf_Projection.xy * center.z

Is this the correct way to create a kind of "camera" effect? Or is there a better way? (the idea is that things that aren't on the screen, don't have to get rendered)

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

I'm using uniform vec3 center to manipulate the camera location. (I'm feeling it should be called an attribute, but I don't know for sure.

其实,为此穿制服是正确的做法。属性用于每个顶点都可以更改的值。制服适用于在绘制调用期间保持不变的值(因此,对于访问它们的所有着色器调用,制服是 "uniform")。对于您正在处理的每个顶点,您的相机规格应该相同。只有顶点位置在顶点之间会发生变化,因此每个顶点最终将相对于某些固定的相机位置(和参数)位于不同的点。