4

我正在学习关于 OpenGL ES 2.0 的教程,并将它与我找到的关于GLSL 照明的教程结合起来,使用 developer.apple.com 上的一个方便的犹他茶壶

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

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

为什么灯光在场景中似乎也在移动?我的意思是,光线就像是用一根看不见的棍子固定在茶壶上一样,无论茶壶朝向哪个方向,它总是指向茶壶的同一侧。

这是顶点着色器

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;
}

“位置”由 Obj-C 代码设置,是对象的顶点,“法线”是来自顶点数组 (VBO) 的法线列表,“投影”和“模型视图”的计算方式如下:

(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”的代码,但不知道将什么放入等效项中,我必须从我的代码中传递给着色器。对“眼睛空间”、“相机空间”、“世界空间”等的引用令人困惑,我知道我可能应该在它们之间进行转换,但不明白为什么或如何(以及在​​代码中或着色器中的位置) ?)

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

4

1 回答 1

5

首先是一些定义:

  • 世界空间:定义你的整个世界的空间。按照惯例,它是一个永远不会移动的静态空间。

  • 视图空间/相机空间/眼睛空间:定义相机的空间。它通常是相对于世界空间的位置和旋转

  • 模型空间:定义模型的空间。与相机空间一样,它通常是相对于世界空间的位置和旋转

  • 光照空间:同模型空间

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

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

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

这是通过计算类似的东西来完成的:

_lightDirUniform = inverseMatrix(model) * inverseMatrix(light) * lightPosition;

光照位置由光转化为世界,再转化为模型空间。如果您没有世界空间,只需省略模型空间转换即可。

于 2011-08-25T18:26:12.110 回答