OpenGL — GLFW — 颜色
OpenGL — GLFW — 颜色
参考教程:https://learnopengl-cn.readthedocs.io/zh/latest/02%20Lighting/01%20Colors/
既然,网络上已经有现成的教程了,我为什么还有在写一遍教程呢?
这个教程不是给大家写的,而是给我自己写的,算是我的学习笔记吧。我将编程序的重点提起出来,并将我的经验和遇到的问题记下来,为日后的我做参考用的。知识会随着时间的流过,而慢慢的被遗忘,当日后有一个项目要用到OpenGL的知识时,那个时候的我可能已经将当初学到的OpenGL忘记的擦不多了,这个时候,我就需要过去的我来帮助我,可以这样理解,跨越时空的两个我在完成一个项目!不错,这就是记笔记的作用。
给模型上颜色,两个步骤:
- 编写片段着色器
- 在主程序中给片段着色器赋值
- 在主主函数中,使用片段着色器
你可能会问,颜色有什么好讲的?我想说:你问对了,真的没有什么好讲的。就是定义一个变量:
glm::vec3 color(1.0f, 0.5f, 0.31f); // 珊瑚红(Coral)
编写程序步骤
第1步:
程序
先顶点着色器程序,就用个精简版的程序:(顶点着色器(Vertex Shader)文件名为:color.vs)
#version 330 core layout (location = 0) in vec3 position; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { gl_Position = projection * view * model * vec4(position, 1.0f); }
解释
layout (location = 0) in vec3 position;
得到CPP程序中是ID是0的数据,将ID为0的数据的物理意义定义为顶点位置
uniform mat4 model; uniform mat4 view; uniform mat4 projection;
这些变量是需要在CPP程序中等待赋值的。
归根结底,这三个变量都是4*4的矩阵,都是作用于模型的每一个顶点的。
但是他们代表着不同的物理意义:
model | 模型自身的姿态矩阵。姿态:旋转和平移组成。 |
---|---|
view | 摄像机姿态矩阵。 |
projection | 透视矩阵。 |
void main() { gl_Position = projection * view * model * vec4(position, 1.0f); }
gl_Position是GLSL(OpenGL Shading Language)着色语言中的一个内置变量,即输出的顶点位置。
总结:这个顶点着色器的作用就是:更新顶点的位置。
第2步:
程序
编写片段着色器:(片段着色器(Fragment shader)文件命名为:color.frag)
#version 330 core out vec4 color; uniform vec3 objectColor; uniform vec3 lightColor; void main() { color = vec4(lightColor * objectColor, 1.0f); }
讲解
out vec4 color;
输出的color变量。
uniform vec3 objectColor; uniform vec3 lightColor;
这两个值在CPP程序中被赋值,分别表示物体色 和 光源颜色。
void main() { color = vec4(lightColor * objectColor, 1.0f); }
将光源颜色与物体颜色相乘,即两个向量相乘,得到最终的颜色。因为定义的color是4维向量,objectColor和lightColor是3维向量。所以这里给color赋值的时候要这样做
color = vec4(vec3, 1.0f);
总结: 这个片段着色器做的事情:更新物体颜色。
第3步
编写CPP程序模板
#include <iostream> #include <cmath> // GLEW #define GLEW_STATIC #include <GL/glew.h> // GLFW #include <GLFW/glfw3.h> // Other Libs #include <SOIL.h> // GLM Mathematics #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> // Other includes #include <learnopengl\shader.h> #include <learnopengl\camera.h> #include <learnopengl\model.h> // Function prototypes void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void do_movement(); // Window dimensions const GLuint WIDTH = 800, HEIGHT = 800; // Camera Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); GLfloat lastX = WIDTH / 2.0; GLfloat lastY = HEIGHT / 2.0; bool keys[1024]; // Deltatime GLfloat deltaTime = 0.0f; // Time between current frame and last frame GLfloat lastFrame = 0.0f; // Time of last frame // The MAIN function, from here we start the application and run the game loop int main() { // Init GLFW glfwInit(); // Set all the required options for GLFW 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); // Create a GLFWwindow object that we can use for GLFW's functions GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "AoboSir OpenGL", nullptr, nullptr); glfwMakeContextCurrent(window); // Set the required callback functions glfwSetKeyCallback(window, key_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); // GLFW Options glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions glewExperimental = GL_TRUE; // Initialize GLEW to setup the OpenGL Function pointers glewInit(); // Define the viewport dimensions glViewport(0, 0, WIDTH, HEIGHT); // OpenGL options glEnable(GL_DEPTH_TEST); //定义着色器类对象 //定义模型类对象 // Game loop while (!glfwWindowShouldClose(window)) { // Calculate deltatime of current frame GLfloat currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions glfwPollEvents(); do_movement(); // Clear the colorbuffer //glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClearColor(0.41f, 0.41f, 0.41f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //给着色器进行赋值 //让模型使用这个着色器对象,显示模型 // Swap the screen buffers glfwSwapBuffers(window); } // Terminate GLFW, clearing any resources allocated by GLFW. glfwTerminate(); return 0; } // Is called whenever a key is pressed/released via GLFW 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 >= 0 && key < 1024) { if (action == GLFW_PRESS) keys[key] = true; else if (action == GLFW_RELEASE) keys[key] = false; } } void do_movement() { // Camera controls if (keys[GLFW_KEY_W]) camera.ProcessKeyboard(FORWARD, deltaTime); if (keys[GLFW_KEY_S]) camera.ProcessKeyboard(BACKWARD, deltaTime); if (keys[GLFW_KEY_A]) camera.ProcessKeyboard(LEFT, deltaTime); if (keys[GLFW_KEY_D]) camera.ProcessKeyboard(RIGHT, deltaTime); } bool firstMouse = true; void mouse_callback(GLFWwindow* window, double xpos, double ypos) { if(glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT )){ if (firstMouse) { lastX = xpos; lastY = ypos; firstMouse = false; } GLfloat xoffset = xpos - lastX; GLfloat yoffset = ypos - lastY; // Reversed since y-coordinates go from bottom to left lastX = xpos; lastY = ypos; camera.ProcessMouseMovement(glm::radians(xoffset), glm::radians(yoffset)); } else { firstMouse = true; } } void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { camera.ProcessMouseScroll(glm::radians(yoffset) ); }
注意:
1.glm::radians(angle)这个函数是将输入的角度转换为弧度。
2.glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT )函数,如果鼠标左键按下,函数会返回非零数据;如果鼠标左键没有被按下,函数会返回0.
第4步
定义着色器对象和模型对象,给着色器对象赋值,并让模型对象使用着色器对象,显示模型。
定义着色器对象和模型对象
//定义着色器类对象 // Build and compile our shader program Shader lightingShader("shader/color.vs", "shader/color.frag"); Shader lampShader("shader/lamp.vs", "shader/lamp.frag"); //定义模型类对象 Model ourModel("meshes/TexMesh.obj"); Model lampModel("meshes/Light_Bulb.obj");
给着色器进行赋值
//给着色器进行赋值 // Use cooresponding shader when setting uniforms/drawing objects lightingShader.Use(); GLint objectColorLoc = glGetUniformLocation(lightingShader.Program, "objectColor"); GLint lightColorLoc = glGetUniformLocation(lightingShader.Program, "lightColor"); glUniform3f(objectColorLoc, 1.0f, 0.5f, 0.31f); glUniform3f(lightColorLoc, 1.0f, 1.0f, 1.0f); // Create camera transformations glm::mat4 view; view = camera.GetViewMatrix(); glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f); // Get the uniform locations GLint modelLoc = glGetUniformLocation(lightingShader.Program, "model"); GLint viewLoc = glGetUniformLocation(lightingShader.Program, "view"); GLint projLoc = glGetUniformLocation(lightingShader.Program, "projection"); // Pass the matrices to the shader glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection)); // Draw the loaded model glm::mat4 model; model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f)); // It's a bit too big for our scene, so scale it down glUniformMatrix4fv(glGetUniformLocation(lightingShader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
让模型使用这个着色器对象,显示模型
//让模型使用这个着色器对象,显示模型 ourModel.Draw(lightingShader);
大功告成,第6步,运行程序
(这其实是以一张倒人脸的背面,你现在看到的是一片珊瑚红色,是因为在我们的这个着色器是最简单的着色器,并且我们没有使用模型的点的法线向量,所以没有阴影的效果。)
我们继续学习下一课。
参考网站:
https://www.geek-share.com/detail/2585587760.html
http://www.glfw.org/docs/latest/group__input.html#gac1473feacb5996c01a7a5a33b5066704
http://learnopengl.com/code_viewer.php?code=model_loading/model_diffuse
下载一个灯泡模型:http://tf3dm.com/3d-model/light-bulb-simple-studio-9032.html
- spark编译问题解决 object apache is not a member of package org
- Win10 Git使用简介
- Linux运维必会(二) - 遍历文件夹,并筛选符合条件的文件名
- Linux|XAMPP Linux 5.6.8 64bit 外网无法访问解决
- linux 命令--压缩
- Centos常用命令及解释
- 基于 flask 框架的模拟instagram 图片分享网站的开发 2
- Nginx + Tomcat 动静分离实现负载均衡
- 关于GOPATH
- 浅谈服务化
- PHP编程之设置apache虚拟目录
- ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统之前端页面框架构建源码分享
- Centos 7 开启端口
- nginx经验
- Docker启动容器时的port公开方式,破除一些含糊的地方
- nginx负载均衡配置。
- cocopods升级到1.0,导入第三方库,出现问题及解决方式
- 关于 shell 脚本中 重定向文件名带问号的解决办法
- 为什么要做SEO
- SEO的定义解读