通过多个类传递 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】:这与 PointLight
和 SpotLight
派生自 DirectionalLight
的事实有关,它们(PointLight 和 SpotLight 对象)将被强制转换为它们的基类,删除它们的“特殊属性”以及何时我会做light.bindLight(shader);
它会调用directionLight 的bindLight 函数。
我通过添加创建三个不同的DirectionalLight
、PointLight
和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);
谢谢你的时间!
【讨论】:
以上是关于通过多个类传递 OpenGL 3.0 制服的问题的主要内容,如果未能解决你的问题,请参考以下文章
与常规缓冲区和制服相比,OpenGL 纹理单元背后的原因是啥?