1、 光照:
四種光照類型:
-
放射光(自發光) emissive : 沒有光照的狀況下物體自身會發射光 如:夜明珠
ios -
環境光 ambient : 即便夜裏房間燈所有關掉,仍是有微弱光(月光)讓你能看見房間物體輪廓,這就是環境光windows
-
漫反射光
函數 -
鏡面反射光 specular :
ui
shininess 材質光澤度對比圖
spa
基本光照模型:
- 計算公式:surfaceColor = emissive + ambient + diffuse + specular (四種光照類型加在一塊兒便可獲得物體表面的顏色)
opengl固定渲染管線已經使用了這個公式 ,咱們只須要設置下參數,opengl內部會自動進行計算,咱們便可看到光照效果。3d
2、光源:
三種光源類型:
-
點光 : 如電燈包,向四周360度發射光 有衰減 (能夠設置衰減係數)
指針 -
平行光 : 如太陽,光源在無限遠處code
- 聚光燈 : 在錐形區域內有光
相關函數
// 禁用光照時 使用 glColor3f()設置顏色 // 啓用光照時 使用 glMaterial()設置材質顏色,glColor3f() 設置顏色無效 glEnable(GL_LIGHTING); // 啓用光照 glEnable(GL_LIGHT0); // 激活燈0 GLfloat light_ambient[4] = {0.3, 0.3, 0.3, 1.0} // GLfloat light_diffuse[4] = {1.0, 1.0, 1.0, 1.0} // GLfloat light_specular[4] = {1.0, 1.0, 1.0, 1.0} // //設置燈屬性參數 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); //設置環境光 (light_ambient爲計算公式:ambient = ka * globalAmbient 中的globalAmbient) glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); //設置漫反射光 (light_diffuse爲計算公式:diffuse = kd * lightColor * max(N.L, 0) 中的lightColor) glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); //設置鏡面反射光 (light_specular爲計算公式:specular = ks * lightColor* facing * (max(N.H, 0))^shininess 中的lightColor) GLfloat light_position[4] = {0, 100, 100, 1} glLightfv(GL_LIGHT0, GL_POSITION, light_position); // 設置燈位置 // 設置光源位置和光源類型 GLfloat light_position[4] = {0, 100, 100, 1} // 前三個參數表示光的位置 第四個參數 0:平行光 1:點光、聚光燈 glLightfv(GL_LIGHT0, GL_POSITION, light_position); // 衰減 (只有點光有衰減) // 計算公式: attenuation = 1/(A0 + A1*D +A2*D^2) // D: 電燈包到被照射物體的距離。 A0、A一、A2: 咱們能夠設置作不一樣衰減 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0f); // 設置A0 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05f); // 設置A1 glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.25f); // 設置A2 // 設置聚光燈 GLfloat light_position[4] = {0, 100, 100, 1} // 聚光燈是一個特殊的點光源 因此第四個參數設置爲1 glLightfv(GL_LIGHT0, GL_POSITION, light_position); GLfloat spot_dir[4] = {-1, -2.5, -10} glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_dir);// 設置方向 glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 7.5f); // 設置角度 glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 128f); // 設置指數 中間光強 周圍減弱
3、代碼:
// 使用燈光例子 #define GLEW_STATIC #include <stdio.h> #include <stdlib.h> #include <math.h> #include <iostream> #include <GL/glew.h> #include <GLFW/glfw3.h> #include <glm/vec3.hpp> // glm::vec3 #include <glm/vec4.hpp> // glm::vec4 #include <glm/mat4x4.hpp> // glm::mat4 #include <glm/ext/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale #include <glm/ext/matrix_clip_space.hpp> #include "FreeImage.h" #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) //這行是取消顯示控制檯 char szTitle[64] = "opengl view"; //glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);//建立一個點 //glm::mat4 trans = glm::mat4(1.0f);//建立單位矩陣 //Window dimensions const GLuint WIDTH = 800, HEIGHT = 600; GLfloat ratio = 1.f; GLfloat xpos, ypos; glm::vec3 _eye(0, 0, 10); glm::vec3 _lookAt(0, 0, 0); glm::vec3 _up(0, 1, 0); glm::mat4 _matProj = glm::mat4(1.0f);//建立單位矩陣 glm::mat4 _matView = glm::mat4(1.0f);//建立單位矩陣 float size = 100.0f; //頂點數據 struct Vertex { float x, y, z; float u, v; }; Vertex g_cubeVertices[] = { { -1.0f, -1.0f, 1.0f, 0.0f, 0.0f }, { 1.0f, -1.0f, 1.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }, { -1.0f, 1.0f, 1.0f, 0.0f, 1.0f }, { -1.0f, -1.0f, -1.0f, 1.0f, 0.0f }, { -1.0f, 1.0f, -1.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, -1.0f, 0.0f, 1.0f }, { 1.0f, -1.0f, -1.0f, 0.0f, 0.0f }, { -1.0f, 1.0f, -1.0f, 0.0f, 1.0f }, { -1.0f, 1.0f, 1.0f, 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f, 0.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, 0.0f, 1.0f }, { 1.0f, -1.0f, 1.0f, 0.0f, 0.0f }, { -1.0f, -1.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, 1.0f }, { 1.0f, 1.0f, 1.0f, 0.0f, 1.0f }, { 1.0f, -1.0f, 1.0f, 0.0f, 0.0f }, { -1.0f, -1.0f, -1.0f, 0.0f, 0.0f }, { -1.0f, -1.0f, 1.0f, 1.0f, 0.0f }, { -1.0f, 1.0f, 1.0f, 1.0f, 1.0f }, { -1.0f, 1.0f, -1.0f, 0.0f, 1.0f }, // 地面數據 { -size, -1.0f, -size, 0.0f, 0.0f }, { -size, -1.0f, size, 100.0f, 0.0f }, { size, -1.0f, size, 100.0f, 100.0f }, { size, 0.0f, -size, 0.0f, 100.0f } }; //紋理ID GLuint _texture; GLuint _vbo; //地面紋理 GLuint _texGround; static void error_callback(int error, const char* description) { fputs(description, stderr); } static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { std::cout << "key " << key << std::endl; switch(key) { case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, GL_TRUE); break; case GLFW_KEY_UP: _eye.z -= 0.1f; //這裏修改攝像機參數 break; case GLFW_KEY_DOWN: _eye.z += 0.1f; break; case GLFW_KEY_RIGHT: _eye.x -= 1.0f; break; case GLFW_KEY_LEFT: _eye.x += 1.0f; break; default: break; } } static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { if(action != GLFW_PRESS) return; switch(button) { case GLFW_MOUSE_BUTTON_LEFT: std::cout << "Mosue left button clicked!" << std::endl; break; case GLFW_MOUSE_BUTTON_MIDDLE: std::cout << "Mosue middle button clicked!" << std::endl; break; case GLFW_MOUSE_BUTTON_RIGHT: std::cout << "Mosue right button clicked!" << std::endl; break; default: return; } return; } static void cursor_position_callback(GLFWwindow* window, double x, double y) { //std::cout << "Mouse position move to X: " << x << " Y: " << y << std::endl; xpos = float((x - WIDTH / 2) / WIDTH) * 2; ypos = float(0 - (y - HEIGHT / 2) / HEIGHT) * 2; return; } static void scroll_callback(GLFWwindow* window, double x, double y) { return; } static unsigned createTexture(int w, int h, const void* data, GLenum type) { unsigned texId; glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, texId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, type, w, h, 0, type, GL_UNSIGNED_BYTE, data); return texId; } /** * 使用FreeImage加載圖片 */ static unsigned createTextureFromImage(const char* fileName) { //1 獲取圖片格式 FREE_IMAGE_FORMAT fifmt = FreeImage_GetFileType(fileName, 0); if(fifmt == FIF_UNKNOWN) { return 0; } //2 加載圖片 FIBITMAP *dib = FreeImage_Load(fifmt, fileName, 0); FREE_IMAGE_COLOR_TYPE type = FreeImage_GetColorType(dib); //3 獲取數據指針 FIBITMAP* temp = dib; dib = FreeImage_ConvertTo32Bits(dib); FreeImage_Unload(temp); BYTE* pixels = (BYTE*)FreeImage_GetBits(dib); int width = FreeImage_GetWidth(dib); int height = FreeImage_GetHeight(dib); for(int i = 0; i < width * height * 4; i += 4) { BYTE temp = pixels[i]; pixels[i] = pixels[i + 2]; pixels[i + 2] = temp; } unsigned res = createTexture(width, height, pixels, GL_RGBA); FreeImage_Unload(dib); return res; } static void onInit() { _texture = createTextureFromImage("../res/1.jpg"); _texGround = createTextureFromImage("../res/dimian.jpg"); glGenBuffers(1, &_vbo); glBindBuffer(GL_ARRAY_BUFFER, _vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(g_cubeVertices), g_cubeVertices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } static void onDestory() { glDeleteTextures(1, &_texture); glDeleteTextures(1, &_texGround); glDeleteBuffers(1, &_vbo); //刪除VBO 顯存中釋放VBO內存 } // 繪製 static void render(GLFWwindow * window) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); //設置燈 glEnable(GL_LIGHTING); // 啓用光照 glEnable(GL_LIGHT0); // 激活燈0 GLfloat light_ambient[4] ={ 0.7, 0.7, 0.7, 1.0 }; // GLfloat light_diffuse[4] ={ 1.0, 1.0, 1.0, 1.0 }; // GLfloat light_specular[4] ={ 1.0, 1.0, 1.0, 1.0 }; // //設置燈屬性參數 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); //設置環境光 (light_ambient爲計算公式:ambient = ka * globalAmbient 中的globalAmbient) glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); //設置漫反射光 (light_diffuse爲計算公式:diffuse = kd * lightColor * max(N.L, 0) 中的lightColor) glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); //設置鏡面反射光 (light_specular爲計算公式:specular = ks * lightColor* facing * (max(N.H, 0))^shininess 中的lightColor) glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0f); // 設置衰減A0 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05f); // 設置衰減A1 glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0f); // 設置衰減A2 GLfloat light_position[4] ={ 30, 30, 30, 1 }; // 前三個參數表示光的位置 第四個參數 0:平行光 1:點光、聚光燈 glLightfv(GL_LIGHT0, GL_POSITION, light_position); // 設置燈位置 glEnable(GL_LIGHT1); // 激活燈1 // 設置聚光燈 GLfloat spot_dir[4] ={ -1, -2.5, -10 }; glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_dir);// 設置方向 glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 7.5f); // 設置角度 glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 128.0f); // 設置指數 中間光強 周圍減弱 GLfloat light_position1[4] ={ 0, 0, 20, 1 }; // 聚光燈是一個特殊的點光源 因此第四個參數設置爲1 glLightfv(GL_LIGHT1, GL_POSITION, light_position1); glMatrixMode(GL_MODELVIEW); _matView = glm::lookAt(_eye, _lookAt, _up); //使用glm數學庫 根據公式計算獲得視圖矩陣 這公式能夠推倒出來 //攝像機圍繞目標旋轉 static float angle = 0; //旋轉角度 float r = 10; //旋轉半徑 _eye.x = cos(angle * glm::pi<double>() / 180) * r; _eye.z = sin(angle * glm::pi<double>() / 180) * r; angle += 1; //角度每幀加一 glm::mat4 matVP = _matProj * _matView; glLoadMatrixf(&matVP[0][0]); //glBindTexture(GL_TEXTURE_2D, _texture); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); //開始使用ID爲 _vbo 的buffer 接下來的操做針對這個VBO glBindBuffer(GL_ARRAY_BUFFER, _vbo); float* addrVertex = (float*)0; float* uvAddress = (float*)12; glVertexPointer(3, GL_FLOAT, sizeof(Vertex), addrVertex); glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), uvAddress); // 繪製 立方體 glDrawArrays(GL_QUADS, 0, 24); //繪製地面 //glLoadIdentity(); //這裏打開 地面就不會跟着旋轉 說明攝像機操做的是模型矩陣 //glBindTexture(GL_TEXTURE_2D, _texGround); //glDrawArrays(GL_QUADS, 24, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glBindTexture(GL_TEXTURE_2D, 0); glfwSwapBuffers(window); glfwPollEvents(); } int main(void) { GLFWwindow * window; glfwSetErrorCallback(error_callback); if(!glfwInit()) return -1; window = glfwCreateWindow(WIDTH, HEIGHT, szTitle, NULL, NULL); if(!window) { glfwTerminate(); exit(EXIT_FAILURE); } glfwSetKeyCallback(window, key_callback); glfwSetMouseButtonCallback(window, mouse_button_callback); glfwSetCursorPosCallback(window, cursor_position_callback); glfwSetScrollCallback(window, scroll_callback); glfwMakeContextCurrent(window); glewExperimental = GL_TRUE; glewInit(); onInit(); glViewport(0, 0, WIDTH, HEIGHT); //設置opengl視口 即看到的顯示區域 _matProj = glm::perspective(glm::radians(60.0f), float(WIDTH) / float(HEIGHT), 0.1f, 1000.0f);//使用glm數學庫 根據公式計算獲得投影矩陣 這公式能夠推倒出來 while(!glfwWindowShouldClose(window)) { render(window); } onDestory(); glfwDestroyWindow(window); glfwTerminate(); return 0; }