通过多个类传递 OpenGL 3.0 制服的问题

Posted

技术标签:

【中文标题】通过多个类传递 OpenGL 3.0 制服的问题【英文标题】:Problems passing OpenGL 3.0 uniforms through multiple classes 【发布时间】:2015-05-25 15:55:40 【问题描述】:

我正在松散地遵循www.learnopengl.com 上的教程,我目前正在将多个灯光传递到我的片段着色器中。为此,我有多个灯光类和一个充当容器的类,以便能够将我的灯光制服传递到着色器中。

着色器设置正确。但是,当我调用函数从 Lights 类传递制服时,制服似乎没有正确传递。但是当我在不使用 Lights 类的情况下调用灯光的绑定函数时(即在主更新循环中)。

光.h

#ifndef LIGHT_H
#define LIGHT_H

#include <iostream>
#include <vector>
#include <string>
#include <GL/glew.h>

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
//#include <glm/gtx/string_cast.hpp>

///Declare the classes <--- Restructure the code so that I won't have to
//Needed for the Lights class
class DirectionalLight;
class PointLight;
class SpotLight;

enum typeOfLight
    pointLight,
    directionalLight,
    spotLight
;

class Lights
    public:
        Lights();
        ~Lights();

        void addLight(DirectionalLight LightToAdd, typeOfLight type);
        void bindLights(GLuint shader);
    private:
        std::vector<DirectionalLight> dirLights;
        std::vector<DirectionalLight> pointLights;
        std::vector<DirectionalLight> spotLights;
;

class DirectionalLight

    public:
        DirectionalLight();
        ~DirectionalLight();

        void bindLight(GLuint shader, int i);
        void initialize(glm::vec3 dir, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 spec);
    //protected:
        glm::vec3 direction;
        glm::vec3 ambientColor;
        glm::vec3 diffuseColor;
        glm::vec3 specularColor;
    private:
;


class PointLight : public DirectionalLight
    public:
        PointLight();
        ~PointLight();
        void bindLight(GLuint shader, int i);
        void initialize(glm::vec3 pos, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 spec, float constAtt, float linAtt, float quadAtt);
   // private:
        float constantAttenuation, linearAttenuation, quadraticAttenuation;

;

class SpotLight : public DirectionalLight
    public:
        SpotLight();
        ~SpotLight();
        void bindLight(GLuint shader, int i);
        void initialize(glm::vec3 pos, glm::vec3 direction, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 specular, float curOff, float outerCutOff, float constAtt, float linAtt, float quadAtt);
    //private:
        glm::vec3 pos;
        float cutOff, outerCutOff, constantAttenuation, linearAttenuation, quadraticAttenuation;
    ;
    #endif // LIGHT_H

Light.cpp

#include "Light.h"
Lights::Lights()
Lights::~Lights()

void Lights::addLight(DirectionalLight LightToAdd, typeOfLight type)
    if(type == directionalLight)
        dirLights.push_back(LightToAdd);
        std::cout << "Added a dir Light" << std::endl;
    else if(type == pointLight)
        pointLights.push_back(LightToAdd);
        std::cout << "Added a point Light" << std::endl;
    else if(type ==  spotLight)
        spotLights.push_back(LightToAdd);
        std::cout << "Added a spot Light" << std::endl;
    


void Lights::bindLights(GLuint shader)
    /*for(DirectionalLight Light : dirLights)
        Light.bindLight(shader, 0);
    
    for(int i = 0; i < pointLights.size(); i++)
        pointLights[i].bindLight(shader, i);
        std::cout << "Bound pointLight nr "<<i<<std::endl;
    
    for(int i = 0; i < spotLights.size(); i++)
        spotLights[i].bindLight(shader, i);
    */
    ///The above is commented out due to debugging
    dirLights[0].bindLight(shader, 0);
    pointLights[0].bindLight(shader, 0);
    pointLights[1].bindLight(shader, 1);
    spotLights[0].bindLight(shader, 0);

DirectionalLight::DirectionalLight()

DirectionalLight::~DirectionalLight()

