日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OpenGL从入门到精通--着色器的使用

發(fā)布時間:2025/3/15 编程问答 79 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenGL从入门到精通--着色器的使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

著色器

github源碼倉庫

opengl環(huán)境準備

opengl編程從入門到精通-hello,window

OpenGL從入門到精通–你好三角形

OpenGL從入門到精通–著色器的使用

著色器(Shader)是運行在GPU上的小程序。這些小程序為圖形渲染管線的某個特定部分而運行。從基本意義上來說,著色器只是一種把輸入轉(zhuǎn)化為輸出的程序。著色器也是一種非常獨立的程序,因為它們之間不能相互通信;它們之間唯一的溝通只有通過輸入和輸出。

GLSL

著色器是使用一種叫做GLSL的類C語言寫成的,GLSL是為圖形計算量身定制的,他包含一些針對向量和矩陣操作的有用特性。

著色器的開頭總是要聲明版本,接著是輸入和輸出變量、uniform和main函數(shù)。每個著色器的入口點都是main函數(shù),在這個函數(shù)中我們處理所有的輸入變量,并將結(jié)果輸出到輸出變量中。如果你不知道什么是uniform也不用擔心,我們后面會進行講解。

如下:

#version version_number in type in_variable_name; in type in_variable_name;out type out_variable_name;uniform type uniform_name;int main() {// 處理輸入并進行一些圖形操作...// 輸出處理過的結(jié)果到輸出變量out_variable_name = weird_stuff_we_processed; }

數(shù)據(jù)類型

和其他編程語言一樣,GLSL有數(shù)據(jù)類型可以來指定變量的種類。GLSL中包含C等其它語言大部分的默認基礎(chǔ)數(shù)據(jù)類型:int、float、double、uint和bool。GLSL也有兩種容器類型,它們會在這個教程中使用很多,分別是向量(Vector)和矩陣(Matrix),其中矩陣我們會在之后的教程里再討論。

向量

GLSL中的向量是一個可以包含有1、2、3或者4個分量的容器,分量的類型可以是前面默認基礎(chǔ)類型的任意一個。它們可以是下面的形式(n代表分量的數(shù)量):

類型含義
vecn包含n個float分量的默認向量
bvecn包含n個bool分量的向量
ivecn包含n個int分量的向量
uvecn包含n個unsigned int分量的向量
dvecn包含n個double分量的向量

向量這一數(shù)據(jù)類型也允許一些有趣而靈活的分量選擇方式,叫做重組(Swizzling)。重組允許這樣的語法:

vec2 someVec; vec4 differentVec = someVec.xyxx; vec3 anotherVec = differentVec.zyw; vec4 otherVec = someVec.xxxx + anotherVec.yxzy;

你可以使用上面4個字母任意組合來創(chuàng)建一個和原來向量一樣長的(同類型)新向量,只要原來向量有那些分量即可;然而,你不允許在一個vec2向量中去獲取.z元素。我們也可以把一個向量作為一個參數(shù)傳給不同的向量構(gòu)造函數(shù),以減少需求參數(shù)的數(shù)量:

vec2 vect = vec2(0.5, 0.7); vec4 result = vec4(vect, 0.0, 0.0); vec4 otherResult = vec4(result.xyz, 1.0);

向量是一種靈活的數(shù)據(jù)類型,我們可以把用在各種輸入和輸出上。學(xué)完教程你會看到很多新穎的管理向量的例子。

輸入與輸出

雖然著色器是各自獨立的小程序,但是它們都是一個整體的一部分,出于這樣的原因,我們希望每個著色器都有輸入和輸出,這樣才能進行數(shù)據(jù)交流和傳遞。GLSL定義了in和out關(guān)鍵字專門來實現(xiàn)這個目的。每個著色器使用這兩個關(guān)鍵字設(shè)定輸入和輸出,只要一個輸出變量與下一個著色器階段的輸入匹配,它就會傳遞下去。但在頂點和片段著色器中會有點不同。

頂點著色器應(yīng)該接收的是一種特殊形式的輸入,否則就會效率低下。頂點著色器的輸入特殊在,它從頂點數(shù)據(jù)中直接接收輸入。為了定義頂點數(shù)據(jù)該如何管理,我們使用location這一元數(shù)據(jù)指定輸入變量,這樣我們才可以在CPU上配置頂點屬性。我們已經(jīng)在前面的教程看過這個了,layout (location = 0)。頂點著色器需要為它的輸入提供一個額外的layout標識,這樣我們才能把它鏈接到頂點數(shù)據(jù)。

頂點著色器

#version 330 core layout (location = 0) in vec3 aPos; // 位置變量的屬性位置值為0out vec4 vertexColor; // 為片段著色器指定一個顏色輸出void main() {gl_Position = vec4(aPos, 1.0); // 注意我們?nèi)绾伟岩粋€vec3作為vec4的構(gòu)造器的參數(shù)vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // 把輸出變量設(shè)置為暗紅色 }

片段著色器

#version 330 core out vec4 FragColor;in vec4 vertexColor; // 從頂點著色器傳來的輸入變量(名稱相同、類型相同)void main() {FragColor = vertexColor; }

Uniform

Uniform是一種從CPU中的應(yīng)用向GPU中國捏的著色器發(fā)送數(shù)據(jù)的方式,但是uniform和頂點的屬性有些不同。首先uniform是全局的,全局意味著uniform變量在每個著色器程序?qū)ο笾卸际仟氁粺o二的,而且他可以被著色器程序的任意著色器在任意階段訪問。無論你把uniform設(shè)置成什么,uniform會一直保存它們的數(shù)據(jù),直到它們被重新設(shè)置或者更新。

#version 330 core out vec4 FragColor;uniform vec4 ourColor; // 在OpenGL程序代碼中設(shè)定這個變量void main() {FragColor = ourColor; }

如果你聲明了一個uniform卻在GLSL代碼中沒用過,編譯器會靜默移除這個變量,導(dǎo)致最后編譯出的版本中并不會包含它,這可能導(dǎo)致幾個非常麻煩的錯誤,記住這點!

float timeValue = glfwGetTime(); float greenValue = (sin(timeValue) / 2.0f) + 0.5f; int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor"); glUseProgram(shaderProgram); glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

首先我們通過glfwGetTime()獲取運行的秒數(shù)。然后我們使用sin函數(shù)讓顏色在0.0到1.0之間改變,最后將結(jié)果儲存到greenValue里。

接著,我們用glGetUniformLocation查詢uniform ourColor的位置值。我們?yōu)椴樵兒瘮?shù)提供著色器程序和uniform的名字(這是我們希望獲得的位置值的來源)。如果glGetUniformLocation返回-1就代表沒有找到這個位置值。最后,我們可以通過glUniform4f函數(shù)設(shè)置uniform值。注意,查詢uniform地址不要求你之前使用過著色器程序,但是更新一個uniform之前你必須先使用程序(調(diào)用glUseProgram),因為它是在當前激活的著色器程序中設(shè)置uniform的。

完整源碼實現(xiàn)

// // Created by andrew on 2021/1/17. //#include <glad/glad.h> #include <GLFW/glfw3.h>#include <iostream> #include <math.h>void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window);// settings const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600;const char *vertexShaderSource = "#version 330 core\n""layout (location = 0) in vec3 aPos;\n""void main()\n""{\n"" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n""}\0"; const char *fragmentShaderSource = "#version 330 core\n""out vec4 FragColor;\n""uniform vec4 ourColor;\n""void main()\n""{\n"" FragColor = ourColor;\n""}\n\0";int main() {// glfw: initialize and configure// ------------------------------glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// glfw window creation// --------------------GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// glad: load all OpenGL function pointers// ---------------------------------------if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// build and compile our shader program// ------------------------------------// vertex shaderint vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);// check for shader compile errorsint success;char infoLog[512];glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// fragment shaderint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);// check for shader compile errorsglGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;}// link shadersint shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// check for linking errorsglGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// set up vertex data (and buffer(s)) and configure vertex attributes// ------------------------------------------------------------------float vertices[] = {0.5f, 0.5f, 0.0f, // top right0.5f, -0.5f, 0.0f, // bottom right-0.5f, 0.5f, 0.0f // top left};unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.// 解綁 VAOglBindVertexArray(0);glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized// uncomment this call to draw in wireframe polygons.//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);// 使用線框模式繪制圖形glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // 查看opengl如何繪制矩形// render loop// -----------while (!glfwWindowShouldClose(window)){// input// -----processInput(window);// render// ------glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// be sure to activate the shader before any calls to glUniformglUseProgram(shaderProgram);// update shader uniformdouble timeValue = glfwGetTime();float greenValue = sin(timeValue) / 2.0f + 0.5f;int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);glDrawArrays(GL_TRIANGLES, 0, 3);// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// -------------------------------------------------------------------------------glfwSwapBuffers(window);glfwPollEvents();}// optional: de-allocate all resources once they've outlived their purpose:// ------------------------------------------------------------------------glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteProgram(shaderProgram);// glfw: terminate, clearing all previously allocated GLFW resources.// ------------------------------------------------------------------glfwTerminate();return 0; }// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly // --------------------------------------------------------------------------------------------------------- void processInput(GLFWwindow *window) {if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true); }// glfw: whenever the window size changed (by OS or user resize) this callback function executes // --------------------------------------------------------------------------------------------- void framebuffer_size_callback(GLFWwindow* window, int width, int height) {// make sure the viewport matches the new window dimensions; note that width and// height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height); }

