对于openGL的API,倒是没有必要花太多时间,重点应该还是在着色器上

一、采样器、glActiveTexture和glBindTexture

在之前测试简单光照时可能出现的两个问题,尽管它们可能不会被察觉:

  1. 着色器中有定义对应的采样器,可是通过glGetUniformLocation方法获取不到对应位置值
  2. 着色器中不止1个采样器,在没有考虑其中某个特定采样器时,它居然也持有纹理

对于①,排除了低级错误后,检查下着色器中对应的采样器是否有参与实质运算,并且这个运算还必须是有效的,如果不满足这个条件,这个采样器就会被“优化”掉,相当于没有定义,当然也获取不到对应位置,例如下面这个着色器,texture_diffuse1就无法被获取:

#version 330 core
struct Material
{sampler2D texture_diffuse1;      //贴图sampler2D texture_specular1;     //镜面贴图
};
//……
void main()
{vec3 result = 0.05f * vec3(texture(material.texture_specular1, texIn));//……color = vec4(result, 1.0f);
}

对于②,需要再深入了解下采样器、glActiveTexture和glBindTexture的关系:

  • 若在着色器中定义了若干个采样器,那么这些采样器的位置值默认都为0
  • 如果没有执行过glActiveTexture以激活当前的采样器位置值,那么默认激活0
  • 主要通过glBindTexture来绑定贴图,每次glBindTexture,都会将对应贴图绑定在当前glActiveTexture激活的位置值上

别忘了openGL是个状态机

所以,下面的这份代码,在某种情况下就是有问题的了

由于下标i从0开始,因此在循环的第一次,第一张贴图就会绑定到所有位置值为0的采样器上,这样如果存在没有处理的采样器,那么这个采样器就会被绑定第一张贴图(因为它的位置值为0),然而事实上它不应该被绑定任何贴图

for (GLuint i = 0; i < this->textures.size(); i++)
{stringstream ss;string name = this->textures[i].type;if (name == "texture_diffuse")ss << diffuseNr++;else if (name == "texture_specular")ss << specularNr++;else if (name == "texture_reflection")ss << reflectionNr++;name = "material." + name + ss.str();glActiveTexture(GL_TEXTURE0 + i + 1);glUniform1i(glGetUniformLocation(shader.Program, name.c_str()), i + 1);//这样的话,着色器中的纹理名就必须有一个对应的规范,例如“texture_diffuse3”代表第三个漫反射贴图//方法不唯一,这是最好理解/最简单的一种规范/写法glBindTexture(GL_TEXTURE_2D, this->textures[i].id);
}

解决方法也很简单:

  • 对于没有读取到的贴图(例如一些物体它就是没有镜面贴图,这很正常),给予一张全黑贴图
  • 下标从1开始,无视0位置值

二、Blinn-Phong光照

前置:OpenGL基础20:镜面光照

之前在计算镜面光照时,都是参照的Phong光照算法,现在尝试换一种算法,为了方便测试,将之前的漫发射贴图改为镜面贴图,并只保留镜面贴图:

只看地面,可以发现存在一定的“镜面区域”,在这个区域中光照还是非常强的,但是只要离开这个范围,光照就会迅速减弱并截止,直至变得完全黑暗,这并不是特别科学,哪怕是只有镜面光也不应该出现这么黑暗的截面

出现这个现象还是在于算法,观察向量和反射向量间的夹角不能大于90度。如果点积的结果为负数,镜面光分量就会变为0.0,如下图所示,存在一定的区域光照完全不可见

对于漫发射光照,当然不会出现这个问题,因为若是角度>90°,那么观察者应该是在地面以下

Blinn-Phong着色是Phong着色模型的拓展,与冯氏模型非常相似,只是对镜面光模型的处理上有一些不同,它不再依赖于反射向量,而是采用了所谓的半程向量(Halfway Vector),即光线与视线夹角一半方向上的一个单位向量,当半程向量与法线向量越接近,镜面光分量就越大

这样就保证了不论观察者向哪个方向看,半程向量与表面法线之间的夹角都不会超过90度,若是角度>90°,那么观察者应该是在地面以下,和漫反射的计算一个道理

公式:

由于算法不同(半程向量和表面法线之间的角度经常会比视线和反射向量之间的夹角更小),在相同的发光参数下,Blinn-Phong着色的平均光照强度要小一点,镜面反射的高光区域倒是会更加锐利,并且当光照不够的情况下,仍然可能出现全黑区域,这只是因为此区域光照强度实在太小

着色器和效果如下:

//blinn-Phong
vec3 halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normal, halfwayDir), 0.0), 16.0);
//Phong
vec3 reflectDir = reflect(-lightDir, normal);
spec = pow(max(dot(viewDir, reflectDir), 0.0), 8.0);

