【问题标题】:lighting in OpenGL with shaders使用着色器在 OpenGL 中进行照明
【发布时间】:2016-09-05 10:10:42
【问题描述】:

我正在尝试对纹理应用一些光照。 我创建了一个带纹理的立方体,并在其中放置了一个相机。 现在,我想照亮它的内部面。有人告诉我应该使用着色器,所以我阅读了很多教程并创建了:

顶点着色器:

const GLchar* vertexSkySource =
#if defined(__APPLE_CC__)
"#version 150 core\n"
#else
"#version 130\n"
#endif
"uniform mat3 view_rot;"
"in vec3 position;"
"out vec3 Coord;"
"void main() {"
"   Coord = view_rot * position;"
"   gl_Position = vec4(position, 1.0);"
"}";

片段着色器

const GLchar* fragmentSkySource =
#if defined(__APPLE_CC__)
"#version 150 core\n"
#else
"#version 130\n"
#endif
"in vec3 Coord;"
"out vec4 outColor;"
"uniform samplerCube textureSampler;"
"void main() {"
"   outColor =  texture(textureSampler, Coord);"
"}";

在我初始化它们之后

void initialize_shader()
{
    // shader per la skybox
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexSkySource, NULL);
    glCompileShader(vertexShader);
    {
        GLchar log[512];
        GLsizei slen = 0;
        glGetShaderInfoLog(vertexShader, 512, &slen, log);
        if (slen)
            std::cerr << log << std::endl;
    }

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentSkySource, NULL);
    glCompileShader(fragmentShader);
    {
        GLchar log[512];
        GLsizei slen = 0;
        glGetShaderInfoLog(fragmentShader, 512, &slen, log);
        if (slen)
            std::cerr << log << std::endl;
    }

    skyProgram = glCreateProgram();
    glAttachShader(skyProgram, vertexShader);
    glAttachShader(skyProgram, fragmentShader);
    glBindFragDataLocation(skyProgram, 0, "outColor");
    glLinkProgram(skyProgram);
    GLint status = 0;
    glGetProgramiv(skyProgram, GL_LINK_STATUS, &status);
    if (!status)
    {
        std::cout << "failed to link" << std::endl;
        GLchar log[256];
        GLsizei slen = 0;
        glGetProgramInfoLog(skyProgram, 256, &slen, log);
        std::cout << log << std::endl;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
}

然后在 main 方法中调用的 draw 方法中,我这样做:

glm::vec3 light_direction = glm::normalize(glm::vec3(1.f, 1.f, 3.f));
glm::vec3 light_position = glm::vec3(1.0f, 1.0f, 0.0f);
glm::vec3 light_intensity = glm::vec3(1.f, 1.f, 1.f);

glDepthMask(GL_FALSE);
glUseProgram(skyProgram);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureCube);
glUniform1i(glGetUniformLocation(skyProgram, "textureSampler"), 3);
glUniform3fv(glGetUniformLocation(skyProgram, "light_direction"), 1, &light_direction[0]);
glUniform3fv(glGetUniformLocation(skyProgram, "light_intensity"), 1, &light_intensity[0]);
glUniform3fv(glGetUniformLocation(skyProgram, "view_position"), 1, &camera_position[0]);
glUniform1f(glGetUniformLocation(skyProgram, "shininess"), 60); // shininess = 60, range is [0.0 - 128.0] 
glUniformMatrix3fv(glGetUniformLocation(skyProgram, "view_rot"), 1, GL_FALSE, &(glm::mat3(glm::inverse(view)))[0][0]);

我在立方体面上看不到灯光,我应该在我的着色器中添加什么?

【问题讨论】:

  • 据我所见,您无法在着色器中计算任何光照。而且您肯定会遇到 OpenGL 错误,因为您正在尝试设置着色器中不存在的制服。
  • @BDL:实际上,使用位置 -1 设置制服显然不会在 GL 中产生错误。

标签: opengl


【解决方案1】:

您正在将光照参数(light_directionlight_intensityview_positionshininess)发送到着色器,但您没有接收到它们或对它们进行任何操作。您的片段着色器仅读取纹理,但不对其应用任何光照:

outColor =  texture(textureSampler, Coord);

完整的着色源会很大,如果没有看到更多代码很难给出,所以我会给出一些指示:

  • 首先是在 C++ 代码的各个部分添加一些 glGetError() 调用,这样您就可以知道是否使用了错误的 OpenGL API。
  • 除了位置之外,您还需要将顶点法线发送到着色器
  • 您需要选择一种着色算法,Blinn-Phong 很简单并且被广泛使用。
  • 您需要确保法线方向和光线方向位于同一坐标空间中

所以,最后你的outColor 需要乘以计算出的阴影:

outColor =  texture(textureSampler, Coord) * shading;

但您需要修改您的顶点和片段着色器以根据光的方向和顶点法线进行计算。

编辑基于GitHub project

我编译并运行了这个项目,不得不修复一些问题:

  • 包含和库路径是为您的计算机设置的,与项目目录无关。

  • 在片段着色器中,您将“着色”声明为“输出”。删除该行并在shading += vec4... 之前添加vec4 shading = vec4(0.0, 0.0, 0.0, 1.0);

  • vec4(light_intensity) 错误,无法在我的 NVIDIA Windows 驱动程序上编译,替换为 vec4(light_intensity,1.0)

即使我将着色器修改为始终输出红色,我也无法在屏幕上显示任何内容。

【讨论】:

  • 感谢您的建议,我修改了代码,但我真的很难理解/使阴影工作。我已经在这里上传了我的整个代码:github.com/luca92c/openGL。我不知道我距离获得一个简单的 Phong 着色效果还有多远,这是我的第一个 openGL 项目..
  • 再次感谢您。现在我可以看到灯光效果了。但是,你能解释一下 vec4(0.0, 0.0, 0.0, 1.0); 中的 4 个参数是什么吗?什么意思?
  • @splunk 红色、绿色、蓝色和 alpha。着色从零开始,每个灯光都对最终着色有贡献(代码中的 +=)。
  • 最后一个问题。如果我要为阴影添加方向怎么办?我该怎么办?
  • @splunk 你的意思是添加另一个灯吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多