目录ios
坐标系统简介git
z缓冲github
举个栗子数组
代码安全
main.cppide
截图测试
参考:LearnOpenGLspa
坐标系统简介将坐标变换为标准化设备坐标(Normalized Device Coordinate, NDC),接着再转化为屏幕坐标的过程一般是分步进行的,也就是相似于流水线那样子。在流水线中,物体的顶点在最终转化为屏幕坐标以前还会被变换到多个坐标系统(Coordinate System)。将物体的坐标变换到几个过渡坐标系(Intermediate Coordinate System)的优势在于,在这些特定的坐标系统中,一些操做或运算更加方便和容易,这一点很快就会变得很明显。对咱们来讲比较重要的总共有5个不一样的坐标系统:
为了将坐标从一个坐标系变换到另外一个坐标系,咱们须要用到几个变换矩阵,最重要的几个分别是模型(Model)、观察(View)、投影(Projection)三个矩阵。
接下来采用透视投影,即人眼所感到的近大远小。
z缓冲
接下来咱们将画多个立方体,问题来了,若是多个立方体有重叠部分,按照咱们视觉来讲,前面的物体,应该遮挡住后面的物体。
那么在OpenGL中该如何实现呢?
OpenGL存储它的全部深度信息于一个Z缓冲(Z-buffer)中,也被称为深度缓冲(Depth Buffer)。GLFW会自动为你生成这样一个缓冲(就像它也有一个颜色缓冲来存储输出图像的颜色)。深度值存储在每一个片断里面(做为片断的z值),当片断想要输出它的颜色时,OpenGL会将它的深度值和z缓冲进行比较,若是当前的片断在其它片断以后,它将会被丢弃,不然将会覆盖。这个过程称为深度测试(Depth Testing),它是由OpenGL自动完成的。
使用下面代码开启深度测试
glEnable(GL_DEPTH_TEST);
使用glclear函数进行清除
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);举个栗子
相对于上篇文章,咱们修改了main.cpp(画了6个面,添加了深度测试)、vertexSource.txt(教程没有给颜色,去除了Color)、fragmentSource.txt(教程没有给颜色,去除了Color)
//头文件 #include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> #include "Shader.h" #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> //函数声明 void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window); // 设置窗体宽高 const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600; //主函数 int main() { // glfw: 初始化和配置 glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif // glfw 窗体生成 GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "rectwithtex", NULL, NULL);//设置标题 //判断窗体是否生成 if (window == NULL) { std::cout << "生成GLFW窗口失败" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // glad: 加载全部的OpenGL功能指针---------------------------------------------------------- if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "初始化GLAD失败" << std::endl; return -1; } //开启深度测试 glEnable(GL_DEPTH_TEST); // 创建并编译着色器-------------------------------------------------------------------- Shader* myShader = new Shader("vertexSource.txt", "fragmentSource.txt"); // 设置点数据 (还有缓冲) 配置点的属性(包含点坐标等) 这里设置了4个,将以索引的方式选择点来画三角形 float 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, 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, 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, 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 }; unsigned int indices[] = { 0, 1, 2, // 第一个三角形选择索引为 0 1 3的三个点 2, 3, 0, // 第一个三角形选择索引为 1 2 3的三个点 }; unsigned int VBO, VAO, EBO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); //注意,这里使用EBO做为缓冲对象 // 绑定顶点数组, 而后绑定并设置缓冲, 最后配置顶点属性------------------------------- glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); //修改属性----------------------------------------------------------------------------- glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(6); //glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); //glEnableVertexAttribArray(7); glVertexAttribPointer(8, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(8); //纹理------------------------------------------------------------------------------- unsigned int TexBufferA, TexBufferB; stbi_set_flip_vertically_on_load(true);//y轴翻转 //木箱部分 glGenTextures(1, &TexBufferA); //激活 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, TexBufferA); /*glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);*/ glDrawArrays(GL_TRIANGLES, 0, 36); glBindTexture(GL_TEXTURE_2D, TexBufferA);//绑定 int width, height, nrChannels; unsigned char *data = stbi_load("container.jpg", &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D);//生成多级渐远纹理 } else { std::cout << "加载纹理失败" << std::endl; } stbi_image_free(data);//释放 //笑脸部分 glGenTextures(1, &TexBufferB); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, TexBufferB); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindTexture(GL_TEXTURE_2D, TexBufferB);//绑定 unsigned char *data2 = stbi_load("awesomeface.png", &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);//注意,有Alpha通道 glGenerateMipmap(GL_TEXTURE_2D);//生成多级渐远纹理 } else { std::cout << "加载纹理失败" << std::endl; } stbi_image_free(data2); //注意这是容许的,对glVertexAttribPointer的调用将VBO注册为顶点属性的绑定顶点缓冲区对象,因此以后咱们能够安全地解除绑定 glBindBuffer(GL_ARRAY_BUFFER, 0); // 记住:当VAO处于活动状态时,不要取消绑定EBO,由于绑定元素缓冲对象IS存储在VAO中; 保持EBO的约束力。 //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // 您能够在以后取消绑定VAO,以便其余VAO调用不会意外地修改此VAO,但这种状况不多发生。不管如何, // 修改其余VAO须要调用glBindVertexArray,所以咱们一般不会在不直接须要时解除VAO(VBO一样)的绑定。 glBindVertexArray(0); // 取消注释此调用会绘制线框多边形。 //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //glm相关------------------------------------------------------------------ // 下面就是矩阵初始化的一个例子,若是使用的是0.9.9及以上版本 // 下面这行代码就须要改成: // glm::mat4 trans = glm::mat4(1.0f) glm::mat4 trans; //trans = glm::translate(trans, glm::vec3(1.0f, 0.0f, 0.0f)); //trans = glm::rotate(trans, glm::radians(45.0f), glm::vec3(0.0f, 0.0f, 1.0f)); //trans = glm::scale(trans, glm::vec3(1.30, 1.30, 1.30)); glm::mat4 modelMat; //modelMat = glm::rotate(modelMat, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f)); glm::mat4 viewMat; // 注意,咱们将矩阵向咱们要进行移动场景的反方向移动。 viewMat = glm::translate(viewMat, glm::vec3(0.0f, 0.0f, -3.0f)); glm::mat4 projMat; projMat = glm::perspective(glm::radians(45.0f),800.0f / 600.0f,0.1f, 100.0f);//(透视投影,远小近大) while (!glfwWindowShouldClose(window)) { //随时间旋转 modelMat = glm::rotate(modelMat, (float)glfwGetTime() * glm::radians(1.0f), glm::vec3(0.5f, 1.0f, 0.0f)); // 输入 processInput(window); Sleep(200); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //清除颜色及深度测试 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //绑定纹理 glActiveTexture(GL_TEXTURE0); // 在绑定纹理以前先激活纹理单元 glBindTexture(GL_TEXTURE_2D, TexBufferA); glActiveTexture(GL_TEXTURE3); // 在绑定纹理以前先激活纹理单元 glBindTexture(GL_TEXTURE_2D, TexBufferB); glBindVertexArray(VAO); /*glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);*/ glDrawArrays(GL_TRIANGLES, 0, 36); //使用着色器 myShader->use(); glUniform1i(glGetUniformLocation(myShader->ID, "ourTexture"), 0); // 手动设置 //glUniform1i(glGetUniformLocation(myShader->ID, "ourFace"), 3); // 手动设置 myShader->setInt("ourFace", 3); // 或者使用着色器类设置 /*unsigned int transformLoc = glGetUniformLocation(myShader->ID, "transform");*/ /*glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));*/ unsigned int modelMatLoc = glGetUniformLocation(myShader->ID, "modelMat"); unsigned int viewMatLoc = glGetUniformLocation(myShader->ID, "viewMat"); unsigned int projMatLoc = glGetUniformLocation(myShader->ID, "projMat"); glUniformMatrix4fv(modelMatLoc, 1, GL_FALSE, glm::value_ptr(modelMat)); glUniformMatrix4fv(viewMatLoc, 1, GL_FALSE, glm::value_ptr(viewMat)); glUniformMatrix4fv(projMatLoc, 1, GL_FALSE, glm::value_ptr(projMat)); // 画矩形-------------------------------------------------------------------------- //能够知道咱们只有一个三角形VAO,不必每次都绑定它,可是咱们这么作会让代码有一点组织性 glBindVertexArray(VAO); //glDrawArrays(GL_TRIANGLES, 0, 6); /*glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);*/ glDrawArrays(GL_TRIANGLES, 0, 36); // glBindVertexArray(0); //不必每次都解绑 // 交换buffers和poll的IO事件 (按键按下/释放,鼠标移动等.) glfwSwapBuffers(window); glfwPollEvents(); } //一旦他们超出已有的资源,就取消全部资源的分配: glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &EBO); // glfw:终止,清空以前全部的GLFW的预分配资源 glfwTerminate(); return 0; } //查询GLFW相关按键是否被按下/释放,根据状况做出反应 void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); } // g不管窗口大小什么时候改变(由操做系统或用户本身)这个回调函数将会被执行 void framebuffer_size_callback(GLFWwindow* window, int width, int height) { //肯定viewport与新的窗口尺寸匹配; 请注意,宽度和高度将明显大于显示器上指定的宽度和高度。 glViewport(0, 0, width, height); }
#version 330 core layout (location = 6) in vec3 aPos; //layout (location = 7) in vec3 aColor; layout (location = 8) in vec2 aTexCoord; //out vec4 vertexColor; out vec2 TexCoord; uniform mat4 transform; uniform mat4 modelMat; uniform mat4 viewMat; uniform mat4 projMat; void main() { //gl_Position = transform * vec4(aPos.x, aPos.y, aPos.z, 1.0); gl_Position = projMat * viewMat * modelMat * vec4(aPos.x, aPos.y, aPos.z, 1.0); //vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0); TexCoord = aTexCoord; }
#version 330 core out vec4 FragColor; //in vec4 vertexColor; in vec2 TexCoord; uniform sampler2D ourTexture; uniform sampler2D ourFace; void main() { //FragColor = vertexColor; FragColor = mix(texture(ourTexture, TexCoord), texture(ourFace, TexCoord), 0.6); }
注:随时间增大,旋转速度加快,电脑性能很差请及时关闭程序,省得变成暖宝宝。
更多OpenGL知识:现代OpenGL入门教程
有问题请下方评论,转载请注明出处,并附有原文连接,谢谢!若有侵权,请及时联系。