通过多个 类 传递 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 发表评论,我将使用代码对其进行编辑。
因为 PointLight
和 SpotLight
派生自 DirectionalLight
,它们(PointLight 和 SpotLight 对象)将被投射到它们的基础 class,删除它们的 "special attributes",当我执行 light.bindLight(shader);
时,它会调用 directionalLight 的 bindLight 函数。
我通过添加分别以 DirectionalLight
、PointLight
和 SpotLight
作为参数创建三个不同的 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);
}
}
谢谢你的时间!
我大致按照 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 发表评论,我将使用代码对其进行编辑。
因为 PointLight
和 SpotLight
派生自 DirectionalLight
,它们(PointLight 和 SpotLight 对象)将被投射到它们的基础 class,删除它们的 "special attributes",当我执行 light.bindLight(shader);
时,它会调用 directionalLight 的 bindLight 函数。
我通过添加分别以 DirectionalLight
、PointLight
和 SpotLight
作为参数创建三个不同的 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);
}
}
谢谢你的时间!