上图左半部分为Phong光照,右半部分为Blinn-Phong光照

三、选择正确的光照参数

有的时候,觉得光照比较奇怪也有可能是光照参数设置的不对,例如明明是渲染夜晚的场景,却设置了较高的平行光强度,能发出平行光的基本只有太阳,所以关于平行光的设置一定要符合实际,前面貌似就犯了这个错误,用了夜晚星空的天空盒,却给予了很高的平行光强。除此之外,假设有2个光源,一个是蜡烛,一个是路灯,那么显然后者的亮度更高,前者的衰减更明显……

当然了,情况远远比这个复杂,包括光的颜色不一定都是白色、光源是火焰、有些光源它不属于点光源、平行光、聚光灯的任意一种等等

太多的glGetUniformLocation会感觉过于复杂,所以为了方便暂时把光照单独抽了出来:

修改了各部分光照的参数,更有夜晚的感觉了:

Light.h:

#ifndef LIGHT_H
#define LIGHT_H
#include<opengl/glew.h>
#include<GLFW/glfw3.h>
#include<opengl/freeglut.h>
#include<glm/glm.hpp>
#include<iostream>
#include<vector>
#include<string>
#include<glm/gtc/matrix_transform.hpp>
using namespace std;
enum Light_Type
{SUNLIGHT,POINTLIGHT,SPOTLIGHT
};
class Light
{private:int MAX_LIGHT_NUM = 16;typedef struct{glm::vec3 direction;glm::vec3 diffuse;glm::vec3 specular;}SunLight;typedef struct{float k0, k1, k2;glm::vec3 position;glm::vec3 diffuse;glm::vec3 specular;}PointLight;typedef struct{float k0, k1, k2;float cutOff, outCutOff;glm::vec3 direction;glm::vec3 position;glm::vec3 diffuse;glm::vec3 specular;}SpotLight;public:SunLight sunLight;vector<PointLight> pointLight;vector<SpotLight> spotLight;Light(){Init();}void Init(){sunLight.diffuse = glm::vec3(0.0);sunLight.specular = glm::vec3(0.0);sunLight.direction = glm::vec3(0.0);pointLight.clear();spotLight.clear();}int AddSunLight(glm::vec3 direction, glm::vec3 diffuse, glm::vec3 specular){sunLight.direction = direction;sunLight.diffuse = diffuse;sunLight.specular = specular;return 1;}int AddPointLight(glm::vec3 position, glm::vec3 diffuse, glm::vec3 specular, float k0 = 1.0f, float k1 = 0.09f, float k2 = 0.032f){PointLight temp;temp.position = position;temp.diffuse = diffuse;temp.specular = specular;temp.k0 = k0, temp.k1 = k1, temp.k2 = k2;pointLight.push_back(temp);return pointLight.size();}int AddSpotLight(glm::vec3 position, glm::vec3 direction, glm::vec3 diffuse, glm::vec3 specular, float k0 = 1.0f, float k1 = 0.007f, float k2 = 0.0002f, float cutOff = glm::cos(glm::radians(12.5f)), float outCutOff = glm::cos(glm::radians(16.0f))){SpotLight temp;temp.position = position;temp.direction = direction;temp.diffuse = diffuse;temp.specular = specular;temp.k0 = k0, temp.k1 = k1, temp.k2 = k2;temp.cutOff = cutOff, temp.outCutOff = outCutOff;spotLight.push_back(temp);return spotLight.size();}bool AppAllLightToShader(GLuint program){AppLightToShader(program, SUNLIGHT, 0, true);for (int i = 0; i < MAX_LIGHT_NUM; i++){AppLightToShader(program, POINTLIGHT, i, true);AppLightToShader(program, SPOTLIGHT, i, true);}if (sunLight.direction != glm::vec3(0.0))AppLightToShader(program, SUNLIGHT);for (int i = 0; i < pointLight.size(); i++)AppLightToShader(program, POINTLIGHT, i);for (int i = 0; i < spotLight.size(); i++)AppLightToShader(program, SPOTLIGHT, i);return true;}bool AppLightToShader(GLuint program, int type, int index = 0, bool isDel = false){if (type == (int)SUNLIGHT){if (sunLight.direction == glm::vec3(0.0) && !isDel){cout << "错误,无法找到对应的平行光数据" << endl;return false;}SunLight sun = sunLight;if (isDel){glUniform3f(glGetUniformLocation(program, "sunLight.diffuse"), 0.0, 0.0, 0.0);glUniform3f(glGetUniformLocation(program, "sunLight.specular"), 0.0, 0.0, 0.0);}else{glUniform3f(glGetUniformLocation(program, "sunLight.direction"), sun.direction.x, sun.direction.y, sun.direction.z);glUniform3f(glGetUniformLocation(program, "sunLight.diffuse"), sun.diffuse.x, sun.diffuse.y, sun.diffuse.z);glUniform3f(glGetUniformLocation(program, "sunLight.specular"), sun.specular.x, sun.specular.y, sun.specular.z);}}else if (type == (int)POINTLIGHT){if (pointLight.size() < index + 1 && !isDel){cout << "错误,无法找到对应的点光源数据" << endl;return false;}string uniform = "pointLights[" + to_string(index) + "]";if (isDel){glUniform3f(glGetUniformLocation(program, (uniform + ".diffuse").c_str()), 0.0, 0.0, 0.0);glUniform3f(glGetUniformLocation(program, (uniform + ".specular").c_str()), 0.0, 0.0, 0.0);}else{PointLight point = pointLight[index];glUniform3f(glGetUniformLocation(program, (uniform + ".position").c_str()), point.position.x, point.position.y, point.position.z);glUniform3f(glGetUniformLocation(program, (uniform + ".diffuse").c_str()), point.diffuse.x, point.diffuse.y, point.diffuse.z);glUniform3f(glGetUniformLocation(program, (uniform + ".specular").c_str()), point.specular.x, point.specular.y, point.specular.z);glUniform1f(glGetUniformLocation(program, (uniform + ".k0").c_str()), point.k0);glUniform1f(glGetUniformLocation(program, (uniform + ".k1").c_str()), point.k1);glUniform1f(glGetUniformLocation(program, (uniform + ".k2").c_str()), point.k2);}}else if (type == (int)SPOTLIGHT){if (spotLight.size() < index + 1 && !isDel){cout << "错误,无法找到对应的聚光数据" << endl;return false;}string uniform = "spotLights[" + to_string(index) + "]";if (isDel){glUniform3f(glGetUniformLocation(program, (uniform + ".diffuse").c_str()), 0.0, 0.0, 0.0);glUniform3f(glGetUniformLocation(program, (uniform + ".specular").c_str()), 0.0, 0.0, 0.0);}else{SpotLight spot = spotLight[index];glUniform3f(glGetUniformLocation(program, (uniform + ".position").c_str()), spot.position.x, spot.position.y, spot.position.z);glUniform3f(glGetUniformLocation(program, (uniform + ".direction").c_str()), spot.direction.x, spot.direction.y, spot.direction.z);glUniform3f(glGetUniformLocation(program, (uniform + ".diffuse").c_str()), spot.diffuse.x, spot.diffuse.y, spot.diffuse.z);glUniform3f(glGetUniformLocation(program, (uniform + ".specular").c_str()), spot.specular.x, spot.specular.y, spot.specular.z);glUniform1f(glGetUniformLocation(program, (uniform + ".k0").c_str()), spot.k0);glUniform1f(glGetUniformLocation(program, (uniform + ".k1").c_str()), spot.k1);glUniform1f(glGetUniformLocation(program, (uniform + ".k2").c_str()), spot.k2);glUniform1f(glGetUniformLocation(program, (uniform + ".cutOff").c_str()), spot.cutOff);glUniform1f(glGetUniformLocation(program, (uniform + ".outCutOff").c_str()), spot.outCutOff);}}return true;}
};
#endif