void DirectionalLight::bindLight(GLuint shader, int i)
    glUniform3f(glGetUniformLocation(shader, "dirLight.direction"), direction.x, direction.y, direction.z);
    glUniform3f(glGetUniformLocation(shader, "dirLight.ambient"), ambientColor.x, ambientColor.y, ambientColor.z);
    glUniform3f(glGetUniformLocation(shader, "dirLight.diffuse"), diffuseColor.x, diffuseColor.y, diffuseColor.z);
    glUniform3f(glGetUniformLocation(shader, "dirLight.specular"), specularColor.x, specularColor.y, specularColor.z);


void DirectionalLight::initialize(glm::vec3 dir, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 spec)
    direction = dir;
    ambientColor = ambient;
    diffuseColor = diffuse;
    specularColor = spec;


PointLight::PointLight()
PointLight::~PointLight()
void PointLight::bindLight(GLuint shader, int i)
    glUniform3f(glGetUniformLocation(shader, ("pointLight[" + std::to_string(i) + "].position").c_str()), direction.x, direction.y, direction.z);
     glUniform3f(glGetUniformLocation(shader, ("pointLight[" + std::to_string(i) + "].ambient").c_str()), ambientColor.x, ambientColor.y, ambientColor.z);
    glUniform3f(glGetUniformLocation(shader, ("pointLight[" + std::to_string(i) + "].diffuse").c_str()), diffuseColor.x, diffuseColor.y, diffuseColor.z);
    glUniform3f(glGetUniformLocation(shader, ("pointLight[" + std::to_string(i) + "].specular").c_str()), specularColor.x, specularColor.y, specularColor.z);
     glUniform1f(glGetUniformLocation(shader, ("pointLight[" + std::to_string(i) + "].constantAttenuation").c_str()), constantAttenuation);
     glUniform1f(glGetUniformLocation(shader, ("pointLight[" + std::to_string(i) + "].linearAttenuation").c_str()), linearAttenuation);
     glUniform1f(glGetUniformLocation(shader, ("pointLight[" + std::to_string(i) + "].quadraticAttenuation").c_str()), quadraticAttenuation);


 void PointLight::initialize(glm::vec3 pos, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 spec, float constAtt, float linAtt, float quadAtt)
    direction = pos;
    ambientColor = ambient;
    diffuseColor = diffuse;
    specularColor = spec;
    constantAttenuation = constAtt;
    linearAttenuation = linAtt;
    quadraticAttenuation = quadAtt;

SpotLight::SpotLight()

SpotLight::~SpotLight()


void SpotLight::bindLight(GLuint shader, int i)
    glUniform3f(glGetUniformLocation(shader, ("spotLight[" + std::to_string(i) + "].position").c_str()), pos.x, pos.y, pos.z);
    glUniform3f(glGetUniformLocation(shader, ("spotLight[" + std::to_string(i) + "].direction").c_str()), direction.x, direction.y, direction.z);
    glUniform3f(glGetUniformLocation(shader, ("spotLight[" + std::to_string(i) + "].ambient").c_str()), ambientColor.x, ambientColor.y, ambientColor.z);
    glUniform3f(glGetUniformLocation(shader, ("spotLight[" + std::to_string(i) + "].diffuse").c_str()), diffuseColor.x, diffuseColor.y, diffuseColor.z);
    glUniform3f(glGetUniformLocation(shader, ("spotLight[" + std::to_string(i) + "].specular").c_str()), specularColor.x, specularColor.y, specularColor.z);
    glUniform1f(glGetUniformLocation(shader, ("spotLight[" + std::to_string(i) + "].cutOff").c_str()), cutOff);
    glUniform1f(glGetUniformLocation(shader, ("spotLight[" + std::to_string(i) + "].outerCutOff").c_str()), outerCutOff);
    glUniform1f(glGetUniformLocation(shader, ("spotLight[" + std::to_string(i) + "].constantAttenuation").c_str()), constantAttenuation);
    glUniform1f(glGetUniformLocation(shader, ("spotLight[" + std::to_string(i) + "].linearAttenuation").c_str()), linearAttenuation);
    glUniform1f(glGetUniformLocation(shader, ("spotLight[" + std::to_string(i) + "].quadraticAttenuation").c_str()), quadraticAttenuation);



