在着色器中更改了OpenGL着色器灯光位置

时间:2014-08-02 08:48:31

标签: c++ opengl glsl shader lighting

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

我不熟悉OpenGL,我刚开始在this教程之后抓住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轴上移动。我弄错了吗?或者我忘记了着色器中的som翻译?

提前致谢:)

2 个答案:

答案 0 :(得分:0)

  

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

该教程使用lightDir作为统一变量。你必须自己设定。通过一些glUniform电话。如果相同或不相同将取决于您在此处设置的灯光位置。这里使用的lightDir是从想要阴影的表面点到光源的矢量。本教程使用方向光,因此场景中的光线方向相同,并且实际上并不依赖于顶点/片段的位置。您可以通过将灯光的w分量设置为0来对固定功能灯光执行相同操作。如果不这样做,结果将会非常不同。

附注:该教程中的GLSL代码不依赖于许多已弃用的功能。如果你学习GLSL,我真的建议你学习现代GL核心简介。

答案 1 :(得分:0)

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变量的选项进行了说明。