main.cpp:

#include<iostream>
#include<opengl/glew.h>
#define GLEW_STATIC
#include<GLFW/glfw3.h>
#include"Shader.h"
#include"Camera.h"
#include"Light.h"
#include<glm/glm.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<glm/gtc/type_ptr.hpp>
#include"Mesh.h"
#include"Model.h"
#include<opengl/freeglut.h>
#include<SOIL.h>bool keys[1024];
Camera camera;
GLfloat lastX, lastY;
bool firstMouse = true;
bool openSpotLight = true;
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
GLuint loadCubemap(vector<const GLchar*> faces);
GLuint getAttachmentTexture();
GLuint getMultiSampleTexture(GLuint samples);           //MSAA几重采样
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
GLuint loadTexture(const GLchar* path, GLboolean alpha);
void cameraMove();
const GLuint WIDTH = 800, HEIGHT = 600;int main()
{//------------------------------------------------------初始化---------------------------------------------------------glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);glfwMakeContextCurrent(window);glfwSetKeyCallback(window, key_callback);glfwSetCursorPosCallback(window, mouse_callback);glfwSetScrollCallback(window, scroll_callback);glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);glewExperimental = GL_TRUE;glewInit();int width, height;glfwGetFramebufferSize(window, &width, &height);glViewport(0, 0, width, height);Shader shaderObj("ObjVShader.vert", "ObjFShader.frag", "ObjGShader.geom");Shader shaderObjWithoutTex("ObjVShaderWithoutTex.vert", "ObjFShaderWithoutTex.frag");Shader shaderLight("LightVShader.vert", "LightFShader.frag");Shader shaderStone("StoneVShader.vert", "StoneFShader.frag");Shader shaderSkyBox("SkyboxVShader.vert", "SkyboxFShader.frag");Shader shaderScreen("ScreenVShader.vert", "ScreenFShader.frag");Shader shaderMirror("MirrorVShader.vert", "MirrorFShader.frag");//------------------------------------------------------数据定义---------------------------------------------------------GLfloat vertices[] = {-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f};GLfloat stoneVertices[] = {0.0f,  0.5f,  0.0f,  0.0f,  0.0f,0.0f, -0.5f,  0.0f,  0.0f,  1.0f,1.0f, -0.5f,  0.0f,  1.0f,  1.0f,0.0f,  0.5f,  0.0f,  0.0f,  0.0f,1.0f, -0.5f,  0.0f,  1.0f,  1.0f,1.0f,  0.5f,  0.0f,  1.0f,  0.0f};glm::vec3 positions[] = {glm::vec3(0.0f, 0.0f, 0.0f),glm::vec3(0.0f, 0.89f, 0.0f),glm::vec3(0.0f, 1.78f, 0.0f),glm::vec3(-2.0f, 0.0f, 0.0f),glm::vec3(-2.0f, 0.89f, 0.0f),glm::vec3(-3.0f, 0.0f, 0.0f),glm::vec3(-2.0f, 0.0f, 1.0f),glm::vec3(-1.0f, 0.0f, -4.0f),};glm::vec3 pointLightPositions[] = {glm::vec3(-1.0f, 1.8f, -2.0f),glm::vec3(0.0f, 0.8f, 2.0f),glm::vec3(-5.0f, 0.8f, 1.0f),};GLfloat quadVertices[] = {-1.0f, 1.0f, 0.0f, 1.0f,-1.0f, -1.0f, 0.0f, 0.0f,1.0f, -1.0f, 1.0f, 0.0f,-1.0f, 1.0f, 0.0f, 1.0f,1.0f, -1.0f, 1.0f, 0.0f,1.0f, 1.0f, 1.0f, 1.0f};GLfloat skyboxVertices[] = {-1.0f,  1.0f, -1.0f,-1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f,1.0f,  1.0f, -1.0f,-1.0f,  1.0f, -1.0f,-1.0f, -1.0f,  1.0f,-1.0f, -1.0f, -1.0f,-1.0f,  1.0f, -1.0f,-1.0f,  1.0f, -1.0f,-1.0f,  1.0f,  1.0f,-1.0f, -1.0f,  1.0f,1.0f, -1.0f, -1.0f,1.0f, -1.0f,  1.0f,1.0f,  1.0f,  1.0f,1.0f,  1.0f,  1.0f,1.0f,  1.0f, -1.0f,1.0f, -1.0f, -1.0f,-1.0f, -1.0f,  1.0f,-1.0f,  1.0f,  1.0f,1.0f,  1.0f,  1.0f,1.0f,  1.0f,  1.0f,1.0f, -1.0f,  1.0f,-1.0f, -1.0f,  1.0f,-1.0f,  1.0f, -1.0f,1.0f,  1.0f, -1.0f,1.0f,  1.0f,  1.0f,1.0f,  1.0f,  1.0f,-1.0f,  1.0f,  1.0f,-1.0f,  1.0f, -1.0f,-1.0f, -1.0f, -1.0f,-1.0f, -1.0f,  1.0f,1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f,-1.0f, -1.0f,  1.0f,1.0f, -1.0f,  1.0f};vector<glm::vec3> vegetation;vegetation.push_back(glm::vec3(-1.5f, -0.01f, -0.48f));vegetation.push_back(glm::vec3(1.5f, -0.01f, 0.51f));vegetation.push_back(glm::vec3(0.0f, -0.01f, 0.7f));vegetation.push_back(glm::vec3(-0.3f, -0.01f, -2.3f));vegetation.push_back(glm::vec3(0.5f, -0.01f, -0.6f));//------------------------------------------------------VAO & VBO---------------------------------------------------------GLuint lightVAO, lightVBO;glGenVertexArrays(1, &lightVAO);glGenBuffers(1, &lightVBO);glBindVertexArray(lightVAO);glBindBuffer(GL_ARRAY_BUFFER, lightVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);GLuint quadVAO, quadVBO;glGenVertexArrays(1, &quadVAO);glGenBuffers(1, &quadVBO);glBindVertexArray(quadVAO);glBindBuffer(GL_ARRAY_BUFFER, quadVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat)));glEnableVertexAttribArray(1);GLuint skyboxVAO, skyboxVBO;glGenVertexArrays(1, &skyboxVAO);glGenBuffers(1, &skyboxVBO);glBindVertexArray(skyboxVAO);glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);GLuint stoneVAO, stoneVBO;glGenVertexArrays(1, &stoneVAO);glGenBuffers(1, &stoneVBO);glBindVertexArray(stoneVAO);glBindBuffer(GL_ARRAY_BUFFER, stoneVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(stoneVertices), stoneVertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));glEnableVertexAttribArray(1);GLuint stone = loadTexture("Texture/stone3.png", true);glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);//------------------------------------------------------UBO---------------------------------------------------------GLuint UBO;/*--已在着色器中设置GLuint uniformCameraM = glGetUniformBlockIndex(shaderMirror.Program, "Matrices");GLuint uniformCameraM2 = glGetUniformBlockIndex(shaderObj.Program, "Matrices");GLuint uniformCameraM4 = glGetUniformBlockIndex(shaderStone.Program, "Matrices");glUniformBlockBinding(shaderMirror.Program, uniformCameraM, 0);glUniformBlockBinding(shaderMirror.Program, uniformCameraM2, 0);glUniformBlockBinding(shaderMirror.Program, uniformCameraM4, 0);*/glGenBuffers(1, &UBO);glBindBuffer(GL_UNIFORM_BUFFER, UBO);glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), NULL, GL_STATIC_DRAW);glBindBuffer(GL_UNIFORM_BUFFER, 0);glBindBufferRange(GL_UNIFORM_BUFFER, 0, UBO, 0, 2 * sizeof(glm::mat4));//------------------------------------------------------帧缓冲---------------------------------------------------------GLuint FBO, RBO;glGenFramebuffers(1, &FBO);glBindFramebuffer(GL_FRAMEBUFFER, FBO);GLuint textureColorBufferMultiSampled = getMultiSampleTexture(4);           //MSAA 4x抗锯齿glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0);glGenRenderbuffers(1, &RBO);glBindRenderbuffer(GL_RENDERBUFFER, RBO);glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, WIDTH, HEIGHT);glBindRenderbuffer(GL_RENDERBUFFER, 0);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO);if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;glBindFramebuffer(GL_FRAMEBUFFER, 0);GLuint screenFBO;glGenFramebuffers(1, &screenFBO);glBindFramebuffer(GL_FRAMEBUFFER, screenFBO);GLuint textureColorBuffer = getAttachmentTexture();glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorBuffer, 0);if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)cout << "ERROR::FRAMEBUFFER:: Intermediate framebuffer is not complete!" << endl;glBindFramebuffer(GL_FRAMEBUFFER, 0);//------------------------------------------------------设置状态、加载模型和天空盒---------------------------------------------------------glEnable(GL_CULL_FACE);glEnable(GL_MULTISAMPLE);glEnable(GL_STENCIL_TEST);glEnable(GL_PROGRAM_POINT_SIZE);glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);             //模板测试和深度测试都成功时,将对应像素的模板值设置为用glStencilFunc函数设置的ref值glEnable(GL_BLEND);glEnable(GL_PROGRAM_POINT_SIZE);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);Model wood("Object/wood/file.fbx", "Object/wood/file.fbx");Model ground("Object/ground/ground.fbx", "Object/ground");Model mirror("Object/mirror/file.fbx", "Object/mirror");vector<const GLchar*> faces;faces.push_back("Texture/Skybox/StarryNight1024/Right.jpg");faces.push_back("Texture/Skybox/StarryNight1024/Left.jpg");faces.push_back("Texture/Skybox/StarryNight1024/Up.jpg");faces.push_back("Texture/Skybox/StarryNight1024/Down.jpg");faces.push_back("Texture/Skybox/StarryNight1024/Back.jpg");faces.push_back("Texture/Skybox/StarryNight1024/Front.jpg");GLuint cubemapTexture = loadCubemap(faces);//------------------------------------------------------实例化---------------------------------------------------------glm::mat4* modelMatrices;modelMatrices = new glm::mat4[1000];glm::mat4 model = glm::mat4(1.0f);for (GLuint i = 0; i <= 7; i++){model = glm::translate(glm::mat4(1.0f), positions[i]);model = glm::scale(model, glm::vec3(0.01f));modelMatrices[i] = model;}wood.UpdateModelMatrix(modelMatrices, 8);GLint groundIndex = 0;for (int i = -4; i <= 4; i++){for (int j = -2; j <= 4; j++){model = glm::translate(glm::mat4(1.0f), glm::vec3(i * 3.52f, -0.05f, j * 3.72f));model = glm::scale(model, glm::vec3(0.1f));model = glm::rotate(model, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));modelMatrices[groundIndex++] = model;}}ground.UpdateModelMatrix(modelMatrices, groundIndex);delete[] modelMatrices;Light light;light.AddSunLight(glm::vec3(-0.2f, -1.0f, -0.3f), glm::vec3(0.03f, 0.03f, 0.03f), glm::vec3(0.036f, 0.036f, 0.036f));for (int i = 0; i <= 2; i++)light.AddPointLight(glm::vec3(pointLightPositions[i].x, pointLightPositions[i].y, pointLightPositions[i].z), glm::vec3(0.8f, 0.8f, 0.8f), glm::vec3(1.0f, 1.0f, 1.0f));light.AddSpotLight(glm::vec3(camera.Position.x, camera.Position.y, camera.Position.z), glm::vec3(camera.Front.x, camera.Front.y, camera.Front.z), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f));//------------------------------------------------------渲染ing---------------------------------------------------------while (!glfwWindowShouldClose(window)){glfwPollEvents();glEnable(GL_DEPTH_TEST);glBindFramebuffer(GL_FRAMEBUFFER, FBO);glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glStencilMask(0xFF);                  //设置模板缓冲区可写入,如果设置为不可写入之后清空模板缓冲区,将会清空失败!毕竟不可写入了glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);cameraMove();shaderLight.Use();glm::mat4 view = camera.GetViewMatrix();glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);glm::mat4 model = glm::mat4(1.0f);GLint modelLoc = glGetUniformLocation(shaderLight.Program, "model");glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glBindBuffer(GL_UNIFORM_BUFFER, UBO);glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(view));glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(projection));glBindBuffer(GL_UNIFORM_BUFFER, 0);glBindVertexArray(lightVAO);glStencilFunc(GL_ALWAYS, 0xFF, 0xFF);                   //无论模板测试如何,一定可以绘制;glUniform3f(glGetUniformLocation(shaderLight.Program, "lightColor"), 1.0f, 1.0f, 1.0f);for (int i = 0; i <= 2; i++){model = glm::translate(glm::mat4(1.0f), pointLightPositions[i]);model = glm::scale(model, glm::vec3(0.2f));glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 36);}glStencilFunc(GL_NOTEQUAL, 0xFF, 0xFF);                 //对应像素模板值若等于256,则对应像素不绘制glStencilMask(0x00);                                    //模板缓冲区不再可写glUniform3f(glGetUniformLocation(shaderLight.Program, "lightColor"), 1.0f, 1.0f, 0.0f);for (int i = 0; i <= 2; i++){model = glm::translate(glm::mat4(1.0f), pointLightPositions[i]);model = glm::scale(model, glm::vec3(0.22f));glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 36);}glStencilFunc(GL_ALWAYS, 0xFF, 0xFF);shaderObj.Use();light.spotLight.clear();if (openSpotLight){light.AddSpotLight(glm::vec3(camera.Position.x, camera.Position.y, camera.Position.z), glm::vec3(camera.Front.x, camera.Front.y, camera.Front.z),glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f));}light.AppAllLightToShader(shaderObj.Program);glUniform3f(glGetUniformLocation(shaderObj.Program, "viewPos"), camera.Position.x, camera.Position.y, camera.Position.z);wood.Draw(shaderObj, 8);ground.Draw(shaderObj, groundIndex + 1);shaderMirror.Use();model = glm::translate(glm::mat4(1.0f), glm::vec3(-0.51f, -0.3f, -3.71f));model = glm::scale(model, glm::vec3(0.0035f));model = glm::rotate(model, glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f));model = glm::rotate(model, glm::radians(3.0f), glm::vec3(-1.0f, 0.0f, 0.0f));glUniformMatrix4fv(glGetUniformLocation(shaderMirror.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));mirror.Draw(shaderObj);shaderStone.Use();glBindVertexArray(stoneVAO);glBindTexture(GL_TEXTURE_2D, stone);for (GLuint i = 0; i < vegetation.size(); i++){model = glm::mat4(1.0f);model = glm::translate(model, vegetation[i]);model = glm::rotate(model, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));glUniformMatrix4fv(glGetUniformLocation(shaderStone.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 6);}shaderSkyBox.Use();glDepthFunc(GL_LEQUAL);view = glm::mat4(glm::mat3(camera.GetViewMatrix()));glUniformMatrix4fv(glGetUniformLocation(shaderSkyBox.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));glUniformMatrix4fv(glGetUniformLocation(shaderSkyBox.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));glBindVertexArray(skyboxVAO);glActiveTexture(GL_TEXTURE0);glUniform1i(glGetUniformLocation(shaderSkyBox.Program, "skybox"), 0);glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);glDrawArrays(GL_TRIANGLES, 0, 36);glDepthFunc(GL_LESS);glBindFramebuffer(GL_READ_FRAMEBUFFER, FBO);glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screenFBO);glBlitFramebuffer(0, 0, WIDTH, HEIGHT, 0, 0, WIDTH, HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST);glBindFramebuffer(GL_FRAMEBUFFER, 0);glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);shaderScreen.Use();glBindVertexArray(quadVAO);glBindTexture(GL_TEXTURE_2D, textureColorBuffer);glDrawArrays(GL_TRIANGLES, 0, 6);glBindTexture(GL_TEXTURE_2D, 0);glBindVertexArray(0);glfwSwapBuffers(window);}//------------------------------------------------------解绑---------------------------------------------------------glDeleteFramebuffers(1, &FBO);glDeleteFramebuffers(1, &screenFBO);glDeleteVertexArrays(1, &lightVAO);glDeleteVertexArrays(1, &stoneVAO);glDeleteBuffers(1, &stoneVBO);glDeleteBuffers(1, &lightVBO);glfwTerminate();return 0;
}GLuint getMultiSampleTexture(GLuint samples)
{GLuint texture;glGenTextures(1, &texture);glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture);glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, WIDTH, HEIGHT, GL_TRUE);glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);return texture;
}GLuint loadCubemap(vector<const GLchar*> faces)
{GLuint textureID;glGenTextures(1, &textureID);int width, height;unsigned char* image;glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);for (GLuint i = 0; i < faces.size(); i++){image = SOIL_load_image(faces[i], &width, &height, 0, SOIL_LOAD_RGB);glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);SOIL_free_image_data(image);}glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);glBindTexture(GL_TEXTURE_CUBE_MAP, 0);return textureID;
}GLuint loadTexture(const GLchar* path, GLboolean alpha)
{GLuint textureID;glGenTextures(1, &textureID);int width, height;unsigned char* image;if (alpha)image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGBA);elseimage = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB);glBindTexture(GL_TEXTURE_2D, textureID);glTexImage2D(GL_TEXTURE_2D, 0, alpha ? GL_RGBA : GL_RGB, width, height, 0, alpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, image);glGenerateMipmap(GL_TEXTURE_2D);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, alpha ? GL_CLAMP_TO_EDGE : GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, alpha ? GL_CLAMP_TO_EDGE : GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glBindTexture(GL_TEXTURE_2D, 0);SOIL_free_image_data(image);return textureID;
}GLuint getAttachmentTexture()
{GLuint textureID;glGenTextures(1, &textureID);glBindTexture(GL_TEXTURE_2D, textureID);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glBindTexture(GL_TEXTURE_2D, 0);return textureID;
}GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;
void cameraMove()
{GLfloat currentFrame = glfwGetTime();deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;GLfloat cameraSpeed = 1.0f * deltaTime;if (keys[GLFW_KEY_W])camera.ProcessKeyboard(Camera_Movement(FORWARD), deltaTime);if (keys[GLFW_KEY_S])camera.ProcessKeyboard(Camera_Movement(BACKWARD), deltaTime);if (keys[GLFW_KEY_A])camera.ProcessKeyboard(Camera_Movement(LEFT), deltaTime);if (keys[GLFW_KEY_D])camera.ProcessKeyboard(Camera_Movement(RIGHT), deltaTime);
}void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)glfwSetWindowShouldClose(window, GL_TRUE);if (key == GLFW_KEY_TAB && action == GLFW_PRESS)openSpotLight = !openSpotLight;if (action == GLFW_PRESS)           //如果当前是按下操作keys[key] = true;else if (action == GLFW_RELEASE)            //松开键盘keys[key] = false;
}void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{camera.ProcessMouseScroll(yoffset);
}void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{if (firstMouse){lastX = xpos;lastY = ypos;firstMouse = false;}GLfloat xoffset = xpos - lastX;GLfloat yoffset = lastY - ypos;lastX = xpos;lastY = ypos;GLfloat sensitivity = 0.05;xoffset *= sensitivity;yoffset *= sensitivity;camera.ProcessMouseMovement(xoffset, yoffset);
}

