math - 为什么我的 GLSL 着色器灯光会随着它所照射的对象在场景中移动?

标签 math ios4 glsl opengl-es-2.0 opengl-es-lighting

我正在关注 a tutorial on OpenGL ES 2.0并将其与 GLSL lighting 上的教程相结合我发现,使用 a handy Utah teapot来自 developer.apple.com。

经过大量的摆弄和实验后,我在屏幕上适度正确地绘制了茶壶,使用照明教程中的“卡通阴影”围绕所有三个轴旋转。由于我只是将整个顶点列表绘制为三角形 strip (如果您查看 teapot.h 文件,在我应该开始新的三角形 strip 的位置嵌入了“-1”,但这是仅测试数据,与我的问题无关)。

我真正感到困惑的是如何在场景中定位灯光。在我的 Objective-C 代码中,我有一个浮点数 3包含 {0,1,0} 的向量并将其传递到着色器中,然后计算光的强度。

为什么灯光似乎也在场景中移动?我的意思是,光就像一根无形的棍子附在茶壶上一样,无论茶壶面向哪个方向,它始终指向它的同一侧。

这是顶点着色器

attribute vec4 Position;
attribute vec4 SourceColor;
attribute vec3 Normal;

uniform mat4 Projection;
uniform mat4 Modelview;

varying vec3 normal;

void main(void) {
    normal = Normal;
    gl_Position = Projection * Modelview * Position;
}

'Position' 由 Obj-C 代码设置,是对象的顶点,'Normal' 是来自顶点数组 (VBO) 的法线列表,'Projection' 和 'Modelview' 计算如下:

(CC3GLMatrix 来自 Cocos3D 库,在上面链接的 GLES 教程中提到)
CC3GLMatrix *projection = [CC3GLMatrix matrix];
float h = 4.0f * self.frame.size.height / self.frame.size.width;
[projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:1 andFar:100];
glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);

CC3GLMatrix *modelView = [CC3GLMatrix matrix];
[modelView populateFromTranslation:CC3VectorMake(0, 0, -7)];
[modelView scaleBy:CC3VectorMake(30, 30, 30)];

_currentRotation += displayLink.duration * 90;
[modelView rotateBy:CC3VectorMake(_currentRotation, _currentRotation, _currentRotation)];

glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);

我通过做在场景中设置灯光
float lightDir[] = {1,0,1};
glUniform3fv(_lightDirUniform, 1, lightDir);

片段着色器看起来像这样
varying lowp vec4 DestinationColor; // 1
varying highp vec3 normal;
uniform highp vec3 LightDir;


void main(void) {
    highp float intensity;
    highp vec4 color;
    intensity = dot(LightDir,normal);
    if (intensity > 0.95)
        color = vec4(1.0,0.5,0.5,1.0);
    else if (intensity > 0.5)
        color = vec4(0.6,0.3,0.3,1.0);
    else if (intensity > 0.25)
        color = vec4(0.4,0.2,0.2,1.0);
    else
        color = vec4(0.2,0.1,0.1,1.0);

    gl_FragColor = color;
}

在尝试解决这个问题时,我遇到了引用(在 GLES 中不存在)'gl_LightSource' 和 'gl_NormalMatrix' 的代码,但不知道将什么放入等效项中,我必须从我的代码传递到着色器中。对“眼睛空间”“相机空间”“世界空间”等的引用令人困惑,我知道我可能应该在它们之间转换事物,但不明白为什么或如何(以及在​​哪里 - 在代码中,或在着色器中?)

每一帧都需要修改光源吗?我用于设置它的代码看起来太简单了。我并没有真正移动茶壶,是吗,而是移动整个场景 - 灯光和四周?

最佳答案

首先是一些定义:

  • 世界空间:定义你的整个世界的空间。按照惯例,它是一个永远不会移动的静态空间。
  • View 空间/相机空间/眼睛空间:定义相机的空间。它通常是相对于世界空间的位置和旋转
  • 模型空间:定义模型的空间。与相机空间一样,它通常是相对于世界空间的位置和旋转
  • 光空间:同模型空间

  • 在简单的例子中(我猜在你的例子中)模型空间和世界空间是相同的。此外,OpenGL 本身没有世界空间的概念,这并不意味着您不能使用世界空间。当您希望在场景中让多个对象独立移动时,它会派上用场。

    现在,您在渲染之前对您的对象所做的是创建一个矩阵,将模型的顶点转换为 View 空间,因此是“modelViewMatrix”。

    在这种情况下,光有点不同。着色器中的光照计算是在模型空间中完成的,因此您必须将每一帧的光照位置转换为模型空间。

    这是通过计算以下内容来完成的:
    _lightDirUniform = inverseMatrix(model) * inverseMatrix(light) * lightPosition;
    

    光照位置从光照到世界,再到模型空间。如果您没有世界空间,只需省略模型空间转换,您应该没问题。

    关于math - 为什么我的 GLSL 着色器灯光会随着它所照射的对象在场景中移动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7193139/

    相关文章:

    javascript - 旋转/平移和恢复后在 Canvas 上定位

    ios - iOS 的可重用组件

    iphone - CLGeoCoder 导致应用程序崩溃?

    c++ - Opengl 中的视差法线贴图问题,GLSL

    algorithm - 有效地找到从 1 到 10^6 的所有数字的所有约数

    java - 当用户输入有字符串时如何调用方法? ( java )

    c++ - 将角度表示为 cos/sin 对

    iphone - 访问和设置 iPhone 默认闹钟

    javascript - WebGL 中的切换着色器程序

    glsl - 在非方形 Canvas 上使用片段着色器在光标位置绘制一个圆圈