酒店網(wǎng)站開(kāi)發(fā)常用的seo工具推薦
文章目錄
- 一、材質(zhì)
- 二、設(shè)置材質(zhì)
- 三、光的屬性
- 四、不同的光源顏色
一、材質(zhì)
在現(xiàn)實(shí)世界里,每個(gè)物體會(huì)對(duì)光產(chǎn)生不同的反應(yīng)。
比如,鋼制物體看起來(lái)通常會(huì)比陶土花瓶更閃閃發(fā)光,一個(gè)木頭箱子也不會(huì)與一個(gè)鋼制箱子反射同樣程度的光。
有些物體反射光的時(shí)候不會(huì)有太多的散射(Scatter),因而產(chǎn)生較小的高光點(diǎn),而有些物體則會(huì)散射很多,產(chǎn)生一個(gè)有著更大半徑的高光點(diǎn)。
如果我們想要在OpenGL中模擬多種類型的物體,我們必須針對(duì)每種表面定義不同的材質(zhì)(Material)屬性。
在跟著LearnOpenGL學(xué)習(xí)10–基礎(chǔ)光照這一篇中,我們定義了一個(gè)物體和光的顏色,并結(jié)合環(huán)境光與鏡面強(qiáng)度分量,來(lái)決定物體的視覺(jué)輸出。
當(dāng)描述一個(gè)表面時(shí),我們可以分別為三個(gè)光照分量定義一個(gè)材質(zhì)顏色(Material Color):
- 環(huán)境光照(Ambient Lighting)
- 漫反射光照(Diffuse Lighting)
- 鏡面光照(Specular Lighting)
通過(guò)為每個(gè)分量指定一個(gè)顏色,我們就能夠?qū)Ρ砻娴念伾敵鲇屑?xì)粒度的控制了。
現(xiàn)在,我們?cè)偬砑右粋€(gè)反光度(Shininess)分量,結(jié)合上述的三個(gè)顏色,我們就有了全部所需的材質(zhì)屬性了:
片段著色器
struct Material { //材質(zhì)描述結(jié)構(gòu)體vec3 ambient; //環(huán)境光照vec3 diffuse; //漫反射光照vec3 specular; //鏡面反射光照float shininess; //反光度
};uniform Material material; //材質(zhì)
在片段著色器中,我們創(chuàng)建一個(gè)結(jié)構(gòu)體(Struct)來(lái)儲(chǔ)存物體的材質(zhì)屬性。
我們也可以把它們儲(chǔ)存為獨(dú)立的uniform值,但是作為一個(gè)結(jié)構(gòu)體來(lái)儲(chǔ)存會(huì)更有條理一些。
我們首先定義結(jié)構(gòu)體的布局(Layout),然后簡(jiǎn)單地以剛創(chuàng)建的結(jié)構(gòu)體作為類型聲明一個(gè)uniform變量。
如你所見(jiàn),我們?yōu)轳T氏光照模型的每個(gè)分量都定義一個(gè)顏色向量:
ambient
材質(zhì)向量:定義了在環(huán)境光照下這個(gè)表面反射的是什么顏色,通常與表面的顏色相同。diffuse
材質(zhì)向量:定義了在漫反射光照下表面的顏色。漫反射顏色(和環(huán)境光照一樣)也被設(shè)置為我們期望的物體顏色。specular
材質(zhì)向量:設(shè)置的是表面上鏡面高光的顏色(或者甚至可能反映一個(gè)特定表面的顏色)。shininess
材質(zhì)向量:影響鏡面高光的散射/半徑。
有這4個(gè)元素定義一個(gè)物體的材質(zhì),我們能夠模擬很多現(xiàn)實(shí)世界中的材質(zhì)。如下表格展示了一系列材質(zhì)屬性,它們模擬了現(xiàn)實(shí)世界中的真實(shí)材質(zhì)。下圖展示了幾組現(xiàn)實(shí)世界的材質(zhì)參數(shù)值對(duì)我們的立方體的影響:
材質(zhì)表格
名字 | 環(huán)境光照 | 漫反射光照 | 鏡面反射光照 | 反射強(qiáng)度 |
---|---|---|---|---|
emerald(翡翠) | 0.0215, 0.1745, 0.0215 | 0.07568, 0.61424, 0.07568 | 0.633, 0.727811, 0.633 | 0.6 |
jade(玉) | 0.135, 0.2225, 0.1575 | 0.54, 0.89, 0.63 | 0.316228, 0.316228, 0.316228 | 0.1 |
obsidian(黑曜石) | 0.05375, 0.05, 0.06625 | 0.18275, 0.17, 0.22525 | 0.332741, 0.328634, 0.346435 | 0.3 |
pearl(珍珠) | 0.25, 0.20725, 0.20725 | 1, 0.829, 0.829 | 0.296648, 0.296648, 0.296648 | 0.088 |
ruby(紅寶石) | 0.1745, 0.01175, 0.01175 | 0.61424, 0.04136, 0.04136 | 0.727811, 0.626959, 0.626959 | 0.6 |
turquoise()綠松石 | 0.1, 0.18725, 0.1745 | 0.396, 0.74151, 0.69102 | 0.297254, 0.30829, 0.306678 | 0.1 |
brass(黃銅) | 0.329412, 0.223529, 0.027451 | 0.780392, 0.568627, 0.113725 | 0.992157, 0.941176, 0.807843 | 0.21794872 |
bronze(青銅) | 0.2125, 0.1275, 0.054 | 0.714, 0.4284, 0.18144 | 0.393548, 0.271906, 0.166721 | 0.2 |
chrome(鉻) | 0.25, 0.25, 0.25 | 0.4, 0.4, 0.4 | 0.774597, 0.774597, 0.774597 | 0.6 |
copper(銅) | 0.19125, 0.0735, 0.0225 | 0.7038, 0.27048, 0.0828 | 0.256777, 0.137622, 0.086014 | 0.1 |
gold(黃金) | 0.24725, 0.1995, 0.0745 | 0.75164, 0.60648,0.22648 | 0.628281, 0.555802, 0.366065 | 0.4 |
silver(銀) | 0.19225, 0.19225, 0.19225 | 0.50754, 0.50754, 0.50754 | 0.508273, 0.508273, 0.508273 | 0.4 |
black plastic(黑色塑料) | 0.0, 0.0, 0.0 | 0.01, 0.01, 0.01 | 0.50, 0.50, 0.50 | 0.25 |
cyan plastic(青色塑料) | 0.0, 0.1, 0.06 | 0.0, 0.50980392, 0.50980392 | 0.50196078, 0.50196078, 0.50196078 | 0.25 |
green plastic(綠色塑料) | 0.0, 0.0, 0.0 | 0.1, 0.35, 0.1 | 0.45, 0.55, 0.45 | 0.25 |
red plastic(紅色塑料) | 0.0, 0.0, 0.0 | 0.5, 0.0, 0.0 | 0.7, 0.6, 0.6 | 0.25 |
white plastic(白色塑料) | 0.0, 0.0, 0.0 | 0.55, 0.55, 0.55 | 0.70, 0.70, 0.70 | 0.25 |
yellow plastic(黃色塑料) | 0.0, 0.0, 0.0 | 0.5, 0.5, 0.0 | 0.60, 0.60, 0.50 | 0.25 |
black rubber(黑色橡膠) | 0.02, 0.02, 0.02 | 0.01, 0.01, 0.01 | 0.4, 0.4, 0.4 | 0.78125 |
cyan rubber(青色橡膠) | 0.0, 0.05, 0.05 | 0.4, 0.5, 0.5 | 0.04, 0.7, 0.7 | 0.78125 |
green rubber(綠色橡膠) | 0.0, 0.05, 0.0 | 0.4, 0.5, 0.4 | 0.04, 0.7, 0.04 | 0.78125 |
red rubber(紅色橡膠) | 0.05, 0.0, 0.0 | 0.5, 0.4, 0.4 | 0.7, 0.04, 0.04 | 0.78125 |
white rubber(白色橡膠) | 0.05, 0.05, 0.05 | 0.5, 0.5, 0.5 | 0.7, 0.7, 0.7 | 0.78125 |
yellow rubber(黃色橡膠) | 0.05, 0.05, 0.0 | 0.5, 0.5, 0.4 | 0.7, 0.7, 0.04 | 0.78125 |
可以看到,通過(guò)正確地指定一個(gè)物體的材質(zhì)屬性,我們對(duì)這個(gè)物體的感知也就不同了。效果非常明顯,但是要想獲得更真實(shí)的效果,我們需要以更復(fù)雜的形狀替換這個(gè)立方體。
搞清楚一個(gè)物體正確的材質(zhì)設(shè)定是個(gè)困難的工程,這主要需要實(shí)驗(yàn)和豐富的經(jīng)驗(yàn)。用了不合適的材質(zhì)而毀了物體的視覺(jué)質(zhì)量是件經(jīng)常發(fā)生的事。
讓我們?cè)囍谥髦袑?shí)現(xiàn)這樣的一個(gè)材質(zhì)系統(tǒng)。
二、設(shè)置材質(zhì)
我們?cè)谄沃髦袆?chuàng)建了一個(gè)材質(zhì)結(jié)構(gòu)體的uniform
,所以下面我們希望修改一下光照的計(jì)算來(lái)遵從新的材質(zhì)屬性。由于所有材質(zhì)變量都儲(chǔ)存在一個(gè)結(jié)構(gòu)體中,我們可以從uniform
變量material
中訪問(wèn)它們:
片段著色器
#version 330 corein vec3 FragPos;
in vec3 Normal;out vec4 FragColor;uniform vec3 objectColor;
uniform vec3 lightColor;
uniform vec3 lightPos;
uniform vec3 viewPos; //觀察者坐標(biāo)struct Material { //材質(zhì)描述結(jié)構(gòu)體vec3 ambient; //環(huán)境光照vec3 diffuse; //漫反射光照vec3 specular; //鏡面反射光照float shininess; //反光度
};uniform Material material; //材質(zhì)void main()
{//環(huán)境光照vec3 ambient = material.ambient * lightColor;//漫反射光照vec3 norm = normalize(Normal);vec3 lightDir = normalize(lightColor - FragPos);float diff = max(dot(norm, lightDir), 0.0);vec3 diffuse = (diff *material.diffuse) * lightColor;//鏡面反射光照vec3 viewDir = normalize(viewPos - FragPos);vec3 reflectDir = reflect(-lightDir, norm);float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);vec3 specular = (material.specular * spec) * lightColor;vec3 result = ambient + diffuse + specular;FragColor = vec4(result, 1.0);
}
可以看到,我們現(xiàn)在在需要的地方訪問(wèn)了材質(zhì)結(jié)構(gòu)體中的所有屬性,并且這次是根據(jù)材質(zhì)的顏色來(lái)計(jì)算最終的輸出顏色的。物體的每個(gè)材質(zhì)屬性都乘上了它們各自對(duì)應(yīng)的光照分量。
我們現(xiàn)在可以通過(guò)設(shè)置適當(dāng)?shù)膗niform來(lái)設(shè)置應(yīng)用中物體的材質(zhì)了。GLSL中一個(gè)結(jié)構(gòu)體在設(shè)置uniform時(shí)并無(wú)任何區(qū)別,結(jié)構(gòu)體只是充當(dāng)uniform變量們的一個(gè)命名空間。所以如果想填充這個(gè)結(jié)構(gòu)體的話,我們必須設(shè)置每個(gè)單獨(dú)的uniform,但要以結(jié)構(gòu)體名為前綴:
lightingShader.setVec3("material.ambient", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);
lightingShader.setFloat("material.shininess", 32.0f);
我們將環(huán)境光和漫反射分量設(shè)置成我們想要讓物體所擁有的顏色,而將鏡面分量設(shè)置為一個(gè)中等亮度的顏色,我們不希望鏡面分量過(guò)于強(qiáng)烈。我們?nèi)詫⒎垂舛缺3譃?2。
現(xiàn)在我們能夠輕松地在應(yīng)用中影響物體的材質(zhì)了。運(yùn)行程序,你會(huì)得到像這樣的結(jié)果:
全部代碼
main.cpp
#include "mainwindow.h"
#include <QApplication>//在包含GLFW的頭文件之前包含了GLAD的頭文件;
//GLAD的頭文件包含了正確的OpenGL頭文件(例如GL/gl.h);
//所以需要在其它依賴于OpenGL的頭文件之前包含GLAD;
#include <glad/glad.h>
#include <GLFW/glfw3.h>//GLM
//#include <glm/glm.hpp>
//#include <glm/gtc/matrix_transform.hpp>
//#include <glm/gtc/type_ptr.hpp>#include <iostream>
#include <QDebug>#include "shader.h"
#include "stb_image.h"
#include "camera.h"void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);// settings
const unsigned int SCR_WIDTH = 1920;
const unsigned int SCR_HEIGHT = 1080;//Camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0;
float lastY = SCR_HEIGHT / 2.0;
bool firstMouse = true;float deltaTime = 0.0f; // 當(dāng)前幀與上一幀的時(shí)間差
float lastFrame = 0.0f; // 上一幀的時(shí)間//Light
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);using namespace std;int main(int argc, char *argv[])
{QApplication a(argc, argv);//MainWindow w;//w.show();//初始化GLFW//--------------------glfwInit();//配置GLFW//--------------------//告訴GLFW使用的OpenGL本是3.3glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//告訴GLFW使用的是核心模式(Core-profile)glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//創(chuàng)建一個(gè)新的OpenGL環(huán)境和窗口//-----------------------------------GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate(); //glfw銷毀窗口和OpenGL環(huán)境,并釋放資源return -1;}//設(shè)置參數(shù)window中的窗口所關(guān)聯(lián)的OpenGL環(huán)境為當(dāng)前環(huán)境//-----------------------------------glfwMakeContextCurrent(window);//設(shè)置窗口尺寸改變大小時(shí)的回調(diào)函數(shù)(窗口尺寸發(fā)送改變時(shí)會(huì)自動(dòng)調(diào)用)//-----------------------------------glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//設(shè)置鼠標(biāo)事件的回調(diào)函數(shù)(鼠標(biāo)移動(dòng)時(shí)會(huì)自動(dòng)調(diào)用)//-----------------------------------glfwSetCursorPosCallback(window, mouse_callback);//設(shè)置鼠標(biāo)滾輪事件的回調(diào)函數(shù)(鼠標(biāo)滾輪移動(dòng)時(shí)會(huì)自動(dòng)調(diào)用)//-----------------------------------glfwSetScrollCallback(window, scroll_callback);//告訴GLFW捕捉鼠標(biāo)glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//glad加載系統(tǒng)相關(guān)的OpenGL函數(shù)指針//---------------------------------------if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}//開(kāi)啟深度測(cè)試glEnable(GL_DEPTH_TEST);Shader objectShader("C:/Qt_Pro/OpenGL_GLFW/shader/shader.vs","C:/Qt_Pro/OpenGL_GLFW/shader/shader.fs");Shader lightShader("C:/Qt_Pro/OpenGL_GLFW/shader/light_cube.vs","C:/Qt_Pro/OpenGL_GLFW/shader/light_cube.fs");//頂點(diǎn)數(shù)據(jù)//---------------------------------------------------------------------float vertices[] = {//頂點(diǎn)數(shù)據(jù) //頂點(diǎn)法向量-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f};//物體//----------------------------------------------------------------unsigned int VBO, objectVAO;glGenVertexArrays(1, &objectVAO); //創(chuàng)建頂點(diǎn)數(shù)組對(duì)象glGenBuffers(1, &VBO); //創(chuàng)建頂點(diǎn)緩沖對(duì)象glBindBuffer(GL_ARRAY_BUFFER, VBO); //將VBO與GL_ARRAY_BUFFER緩沖區(qū)綁定glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //將頂點(diǎn)數(shù)據(jù)復(fù)制到GL_ARRAY_BUFFER緩沖區(qū),之后可通過(guò)VBO進(jìn)行操作glBindVertexArray(objectVAO); //綁定VAO//設(shè)定頂點(diǎn)屬性指針//位置屬性glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//法向量屬性glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);//光源(VBO用上面的)//----------------------------------------------------------------unsigned int lightVAO;glGenVertexArrays(1, &lightVAO); //創(chuàng)建頂點(diǎn)數(shù)組對(duì)象glBindVertexArray(lightVAO); //綁定VAOglBindBuffer(GL_ARRAY_BUFFER, VBO); //將VBO與GL_ARRAY_BUFFER緩沖區(qū)綁定glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//渲染循環(huán)//我們可不希望只繪制一個(gè)圖像之后我們的應(yīng)用程序就立即退出并關(guān)閉窗口;//我們希望程序在我們主動(dòng)關(guān)閉它之前不斷繪制圖像并能夠接受用戶輸入;//因此,我們需要在程序中添加一個(gè)while循環(huán),它能在我們讓GLFW退出前一直保持運(yùn)行;//------------------------------------------------------------------------------while (!glfwWindowShouldClose(window)) //如果用戶準(zhǔn)備關(guān)閉參數(shù)window所指定的窗口,那么此接口將會(huì)返回GL_TRUE,否則將會(huì)返回GL_FALSE{//更新時(shí)間差float currentFrame = static_cast<float>(glfwGetTime());deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;//用戶輸入//------------------------------------------------------------------------------processInput(window); //檢測(cè)是否有輸入//渲染指令//------------------------------------------------------------------------------glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//被投光物體//============================================================//激活著色器程序?qū)ο?/span>objectShader.use();objectShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);objectShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);objectShader.setVec3("lightPos", lightPos);objectShader.setVec3("viewPos", camera.Position);objectShader.setVec3("material.ambient", 1.0f, 0.5f, 0.31f);objectShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f);objectShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);objectShader.setFloat("material.shininess", 32.0f);//創(chuàng)建變換矩陣glm::mat4 model = glm::mat4(1.0f);objectShader.setMat4("model", model);glm::mat4 view = camera.GetViewMatrix();objectShader.setMat4("view", view);glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);objectShader.setMat4("projection", projection);//繪制三角形glBindVertexArray(objectVAO); //綁定VAOglDrawArrays(GL_TRIANGLES, 0, 36);//============================================================//光源//============================================================//激活著色器程序?qū)ο?/span>lightShader.use();lightShader.setMat4("view", view);lightShader.setMat4("projection", projection);model = glm::mat4(1.0f);model = glm::translate(model, lightPos);model = glm::scale(model, glm::vec3(0.2f));lightShader.setMat4("model", model);//繪制三角形glBindVertexArray(lightVAO); //綁定VAOglDrawArrays(GL_TRIANGLES, 0, 36);//============================================================//告訴GLFW檢查所有等待處理的事件和消息,包括操作系統(tǒng)和窗口系統(tǒng)中應(yīng)當(dāng)處理的消息。如果有消息正在等待,它會(huì)先處理這些消息再返回;否則該函數(shù)會(huì)立即返回//---------------------------------------------------------------------------------------------------------------------------------glfwPollEvents();//請(qǐng)求窗口系統(tǒng)將參數(shù)window關(guān)聯(lián)的后緩存畫(huà)面呈現(xiàn)給用戶(雙緩沖繪圖)//------------------------------------------------------------------------------glfwSwapBuffers(window);}//釋放資源glDeleteVertexArrays(1, &objectVAO);glDeleteVertexArrays(1, &lightVAO);glDeleteBuffers(1, &VBO);//glDeleteProgram(objectShader);//glDeleteProgram(lightShader);//glfw銷毀窗口和OpenGL環(huán)境,并釋放資源(之后必須再次調(diào)用glfwInit()才能使用大多數(shù)GLFW函數(shù))//------------------------------------------------------------------glfwTerminate();return a.exec();
}//檢測(cè)是否有輸入
//---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) //ESC鍵,退出glfwSetWindowShouldClose(window, true);float cameraSpeed = static_cast<float>(2.5 * deltaTime);if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)camera.ProcessKeyboard(FORWARD, deltaTime);if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)camera.ProcessKeyboard(BACKWARD, deltaTime);if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)camera.ProcessKeyboard(LEFT, deltaTime);if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)camera.ProcessKeyboard(RIGHT, deltaTime);
}//給glfw窗口注冊(cè)的尺寸改變回調(diào)函數(shù)
//---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{//確保視口匹配新的窗口尺寸,請(qǐng)注意:寬度和高度將比視網(wǎng)膜顯示器上指定的大得多glViewport(0, 0, width, height);
}
// 鼠標(biāo)移動(dòng)時(shí)的回調(diào)函數(shù)
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
{float xpos = static_cast<float>(xposIn);float ypos = static_cast<float>(yposIn);if (firstMouse){lastX = xpos;lastY = ypos;firstMouse = false;}float xoffset = lastX - xpos;float yoffset = ypos - lastY; //翻轉(zhuǎn),因?yàn)閅軸是從下到上越來(lái)越大lastX = xpos;lastY = ypos;camera.ProcessMouseMovement(xoffset, yoffset);
}//鼠標(biāo)滾輪的回調(diào)函數(shù)
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{camera.ProcessMouseScroll(static_cast<float>(yoffset));
}
三、光的屬性
不過(guò)看起來(lái)真的不太對(duì)勁?這個(gè)物體太亮了。
物體過(guò)亮的原因是環(huán)境光、漫反射和鏡面光這三個(gè)顏色對(duì)任何一個(gè)光源都全力反射。
光源對(duì)環(huán)境光、漫反射和鏡面光分量也分別具有不同的強(qiáng)度。前面的章節(jié)中,我們通過(guò)使用一個(gè)強(qiáng)度值改變環(huán)境光和鏡面光強(qiáng)度的方式解決了這個(gè)問(wèn)題。我們想做類似的事情,但是這次是要為每個(gè)光照分量分別指定一個(gè)強(qiáng)度向量。
如果我們假設(shè)lightColor
是vec3(1.0),代碼會(huì)看起來(lái)像這樣:
vec3 ambient = vec3(1.0) * material.ambient;
vec3 diffuse = vec3(1.0) * (diff * material.diffuse);
vec3 specular = vec3(1.0) * (spec * material.specular);
所以物體的每個(gè)材質(zhì)屬性對(duì)每一個(gè)光照分量都返回了最大的強(qiáng)度。
對(duì)單個(gè)光源來(lái)說(shuō),這些vec3(1.0)值同樣可以對(duì)每種光源分別改變,而這通常就是我們想要的。
現(xiàn)在,物體的環(huán)境光分量完全地影響了立方體的顏色,可是環(huán)境光分量實(shí)際上不應(yīng)該對(duì)最終的顏色有這么大的影響,所以我們會(huì)將光源的環(huán)境光強(qiáng)度設(shè)置為一個(gè)小一點(diǎn)的值,從而限制環(huán)境光顏色:
vec3 ambient = vec3(0.1) * material.ambient;
我們可以用同樣的方式影響光源的漫反射和鏡面光強(qiáng)度。這和我們?cè)谏弦还?jié)中所做的極為相似,你可以認(rèn)為我們已經(jīng)創(chuàng)建了一些光照屬性來(lái)影響各個(gè)光照分量。我們希望為光照屬性創(chuàng)建類似材質(zhì)結(jié)構(gòu)體的東西:
struct Light {vec3 position;vec3 ambient;vec3 diffuse;vec3 specular;
};uniform Light light;
- 一個(gè)光源對(duì)它的
ambient
、diffuse
和specular
光照分量有著不同的強(qiáng)度。 - 環(huán)境光照通常被設(shè)置為一個(gè)比較低的強(qiáng)度,因?yàn)槲覀儾幌Mh(huán)境光顏色太過(guò)主導(dǎo)。
- 光源的漫反射分量通常被設(shè)置為我們希望光所具有的那個(gè)顏色,通常是一個(gè)比較明亮的白色。
- 鏡面光分量通常會(huì)保持為vec3(1.0),以最大強(qiáng)度發(fā)光。
- 注意:我們也將光源的位置向量加入了結(jié)構(gòu)體。
和材質(zhì)uniform一樣,我們需要更新片段著色器:
片段著色器
#version 330 corein vec3 FragPos;
in vec3 Normal;out vec4 FragColor;uniform vec3 objectColor;
uniform vec3 lightColor;
uniform vec3 lightPos;
uniform vec3 viewPos; //觀察者坐標(biāo)struct Material { //材質(zhì)描述結(jié)構(gòu)體vec3 ambient; //環(huán)境光照vec3 diffuse; //漫反射光照vec3 specular; //鏡面反射光照float shininess; //反光度
};
uniform Material material; //材質(zhì)struct Light { //光照強(qiáng)度vec3 position;vec3 ambient;vec3 diffuse;vec3 specular;
};
uniform Light light;void main()
{//環(huán)境光照vec3 ambient = material.ambient * light.ambient;//漫反射光照vec3 norm = normalize(Normal);vec3 lightDir = normalize(lightColor - FragPos);float diff = max(dot(norm, lightDir), 0.0);vec3 diffuse = (diff *material.diffuse) * light.diffuse;//鏡面反射光照vec3 viewDir = normalize(viewPos - FragPos);vec3 reflectDir = reflect(-lightDir, norm);float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);vec3 specular = (material.specular * spec) * light.specular;vec3 result = ambient + diffuse + specular;FragColor = vec4(result, 1.0);
}
我們接下來(lái)在應(yīng)用中設(shè)置光照強(qiáng)度:
objectShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f);
objectShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f); // 將光照調(diào)暗了一些以搭配場(chǎng)景
objectShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
現(xiàn)在我們已經(jīng)調(diào)整了光照對(duì)物體材質(zhì)的影響,我們得到了一個(gè)與上一節(jié)很相似的視覺(jué)效果。但這次我們有了對(duì)光照和物體材質(zhì)的完全掌控:
四、不同的光源顏色
到目前為止,我們都只對(duì)光源設(shè)置了從白到灰到黑范圍內(nèi)的顏色,這樣只會(huì)改變物體各個(gè)分量的強(qiáng)度,而不是它的真正顏色。
由于現(xiàn)在能夠非常容易地訪問(wèn)光照的屬性了,我們可以隨著時(shí)間改變它們的顏色,從而獲得一些非常有意思的效果。
由于所有的東西都在片段著色器中配置好了,修改光源的顏色非常簡(jiǎn)單,并立刻創(chuàng)造一些很有趣的效果:
//光照強(qiáng)度
glm::vec3 lightColor;
lightColor.x = static_cast<float>(sin(glfwGetTime() * 2.0));
lightColor.y = static_cast<float>(sin(glfwGetTime() * 0.7));
lightColor.z = static_cast<float>(sin(glfwGetTime() * 1.3));
glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f); // decrease the influence
glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); // low influence
objectShader.setVec3("light.ambient", ambientColor);
objectShader.setVec3("light.diffuse", diffuseColor);
objectShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
你可以看到,不同的光照顏色能夠極大地影響物體的最終顏色輸出。由于光照顏色能夠直接影響物體能夠反射的顏色,這對(duì)視覺(jué)輸出有著顯著的影響。
全部代碼
#include "mainwindow.h"
#include <QApplication>//在包含GLFW的頭文件之前包含了GLAD的頭文件;
//GLAD的頭文件包含了正確的OpenGL頭文件(例如GL/gl.h);
//所以需要在其它依賴于OpenGL的頭文件之前包含GLAD;
#include <glad/glad.h>
#include <GLFW/glfw3.h>//GLM
//#include <glm/glm.hpp>
//#include <glm/gtc/matrix_transform.hpp>
//#include <glm/gtc/type_ptr.hpp>#include <iostream>
#include <QDebug>#include "shader.h"
#include "stb_image.h"
#include "camera.h"void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);// settings
const unsigned int SCR_WIDTH = 1920;
const unsigned int SCR_HEIGHT = 1080;//Camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0;
float lastY = SCR_HEIGHT / 2.0;
bool firstMouse = true;float deltaTime = 0.0f; // 當(dāng)前幀與上一幀的時(shí)間差
float lastFrame = 0.0f; // 上一幀的時(shí)間//Light
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);using namespace std;int main(int argc, char *argv[])
{QApplication a(argc, argv);//MainWindow w;//w.show();//初始化GLFW//--------------------glfwInit();//配置GLFW//--------------------//告訴GLFW使用的OpenGL本是3.3glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//告訴GLFW使用的是核心模式(Core-profile)glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//創(chuàng)建一個(gè)新的OpenGL環(huán)境和窗口//-----------------------------------GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate(); //glfw銷毀窗口和OpenGL環(huán)境,并釋放資源return -1;}//設(shè)置參數(shù)window中的窗口所關(guān)聯(lián)的OpenGL環(huán)境為當(dāng)前環(huán)境//-----------------------------------glfwMakeContextCurrent(window);//設(shè)置窗口尺寸改變大小時(shí)的回調(diào)函數(shù)(窗口尺寸發(fā)送改變時(shí)會(huì)自動(dòng)調(diào)用)//-----------------------------------glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//設(shè)置鼠標(biāo)事件的回調(diào)函數(shù)(鼠標(biāo)移動(dòng)時(shí)會(huì)自動(dòng)調(diào)用)//-----------------------------------glfwSetCursorPosCallback(window, mouse_callback);//設(shè)置鼠標(biāo)滾輪事件的回調(diào)函數(shù)(鼠標(biāo)滾輪移動(dòng)時(shí)會(huì)自動(dòng)調(diào)用)//-----------------------------------glfwSetScrollCallback(window, scroll_callback);//告訴GLFW捕捉鼠標(biāo)glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//glad加載系統(tǒng)相關(guān)的OpenGL函數(shù)指針//---------------------------------------if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}//開(kāi)啟深度測(cè)試glEnable(GL_DEPTH_TEST);Shader objectShader("C:/Qt_Pro/OpenGL_GLFW/shader/shader.vs","C:/Qt_Pro/OpenGL_GLFW/shader/shader.fs");Shader lightShader("C:/Qt_Pro/OpenGL_GLFW/shader/light_cube.vs","C:/Qt_Pro/OpenGL_GLFW/shader/light_cube.fs");//頂點(diǎn)數(shù)據(jù)//---------------------------------------------------------------------float vertices[] = {//頂點(diǎn)數(shù)據(jù) //頂點(diǎn)法向量-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f};//物體//----------------------------------------------------------------unsigned int VBO, objectVAO;glGenVertexArrays(1, &objectVAO); //創(chuàng)建頂點(diǎn)數(shù)組對(duì)象glGenBuffers(1, &VBO); //創(chuàng)建頂點(diǎn)緩沖對(duì)象glBindBuffer(GL_ARRAY_BUFFER, VBO); //將VBO與GL_ARRAY_BUFFER緩沖區(qū)綁定glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //將頂點(diǎn)數(shù)據(jù)復(fù)制到GL_ARRAY_BUFFER緩沖區(qū),之后可通過(guò)VBO進(jìn)行操作glBindVertexArray(objectVAO); //綁定VAO//設(shè)定頂點(diǎn)屬性指針//位置屬性glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//法向量屬性glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);//光源(VBO用上面的)//----------------------------------------------------------------unsigned int lightVAO;glGenVertexArrays(1, &lightVAO); //創(chuàng)建頂點(diǎn)數(shù)組對(duì)象glBindVertexArray(lightVAO); //綁定VAOglBindBuffer(GL_ARRAY_BUFFER, VBO); //將VBO與GL_ARRAY_BUFFER緩沖區(qū)綁定glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//渲染循環(huán)//我們可不希望只繪制一個(gè)圖像之后我們的應(yīng)用程序就立即退出并關(guān)閉窗口;//我們希望程序在我們主動(dòng)關(guān)閉它之前不斷繪制圖像并能夠接受用戶輸入;//因此,我們需要在程序中添加一個(gè)while循環(huán),它能在我們讓GLFW退出前一直保持運(yùn)行;//------------------------------------------------------------------------------while (!glfwWindowShouldClose(window)) //如果用戶準(zhǔn)備關(guān)閉參數(shù)window所指定的窗口,那么此接口將會(huì)返回GL_TRUE,否則將會(huì)返回GL_FALSE{//更新時(shí)間差float currentFrame = static_cast<float>(glfwGetTime());deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;//用戶輸入//------------------------------------------------------------------------------processInput(window); //檢測(cè)是否有輸入//渲染指令//------------------------------------------------------------------------------glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//被投光物體//============================================================//激活著色器程序?qū)ο?/span>objectShader.use();objectShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);objectShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);objectShader.setVec3("lightPos", lightPos);objectShader.setVec3("viewPos", camera.Position);//光照強(qiáng)度glm::vec3 lightColor;lightColor.x = static_cast<float>(sin(glfwGetTime() * 2.0));lightColor.y = static_cast<float>(sin(glfwGetTime() * 0.7));lightColor.z = static_cast<float>(sin(glfwGetTime() * 1.3));glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f); // decrease the influenceglm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); // low influenceobjectShader.setVec3("light.ambient", ambientColor);objectShader.setVec3("light.diffuse", diffuseColor);objectShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);//材質(zhì)objectShader.setVec3("material.ambient", 1.0f, 0.5f, 0.31f);objectShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f);objectShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);objectShader.setFloat("material.shininess", 32.0f);//創(chuàng)建變換矩陣glm::mat4 model = glm::mat4(1.0f);objectShader.setMat4("model", model);glm::mat4 view = camera.GetViewMatrix();objectShader.setMat4("view", view);glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);objectShader.setMat4("projection", projection);//繪制三角形glBindVertexArray(objectVAO); //綁定VAOglDrawArrays(GL_TRIANGLES, 0, 36);//============================================================//光源//============================================================//激活著色器程序?qū)ο?/span>lightShader.use();lightShader.setMat4("view", view);lightShader.setMat4("projection", projection);model = glm::mat4(1.0f);model = glm::translate(model, lightPos);model = glm::scale(model, glm::vec3(0.2f));lightShader.setMat4("model", model);//繪制三角形glBindVertexArray(lightVAO); //綁定VAOglDrawArrays(GL_TRIANGLES, 0, 36);//============================================================//告訴GLFW檢查所有等待處理的事件和消息,包括操作系統(tǒng)和窗口系統(tǒng)中應(yīng)當(dāng)處理的消息。如果有消息正在等待,它會(huì)先處理這些消息再返回;否則該函數(shù)會(huì)立即返回//---------------------------------------------------------------------------------------------------------------------------------glfwPollEvents();//請(qǐng)求窗口系統(tǒng)將參數(shù)window關(guān)聯(lián)的后緩存畫(huà)面呈現(xiàn)給用戶(雙緩沖繪圖)//------------------------------------------------------------------------------glfwSwapBuffers(window);}//釋放資源glDeleteVertexArrays(1, &objectVAO);glDeleteVertexArrays(1, &lightVAO);glDeleteBuffers(1, &VBO);//glDeleteProgram(objectShader);//glDeleteProgram(lightShader);//glfw銷毀窗口和OpenGL環(huán)境,并釋放資源(之后必須再次調(diào)用glfwInit()才能使用大多數(shù)GLFW函數(shù))//------------------------------------------------------------------glfwTerminate();return a.exec();
}//檢測(cè)是否有輸入
//---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) //ESC鍵,退出glfwSetWindowShouldClose(window, true);float cameraSpeed = static_cast<float>(2.5 * deltaTime);if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)camera.ProcessKeyboard(FORWARD, deltaTime);if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)camera.ProcessKeyboard(BACKWARD, deltaTime);if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)camera.ProcessKeyboard(LEFT, deltaTime);if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)camera.ProcessKeyboard(RIGHT, deltaTime);
}//給glfw窗口注冊(cè)的尺寸改變回調(diào)函數(shù)
//---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{//確保視口匹配新的窗口尺寸,請(qǐng)注意:寬度和高度將比視網(wǎng)膜顯示器上指定的大得多glViewport(0, 0, width, height);
}
// 鼠標(biāo)移動(dòng)時(shí)的回調(diào)函數(shù)
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
{float xpos = static_cast<float>(xposIn);float ypos = static_cast<float>(yposIn);if (firstMouse){lastX = xpos;lastY = ypos;firstMouse = false;}float xoffset = lastX - xpos;float yoffset = ypos - lastY; //翻轉(zhuǎn),因?yàn)閅軸是從下到上越來(lái)越大lastX = xpos;lastY = ypos;camera.ProcessMouseMovement(xoffset, yoffset);
}//鼠標(biāo)滾輪的回調(diào)函數(shù)
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{camera.ProcessMouseScroll(static_cast<float>(yoffset));
}