现在可以通过Tab按键来控制聚光灯的开关了

OpenGL基础44:光照矫正(上)相关推荐

  1. OpenGL基础知识梳理——Windows上搭建opengles运行环境

    1.概念介绍 1)OpenGLES 官方介绍:https://www.khronos.org/opengles/ OpenGLES(OpenGL for embeded systems)是用于嵌入式设 ...

  2. OpenGL基础45:光照矫正(下)之Gamma校正

    接上文:OpenGL基础44:光照矫正(上) 四.Gamma矫正 4.1.人的视觉特性 和很多错视图一样,对于下面这张灰阶图,如果1表示纯白,0表示纯黑,那么这张图片的哪个位置代表的是0.5,也就是自 ...

  3. OpenGL基础33:帧缓冲(上)之离屏渲染

    在之前的章节,所有的物体都是中规中矩的显示的,只考虑了光照对物体的影响,那假设想要显示特殊的效果该怎么操作呢?例如马赛克风.将所有的物体都显示为黑白色,就像上世纪80年代的灰白电视一样,又或者说将整个 ...

  4. OpenGL基础20:镜面光照

    前置:OpenGL基础19:法向量与漫反射 一.镜面光照 前面物体已经拥有了环境光和漫反射光,现在再加上镜面光照就完美了,镜面光照的效果是:当我们去看光被物体所反射的那个方向的时候,会看到一个高光 和 ...

  5. OpenGL 基础光照ColorsBasic Lighting

    OpenGL 基础光照ColorsBasic Lighting 基础光照ColorsBasic Lighting简介 环境光照 漫反射光照 法向量 计算漫反射光照 最后一件事 镜面光照 基础光照Col ...

  6. OpenGL基础50:HDR

    一.HDR与LDR 由于显示器只能显示值为0.0到1.0间的颜色,因此当数据存储在帧缓冲(Framebuffer)中时,亮度和颜色的值也是默认被限制在0.0到1.0之间的,这个颜色范围即是LDR(Lo ...

  7. OpenGL基础23:平行光与点光源

    前面几章主要是针对物体,现在开始针对光源! 一.平行光 在 OpenGL基础18:光照基础 这一章里面讲了几种常见光源,先看平行光吧 一个很好的例子就是太阳光,因为离我们的距离过远,所以太阳光的特点就 ...

  8. PBR理论基础3:基于图像的光照(上)

    一.基于图像的光照(Image based lighting, IBL) 只要了解了下面这些,就很容易理解基于图像的光照了: 直接光与间接光的区别(UnityShader9:光照基础回顾) PBR理论 ...

  9. OpenGL基础54:点光源阴影

    前置: OpenGL基础53:阴影映射(下) 一.万象阴影贴图 之前成功实现了平行光阴影,生成阴影贴图时使用的矩阵是正交矩阵,若是想要实现点光源的阴影效果,那么理论上只需要修改投影矩阵为透视矩阵就好了 ...

最新文章

  1. 自定义用户验证控件CustomValidator
  2. 大数据教父Micheal Stonebraker告诉你大数据的秘密
  3. HP ML110/120 G7配置阵列卡安装server 2003
  4. Linux之ln命令
  5. 猜猜乐游戏php源码,C/C++百行代码实现热门游戏消消乐功能的示例代码
  6. python下几种打开文件的方式
  7. SpringCloud -创建统一的依赖管理
  8. 转:深度学习与自然语言处理之五:从RNN到LSTM
  9. Axure下拉框级联操作
  10. 传锤子科技解散成都分公司 才搬迁一年罗永浩就顶不住了
  11. python 字符串操作list【:-1】的几种用法
  12. mysql插入报主键冲突,解决方法主键索引重新排序
  13. 关于 MySQL 8.0 新特性“隐藏索引”的一点思考
  14. 雨松MOMO《Unity 3D游戏开发》源码公布
  15. 参考文献中英文人名_参考文献中英文人名的缩写规则
  16. 人工智能:博弈--人机中国象棋
  17. 智慧交通:数智化地铁大屏管控运维平台
  18. bootstrap框架写手机端app模板也很漂亮
  19. 试题 基础练习 圆的面积-蓝桥杯
  20. 一篇超频菜鸟必看的基础知识大全!

热门文章

  1. python是哪个专业学的-我们为什么要选择学习python?学习python有什么用?
  2. python编程入门经典-总算理解python编程入门经典教程
  3. python入门经典代码-【python】编程语言入门经典100例--11
  4. python语言-Python语言的一些基本常用语句
  5. python中文读音-python中文谐音 Python 的中文谐音是什么?
  6. 语音识别开放平台调研以及主要技术
  7. linux shell eval,【shell】bash shell 中 set 和 eval 命令的使用
  8. leaks Android内存泄露,Android LeakCanary 检测内存泄露
  9. 从输入url到页面加载完成发生了什么
  10. SpringBoot 实现接口参数加密解密功能