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; }