<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 第二課: 畫第一個三角形 這將又是一篇長教程。 用OpenGL 3實現復雜的東西很方便;為此付出的代價是,畫一個簡單的三角形變得比較麻煩。 不要忘了,定期復制粘貼,跑一下代碼。 > 如果程序啟動時崩潰了,很可能是你從錯誤的目錄下運行了它。請仔細地閱讀第一課中講到的如何配置Visual Studio! ## 頂點數組對象(VAO) 你需要創建一個頂點數組對象,并將它設為當前對象(細節暫不深入): ~~~ GLuint VertexArrayID; glGenVertexArrays(1, &VertexArrayID); glBindVertexArray(VertexArrayID); ~~~ 當窗口創建成功后(即OpenGL上下文創建后),馬上做這一步工作;必須在任何其他OpenGL調用前完成。 若想進一步了解頂點數組對象(VAO),可以參考其他教程;但這不是很重要。 ## 屏幕坐標系 三點定義一個三角形。當我們在三維圖形學中談論“點(point)”時,我們經常說“頂點(Vertex)”。一個頂點有三個坐標:X,Y和Z。你可以用以下方式來想象這三個坐標: X 在你的右方Y 在你的上方Z 是你背后的方向(是的,背后,而不是你的前方)這里有一個更形象的方法:使用右手定則 X 是你的拇指Y 是你的食指Z 是你的中指。如果你把你的拇指指向右邊,食指指向天空,那么中指將指向你的背后。讓Z指往這個方向很奇怪,為什么要這樣呢?簡單的說:因為基于右手定則的坐標系被廣泛使用了100多年,它會給你很多有用的數學工具;而唯一的缺點只是Z方向不直觀。 `補充:`注意,你可以自由地移動你的手:你的X,Y和Z軸也將跟著移動(詳見后文)。 我們需要三個三維點來組成一個三角形;現在開始: ~~~ // An array of 3 vectors which represents 3 vertices static const GLfloat g_vertex_buffer_data[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f,? 1.0f, 0.0f, }; ~~~ 第一個頂點是(-1, -1, 0)。 這意味著除非我們以某種方式變換它,否則它將顯示在屏幕的(-1, -1)位置。什么意思呢?屏幕的原點在中間,X在右方,Y在上方。屏幕坐標如下圖: ![screenCoordinates](https://box.kancloud.cn/2015-11-02_5636f301c85be.png) 該機制內置于顯卡,無法改變。因此(-1, -1)是屏幕的左下角,(1, -1)是右下角,(0, 1)在中上位置。這個三角形應該占滿了大部分屏幕。 ## 畫我們的三角形 下一步把這個三角形傳給OpenGL。我們通過創建一個緩沖區完成: ~~~ // This will identify our vertex buffer GLuint vertexbuffer; // Generate 1 buffer, put the resulting identifier in vertexbuffer glGenBuffers(1, &vertexbuffer); // The following commands will talk about our 'vertexbuffer' buffer glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); // Give our vertices to OpenGL. glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW); ~~~ 這只要做一次。 現在,我們的主循環中,那個之前啥都沒有的地方,就能畫我們宏偉的三角形了: ~~~ // 1rst attribute buffer : vertices glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, // attribute 0. No particular reason for 0, but must match the layout in the shader. 3, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)0 // array buffer offset ); // Draw the triangle ! glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices total -> 1 triangle glDisableVertexAttribArray(0); ~~~ 結果如圖: ![triangle_no_shader](https://box.kancloud.cn/2015-11-02_5636f301d42d1.png) 白色略顯無聊。讓我們來看看怎么把它涂成紅色。這就需要用到一個叫『著色器(Shader)』的東西。 ## 著色器 ### 編譯著色器 在最簡單的配置下,你將需要兩個著色器:一個叫頂點著色器,它將作用于每個頂點上;另一個叫片斷(Fragment)著色器,它將作用于每一個采樣點。我們使用4倍反走樣,因此每像素有四個采樣點。 著色器編程使用GLSL(GL Shader Language,GL著色語言),它是OpenGL的一部分。與C或Java不同,GLSL必須在運行時編譯,這意味著每次啟動程序,所有的著色器將重新編譯。 這兩個著色器通常放在單獨的文件里。本例中,我們有SimpleFragmentShader.fragmentshader和SimpleVertexShader.vertexshader兩個著色器。他們的擴展名是無關緊要的,可以是.txt或者.glsl。 以下是代碼。完全理解它不是很重要,因為通常一個程序只做一次,看懂注釋就夠了。所有其他課程代碼都用到了這個函數,所以它被放在一個單獨的文件中:common/loadShader.cpp。注意,和緩沖區一樣,著色器不能直接訪問:我們僅僅有一個編號(ID)。真正的實現隱藏在驅動程序中。 ~~~ GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){ // Create the shaders GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); // Read the Vertex Shader code from the file std::string VertexShaderCode; std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); if(VertexShaderStream.is_open()) { std::string Line = ""; while(getline(VertexShaderStream, Line)) VertexShaderCode += "\n" + Line; VertexShaderStream.close(); } // Read the Fragment Shader code from the file std::string FragmentShaderCode; std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); if(FragmentShaderStream.is_open()){ std::string Line = ""; while(getline(FragmentShaderStream, Line)) FragmentShaderCode += "\n" + Line; FragmentShaderStream.close(); } GLint Result = GL_FALSE; int InfoLogLength; // Compile Vertex Shader printf("Compiling shader : %s\n", vertex_file_path); char const * VertexSourcePointer = VertexShaderCode.c_str(); glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL); glCompileShader(VertexShaderID); // Check Vertex Shader glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector VertexShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]); // Compile Fragment Shader printf("Compiling shader : %s\n", fragment_file_path); char const * FragmentSourcePointer = FragmentShaderCode.c_str(); glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); glCompileShader(FragmentShaderID); // Check Fragment Shader glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector FragmentShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]); // Link the program fprintf(stdout, "Linking programn"); GLuint ProgramID = glCreateProgram(); glAttachShader(ProgramID, VertexShaderID); glAttachShader(ProgramID, FragmentShaderID); glLinkProgram(ProgramID); // Check the program glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector ProgramErrorMessage( max(InfoLogLength, int(1)) ); glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); fprintf(stdout, "%s\n", &ProgramErrorMessage[0]); glDeleteShader(VertexShaderID); glDeleteShader(FragmentShaderID); return ProgramID; } ~~~ ### 我們的頂點著色器 我們先寫頂點著色器。 第一行告訴編譯器我們將用OpenGL 3的語法。 ~~~ #version 330 core ~~~ 第二行聲明輸入數據: ~~~ layout(location = 0) in vec3 vertexPosition_modelspace; ~~~ 具體解釋一下這一行: “vec3”在GLSL中是一個三維向量。類似于(但不相同)以前我們用來聲明三角形的glm::vec3。最重要的是,如果我們在C++中使用三維向量,那么在GLSL中也使用三維向量。 “layout(location = 0)”指我們用來賦給vertexPosition_modelspace這個屬性的緩沖區。每個頂點能有多種屬性:位置,一種或多種顏色,一個或多個紋理坐標,等等。OpenGL不知道什么是顏色:它只是看到一個vec3。因此我們必須告訴它,哪個緩沖對應哪個輸入。通過將glvertexAttribPointer函數的第一個參數值賦給layout,我們就完成了這一點。參數值“0”并不重要,它可以是12(但是不大于glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &v));重要的是兩邊參數值保持一致。 “vertexPosition_modelspace”這個變量名你可以任取,它將包含每個頂點著色器運行所需的頂點位置值。 “in”的意思是這是一些輸入數據。不久我們將會看到“out”關鍵詞。 每個頂點都會調用main函數(和C語言一樣): ~~~ void main(){ ~~~ 我們的main函數只是將頂點的位置設為緩沖區里的值,無論這值是多少。因此如果我們給出位置(1,1),那么三角形將有一個頂點在屏幕的右上角。在下一課中我們將看到,怎樣對輸入位置做一些更有趣的計算。 ~~~ gl_Position.xyz = vertexPosition_modelspace; gl_Position.w = 1.0; } ~~~ gl_Position是為數不多的內置變量之一:你必須賦一個值給它。其他操作都是可選的,我們將在第四課中看到“其他操作”指的是什么。 ### 我們的片斷著色器 作為我們的第一個片斷著色器,我們只做一個簡單的事:設置每個片斷的顏色為紅色。(記住,每像素有4個片斷,因為我們用的是4倍反走樣) ~~~ out vec3 color; void main(){ color = vec3(1,0,0); } ~~~ vec3(1,0,0)代表紅色。因為在計算機屏幕上,顏色由紅,綠,藍這個順序三元組表示。因此(1,0,0)意思是全紅,沒有綠色,也沒有藍色。 ## 把它們組合起來 在main循環前,調用我們的LoadShaders函數: ~~~ // Create and compile our GLSL program from the shaders GLuint programID = LoadShaders( "SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader" ); ~~~ 現在在main循環中,首先清屏: ~~~ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ~~~ 然后告訴OpenGL你想用你的著色器: ~~~ // Use our shader glUseProgram(programID); // Draw triangle... ~~~ …接著轉眼間,這就是你的紅色三角形! ![red_triangle](https://box.kancloud.cn/2015-11-02_5636f301e500d.png) 下一課中我們將學習變換:如何設置你的相機,移動物體等等。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看