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

时间:2015-05-25 15:55:40

标签: c++ opengl shader opengl-3 lighting

我正在松散地关注www.learnopengl.com上的教程,我正在将多个灯光传递给我的碎片器。为此,我有多个灯箱和一个充当容器的类,可以将我的灯制服传递到着色器。

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

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());

(灯光是灯光的对象)

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 个答案:

答案 0 :(得分:0)

这与PointLightSpotLight来自DirectionalLight的事实有关,他们(PointLight和SpotLight对象)会被转换为他们的基类,删除他们的“特殊属性”,当我做light.bindLight(shader);时,它会调用directionalLight的bindLight函数。 我通过添加addLightDirectionalLightPointLight作为参数创建三个不同的SpotLight函数来解决它。 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);
    }

}

比你的时间多了!