目錄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入門教程
有問題請下方評論,轉載請註明出處,並附有原文連接,謝謝!若有侵權,請及時聯繫。