在 GLSL 中让相机正常

Posted

技术标签:

【中文标题】在 GLSL 中让相机正常【英文标题】:Get the camera normal in GLSL 【发布时间】:2015-11-08 10:13:41 【问题描述】:

我有一个 OpenGL 场景,我在其中查看这样的对象:

gluLookAt(10, 10, -10, -10, -10, 10, 0, 1, 0);

所以我知道如果我想在着色器中使用我的相机的 z 轴,它看起来就像这个的归一化向量:

vec3(1.0, 1.0, -1,0);

有没有办法在顶点着色器中计算这个向量?

我想计算近/远裁剪平面的法线,但在顶点(或片段)着色器中找不到方法。

我正在使用旧管道(OpenGL v2.0/ GLSL v. 1.10)并且不想将矢量传递给着色器(尽管我知道这是执行此操作的常用且高效的方法)。

【问题讨论】:

欢迎来到 SO!请将 OpenGL 版本(和 GLSL 版本,如果相关)添加到 OpenGL/GLSL 问题中。 gluLookAt 已弃用,但在讨论 OpenGL 时仍将其用作短语,因此我不知道您是在技术上使用它还是仅用于说明。 OpenGL 1.1 没有 GLSL。从 OpenGL 2.0 开始 对不起,这是 OpenGL v2.0 / GLSL v1.10 现在更有意义了。 ;) 【参考方案1】:

固定函数顶点变换通过应用两个矩阵来工作:

    从对象空间到眼睛空间的“ModelView”矩阵 从眼睛空间到剪辑空间的“投影”矩阵

gluLookAt() 所做的是通过在世界空间中定义一些相机来指定视图矩阵。而你似乎想要重构的是这个世界空间中的观察方向。

但是,对于固定功能 GL,这是不可能的。您所拥有的只是产品 view * model。如果没有更多信息,您无法将其分解为 viewmodel 部分。并且这些信息都不存在于固定函数 GL 中——它从来没有拥有一个世界空间,或者关心一个单独的视图矩阵。这种区别确实发生了——如果有的话——在应用程序逻辑中。

有趣的问题是:你甚至需要世界空间的观察方向来做什么?固定函数 GL 在眼睛空间中进行此类计算,其中观察方向只是 (0,0,-1,0)。

所以我看到了两种选择:

    使用统一(或将数据传输到着色器的其他方式)指定一些附加信息,就像其他答案已经建议的那样 直接在眼睛空间中进行计算

【讨论】:

第 2 点。成功了。我想计算相机观察方向和顶点法线的点积。所以诀窍不仅在于尝试转换相机的法线,还在于转换顶点: 最后我用了这个:vertexNormal = gl_NormalMatrix*gl_Normal;vertexViewDirection = -normalize(gl_ModelViewMatrix*gl_Vertex).xyz;【参考方案2】:

将其作为制服传递给您的着色器。请参阅glUniform3f 的文档。

在客户端代码中,执行如下操作:

auto cameraUp = camera.getUp();
glUniform3f(uniformLocationInShader, cameraUp.x, cameraUp.y, cameraUp.z)

在顶点着色器中,为相机向上矢量添加一个制服,然后按预期使用它。

uniform vec3 cameraUp;

void main() 

   // do stuff with cameraUp
 

【讨论】:

我知道这很聪明,但这正是我不想做的事情;-) 嗯,您需要将某种制服传递给着色器以获取此信息...如果您将视图矩阵作为制服,您应该能够从这些列之一。 所以我想这是唯一的方法吗?我不能使用眼睛平面或类似的东西吗? 是的,这正是制服的目的:将信息传递给着色器...顺便说一句,近和远剪辑平面是您的 投影 矩阵的一部分。这与您的相机的向上矢量无关。 好吧,我只需要 z 向量。我可以从投影矩阵中提取它吗?【参考方案3】:

(已弃用)gluLookAt 的参数是 (vec3) eye_、center_ 和 up_ 的分量(x_ 表示向量值基准 x_

f: ℝ^3 x ℝ^3 x ℝ^3 -> ℝ4xℝ4 
eye_, center_, up_ -> ViewMatrix

因此您可能会寻找的是

dir_ = normalize(center_ - eye_), 

在着色器中获取它们的最佳方式和位置取决于您使用的 GL 和 GLSL 版本。

这个向量

vec3(1.0, 1.0, -1,0);

btw 的长度为 sqrt(3),因此没有标准化。

编辑

在了解 OpenGL 和 GLSL 版本后,您可以从中获取

legacy GLSL 1.10.59 doc

GLSL 1.10.59 已经有了自定义制服(我记不清了,2.0/1.10 太早了);因此,您只需将该向量作为制服传递,就是这样。

因为它用于每个顶点,所以计算一次比在着色器中对每个顶点再次计算效率更高(当然,鉴于渲染的顶点块相当大)。

【讨论】:

感谢您的回答,但我正在寻找一种方法来计算此法线在顶点着色器中。有没有办法做到这一点? @Corbie 当然,但请发布您的 GL 和 GLSL 版本! @Corbie 和你在着色器中填充的制服,如果有的话。 我已经添加了版本。没有相关的制服。

以上是关于在 GLSL 中让相机正常的主要内容,如果未能解决你的问题,请参考以下文章

glsl 着色器 - 颜色混合,正常模式(如在 Photoshop 中)

我的 GLSL 着色器程序链接正常,但是当我尝试使用它时出错——我该如何调试它?

GLSL 灯光/高光随相机移动

如何在 Android 中保存相机拍摄的图片(应用 glsl 效果)?

Opengl 3.3 不绘制任何东西。使用 GLSL 330 核心

从相机和图库上传在所有版本中都无法正常工作