diff --git a/FinalProject/fragmentshader.fs b/FinalProject/fragmentshader.fs index b2d475d..5dbf34b 100644 --- a/FinalProject/fragmentshader.fs +++ b/FinalProject/fragmentshader.fs @@ -1,20 +1,48 @@ #version 430 core out vec4 FragColor; - struct Material { sampler2D texture_diffuse1; sampler2D texture_specular1; float shininess; }; -struct Light { - vec3 position; +struct DirLight { + vec3 direction; + vec3 ambient; vec3 diffuse; vec3 specular; }; +struct PointLight { + vec3 position; + + float constant; + float linear; + float quadratic; + + vec3 ambient; + vec3 diffuse; + vec3 specular; +}; + +struct SpotLight { + vec3 position; + vec3 direction; + float cutOff; + float outerCutOff; + + float constant; + float linear; + float quadratic; + + vec3 ambient; + vec3 diffuse; + vec3 specular; +}; + +#define NR_POINT_LIGHTS 4 in vec3 FragPos; in vec3 Normal; @@ -22,27 +50,99 @@ in vec2 TexCoords; uniform vec3 viewPos; +uniform DirLight dirLight; +uniform PointLight pointLights[NR_POINT_LIGHTS]; +uniform SpotLight spotLight; uniform Material material; -uniform Light light; +// function prototypes +vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir); +vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); +vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir); void main() -{ -// ambient - vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb; - - // diffuse +{ + // properties vec3 norm = normalize(Normal); - vec3 lightDir = normalize(light.position - FragPos); - float diff = max(dot(norm, lightDir), 0.0); - vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb; - - // specular vec3 viewDir = normalize(viewPos - FragPos); - vec3 reflectDir = reflect(-lightDir, norm); - float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); - vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb; - - vec3 result = ambient + diffuse + specular; + + // == ===================================================== + // Our lighting is set up in 3 phases: directional, point lights and an optional flashlight + // For each phase, a calculate function is defined that calculates the corresponding color + // per lamp. In the main() function we take all the calculated colors and sum them up for + // this fragment's final color. + // == ===================================================== + // phase 1: directional lighting + vec3 result = CalcDirLight(dirLight, norm, viewDir); + // phase 2: point lights + for(int i = 0; i < NR_POINT_LIGHTS; i++) + result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); + // phase 3: spot light + result += CalcSpotLight(spotLight, norm, FragPos, viewDir); + FragColor = vec4(result, 1.0); +} + +// calculates the color when using a directional light. +vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir) +{ + vec3 lightDir = normalize(-light.direction); + // diffuse shading + float diff = max(dot(normal, lightDir), 0.0); + // specular shading + vec3 reflectDir = reflect(-lightDir, normal); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); + // combine results + vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, TexCoords)); + vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, TexCoords)); + vec3 specular = light.specular * spec * vec3(texture(material.texture_specular1, TexCoords)); + return (ambient + diffuse + specular); +} + +// calculates the color when using a point light. +vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) +{ + vec3 lightDir = normalize(light.position - fragPos); + // diffuse shading + float diff = max(dot(normal, lightDir), 0.0); + // specular shading + vec3 reflectDir = reflect(-lightDir, normal); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); + // attenuation + float distance = length(light.position - fragPos); + float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); + // combine results + vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, TexCoords)); + vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, TexCoords)); + vec3 specular = light.specular * spec * vec3(texture(material.texture_specular1, TexCoords)); + ambient *= attenuation; + diffuse *= attenuation; + specular *= attenuation; + return (ambient + diffuse + specular); +} + +// calculates the color when using a spot light. +vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir) +{ + vec3 lightDir = normalize(light.position - fragPos); + // diffuse shading + float diff = max(dot(normal, lightDir), 0.0); + // specular shading + vec3 reflectDir = reflect(-lightDir, normal); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); + // attenuation + float distance = length(light.position - fragPos); + float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); + // spotlight intensity + float theta = dot(lightDir, normalize(-light.direction)); + float epsilon = light.cutOff - light.outerCutOff; + float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0); + // combine results + vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, TexCoords)); + vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, TexCoords)); + vec3 specular = light.specular * spec * vec3(texture(material.texture_specular1, TexCoords)); + ambient *= attenuation * intensity; + diffuse *= attenuation * intensity; + specular *= attenuation * intensity; + return (ambient + diffuse + specular); } \ No newline at end of file diff --git a/FinalProject/lightCaster.cpp b/FinalProject/lightCaster.cpp index 08e10e6..836d0a4 100644 --- a/FinalProject/lightCaster.cpp +++ b/FinalProject/lightCaster.cpp @@ -1,19 +1,228 @@ #include"lightCaster.h" -Illuminant::Illuminant() { - _position = glm::vec3(0.0f); - _color = glm::vec3(1.0f); +ShaderProgram* lastShader = NULL; + +queue available = queue(); + +Illuminant::Illuminant(){ + Logger::debug("We do not recommend to construct illuminant without parameter"); } -Illuminant::Illuminant(glm::vec3 position, glm::vec3 color) { +// white color by default +Illuminant::Illuminant(glm::vec3 position, LightType lightType){ _position = position; - _color = color; + setType(lightType); } - - - -void Illuminant::setPosition(glm::vec3 position) { +// set up with one color +Illuminant::Illuminant(glm::vec3 position, glm::vec3 color, LightType lightType){ _position = position; + _ambient = color * 0.05f; + _diffuse = color * 0.8f; + _specular = color; + setType(lightType); } -void Illuminant::setColor(glm::vec3 color) { - _color = color; +//set up by assign all colors +Illuminant::Illuminant(glm::vec3 position, glm::vec3 ambient, + glm::vec3 diffuse, glm::vec3 specular, LightType lightType){ + _position = position; + _ambient = ambient; + _diffuse = diffuse; + _specular = specular; + setType(lightType); +} +// set up with one color,建议平行光源使用这个 +Illuminant::Illuminant(LightType lightType, glm::vec3 direction, glm::vec3 color) { + _direction = direction; + _ambient = color * 0.05f; + _diffuse = color * 0.8f; + _specular = color; + setType(lightType); +} + +// set up with one color,建议聚光灯光源使用这个 +Illuminant::Illuminant(glm::vec3 position, glm::vec3 direction, glm::vec3 color, LightType lightType) { + _direction = direction; + _position = position; + _ambient = color * 0.05f; + _diffuse = color * 0.8f; + _specular = color; + setType(lightType); +} + +Illuminant::~Illuminant() { + switchOff(); + if (_lightType == point) { + available.push(this->pointID); + } + +} + +void Illuminant::setAttenuation(float constant, float linear, float quadratic){ + _constant = constant; + _linear = linear; + _quadratic = quadratic; +} + +glm::vec3 Illuminant::direction(){ + return _direction; +} +glm::vec3 Illuminant::position(){ + return _position; +} +glm::vec3 Illuminant::ambient(){ + return _ambient; +} +glm::vec3 Illuminant::diffuse(){ + return _diffuse; +} +glm::vec3 Illuminant::specular(){ + return _specular; +} + +Illuminant::LightType Illuminant::type(){ + return _lightType; +} + +void Illuminant::move(glm::vec3 deltaPos){ + _position += deltaPos; +} +void Illuminant::setPosition(glm::vec3 Pos){ + _position = Pos; +} + +void Illuminant::setColor(glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 specular){ + _ambient = ambient; + _diffuse = diffuse; + _specular = specular; +} + +// 使用默认的分配系数 +void Illuminant::setColor(glm::vec3 color){ + _ambient = color * 0.05f; + _diffuse = color * 0.8f; + _specular = color; +} +void Illuminant::setDirection(glm::vec3 direction) { + _direction = direction; +} + +void Illuminant::setType(LightType type){ + + if (available.size() == 0 and type == point) { + Logger::error("Point light number exceed!\n"); + return; + } + _lightType = type; + if (type == point) { + pointID = available.front(); + available.pop(); + } +} + +void Illuminant::updateLight(ShaderProgram& shader) { + if (_lightType == dir) { + // directional light + shader.setUniform("dirLight.direction", _direction); + shader.setUniform("dirLight.ambient", _ambient); + shader.setUniform("dirLight.diffuse", _diffuse); + shader.setUniform("dirLight.specular",_specular); + } + else if (_lightType == point) + { // point light 1 + string prefix = "pointLights[" + std::to_string(pointID) + "]."; + + shader.setUniform(prefix+"position", _position); + shader.setUniform(prefix + "ambient", _ambient); + shader.setUniform(prefix + "diffuse", _diffuse); + shader.setUniform(prefix + "specular", _specular); + shader.setUniform(prefix + "constant",_constant); + shader.setUniform(prefix + "linear", _linear); + shader.setUniform(prefix + "quadratic", _quadratic); + + } + else { + // spotLight + shader.setUniform("spotLight.position", _position); + shader.setUniform("spotLight.direction", _direction); + shader.setUniform("spotLight.ambient", _ambient); + shader.setUniform("spotLight.diffuse", _diffuse); + shader.setUniform("spotLight.specular", _specular); + shader.setUniform("spotLight.constant", _constant); + shader.setUniform("spotLight.linear", _linear); + shader.setUniform("spotLight.quadratic", _quadratic); + shader.setUniform("spotLight.cutOff", glm::cos(glm::radians(12.5f))); + shader.setUniform("spotLight.outerCutOff", glm::cos(glm::radians(15.0f))); + } + + +} + +void Illuminant::switchOff() { + // 只要没有颜色就行了 + setColor(glm::vec3(0.0f, 0.0f, 0.0f)); + if (lastShader != NULL) { + updateLight(*lastShader); + } +} + +void init_queue() { + for (int i = 0; i < Illuminant::MAXPOINTLIGHT; i++) { + available.push(i); + Logger::info("23533423q543"); + } +} +double r = 1; + +// 初始设置所有变量 +void setAllLigntUniform(ShaderProgram& shader) { + r = r + 1; + double rr = sin(r / 20)*8; + + shader.setUniform("dirLight.direction",0,1,0); + shader.setUniform("dirLight.ambient", 0.0f, 0.0f, 0.0f); + shader.setUniform("dirLight.diffuse", 0.0f, 100.0f, 220.0f); + shader.setUniform("dirLight.specular", 00.0f, 0.0f, 0.0f); + // point light 1 + + shader.setUniform("pointLights[0].position", 0, 0, 0); + shader.setUniform("pointLights[0].ambient", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[0].diffuse", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[0].specular", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[0].constant", 1.0f); + shader.setUniform("pointLights[0].linear", 0.09f); + shader.setUniform("pointLights[0].quadratic", 0.032f); + // point light 2 + shader.setUniform("pointLights[1].position", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[1].ambient", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[1].diffuse", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[1].specular", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[1].constant", 1.0f); + shader.setUniform("pointLights[1].linear", 0.09f); + shader.setUniform("pointLights[1].quadratic", 0.032f); + // point light 3 + shader.setUniform("pointLights[2].position", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[2].ambient", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[2].diffuse", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[2].specular", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[2].constant", 1.0f); + shader.setUniform("pointLights[2].linear", 0.09f); + shader.setUniform("pointLights[2].quadratic", 0.032f); + // point light 4 + shader.setUniform("pointLights[3].position", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[3].ambient", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[3].diffuse", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[3].specular", 0.0f, 0.0f, 0.0f); + shader.setUniform("pointLights[3].constant", 1.0f); + shader.setUniform("pointLights[3].linear", 0.09f); + shader.setUniform("pointLights[3].quadratic", 0.032f); + // spotLight + shader.setUniform("spotLight.position", 0.0f, 0.0f, 3.0f); + shader.setUniform("spotLight.direction", -0.0f,-0.0f, -1.0f); + shader.setUniform("spotLight.ambient", 0.0f, 0.0f, 0.0f); + shader.setUniform("spotLight.diffuse", 0.0f, 0.0f, 0.0f); + shader.setUniform("spotLight.specular", 0.0f, 0.0f, 0.0f); + shader.setUniform("spotLight.constant", 1.0f); + shader.setUniform("spotLight.linear", 0.09f); + shader.setUniform("spotLight.quadratic", 0.032f); + shader.setUniform("spotLight.cutOff", glm::cos(glm::radians(12.5f))); + shader.setUniform("spotLight.outerCutOff", glm::cos(glm::radians(15.0f))); } \ No newline at end of file diff --git a/FinalProject/lightCaster.h b/FinalProject/lightCaster.h index ca4b7e1..986becf 100644 --- a/FinalProject/lightCaster.h +++ b/FinalProject/lightCaster.h @@ -1,27 +1,86 @@ #pragma once #include"shader.h" #include +#include +#include"logger.h" +#include + +using std::queue; +using std::string; // 发光物不需要纹理,所以说需要另外的shader // 在sceneviewer中被包含 class Illuminant { -private: - glm::vec3 _position; - glm::vec3 _color; public: + enum LightType { dir, spot, point }; + int pointID = -1; +private: + LightType _lightType = dir; + + glm::vec3 _direction = glm::vec3(0,2,-1); + glm::vec3 _position = glm::vec3(0.0f); + glm::vec3 _ambient = glm::vec3(0.05f, 0.05f, 0.05f); + glm::vec3 _diffuse = glm::vec3(0.8f, 0.8f, 0.8f); + glm::vec3 _specular = glm::vec3(0.8f, 0.8f, 0.8f); + + float _constant = 1.0f; + float _linear = 0.09f; + float _quadratic = 0.032f; + + +public: + // 修改此处必须同步修改fragment shader的数组定义语句,目前此值最大为4 + const static int MAXPOINTLIGHT = 4; + Illuminant(); - Illuminant(glm::vec3 position, glm::vec3 color); + // white color by default, + Illuminant(glm::vec3 position, LightType lightType); + // set up with one color,建议点光源使用这个 + Illuminant(glm::vec3 position,glm::vec3 color, LightType lightType); - inline glm::vec3 position(); - glm::vec3 color(); + // set up with one color,建议平行光源使用这个 + Illuminant(LightType lightType,glm::vec3 direction, glm::vec3 color); - void setPosition(glm::vec3 position); + // set up with one color,建议聚光灯光源使用这个 + Illuminant(glm::vec3 position, glm::vec3 direction,glm::vec3 color, LightType lightType); + + //set up by assign all colors + Illuminant(glm::vec3 position, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 specular, LightType lightType); + + // 析构函数中,如果是点光源,应该增加可用点光源数目。不过暂时没有实现,在上层进行控制 + // 无论如何,将此函数置为黑色 + ~Illuminant(); + void setAttenuation(float constant, float linear, float quadratic); + + glm::vec3 direction(); + glm::vec3 position(); + glm::vec3 ambient(); + glm::vec3 diffuse(); + glm::vec3 specular(); + LightType type(); + + void move(glm::vec3 deltaPos); + void setPosition(glm::vec3 Pos); + // 平行光与手电筒必须设置此项 + void setDirection(glm::vec3 direction); + + void setColor(glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 specular); + // 使用默认的分配系数 void setColor(glm::vec3 color); + // 将本光源的信息传递给着色器 + void updateLight(ShaderProgram& shader); + + + +private: + // 只能在最初设定光源类型,没有必要在期间修改 + void setType(LightType type); + + // 懒惰删除 + void switchOff(); }; -inline glm::vec3 Illuminant::position() { - return _position; -} -inline glm::vec3 Illuminant::color() { - return _color; -} \ No newline at end of file +// 初始设置所有变量 +void setAllLigntUniform(ShaderProgram& lightingShader); + +void init_queue(); \ No newline at end of file diff --git a/FinalProject/mesh.cpp b/FinalProject/mesh.cpp index 2bdffe8..bcd149e 100644 --- a/FinalProject/mesh.cpp +++ b/FinalProject/mesh.cpp @@ -22,6 +22,7 @@ Mesh::Mesh(const std::vector& vertices, const std::vector& text void Mesh::render(const ShaderProgram& shader) const { unsigned int diffuseNr = 1; unsigned int specularNr = 1; + shader.setUniform("material.shininess",_shininess); for (int i = 0; i < _textures.size(); i++) { OPENGL_EXTRA_FUNCTIONS->glActiveTexture(GL_TEXTURE0 + i); // activate proper texture unit before binding // retrieve texture number (the N in diffuse_textureN) diff --git a/FinalProject/mesh.h b/FinalProject/mesh.h index 574737a..014a206 100644 --- a/FinalProject/mesh.h +++ b/FinalProject/mesh.h @@ -14,7 +14,7 @@ private: std::vector _textures; // we can control shininess in mesh - float _shininess = 64.0f; + float _shininess = 32.0f; VertexArrayObject _vao = VertexArrayObject::empty(); diff --git a/FinalProject/sceneviewer.cpp b/FinalProject/sceneviewer.cpp index 5149f61..ef8448b 100644 --- a/FinalProject/sceneviewer.cpp +++ b/FinalProject/sceneviewer.cpp @@ -60,7 +60,7 @@ SceneViewer::~SceneViewer() { void SceneViewer::initializeGL() { initializeOpenGLFunctions(); - + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -78,6 +78,12 @@ void SceneViewer::initializeGL() { vertexShader.dispose(); fragmentShader.dispose(); + // 进行光照初始化 + setAllLigntUniform(_shaderProgram); + init_queue(); + // 设置光照 + + Model* backpackModel = new Model("D:\\code\\ComputerGraphic\\backpack\\backpack.obj"); Logger::info("Model loaded"); Renderable backpack(backpackModel); @@ -190,16 +196,20 @@ void SceneViewer::wheelEvent(QWheelEvent* event) { void SceneViewer::update_light() { - // 对于发光体, - //model is in Illuminate - // view is from camera - // projection is from caller + + setAllLigntUniform(_shaderProgram); + for (int i = 0; i < _illuminants.size(); i++) { + _illuminants[i].updateLight(_shaderProgram); + } - - _shaderProgram.setUniform("lightPos",_illuminants[0].position()); - _shaderProgram.setUniform("lightColor", _illuminants[0].color()); - - _shaderProgram.setUniform("viewPos", _camera.position()); - // 要给着色器传递viewPos - } + +void SceneViewer::addDirLight(glm::vec3 direction, glm::vec3 color) { + _illuminants.push_back(Illuminant(Illuminant::LightType::dir, direction,color)); +} +void SceneViewer::addPointLight(glm::vec3 position, glm::vec3 color) { + _illuminants.push_back(Illuminant(position, color, Illuminant::LightType::point)); +} +void SceneViewer::addSpotLight(glm::vec3 direction, glm::vec3 position, glm::vec3 color) { + _illuminants.push_back(Illuminant(position,direction, color, Illuminant::LightType::spot)); +} \ No newline at end of file diff --git a/FinalProject/sceneviewer.h b/FinalProject/sceneviewer.h index d42ad39..9f47fc4 100644 --- a/FinalProject/sceneviewer.h +++ b/FinalProject/sceneviewer.h @@ -45,6 +45,9 @@ public: SceneViewer(QWidget* parent = 0); ~SceneViewer(); void update_light(); + void addDirLight(glm::vec3 direction, glm::vec3 color); + void addPointLight(glm::vec3 position, glm::vec3 color); + void addSpotLight(glm::vec3 direction,glm::vec3 position, glm::vec3 color); protected: // OpenGL functions diff --git a/FinalProject/vertexshader.vs b/FinalProject/vertexshader.vs index 97c08db..056e569 100644 --- a/FinalProject/vertexshader.vs +++ b/FinalProject/vertexshader.vs @@ -15,7 +15,7 @@ void main() { FragPos = vec3(model * vec4(aPos, 1.0)); Normal = mat3(transpose(inverse(model))) * aNormal; - - TexCoords = aTexCoords; + TexCoords = aTexCoords; + gl_Position = projection * view * vec4(FragPos, 1.0); } \ No newline at end of file