更多屬性!

在前面的教程中,我們了解了如何填充VBO、配置頂點屬性指針以及如何把它們都儲存到一個VAO里。這次,我們同樣打算把顏色數(shù)據(jù)加進頂點數(shù)據(jù)中。我們將把顏色數(shù)據(jù)添加為3個float值至vertices數(shù)組。我們將把三角形的三個角分別指定為紅色、綠色和藍色:

float vertices[] = {// 位置 // 顏色0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 頂部 };

由于現(xiàn)在有更多的數(shù)據(jù)要發(fā)送到頂點著色器,我們有必要去調(diào)整一下頂點著色器,使它能夠接收顏色值作為一個頂點屬性輸入。需要注意的是我們用layout標識符來把aColor屬性的位置值設(shè)置為1:

#version 330 core layout (location = 0) in vec3 aPos; // 位置變量的屬性位置值為 0 layout (location = 1) in vec3 aColor; // 顏色變量的屬性位置值為 1out vec3 ourColor; // 向片段著色器輸出一個顏色void main() {gl_Position = vec4(aPos, 1.0);ourColor = aColor; // 將ourColor設(shè)置為我們從頂點數(shù)據(jù)那里得到的輸入顏色 }

由于我們不再使用uniform來傳遞片段的顏色了,現(xiàn)在使用ourColor輸出變量,我們必須再修改一下片段著色器:

#version 330 core out vec4 FragColor; in vec3 ourColor;void main() {FragColor = vec4(ourColor, 1.0); }

因為我們添加了另一個頂點屬性,并且更新了VBO的內(nèi)存,我們就必須重新配置頂點屬性指針。更新后的VBO內(nèi)存中的數(shù)據(jù)現(xiàn)在看起來像這樣:

知道了現(xiàn)在使用的布局,我們就可以使用glVertexAttribPointer函數(shù)更新頂點格式,

// 位置屬性 // 第一個參數(shù)和 layout (location = 0)對應(yīng) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // 顏色屬性 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float))); glEnableVertexAttribArray(1);

glVertexAttribPointer函數(shù)的前幾個參數(shù)比較明了。這次我們配置屬性位置值為1的頂點屬性。顏色值有3個float那么大,我們不去標準化這些值。

由于我們現(xiàn)在有了兩個頂點屬性,我們不得不重新計算步長值。為獲得數(shù)據(jù)隊列中下一個屬性值(比如位置向量的下個x分量)我們必須向右移動6個float,其中3個是位置值,另外3個是顏色值。這使我們的步長值為6乘以float的字節(jié)數(shù)(=24字節(jié))。
同樣,這次我們必須指定一個偏移量。對于每個頂點來說,位置頂點屬性在前,所以它的偏移量是0。顏色屬性緊隨位置數(shù)據(jù)之后,所以偏移量就是3 * sizeof(float),用字節(jié)來計算就是12字節(jié)。

運行程序你應(yīng)該會看到如下結(jié)果:

如果你在哪卡住了,可以在這里查看源碼。

這個圖片可能不是你所期望的那種,因為我們只提供了3個顏色,而不是我們現(xiàn)在看到的大調(diào)色板。這是在片段著色器中進行的所謂片段插值(Fragment Interpolation)的結(jié)果。當渲染一個三角形時,光柵化(Rasterization)階段通常會造成比原指定頂點更多的片段。光柵會根據(jù)每個片段在三角形形狀上所處相對位置決定這些片段的位置。
基于這些位置,它會插值(Interpolate)所有片段著色器的輸入變量。比如說,我們有一個線段,上面的端點是綠色的,下面的端點是藍色的。如果一個片段著色器在線段的70%的位置運行,它的顏色輸入屬性就會是一個綠色和藍色的線性結(jié)合;更精確地說就是30%藍 + 70%綠。

這正是在這個三角形中發(fā)生了什么。我們有3個頂點,和相應(yīng)的3個顏色,從這個三角形的像素來看它可能包含50000左右的片段,片段著色器為這些像素進行插值顏色。如果你仔細看這些顏色就應(yīng)該能明白了:紅首先變成到紫再變?yōu)樗{色。片段插值會被應(yīng)用到片段著色器的所有輸入屬性上。

完整代碼

// // Created by andrew on 2021/1/17. //#include <glad/glad.h> #include <GLFW/glfw3.h>#include <iostream> #include <cmath>using namespace std;void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window);// settings const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600;const char *vertexShaderSource = "#version 330 core\n""layout (location = 0) in vec3 aPos;\n""layout (location = 1) in vec3 aColor;\n""out vec3 ourColor;\n""void main()\n""{\n"" gl_Position = vec4(aPos, 1.0);\n"" ourColor = aColor;\n""}\0"; const char *fragmentShaderSource = "#version 330 core\n""out vec4 FragColor;\n""in vec3 ourColor;\n""void main()\n""{\n"" FragColor = vec4(ourColor, 1.0f);\n""}\n\0";int main() {// glfw: initialize and configure// ------------------------------glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// glfw window creation// --------------------GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){cout << "Failed to create GLFW window" << endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// glad: load all OpenGL function pointers// ---------------------------------------if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){cout << "Failed to initialize GLAD" << endl;return -1;}// build and compile our shader program// ------------------------------------// vertex shaderint vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);// check for shader compile errorsint success;char infoLog[512];glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// fragment shaderint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);glCompileShader(fragmentShader);// check for shader compile errorsglGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;}// link shadersint shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// check for linking errorsglGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// set up vertex data (and buffer(s)) and configure vertex attributes// ------------------------------------------------------------------float vertices[] = {// positions // colors0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top};unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 要和shader對應(yīng), "layout (location = 0) in vec3 aPos;\n" 對應(yīng)這里第一個參數(shù),也就是索引// 這里第一個參數(shù)對應(yīng)的0 要說明0參數(shù)加載的方式 // 6 * sizeof(float) 每次的步長glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// color attributeglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.// 解綁 VAO 防止有多個 VAO時渲染出錯glBindVertexArray(0);// uncomment this call to draw in wireframe polygons.//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);// 使用線框模式繪制圖形// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // 查看opengl如何繪制矩形// seeing as we only have a single VAO there's// no need to bind it every time, but we'll do so to keep things a bit more organized// VAO只有一個只需要綁定一次就行了glBindVertexArray(VAO);// 連接器只有一個,只需要綁定一次就行了// as we only have a single shader, we could also just activate our shader once beforehand if we want toglUseProgram(shaderProgram);// render loop// -----------while (!glfwWindowShouldClose(window)){// input// -----processInput(window);// render// ------glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// 繪制三角形,渲染三角形glDrawArrays(GL_TRIANGLES, 0, 3);// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// -------------------------------------------------------------------------------glfwSwapBuffers(window);glfwPollEvents();}// optional: de-allocate all resources once they've outlived their purpose:// ------------------------------------------------------------------------glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteProgram(shaderProgram);// glfw: terminate, clearing all previously allocated GLFW resources.// ------------------------------------------------------------------glfwTerminate();return 0; }// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly // --------------------------------------------------------------------------------------------------------- void processInput(GLFWwindow *window) {if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true); }// glfw: whenever the window size changed (by OS or user resize) this callback function executes // --------------------------------------------------------------------------------------------- void framebuffer_size_callback(GLFWwindow* window, int width, int height) {// make sure the viewport matches the new window dimensions; note that width and// height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height); }

讀取文件獲取vs和fs

將著色器的處理封裝到一個類中,這樣就不用每次都處理著色器的代碼了

shader_s.h

// // Created by andrew on 2021/1/17. //#ifndef OPENGL_SHADER_S_H #define OPENGL_SHADER_S_H#include <glad/glad.h>#include <string> #include <fstream> #include <sstream> #include <iostream>class Shader { public:// 程序IDunsigned int ID;// 構(gòu)造器讀取并構(gòu)建著色器// constructor generates the shader on the fly// ------------------------------------------------------------------------Shader(const char* vertexPath, const char* fragmentPath){// 1. retrieve the vertex/fragment source code from filePathstd::string vertexCode;std::string fragmentCode;std::ifstream vShaderFile;std::ifstream fShaderFile;// ensure ifstream objects can throw exceptions:vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);try{// open filesvShaderFile.open(vertexPath);fShaderFile.open(fragmentPath);std::stringstream vShaderStream, fShaderStream;// read file's buffer contents into streamsvShaderStream << vShaderFile.rdbuf();fShaderStream << fShaderFile.rdbuf();std::cout << vShaderStream.str() << std::endl;// close file handlersvShaderFile.close();fShaderFile.close();// convert stream into stringvertexCode = vShaderStream.str();fragmentCode = fShaderStream.str();}catch (std::ifstream::failure& e){std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;}const char* vShaderCode = vertexCode.c_str();const char * fShaderCode = fragmentCode.c_str();// 2. compile shadersunsigned int vertex, fragment;// vertex shadervertex = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertex, 1, &vShaderCode, NULL);glCompileShader(vertex);checkCompileErrors(vertex, "VERTEX");// fragment Shaderfragment = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragment, 1, &fShaderCode, NULL);glCompileShader(fragment);checkCompileErrors(fragment, "FRAGMENT");// shader ProgramID = glCreateProgram();glAttachShader(ID, vertex);glAttachShader(ID, fragment);glLinkProgram(ID);checkCompileErrors(ID, "PROGRAM");// delete the shaders as they're linked into our program now and no longer necessaryglDeleteShader(vertex);glDeleteShader(fragment);}// activate the shader// ------------------------------------------------------------------------void use() const{glUseProgram(ID);}// 注意下面這幾個函數(shù)一定要在use之后才能是使用,只有激活了對應(yīng)的程序更改uniform值才能生效// utility uniform functions// ------------------------------------------------------------------------void setBool(const std::string &name, bool value) const{glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);}// ------------------------------------------------------------------------void setInt(const std::string &name, int value) const{glUniform1i(glGetUniformLocation(ID, name.c_str()), value);}// ------------------------------------------------------------------------void setFloat(const std::string &name, float value) const{// glGetUniformLocation獲取對應(yīng)uniform的location的名字 // std::cout << name.c_str() << "ID" <<ID << std::endl;glUniform1f(glGetUniformLocation(ID, name.c_str()), value);}private:// utility function for checking shader compilation/linking errors.// ------------------------------------------------------------------------static void checkCompileErrors(unsigned int shader, std::string type){int success;char infoLog[1024];if (type != "PROGRAM"){glGetShaderiv(shader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(shader, 1024, NULL, infoLog);std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;}}else{glGetProgramiv(shader, GL_LINK_STATUS, &success);if (!success){glGetProgramInfoLog(shader, 1024, NULL, infoLog);std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;}}} };#endif //OPENGL_SHADER_S_H

著色器代碼放到文件中

shader_vs1.vs

#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aColor;out vec3 ourColor;void main() {gl_Position = vec4(aPos, 1.0);ourColor = aColor; }

shader_vs2.vs

#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aColor;out vec3 ourColor;void main() {vec3 tmpPos;tmpPos = vec3(aPos.x, -aPos.y, aPos.z);gl_Position = vec4(tmpPos, 1.0);ourColor = aColor; }

shader_vs3.vs

#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aColor;out vec3 ourColor;uniform float xOffset;void main() {gl_Position = vec4(aPos.x + xOffset, aPos.y, aPos.z, 1.0); // add the xOffset to the x position of the vertex positionourColor = aColor; }

shader_vs4.vs

// Vertex shader: // ============== #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aColor;// out vec3 ourColor; out vec3 ourPosition;void main() {gl_Position = vec4(aPos, 1.0);// ourColor = aColor;ourPosition = aPos; }

shader_fs4,fs

// Fragment shader: // ================ #version 330 core out vec4 FragColor; // in vec3 ourColor; in vec3 ourPosition;void main() {FragColor = vec4(ourPosition, 1.0); // note how the position value is linearly interpolated to get all the different colors }/* Answer to the question: Do you know why the bottom-left side is black? -- -------------------------------------------------------------------- Think about this for a second: the output of our fragment's color is equal to the (interpolated) coordinate of the triangle. What is the coordinate of the bottom-left point of our triangle? This is (-0.5f, -0.5f, 0.0f). Since the xy values are negative they are clamped to a value of 0.0f. This happens all the way to the center sides of the triangle since from that point on the values will be interpolated positively again. Values of 0.0f are of course black and that explains the black side of the triangle. */

通過修改vs文件實現(xiàn)三角形的反轉(zhuǎn)

// // Created by andrew on 2021/1/17. // #include "glad/glad.h" #include <GLFW/glfw3.h> #include "shader/shader_s.h"#include <iostream>using namespace std;void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window);// settings const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600;int main() {// 對glfw進行初始化glfwInit();// 打印出glfw的版本信息// int* major, int* minor, int* revint major, minor, rev;glfwGetVersion(&major, &minor, &rev);cout << "major = " << major << " minor = " << minor << " rev = " << rev << endl;glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// glfw window creation// glfw創(chuàng)建窗口GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr);if (window == nullptr){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}// 為當前window設(shè)置上下文,每個線程只能設(shè)置一個,并且線程之間共用時,需要將當前線程設(shè)置為 non-currentglfwMakeContextCurrent(window);// 設(shè)置窗口大小的回調(diào)函數(shù),當窗口大小改變時,會調(diào)用該函數(shù)調(diào)整串口的大小// 注冊窗口大小改變回調(diào)函數(shù)glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// glad: load all OpenGL function pointers// glad 會加載所有openGL函數(shù)指針,在調(diào)用任何opengl函數(shù)之前需要先初始化gladif (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){cout << "Failed to initialize GLAD" << std::endl;return -1;}// build and compile our shader program// ------------------------------------Shader ourShader("/work/opengl_tutorial/src/shader_src/shader_vs2.vs","/work/opengl_tutorial/src/shader_src/shader_fs1.fs"); // you can name your shader files however you like// set up vertex data (and buffer(s)) and configure vertex attributes// ------------------------------------------------------------------float vertices[] = {// positions // colors0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top};unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s)./* 要想使用VAO,要做的只是使用glBindVertexArray綁定VAO。從綁定之后起,我們應(yīng)該綁定和配置對應(yīng)的VBO和屬性指針,之后解綁VAO供之后使用 *//* // ..:: 初始化代碼(只運行一次 (除非你的物體頻繁改變)) :: ..// 1. 綁定VAO */glBindVertexArray(VAO);// 2. 把頂點數(shù)組復(fù)制到緩沖中供OpenGL使用glBindBuffer(GL_ARRAY_BUFFER, VBO);// 把之前定義的頂點,復(fù)制到緩沖的內(nèi)存中去/*GL_STATIC_DRAW :數(shù)據(jù)不會或幾乎不會改變。GL_DYNAMIC_DRAW:數(shù)據(jù)會被改變很多。GL_STREAM_DRAW :數(shù)據(jù)每次繪制時都會改變。 *//*三角形的位置數(shù)據(jù)不會改變,每次渲染調(diào)用時都保持原樣,所以它的使用類型最好是GL_STATIC_DRAW。如果,比如說一個緩沖中的數(shù)據(jù)將頻繁被改變,那么使用的類型就是GL_DYNAMIC_DRAW或GL_STREAM_DRAW,這樣就能確保顯卡把數(shù)據(jù)放在能夠高速寫入的內(nèi)存部分。 */glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);/*位置數(shù)據(jù)被儲存為32位(4字節(jié))浮點值。每個位置包含3個這樣的值。在這3個值之間沒有空隙(或其他值)。這幾個值在數(shù)組中緊密排列(Tightly Packed)。數(shù)據(jù)中第一個值在緩沖開始的位置 */// 告訴GPU數(shù)據(jù)怎樣取/*第一個參數(shù)指定我們要配置的頂點屬性。還記得我們在頂點著色器中使用layout(location = 0)定義了position頂點屬性的位置值(Location)嗎?它可以把頂點屬性的位置值設(shè)置為0。因為我們希望把數(shù)據(jù)傳遞到這一個頂點屬性中,所以這里我們傳入0。第二個參數(shù)指定頂點屬性的大小。頂點屬性是一個vec3,它由3個值組成,所以大小是3。第三個參數(shù)指定數(shù)據(jù)的類型,這里是GL_FLOAT(GLSL中vec*都是由浮點數(shù)值組成的)。下個參數(shù)定義我們是否希望數(shù)據(jù)被標準化(Normalize)。如果我們設(shè)置為GL_TRUE,所有數(shù)據(jù)都會被映射到0(對于有符號型signed數(shù)據(jù)是-1)到1之間。我們把它設(shè)置為GL_FALSE。第五個參數(shù)叫做步長(Stride),它告訴我們在連續(xù)的頂點屬性組之間的間隔。由于下個組位置數(shù)據(jù)在3個float之后,我們把步長設(shè)置為3 * sizeof(float)。要注意的是由于我們知道這個數(shù)組是緊密排列的(在兩個頂點屬性之間沒有空隙)我們也可以設(shè)置為0來讓OpenGL決定具體步長是多少(只有當數(shù)值是緊密排列時才可用)。一旦我們有更多的頂點屬性,我們就必須更小心地定義每個頂點屬性之間的間隔,我們在后面會看到更多的例子(譯注: 這個參數(shù)的意思簡單說就是從這個屬性第二次出現(xiàn)的地方到整個數(shù)組0位置之間有多少字節(jié))。最后一個參數(shù)的類型是void*,所以需要我們進行這個奇怪的強制類型轉(zhuǎn)換。它表示位置數(shù)據(jù)在緩沖中起始位置的偏移量(Offset)。由于位置數(shù)據(jù)在數(shù)組的開頭,所以這里是0。我們會在后面詳細解釋這個參數(shù)。 */// 設(shè)置頂點屬性指針glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);/*現(xiàn)在我們已經(jīng)定義了OpenGL該如何解釋頂點數(shù)據(jù),我們現(xiàn)在應(yīng)該使用glEnableVertexAttribArray,以頂點屬性位置值作為參數(shù),啟用頂點屬性;頂點屬性默認是禁用的。 */glEnableVertexAttribArray(0);// color attributeglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));// 啟用對應(yīng)頂點的屬性,頂點定義在vs完成glEnableVertexAttribArray(1);// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.// glBindVertexArray(0);// uncomment this call to draw in wireframe polygons.//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);/*就這么多了!前面做的一切都是等待這一刻,一個儲存了我們頂點屬性配置和應(yīng)使用的VBO的頂點數(shù)組對象。一般當你打算繪制多個物體時,你首先要生成/配置所有的VAO(和必須的VBO及屬性指針),然后儲存它們供后面使用。當我們打算繪制物體的時候就拿出相應(yīng)的VAO,綁定它,繪制完物體后,再解綁VAO。*/// render loop// -----------while (!glfwWindowShouldClose(window)){// input// -----processInput(window);// render// ------// 北背景glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// draw our first triangle// 2. 當我們渲染一個物體時要使用著色器程序ourShader.use();glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized// 3. 繪制物體glDrawArrays(GL_TRIANGLES, 0, 3);// glBindVertexArray(0); // no need to unbind it every time// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// -------------------------------------------------------------------------------glfwSwapBuffers(window);glfwPollEvents();}// 正確的釋放之前分配的所有資源glfwTerminate();return 0; }// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly // --------------------------------------------------------------------------------------------------------- void processInput(GLFWwindow *window) {// 用戶按下 esc鍵,就設(shè)置退出串口為真if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true); }// glfw: whenever the window size changed (by OS or user resize) this callback function executes // --------------------------------------------------------------------------------------------- void framebuffer_size_callback(GLFWwindow* window, int width, int height) {// opengl渲染串口大小,每次調(diào)整窗口cout << "view port call back" << endl;//glViewport(0, 0, width, height); }

通過更改uniform實現(xiàn)三角形右移

float offset = 0.5f; ourShader.setFloat("xOffset", offset); // // Created by andrew on 2021/1/17. // #include "glad/glad.h" #include <GLFW/glfw3.h> #include "shader/shader_s.h"#include <iostream>using namespace std;void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window);// settings const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600;int main() {// 對glfw進行初始化glfwInit();// 打印出glfw的版本信息// int* major, int* minor, int* revint major, minor, rev;glfwGetVersion(&major, &minor, &rev);cout << "major = " << major << " minor = " << minor << " rev = " << rev << endl;glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// glfw window creation// glfw創(chuàng)建窗口GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr);if (window == nullptr){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}// 為當前window設(shè)置上下文,每個線程只能設(shè)置一個,并且線程之間共用時,需要將當前線程設(shè)置為 non-currentglfwMakeContextCurrent(window);// 設(shè)置窗口大小的回調(diào)函數(shù),當窗口大小改變時,會調(diào)用該函數(shù)調(diào)整串口的大小// 注冊窗口大小改變回調(diào)函數(shù)glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// glad: load all OpenGL function pointers// glad 會加載所有openGL函數(shù)指針,在調(diào)用任何opengl函數(shù)之前需要先初始化gladif (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){cout << "Failed to initialize GLAD" << std::endl;return -1;}// build and compile our shader program// ------------------------------------Shader ourShader("/work/opengl_tutorial/src/shader_src/shader_vs3.vs","/work/opengl_tutorial/src/shader_src/shader_fs1.fs"); // you can name your shader files however you like// set up vertex data (and buffer(s)) and configure vertex attributes// ------------------------------------------------------------------float vertices[] = {// positions // colors0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top};unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s)./* 要想使用VAO,要做的只是使用glBindVertexArray綁定VAO。從綁定之后起,我們應(yīng)該綁定和配置對應(yīng)的VBO和屬性指針,之后解綁VAO供之后使用 *//* // ..:: 初始化代碼(只運行一次 (除非你的物體頻繁改變)) :: ..// 1. 綁定VAO */glBindVertexArray(VAO);// 2. 把頂點數(shù)組復(fù)制到緩沖中供OpenGL使用glBindBuffer(GL_ARRAY_BUFFER, VBO);// 把之前定義的頂點,復(fù)制到緩沖的內(nèi)存中去/*GL_STATIC_DRAW :數(shù)據(jù)不會或幾乎不會改變。GL_DYNAMIC_DRAW:數(shù)據(jù)會被改變很多。GL_STREAM_DRAW :數(shù)據(jù)每次繪制時都會改變。 *//*三角形的位置數(shù)據(jù)不會改變,每次渲染調(diào)用時都保持原樣,所以它的使用類型最好是GL_STATIC_DRAW。如果,比如說一個緩沖中的數(shù)據(jù)將頻繁被改變,那么使用的類型就是GL_DYNAMIC_DRAW或GL_STREAM_DRAW,這樣就能確保顯卡把數(shù)據(jù)放在能夠高速寫入的內(nèi)存部分。 */glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);/*位置數(shù)據(jù)被儲存為32位(4字節(jié))浮點值。每個位置包含3個這樣的值。在這3個值之間沒有空隙(或其他值)。這幾個值在數(shù)組中緊密排列(Tightly Packed)。數(shù)據(jù)中第一個值在緩沖開始的位置 */// 告訴GPU數(shù)據(jù)怎樣取/*第一個參數(shù)指定我們要配置的頂點屬性。還記得我們在頂點著色器中使用layout(location = 0)定義了position頂點屬性的位置值(Location)嗎?它可以把頂點屬性的位置值設(shè)置為0。因為我們希望把數(shù)據(jù)傳遞到這一個頂點屬性中,所以這里我們傳入0。第二個參數(shù)指定頂點屬性的大小。頂點屬性是一個vec3,它由3個值組成,所以大小是3。第三個參數(shù)指定數(shù)據(jù)的類型,這里是GL_FLOAT(GLSL中vec*都是由浮點數(shù)值組成的)。下個參數(shù)定義我們是否希望數(shù)據(jù)被標準化(Normalize)。如果我們設(shè)置為GL_TRUE,所有數(shù)據(jù)都會被映射到0(對于有符號型signed數(shù)據(jù)是-1)到1之間。我們把它設(shè)置為GL_FALSE。第五個參數(shù)叫做步長(Stride),它告訴我們在連續(xù)的頂點屬性組之間的間隔。由于下個組位置數(shù)據(jù)在3個float之后,我們把步長設(shè)置為3 * sizeof(float)。要注意的是由于我們知道這個數(shù)組是緊密排列的(在兩個頂點屬性之間沒有空隙)我們也可以設(shè)置為0來讓OpenGL決定具體步長是多少(只有當數(shù)值是緊密排列時才可用)。一旦我們有更多的頂點屬性,我們就必須更小心地定義每個頂點屬性之間的間隔,我們在后面會看到更多的例子(譯注: 這個參數(shù)的意思簡單說就是從這個屬性第二次出現(xiàn)的地方到整個數(shù)組0位置之間有多少字節(jié))。最后一個參數(shù)的類型是void*,所以需要我們進行這個奇怪的強制類型轉(zhuǎn)換。它表示位置數(shù)據(jù)在緩沖中起始位置的偏移量(Offset)。由于位置數(shù)據(jù)在數(shù)組的開頭,所以這里是0。我們會在后面詳細解釋這個參數(shù)。 */// 設(shè)置頂點屬性指針glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);/*現(xiàn)在我們已經(jīng)定義了OpenGL該如何解釋頂點數(shù)據(jù),我們現(xiàn)在應(yīng)該使用glEnableVertexAttribArray,以頂點屬性位置值作為參數(shù),啟用頂點屬性;頂點屬性默認是禁用的。 */glEnableVertexAttribArray(0);// color attributeglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));// 啟用對應(yīng)頂點的屬性,頂點定義在vs完成glEnableVertexAttribArray(1);// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.// glBindVertexArray(0);// uncomment this call to draw in wireframe polygons.//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);/*就這么多了!前面做的一切都是等待這一刻,一個儲存了我們頂點屬性配置和應(yīng)使用的VBO的頂點數(shù)組對象。一般當你打算繪制多個物體時,你首先要生成/配置所有的VAO(和必須的VBO及屬性指針),然后儲存它們供后面使用。當我們打算繪制物體的時候就拿出相應(yīng)的VAO,綁定它,繪制完物體后,再解綁VAO。*/// render loop// -----------while (!glfwWindowShouldClose(window)){// input// -----processInput(window);// render// ------// 北背景glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// draw our first triangle// 2. 當我們渲染一個物體時要使用著色器程序ourShader.use();float offset = 0.5f;ourShader.setFloat("xOffset", offset);glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized// 3. 繪制物體glDrawArrays(GL_TRIANGLES, 0, 3);// glBindVertexArray(0); // no need to unbind it every time// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// -------------------------------------------------------------------------------glfwSwapBuffers(window);glfwPollEvents();}// 正確的釋放之前分配的所有資源glfwTerminate();return 0; }// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly // --------------------------------------------------------------------------------------------------------- void processInput(GLFWwindow *window) {// 用戶按下 esc鍵,就設(shè)置退出串口為真if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true); }// glfw: whenever the window size changed (by OS or user resize) this callback function executes // --------------------------------------------------------------------------------------------- void framebuffer_size_callback(GLFWwindow* window, int width, int height) {// opengl渲染串口大小,每次調(diào)整窗口cout << "view port call back" << endl;//glViewport(0, 0, width, height); }

將三角形的頂點數(shù)據(jù)作為顏色數(shù)據(jù)使用

// // Created by andrew on 2021/1/17. // #include "glad/glad.h" #include <GLFW/glfw3.h> #include "shader/shader_s.h"#include <iostream>using namespace std;void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window);// settings const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600;int main() {// 對glfw進行初始化glfwInit();// 打印出glfw的版本信息// int* major, int* minor, int* revint major, minor, rev;glfwGetVersion(&major, &minor, &rev);cout << "major = " << major << " minor = " << minor << " rev = " << rev << endl;glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// glfw window creation// glfw創(chuàng)建窗口GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr);if (window == nullptr){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}// 為當前window設(shè)置上下文,每個線程只能設(shè)置一個,并且線程之間共用時,需要將當前線程設(shè)置為 non-currentglfwMakeContextCurrent(window);// 設(shè)置窗口大小的回調(diào)函數(shù),當窗口大小改變時,會調(diào)用該函數(shù)調(diào)整串口的大小// 注冊窗口大小改變回調(diào)函數(shù)glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// glad: load all OpenGL function pointers// glad 會加載所有openGL函數(shù)指針,在調(diào)用任何opengl函數(shù)之前需要先初始化gladif (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){cout << "Failed to initialize GLAD" << std::endl;return -1;}// build and compile our shader program// ------------------------------------Shader ourShader("/work/opengl_tutorial/src/shader_src/shader_vs4.vs","/work/opengl_tutorial/src/shader_src/shader_fs4.fs"); // you can name your shader files however you like// set up vertex data (and buffer(s)) and configure vertex attributes// ------------------------------------------------------------------float vertices[] = {// positions // colors0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top};unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s)./* 要想使用VAO,要做的只是使用glBindVertexArray綁定VAO。從綁定之后起,我們應(yīng)該綁定和配置對應(yīng)的VBO和屬性指針,之后解綁VAO供之后使用 *//* // ..:: 初始化代碼(只運行一次 (除非你的物體頻繁改變)) :: ..// 1. 綁定VAO */glBindVertexArray(VAO);// 2. 把頂點數(shù)組復(fù)制到緩沖中供OpenGL使用glBindBuffer(GL_ARRAY_BUFFER, VBO);// 把之前定義的頂點,復(fù)制到緩沖的內(nèi)存中去/*GL_STATIC_DRAW :數(shù)據(jù)不會或幾乎不會改變。GL_DYNAMIC_DRAW:數(shù)據(jù)會被改變很多。GL_STREAM_DRAW :數(shù)據(jù)每次繪制時都會改變。 *//*三角形的位置數(shù)據(jù)不會改變,每次渲染調(diào)用時都保持原樣,所以它的使用類型最好是GL_STATIC_DRAW。如果,比如說一個緩沖中的數(shù)據(jù)將頻繁被改變,那么使用的類型就是GL_DYNAMIC_DRAW或GL_STREAM_DRAW,這樣就能確保顯卡把數(shù)據(jù)放在能夠高速寫入的內(nèi)存部分。 */glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);/*位置數(shù)據(jù)被儲存為32位(4字節(jié))浮點值。每個位置包含3個這樣的值。在這3個值之間沒有空隙(或其他值)。這幾個值在數(shù)組中緊密排列(Tightly Packed)。數(shù)據(jù)中第一個值在緩沖開始的位置 */// 告訴GPU數(shù)據(jù)怎樣取/*第一個參數(shù)指定我們要配置的頂點屬性。還記得我們在頂點著色器中使用layout(location = 0)定義了position頂點屬性的位置值(Location)嗎?它可以把頂點屬性的位置值設(shè)置為0。因為我們希望把數(shù)據(jù)傳遞到這一個頂點屬性中,所以這里我們傳入0。第二個參數(shù)指定頂點屬性的大小。頂點屬性是一個vec3,它由3個值組成,所以大小是3。第三個參數(shù)指定數(shù)據(jù)的類型,這里是GL_FLOAT(GLSL中vec*都是由浮點數(shù)值組成的)。下個參數(shù)定義我們是否希望數(shù)據(jù)被標準化(Normalize)。如果我們設(shè)置為GL_TRUE,所有數(shù)據(jù)都會被映射到0(對于有符號型signed數(shù)據(jù)是-1)到1之間。我們把它設(shè)置為GL_FALSE。第五個參數(shù)叫做步長(Stride),它告訴我們在連續(xù)的頂點屬性組之間的間隔。由于下個組位置數(shù)據(jù)在3個float之后,我們把步長設(shè)置為3 * sizeof(float)。要注意的是由于我們知道這個數(shù)組是緊密排列的(在兩個頂點屬性之間沒有空隙)我們也可以設(shè)置為0來讓OpenGL決定具體步長是多少(只有當數(shù)值是緊密排列時才可用)。一旦我們有更多的頂點屬性,我們就必須更小心地定義每個頂點屬性之間的間隔,我們在后面會看到更多的例子(譯注: 這個參數(shù)的意思簡單說就是從這個屬性第二次出現(xiàn)的地方到整個數(shù)組0位置之間有多少字節(jié))。最后一個參數(shù)的類型是void*,所以需要我們進行這個奇怪的強制類型轉(zhuǎn)換。它表示位置數(shù)據(jù)在緩沖中起始位置的偏移量(Offset)。由于位置數(shù)據(jù)在數(shù)組的開頭,所以這里是0。我們會在后面詳細解釋這個參數(shù)。 */// 設(shè)置頂點屬性指針glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);/*現(xiàn)在我們已經(jīng)定義了OpenGL該如何解釋頂點數(shù)據(jù),我們現(xiàn)在應(yīng)該使用glEnableVertexAttribArray,以頂點屬性位置值作為參數(shù),啟用頂點屬性;頂點屬性默認是禁用的。 */glEnableVertexAttribArray(0);// color attributeglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));// 啟用對應(yīng)頂點的屬性,頂點定義在vs完成glEnableVertexAttribArray(1);// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.// glBindVertexArray(0);// uncomment this call to draw in wireframe polygons.//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);/*就這么多了!前面做的一切都是等待這一刻,一個儲存了我們頂點屬性配置和應(yīng)使用的VBO的頂點數(shù)組對象。一般當你打算繪制多個物體時,你首先要生成/配置所有的VAO(和必須的VBO及屬性指針),然后儲存它們供后面使用。當我們打算繪制物體的時候就拿出相應(yīng)的VAO,綁定它,繪制完物體后,再解綁VAO。*/// render loop// -----------while (!glfwWindowShouldClose(window)){// input// -----processInput(window);// render// ------// 北背景glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// draw our first triangle// 2. 當我們渲染一個物體時要使用著色器程序ourShader.use();float offset = 0.5f;ourShader.setFloat("xOffset", offset);glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized// 3. 繪制物體glDrawArrays(GL_TRIANGLES, 0, 3);// glBindVertexArray(0); // no need to unbind it every time// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// -------------------------------------------------------------------------------glfwSwapBuffers(window);glfwPollEvents();}// 正確的釋放之前分配的所有資源glfwTerminate();return 0; }// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly // --------------------------------------------------------------------------------------------------------- void processInput(GLFWwindow *window) {// 用戶按下 esc鍵,就設(shè)置退出串口為真if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true); }// glfw: whenever the window size changed (by OS or user resize) this callback function executes // --------------------------------------------------------------------------------------------- void framebuffer_size_callback(GLFWwindow* window, int width, int height) {// opengl渲染串口大小,每次調(diào)整窗口cout << "view port call back" << endl;//glViewport(0, 0, width, height); }

與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的OpenGL从入门到精通--着色器的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

a级国产乱理论片在线观看 特级毛片在线观看 | 91av看片| 91成熟丰满女人少妇 | 中文字幕av全部资源www中文字幕在线观看 | 激情综合五月天 | www.久久视频| 国产综合91 | 日韩中字在线观看 | 色婷婷视频 | 国产精品美女久久久久久久久久久 | 日本三级在线观看中文字 | 视频在线一区二区三区 | 国产精品成人aaaaa网站 | 香蕉视频在线免费看 | 蜜臀aⅴ精品一区二区三区 久久视屏网 | 国产欧美日韩一区 | 午夜.dj高清免费观看视频 | 最近2019年日本中文免费字幕 | 久久久久国产免费免费 | 欧美精品黑人性xxxx | 久久免费在线 | 国产精品久久久久久久久久久久 | 国产精品福利久久久 | 国产黄色在线网站 | 黄色一级在线视频 | 少妇bbbb搡bbbb搡bbbb | 国内毛片毛片 | 久久久噜噜噜久久久 | 久久久久久亚洲精品 | 在线视频免费观看 | 999电影免费在线观看 | 91精品久久久久久久久 | 一级片免费观看 | 久久伊人精品一区二区三区 | 18国产精品白浆在线观看免费 | 在线中文字幕观看 | 亚洲在线观看av | 亚洲九九九在线观看 | 狠狠狠色丁香婷婷综合久久五月 | 在线观看视频91 | 日韩av不卡在线 | 亚洲精品午夜久久久久久久 | 天天干,天天干 | 日韩高清精品一区二区 | 国产小视频在线观看免费 | 色综合久久久网 | 91精品爽啪蜜夜国产在线播放 | 国产一级二级三级在线观看 | 国产免费国产 | 国产小视频免费在线观看 | 天堂av免费在线 | 成人一级黄色片 | 91久久人澡人人添人人爽欧美 | 婷婷国产在线观看 | 伊人婷婷激情 | 成年人电影免费在线观看 | 日韩在线视频一区 | 97品白浆高清久久久久久 | 国产私拍在线 | 麻豆国产在线视频 | 91av视频在线观看免费 | 天天鲁一鲁摸一摸爽一爽 | 美女网站色在线观看 | 国产视频在线免费观看 | 麻豆视频在线免费看 | 伊人色综合久久天天网 | 国产高清av免费在线观看 | 岛国一区在线 | 国产精品99久久久久久武松影视 | 一级黄色毛片 | 日韩在线一二三区 | 亚洲精品在线视频网站 | 在线观看亚洲精品视频 | 国产日韩欧美在线 | 欧美精品免费一区二区 | 超碰在线cao | 婷婷国产一区二区三区 | 一级国产视频 | 午夜视频在线观看一区二区三区 | 天堂av色婷婷一区二区三区 | 中文字幕中文 | 国产精品一区二区电影 | 国产日本亚洲高清 | 国产一二三四在线视频 | 精品久久影院 | 国产在线第三页 | 激情综合网五月 | 超碰在线人人爱 | 99国产免费网址 | 92中文资源在线 | 色av资源网| 成人丝袜| 夜夜操天天干 | 国产精品美乳一区二区免费 | 日韩精品免费在线观看视频 | 综合精品久久 | 久久超碰99| 99久久www | 一区二区三区在线视频111 | 久久精品国产亚洲精品 | 亚洲国产精品999 | 人人超碰97 | 91麻豆高清视频 | 亚洲经典视频在线观看 | 久草在线99| 99在线精品视频在线观看 | 肉色欧美久久久久久久免费看 | 黄色成人在线观看 | 日韩免费中文 | 久久热亚洲 | 日本系列中文字幕 | 黄色特级毛片 | 黄色a在线观看 | 国产精品永久久久久久久www | 永久免费毛片在线观看 | 一区电影 | 伊人久久五月天 | 亚洲一区欧美精品 | 欧美日韩精品电影 | 欧美色图另类 | 欧美日性视频 | 日韩高清在线一区二区 | 二区三区中文字幕 | 五月婷婷深开心 | 日韩一级成人av | 成人免费观看完整版电影 | 亚洲影院国产 | 日韩二区三区在线观看 | 久久情侣偷拍 | 成人av电影在线 | 丁香色综合| 成人蜜桃视频 | 六月婷操 | 久久久久久久久艹 | 亚洲无线视频 | 国产成人亚洲精品自产在线 | 午夜视频一区二区 | 精品中文字幕在线观看 | 亚洲乱码精品 | 免费看的黄色 | 国产精品嫩草影院99网站 | 日韩精品视频久久 | 亚洲激情精品 | 精品嫩模福利一区二区蜜臀 | 国产精品免费久久久久 | 我爱av激情网 | 欧美一区二区三区在线播放 | 激情五月五月婷婷 | 国产黄色一级大片 | 日韩精品一区在线播放 | 97视频在线观看成人 | 天天干天天操天天操 | 91精品国产乱码 | 欧美日韩高清 | 精品国产伦一区二区三区观看方式 | av大片网址 | 日本大片免费观看在线 | 免费在线观看一区二区三区 | 亚洲jizzjizz日本少妇 | 狠狠狠色丁香婷婷综合久久88 | h视频日本 | 五月婷婷播播 | 国产一区二区网址 | 天天干.com | 国产黄色片在线 | 黄色av网站在线观看免费 | 国产日韩av在线 | 日本爱爱片 | 蜜臀精品久久久久久蜜臀 | 免费在线激情电影 | 国产情侣一区 | 丁香婷五月 | 在线观看视频免费播放 | 国产美女免费观看 | 999久久a精品合区久久久 | 青青河边草免费观看完整版高清 | 国产成人免费精品 | av中文在线影视 | 国产精品女人久久久久久 | 四虎5151久久欧美毛片 | 黄色在线免费观看网址 | zzijzzij亚洲日本少妇熟睡 | 99视频在线免费观看 | 伊人色综合久久天天 | 在线看片一区 | 精品国产大片 | 欧美日韩国产一区二区三区 | 国产小视频91| 五月婷婷色综合 | av成人动漫 | 中文字幕色在线视频 | 亚洲欧美精品一区 | 日批视频在线 | 国内久久久 | 日本精a在线观看 | 国产在线观看免费 | 国产精品久久久999 国产91九色视频 | 91精品国产三级a在线观看 | 99久久精品免费 | 国产区欧美 | 又色又爽又黄高潮的免费视频 | 日韩激情三级 | 久久女教师| 日韩精品一区二区免费视频 | 国产美女免费视频 | 亚洲精品自拍视频在线观看 | 欧美日韩视频在线 | 日韩v欧美v日本v亚洲v国产v | 91桃色视频 | 亚洲日本成人 | 在线观看国产日韩 | 亚州中文av | 久久精品牌麻豆国产大山 | 天天射综合 | 国产一区欧美一区 | 国产精品不卡 | 在线观看视频国产 | av在线免费不卡 | 麻豆免费精品视频 | 欧美日韩亚洲在线观看 | 国产99久久久国产精品免费二区 | 五月天婷亚洲天综合网鲁鲁鲁 | 久久精品79国产精品 | caobi视频| 91色国产在线 | av综合av| 婷婷久久网站 | 久久99国产精品免费 | 中文超碰字幕 | 伊人天天综合 | 欧美视频一区二 | 99久久婷婷国产一区二区三区 | 久久五月婷婷丁香社区 | 精品99免费 | 久久在线影院 | 国产a视频免费观看 | 日批网站在线观看 | 国产一区二区三精品久久久无广告 | 色国产精品一区在线观看 | 婷婷av网| 国产精品免费av | 91精品久久香蕉国产线看观看 | 超碰97在线资源 | 日韩在线 一区二区 | 欧美福利视频 | 伊人亚洲综合网 | 天天激情在线 | 欧美久久久久久久久中文字幕 | av在线a| 黄色录像av| 911国产 | 欧美另类视频 | 日韩性网站 | 亚洲免费av电影 | 国产一级片观看 | 成 人 黄 色 视频免费播放 | 人人澡人人模 | 91成人免费视频 | 欧美激情精品久久久久久免费 | 激情电影在线观看 | 亚洲国产精品va在线看黑人 | 日韩手机在线观看 | 色婷婷狠狠操 | 成年人在线观看网站 | 国产专区一 | 99成人免费视频 | 久久99久久99精品免观看粉嫩 | 欧美少妇影院 | 欧美不卡视频在线 | 日韩有码中文字幕在线 | 国产精品手机视频 | h久久| 亚洲日本韩国一区二区 | 中文字幕亚洲欧美日韩 | 国产主播大尺度精品福利免费 | 91人人干 | 韩国一区二区在线观看 | 亚洲一区 影院 | 中文字幕一区二区三区精华液 | 亚洲精品tv久久久久久久久久 | 国产伦精品一区二区三区在线 | 草久久影院 | 国产小视频你懂的在线 | 色婷婷狠狠18 | 狠狠干夜夜爱 | 中文字幕乱码亚洲精品一区 | 国产精品伦一区二区三区视频 | 久久99网| а天堂中文最新一区二区三区 | adn—256中文在线观看 | 国产一级高清视频 | 尤物九九久久国产精品的分类 | 麻豆国产精品一区二区三区 | 天天躁日日躁狠狠躁av中文 | 一本一本久久a久久 | 成人手机在线视频 | 色视频在线免费 | 欧美孕妇与黑人孕交 | 免费三级在线 | 色综合久久综合中文综合网 | 国产精品成人自产拍在线观看 | www.久久久 | 成年美女黄网站色大片免费看 | 日日干美女 | 国产精品xxxx18a99 | 99色在线播放 | 手机在线观看国产精品 | 日日碰狠狠躁久久躁综合网 | 少妇bbr搡bbb搡bbb | 亚洲免费在线播放视频 | 国产高清久久久久 | 日韩二区在线播放 | 国产96在线 | 久久精品一二区 | 黄色毛片视频免费观看中文 | 在线观看免费一级片 | 97色综合| 性色av免费观看 | 成人国产电影在线观看 | 香蕉久草在线 | 天天干天天拍天天操天天拍 | 成人a在线观看高清电影 | av电影不卡在线 | 狠狠狠狠狠色综合 | 免费亚洲精品视频 | 国产在线探花 | 亚洲国产成人av网 | 国产一线二线三线在线观看 | 丁香 久久 综合 | 色播激情五月 | 国产精品九九久久久久久久 | 中国一级片在线播放 | 亚洲乱码在线观看 | 国产经典av | 激情深爱 | 夜夜澡人模人人添人人看 | 国产精品久久艹 | 九九久久成人 | 免费观看成人网 | 五月婷婷中文网 | 午夜男人影院 | 亚洲欧美经典 | 久久久久久久久久久国产精品 | 午夜国产福利在线 | a级片韩国 | 狠狠狠色丁香婷婷综合激情 | av福利第一导航 | 亚洲精品tv久久久久久久久久 | 国产一区二区三区午夜 | 91国内在线视频 | 国产一二区免费视频 | 天天操天天透 | 最新中文字幕在线播放 | 在线三级av | 蜜臀久久99静品久久久久久 | 免费黄色在线 | 丁香久久五月 | 手机成人免费视频 | av播放在线 | 日本字幕网 | 五月婷综合网 | 99一区二区三区 | 国产 欧美 日产久久 | 天天操偷偷干 | 中文字幕视频三区 | www.天天干| 99视频国产在线 | 久久69av | 亚洲欧美综合 | 国产一区二区三区四区在线 | 麻豆免费视频 | 字幕网在线观看 | 天天爱综合 | 国产不卡一二三区 | 最近中文字幕国语免费高清6 | 久久99九九99精品 | 国产色道 | 99视频导航 | 亚洲激情中文 | 日日爱网址 | 人人爽人人爽人人 | 国产69精品久久久久99 | 国产精品久久久久免费 | 精品免费视频123区 午夜久久成人 | 99久久这里有精品 | 操操操av| 免费观看高清 | 成人一级免费视频 | 免费看污污视频的网站 | 日韩三级免费 | 欧美a√大片 | 香蕉影视 | 一本一本久久aa综合精品 | 99久久精品免费看国产免费软件 | 亚洲精品视 | 青青草在久久免费久久免费 | 国产拍在线 | 香蕉久草 | 黄色网大全 | 色婷婷播放 | 少妇bbb搡bbbb搡bbbb′ | 四虎精品成人免费网站 | 香蕉色综合| 亚洲精品视频免费看 | 国产+日韩欧美 | 欧美美女一级片 | 日韩网站中文字幕 | 玖玖在线免费视频 | 婷婷激情综合网 | 免费视频在线观看网站 | 激情综合交 | 免费看成人a | 人人精久 | 黄色在线看网站 | 成年人在线电影 | 欧美专区日韩专区 | 六月丁香综合 | 四虎免费在线观看 | 欧美日韩xxxxx | 久av电影| 亚洲精品网站在线 | 中文字幕91视频 | 午夜精品一区二区三区免费视频 | 久久综合亚洲鲁鲁五月久久 | 一本一本久久aa综合精品 | 99视频网址 | 久久精品三级 | 日本最新高清不卡中文字幕 | 成人在线免费看 | 国产成人在线观看免费 | 五月亚洲 | 久久久久久免费毛片精品 | 国产vs久久 | 国产自产高清不卡 | 综合激情 | 亚洲精品99久久久久久 | 九九九九九精品 | 波多野结衣电影久久 | 日韩视频在线一区 | 国产精品麻豆99久久久久久 | 激情九九 | av大全在线看 | 欧美一二三区播放 | www.91av在线 | 黄色av电影在线观看 | 欧美成人视 | 国产成人免费av电影 | 亚洲欧洲中文日韩久久av乱码 | 久久久精品欧美一区二区免费 | 久草在线视频看看 | 国产精品久久久久久久久软件 | 一级性视频 | 日韩电影在线观看一区二区 | 黄色三级免费网址 | 成人91在线 | 成人黄色毛片 | 日韩免费在线视频观看 | 91精品导航 | 中文字幕在线观看91 | 亚洲第一区在线观看 | 日韩av一卡二卡三卡 | 欧美一二三区在线观看 | 欧美另类一二三四区 | 免费a网| 丁香婷婷亚洲 | 日韩免费一区二区三区 | 蜜桃传媒一区二区 | 97国产大学生情侣酒店的特点 | 97在线精品国自产拍中文 | 黄色一级性片 | 99久久www免费| 久久精品一区二区三区视频 | 亚洲欧美婷婷六月色综合 | 国产精品久久久免费看 | 久久久久国 | 91麻豆精品国产自产在线游戏 | 国产一级在线观看视频 | 日韩精品久久一区二区 | 亚洲黄色高清 | 国产精品一区二区久久精品 | 在线视频 影院 | 一二三精品视频 | 中文字幕日韩一区二区三区不卡 | 欧美日韩一级久久久久久免费看 | 精品在线视频观看 | www欧美xxxx| 99re久久资源最新地址 | 国产视频2| 国产va饥渴难耐女保洁员在线观看 | 日韩精品一二三 | 精品久久久久一区二区国产 | 日韩欧美一级二级 | 摸bbb搡bbb搡bbbb | 精品国产免费看 | 国产精品久久久久久模特 | 国产亚洲va综合人人澡精品 | 欧美伦理一区二区 | 成人一级黄色片 | 久草影视在线观看 | 在线观看岛国av | 日韩欧美高清不卡 | 黄色亚洲精品 | 深爱五月激情网 | 免费成人结看片 | 国产999久久久 | 91精品国产福利在线观看 | 日韩av一区二区在线影视 | 人人澡人 | 日韩一区二区三区高清在线观看 | 国产小视频免费在线观看 | 久久久国产99久久国产一 | 久久精品视频播放 | 美女黄濒| 久久精品一区二区 | 中文字幕在线看视频国产 | 日本黄色免费大片 | 久久亚洲欧美 | 色噜噜在线观看 | 99精品免费在线 | 国产最新精品视频 | 一级黄色片毛片 | 91成人精品国产刺激国语对白 | 国产精品视频永久免费播放 | 成人黄大片 | 亚洲激情电影在线 | 国产一区二区在线视频观看 | 亚洲va欧美va国产va黑人 | 午夜丁香视频在线观看 | 成人精品电影 | 亚洲国产精品成人精品 | www在线免费观看 | 国产福利专区 | 久久国产欧美日韩 | 国产精品成人自产拍在线观看 | 欧美日韩精品在线免费观看 | 久久国产精品免费视频 | 四虎永久免费网站 | 久久综合婷婷国产二区高清 | 国产原创中文在线 | 亚洲亚洲精品在线观看 | 狠狠狠狠狠操 | 国产精品一区二区av影院萌芽 | 91成人观看 | 日韩精品中文字幕有码 | 中文字幕乱视频 | 91精品国产福利在线观看 | 国产中出在线观看 | 五月激情丁香图片 | 久久人人精品 | 在线视频日韩欧美 | 久久精品成人热国产成 | 欧美另类xxxxx | 国产精品毛片一区二区在线看 | 久久av一区二区三区亚洲 | 国产免费中文字幕 | 日韩视频免费看 | 成人黄色在线看 | 婷婷色在线资源 | 日韩成人免费电影 | 91九色porny蝌蚪视频 | 91大神电影 | 欧美激情视频一二区 | 免费日韩一区二区三区 | 免费欧美 | 国产小视频免费观看 | 国产无遮挡又黄又爽馒头漫画 | 久久免费播放视频 | 亚州av免费| 欧美a级片免费看 | 亚洲一级影院 | 亚洲乱码在线观看 | 美女视频永久黄网站免费观看国产 | 亚洲视频久久久 | 最新日韩在线观看视频 | 成人资源站 | 欧美高清视频不卡网 | 久久久久伦理电影 | 综合色天天 | 黄色三级免费看 | 九九久久视频 | 天堂av在线免费观看 | 青青草国产成人99久久 | 中文字幕一区二区三区在线观看 | 91视频在线免费看 | 国产一级不卡视频 | 黄色aaaaa | 日韩免费观看一区二区 | 久久人人精品 | 欧美日比视频 | 国产黄色一级片 | 69av在线播放| 亚洲影音先锋 | 亚洲做受高潮欧美裸体 | 久久综合影视 | 波多野结衣视频在线 | 成人91视频| 国产精品久久久久久久久蜜臀 | 久久国产精品久久精品国产演员表 | 亚洲成人一区 | 99免费在线观看 | 在线 影视 一区 | 免费婷婷| 狠狠躁日日躁 | 久久99热精品这里久久精品 | 人人爽人人爽人人片av免 | 西西人体www444 | 久久呀 | 国产韩国日本高清视频 | 国产精品成人一区二区 | 亚洲粉嫩av| 黄色在线视频网址 | 国产一区二区久久 | 久久国内视频 | 日韩av一区二区三区在线观看 | 久久激情视频免费观看 | 最新久久久 | 国产精品99久久久精品免费观看 | 国产日韩欧美精品在线观看 | 午夜国产影院 | 成人app在线播放 | 婷婷在线免费观看 | 日韩理论片在线观看 | 999久久久久久久久 69av视频在线观看 | 国产精品免费一区二区三区 | 日韩精品第一区 | 人人艹视频 | 免费看国产精品 | 特级毛片网站 | 午夜精品电影一区二区在线 | 麻豆视频一区二区 | 成+人+色综合 | 中文字幕视频一区二区 | 国产剧情在线一区 | 中文字幕av有码 | 国产区久久 | 久久人人97超碰国产公开结果 | 日韩精品一区二区三区丰满 | 91麻豆文化传媒在线观看 | 免费污片| 亚洲精品久久视频 | 天天躁日日躁狠狠 | 国际精品网| 人人澡人摸人人添学生av | 国产精品一区二区久久精品 | 91av在线播放视频 | 96国产在线 | 亚洲精品视频在线观看视频 | 久久久亚洲精华液 | 午夜电影一区 | 精品视频在线观看 | wwwav视频| 国产精品欧美久久久久天天影视 | 92精品国产成人观看免费 | 亚洲91中文字幕无线码三区 | 亚洲精品午夜一区人人爽 | 久久久婷| 国产免费影院 | 亚洲 欧洲 国产 日本 综合 | av高清网站在线观看 | 亚洲午夜在线视频 | 人人干人人爽 | 日韩激情网 | 色偷偷网站视频 | 国产精品嫩草69影院 | 激情五月婷婷综合网 | 国产精品久久久久久一区二区 | 99久久精品免费看 | 97超碰在| 精品在线观 | 丁香六月伊人 | 亚洲乱码在线 | 精品一区二区亚洲 | 在线看v片成人 | 久久久久久久久久久高潮一区二区 | 国产在线成人 | 亚洲成人在线免费 | 久久优| 日日爱网址 | 日韩中文三级 | 免费国产黄线在线观看视频 | av电影免费在线看 | 亚洲毛片久久 | 国产亚洲高清视频 | 狠狠的操你 | 在线天堂亚洲 | 久久久久99精品国产片 | 天天曰天天 | 亚洲精品一区二区三区高潮 | 久久国产精品色婷婷 | 天天干,夜夜爽 | www.久久色.com | 久久国产成人午夜av影院宅 | 国产免费不卡av | 亚洲欧洲日韩在线观看 | 福利视频一区二区 | 久久精品国产免费观看 | 久章操| 国产精品视频全国免费观看 | www.夜夜干.com| 91色偷偷 | 成 人 免费 黄 色 视频 | 国产麻豆视频网站 | 五月天激情视频在线观看 | 国产中文字幕一区二区三区 | 久久免费国产精品1 | 婷婷精品国产一区二区三区日韩 | 精品视频123区在线观看 | 免费av在线网站 | 国产精品免费人成网站 | 欧美日本一二三 | 在线中文视频 | 色婷婷免费 | 9草在线| 香蕉日日 | 久草视频视频在线播放 | 97国产大学生情侣酒店的特点 | 国产精品久久久久久久久久久久午夜 | 久草免费在线观看视频 | 91看片看淫黄大片 | 亚洲伦理一区 | 欧美a级一区二区 | 国际av在线 | 日韩有码欧美 | 日韩三级在线观看 | 久久视频网址 | 欧美韩国日本在线观看 | 欧美综合干 | 午夜国产一区二区 | 日韩国产精品久久 | 国产精品自产拍在线观看网站 | 黄色网免费 | 中文字幕在线观看的网站 | 久久免费美女视频 | 日本中文字幕电影在线免费观看 | 夜色资源站wwwcom | 亚洲欧美偷拍另类 | 91九色精品 | 97精品久久人人爽人人爽 | 国产精品国产亚洲精品看不卡15 | 婷婷五综合 | 久久国产精品色婷婷 | 成人三级网站在线观看 | 日韩精品一区二区三区高清免费 | 中文字幕91 | av片一区| 国产一级片一区二区三区 | 日韩精品免费在线播放 | 在线精品在线 | 九九九热精品免费视频观看网站 | 日韩黄色在线电影 | 日韩欧美在线观看一区 | 国产精品久久久久三级 | 国产亚洲精品久久久久久久久久久久 | av色影院 | 亚洲欧美婷婷六月色综合 | 四虎影视成人永久免费观看亚洲欧美 | 精品国产一区在线观看 | 在线观看亚洲免费视频 | 就操操久久 | 少妇资源站 | www久久99| 色婷婷亚洲婷婷 | 人人狠狠综合久久亚洲 | 在线观看国产成人av片 | 国产女人18毛片水真多18精品 | 婷婷六月综合亚洲 | 狠狠做深爱婷婷综合一区 | 最近中文字幕国语免费高清6 | 青青草国产在线 | 婷婷在线免费观看 | 日韩免费区 | 人人插人人爱 | 91高清完整版在线观看 | 日韩精品播放 | 精品欧美一区二区精品久久 | 亚洲国内精品视频 | 欧美视频国产视频 | 最新av在线免费观看 | 婷婷成人亚洲综合国产xv88 | 国内精品久久久久国产 | 四虎成人网 | 亚洲成人av在线电影 | 久久精品香蕉 | 中文在线天堂资源 | 在线视频1卡二卡三卡 | 日韩在线观看你懂的 | 欧美日韩不卡一区 | 久99久中文字幕在线 | 久久不射电影院 | 亚洲 欧美 日韩 综合 | 国产精品自在线拍国产 | 又黄又刺激又爽的视频 | 91视频免费国产 | 婷婷久久精品 | 亚洲精品动漫久久久久 | 毛片网在线播放 | 日本高清dvd| 欧美一区免费在线观看 | 中文字幕视频播放 | 久久热首页 | 精品国产免费观看 | 中文字幕在线视频网站 | 日韩欧美一区二区三区黑寡妇 | 久久久久久高清 | 黄色av大片 | 999成人国产 | 五月婷婷在线观看视频 | 日本成人中文字幕在线观看 | 久久久久伊人 | 成人91av| 欧美激情第28页 | 国产乱对白刺激视频在线观看女王 | 国内外成人免费在线视频 | 欧美激情综合五月色丁香 | 欧美日韩高清一区二区 国产亚洲免费看 | av丝袜美腿 | 国产成人精品av久久 | 黄色成人影院 | 日韩在线观看 | 国产超碰在线观看 | 国产99久久久国产精品免费二区 | 狠狠干天天操 | 国产无套精品久久久久久 | 午夜国产在线 | 免费三级大片 | a黄色影院 | 五月香视频在线观看 | 日韩欧美在线免费观看 | 欧美日韩中文字幕视频 | 西西444www大胆高清视频 | 一区二区三区动漫 | 91av观看| 手机在线日韩视频 | 五月婷婷一级片 | 精品99久久久久久 | 欧美性爽爽 | 日韩精品国产一区 | 97精品国产97久久久久久 | 超碰国产在线播放 | 顶级欧美色妇4khd | 四虎影院在线观看av | 日韩免费av网址 | 国产伦精品一区二区三区… | 日韩在线免费电影 | 亚洲欧洲国产精品 | 男女拍拍免费视频 | 黄色电影网站在线观看 | 99中文字幕视频 | 精品视频在线视频 | 狠狠操天天操 | 久久久久久免费网 | 色婷婷成人网 | 99视频网址 | 在线观看中文 | 午夜美女wwww| 最近2019好看的中文字幕免费 | 午夜视频免费播放 | 国产精品99久久久久久久久久久久 | 国产福利在线不卡 | 中文字幕在线观看av | 久久久久国产精品免费 | 超碰97人人射妻 | 欧洲在线免费视频 | 亚洲综合日韩在线 | 成人a免费 | 狠狠色丁香婷婷综合 | 国产精品av久久久久久无 | 久久国产精品免费视频 | 西西www4444大胆视频 | 亚洲专区欧美专区 | 亚洲激情网站免费观看 | 亚洲成人蜜桃 | 国产精品国产三级国产专区53 | 欧美激情第一区 | 三级黄色免费 | www色综合 | 深夜激情影院 | 国产精品九九视频 | 亚洲精品一区二区三区在线观看 | h网站免费在线观看 | 日日干天天爽 | 国产第一页在线观看 | 久草精品电影 | 国产成人精品一区二区在线 | 国内精品久久久久久久久久久久 | 国产18精品乱码免费看 | 狠狠干中文字幕 | 久久久久亚洲精品中文字幕 | 91久久国产自产拍夜夜嗨 | 丁香电影小说免费视频观看 | 不卡av在线免费观看 | 免费大片黄在线 | 国产片网站| 欧美久久久久久 | 国产亚洲精品日韩在线tv黄 | 久草视频在线免费 | 97精品国产91久久久久久久 | 国内一区二区视频 | 欧美精品久久久久性色 | 亚洲黄色app | 黄污污网站 | 在线有码中文 | 超级碰99| 国产玖玖在线 | 激情自拍av | 亚洲精品中文字幕在线观看 | 日韩经典一区二区三区 | 欧美久久成人 | 亚洲欧美乱综合图片区小说区 | 久久国产电影院 | 91精品亚洲影视在线观看 | 成人av资源网站 | 色婷婷激情 | 色狠狠婷婷 | 一区二区三区在线免费观看视频 | 网站免费黄色 | 久久综合在线 | 91精品国产91p65 | 欧美另类高清 videos | 国产精品午夜久久 | 久久九九免费视频 | 精品国产一区二区三区四区vr | 午夜三级毛片 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 色综合久久久久 | 精品毛片久久久久久 | 久久免费av电影 | 国产精品久久久久久一区二区三区 | 五月婷婷狠狠 | 中文字幕亚洲综合久久五月天色无吗'' | 日韩天堂网 | 亚洲精品国产精品国自产在线 | 日本中文一级片 | 色婷婷骚婷婷 | 91在线精品秘密一区二区 | 在线视频日韩精品 | 91视频91蝌蚪| 精品视频123区在线观看 | 一级免费黄色 | 日韩亚洲在线 | 操操色 | 国产在线观看你懂得 | 日韩精品一二三 | 国产群p | 992tv在线 | 久久久久国产精品一区 | 国产不卡视频在线 | 亚洲区色 | 欧美日本国产在线观看 | 一区二区三区国产精品 | 亚洲欧美国产精品va在线观看 | 午夜久久福利影院 | 欧美色黄 | 99精品视频在线播放免费 | 波多野结衣综合网 | 99久久99久久精品免费 | 国产精品视屏 | 99国产一区二区三精品乱码 | 天天干天天操天天做 | 成人动漫一区二区三区 | bayu135国产精品视频 | 色婷婷播放 | 日日干天天爽 | 国产精品久久久久久久久久免费 | 国产不卡在线 | 黄www在线观看 | 日韩欧美在线第一页 | 成人资源站| www.色午夜.com | 国产日韩中文字幕 | 婷色| 最近免费在线观看 | 波多野结衣精品在线 | 操夜夜操 | 亚洲美女免费精品视频在线观看 | 久久97久久97精品免视看 | av一级久久| 久久精品国产第一区二区三区 | 国精产品999国精产 久久久久 | 亚洲成人av在线播放 | 国产高清精 | 精品国产乱子伦一区二区 | 亚洲三区在线 | 婷婷网站天天婷婷网站 | 国产精品在线看 | 精品久久久999 | 成人免费观看视频大全 | 精品久久九九 | 免费精品人在线二线三线 | 国产日韩精品一区二区在线观看播放 | 日韩理论在线视频 | 最近乱久中文字幕 | 超碰av在线 | 久久久黄色av | 国产手机视频精品 | 九色91视频| 亚洲视频在线免费看 | 欧美另类调教 |