OpenGL着色器光照位置在着色器中改变

OpenGL shader light position changed in shader

本文关键字:改变 OpenGL 位置      更新时间:2023-10-16

首先,如果标题误导了我,我很抱歉,但我不太确定如何描述这个问题,如果这是一个问题的话。

我是一个全新的OpenGL,我刚刚开始刮伤表面的GLSL跟随本教程。

渲染函数的主要部分如下所示

GLfloat ambientLight[] = {0.5f, 0.5f, 0.5f, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
//Add directed light
GLfloat lightColor1[] = {0.5f, 0.5f, 0.5f, 1.0f}; //Color (0.5, 0.2, 0.2)
//Coming from the direction (-1, 0.5, 0.5)
GLfloat lightPos1[] = { 40.0 * cos((float) elapsed_time / 500.0) , 40.0 * sin((float)      elapsed_time / 500.0), -20.0f, 0.0f};
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor1);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos1); 

glPushMatrix();
glTranslatef(0,0,-50);
glColor3f(1.0, 1.0, 1.0);
glRotatef( (float) elapsed_time / 100.0, 0.0,1.0,0.0 );
glUseProgram( shaderProg );
glutSolidTeapot( 10 );
glPopMatrix();

其中"shaderProg"是一个由顶点着色器组成的着色程序

varying vec3 normal;
void main(void)
{
  normal = gl_Normal;
  gl_Position = ftransform();
}  

和一个片段着色器

uniform vec3 lightDir;
varying vec3 normal;
void main() {
  float intensity;
  vec4 color;
  intensity = dot(vec3(gl_LightSource[0].position), normalize(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;
}

我有两个问题

首先,根据教程,统一的lightDir应该是可用的,但我只得到vec3(gl_LightSource[0].position)的结果。这两者有什么区别吗?

另一个问题是,当使用着色器程序时,设置围绕茶壶旋转的光线不同。没有着色器,光线在相机的XY轴上围绕茶壶旋转。然而,如果使用了着色器,光线会沿着相机的XZ轴移动。我错了吗?还是我忘记了一些着色器的翻译?

提前感谢:)

首先,根据教程,统一的lightDir应该是可用,但我只得到vec3(gl_LightSource[0].position)的结果。这两者有什么区别吗?

该教程使用lightDir作为统一变量。你必须自己设定。通过glUniform呼叫。是否相同取决于你在这里设置的光源位置。这里使用的lightDir是从表面点到光源的矢量,你想要遮阳。本教程使用方向光,所以光线方向在场景中的任何地方都是相同的,并不真正依赖于顶点/片段的位置。通过将光源位置的w分量设置为0,可以对固定功能照明进行相同的操作。如果你不这样做,结果将会非常不同。

旁注:不幸的是,该教程中的GLSL代码依赖于许多已弃用的特性。如果你学习GLSL,我强烈建议你学习现代GL核心配置文件。

lightDir不是预定义的统一。光方向矢量的典型定义是你的着色器中光位置的标准化矢量,你可以通过规范化位置矢量轻松计算:

vec3 lightDir = normalize(gl_LightSource[0].position.xyz);

你也可以把它作为你自己定义的统一传递到着色器中。对于这种方法,你将在你的片段着色器中定义统一:

uniform vec3 lightDir;

,然后通过glGetUniformLocation()调用获得统一的位置,并通过glUniform3f()调用设置一个值。链接完着色器后,你会看到:

GLint lightDirLoc = glGetUniformLocation(shaderProg, "lightDir");

,然后每次你想改变光的方向为(vx, vy, vz):

glUniform3f(lightDirLoc, vx, vy, vz);

对于你的问题的第二部分:与你自己的着色器相比,你用固定管道得到的光位置的不同行为的原因是固定管道将当前的模型视图矩阵应用到指定的光位置,这在你的着色器中没有完成。

正如许多其他人已经建议的那样:如果你现在学习OpenGL,我强烈建议你跳过遗留特性,其中包括固定函数光源参数。在这种情况下,您可以简单地使用自己定义的uniform变量,正如我已经说明的那样,作为上面lightDir变量的选项。