通过多个 类 传递 OpenGL 3.0 制服时出现问题

Problems passing OpenGL 3.0 uniforms through multiple classes

我大致按照 www.learnopengl.com 上的教程进行操作,我目前正在将多个灯光传递到我的片段着色器中。为此,我有多个灯光 class 和一个 class 作为容器,可以将我的灯光制服传递到着色器中。

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

Light.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 是 class Lights 的一个对象)

Fragmentshader:(考虑到当我在没有灯光的情况下通过制服时它可以工作,这里应该没有任何问题class)

#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。如果您需要更多代码示例,请对此 post 发表评论,我将使用代码对其进行编辑。

因为 PointLightSpotLight 派生自 DirectionalLight,它们(PointLight 和 SpotLight 对象)将被投射到它们的基础 class,删除它们的 "special attributes",当我执行 light.bindLight(shader); 时,它会调用 directionalLight 的 bindLight 函数。 我通过添加分别以 DirectionalLightPointLightSpotLight 作为参数创建三个不同的 addLight 函数来解决它。 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);
    }

}

谢谢你的时间!