void SpotLight::initialize(glm::vec3 pos, glm::vec3 direction, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 spec, float cutOff, float outerCutOff, float constAtt, float linAtt, float quadAtt)
    this->pos = pos;
    this->direction = direction;
    this->ambientColor = ambient;
    this->diffuseColor = diffuse;
    this->specularColor = spec;
    this->cutOff = cutOff;
    this->outerCutOff = outerCutOff;

    constantAttenuation = constAtt;
    linearAttenuation = linAtt;
    quadraticAttenuation = quadAtt;

当我直接从 main.cpp 调用 bindLight() 函数时,它看起来像这样:(这有效)

dirLight.bindLight(unlit.getShaderProgram(), 0);
pointLight1.bindLight(unlit.getShaderProgram(), 0);
spotLight1.bindLight(unlit.getShaderProgram(), 0);
pointLight2.bindLight(unlit.getShaderProgram(), 1);

否则我只打电话:(这不起作用)

lights.bindLights(unlit.getShaderProgram());

(其中lights是Lights类的一个对象)

Fragmentshader:(考虑到当我通过没有 Lights 类的制服时它可以工作,这里应该没有任何问题)

#version 130

struct Material
    sampler2D diffuse;
    sampler2D specular;
    float shininess;
;

struct DirectionalLight
    vec3 direction;
    vec3 diffuse;
    vec3 ambient;
    vec3 specular;
;

struct PointLight
    vec3 position;
    vec3 diffuse;
    vec3 ambient;
    vec3 specular;

    float constantAttenuation;
    float linearAttenuation;
    float quadraticAttenuation;
;

struct SpotLight
    vec3 position;
    vec3 direction;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float cutOff;
    float outerCutOff;

    float constantAttenuation;
    float linearAttenuation;
    float quadraticAttenuation;
;

out vec4 outColor;

in vec3 fragPos;
in vec3 normal;
in vec2 texcoord;
in vec3 viewPos;

uniform vec3 lightPos;
uniform vec3 lightColor;

uniform Material material;
uniform DirectionalLight dirLight;
#define NR_POINT_LIGHTS 2
uniform PointLight pointLight[NR_POINT_LIGHTS];
#define NR_SPOT_LIGHTS 1
uniform SpotLight spotLight[NR_SPOT_LIGHTS];

vec3 calcDirectionalLight(vec3 Normal, vec3 viewDir);
vec3 calcPointLight(PointLight Light, vec3 Normal, vec3 viewDir);
vec3 calcSpotLight(SpotLight Light, vec3 Normal, vec3 viewDir);

void main()
    vec3 viewDir = normalize(viewPos - fragPos);
    vec3 Normal = normalize(normal);

    vec3 result = calcDirectionalLight(Normal, viewDir);
    for(int i = 0; i < NR_POINT_LIGHTS; i++)
        result += calcPointLight(pointLight[i], Normal, viewDir);
    
    for(int i = 0; i < NR_SPOT_LIGHTS; i++)
        result += calcSpotLight(spotLight[i], Normal, viewDir);
    
    outColor = vec4(result, 1.0f);


vec3 calcDirectionalLight(vec3 Normal, vec3 viewDir)
    vec3 ambient = dirLight.ambient * vec3(texture(material.diffuse, texcoord));

    //Diffuse

    vec3 lightDir = normalize(-dirLight.direction);
    float diff = max(dot(Normal, lightDir), 0.0f);
    vec3 diffuse = dirLight.diffuse * diff * vec3(texture(material.diffuse, texcoord));
    //texture(tex, texcoord)

    //Specular
    vec3 reflectDir = reflect(-lightDir, Normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = dirLight.specular * spec * vec3(texture(material.specular, texcoord));

    vec3 result = (ambient + diffuse + specular);
    return result;


vec3 calcPointLight(PointLight Light, vec3 Normal, vec3 viewDir)
    vec3 lightDir = normalize(Light.position - fragPos);
    //Diffuse
    float diff = max(dot(Normal, lightDir), 0.0f);
    //Specular
    vec3 reflectDir = reflect(-lightDir, Normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0f), material.shininess);
    //Attenuation
    float distance = length(Light.position - fragPos);
    float attenuation = 1.0f / (Light.constantAttenuation + Light.linearAttenuation * distance + Light.quadraticAttenuation * (distance * distance));

    //Colors
    vec3 ambient = Light.ambient * vec3(texture(material.diffuse, texcoord));
    vec3 diffuse = Light.diffuse * diff * vec3(texture(material.diffuse, texcoord));
    vec3 specular = Light.specular * spec * vec3(texture(material.specular, texcoord));

    ambient *= attenuation;
    diffuse *= attenuation;
    specular *= attenuation;
    return (ambient + diffuse + specular);


vec3 calcSpotLight(SpotLight Light, vec3 Normal, vec3 viewDir)
    vec3 lightDir = normalize(Light.position - fragPos);


   // if(theta > Light.cutOff)
        float diff = max(dot(Normal, lightDir), 0.0f);
        vec3 diffuse = Light.diffuse * diff * vec3(texture(material.diffuse, texcoord));

        vec3 reflectDir = reflect(-lightDir, Normal);
        float spec = pow(max(dot(viewDir, reflectDir), 0.0f), material.shininess);
        float distance = length(Light.position - fragPos);
        vec3 specular = Light.specular * spec * vec3(texture(material.specular, texcoord));
        float attenuation = 1.0f / (Light.constantAttenuation + Light.linearAttenuation * distance + Light.quadraticAttenuation * (distance * distance));

        float theta = dot(lightDir, normalize(-Light.direction));
        float epsilon = Light.cutOff - Light.outerCutOff;
        float intensity = clamp((theta - Light.outerCutOff) / epsilon, 0.0f, 1.0f);

        diffuse *= intensity;
        specular *= intensity;

        diffuse *= attenuation;
        specular *= attenuation;

        return (diffuse + specular);


我正在使用 OpenGL 3.0。如果您需要更多代码示例,请在这篇文章中发表评论,我将使用代码对其进行编辑。

【问题讨论】:

【参考方案1】:

这与 PointLightSpotLight 派生自 DirectionalLight 的事实有关,它们(PointLight 和 SpotLight 对象)将被强制转换为它们的基类,删除它们的“特殊属性”以及何时我会做light.bindLight(shader); 它会调用directionLight 的bindLight 函数。 我通过添加创建三个不同的DirectionalLightPointLightSpotLight 分别作为参数的函数来解决它。 Lights 代码现在如下所示。

Lights.h

class Lights
    public:
        Lights();
        ~Lights();
        void addLight(DirectionalLight lightToAdd);
        void addLight(SpotLight lightToAdd);
        void addLight(PointLight lightToAdd);
        void bindLights(GLuint shader);

    private:
        std::vector<DirectionalLight> dirLights;
        std::vector<PointLight> pointLights;
        std::vector<SpotLight> spotLights;

;

Lights.cpp

Lights::Lights();
Lights::~Lights();
Lights::addLight(DirectionalLight lightToAdd)
    dirLights.push_back(lightToAdd);

Lights::addLight(SpotLight lightToAdd)
    spotLights.push_back(lightToAdd);

Lights::addLight(PointLight lightToAdd)
    pointLights.push_back(lightToAdd);


Lights.bindLights(GLuint shader)
    for(int i = 0; i < dirLights.size(); i++)
        dirLights[i].bindLight(shader, i);
    
    for(int i = 0; i < pointLights.size(); i++)
        pointLights[i].bindLight(shader, i);
    
    for(int i = 0; i < spotLights.size(); i++)
        spotLights[i].bindLight(shader, i);
    


谢谢你的时间!

【讨论】:

以上是关于通过多个类传递 OpenGL 3.0 制服的问题的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 4.1 程序流水线制服

与常规缓冲区和制服相比,OpenGL 纹理单元背后的原因是啥?

具有多个缓冲区的片段着色器颜色错误

使用制服时 Xamarin OpenGL 片段着色器的奇怪行为

opengl getUniformLocation

Opengl 统一行为