<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 第十四課:渲染到紋理 “渲染到紋理”是一系列特效方法之一。基本思想是:像通常那樣渲染一個場景——只是這次是渲染到可以重用的紋理中。 應用包括:游戲(in-game)相機、后期處理(post-processing)以及你能想象到一切. ## 渲染到紋理 我們有三個任務:創建要渲染的紋理對象;將紋理渲染到對象上;使用生成的紋理。 ## 創建渲染目標(Render Target) 我們要渲染的對象叫做幀緩存。它像一個容器,用來存紋理和一個可選的深度緩沖區(depth buffer)。在OpenGL中我們可以像創建其他對象一樣創建它: ~~~ // The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer. GLuint FramebufferName = 0; glGenFramebuffers(1, &amp;FramebufferName); glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); ~~~ 現在需要創建紋理,紋理中包含著色器的RGB輸出。這段代碼非常的經典: ~~~ // The texture we're going to render to GLuint renderedTexture; glGenTextures(1, &amp;renderedTexture); // "Bind" the newly created texture : all future texture functions will modify this texture glBindTexture(GL_TEXTURE_2D, renderedTexture); // Give an empty image to OpenGL ( the last &quot;0&quot; ) glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, 1024, 768, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); // Poor filtering. Needed ! glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); ~~~ 同時還需要一個深度緩沖區(depth buffer)。這是可選的,取決于紋理中實際需要畫的東西;由于我們渲染的是小猴Suzanne,所以需要深度測試。 ~~~ // The depth buffer GLuint depthrenderbuffer; glGenRenderbuffers(1, &amp;depthrenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1024, 768); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer); ~~~ 最后,配置frameBuffer。 ~~~ // Set "renderedTexture" as our colour attachement #0 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0); // Set the list of draw buffers. GLenum DrawBuffers[2] = {GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers ~~~ 這個過程中可能出現一些錯誤,取決于GPU的性能;下面是檢查的方法: ~~~ // Always check that our framebuffer is ok if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) return false; ~~~ ## 渲染到紋理 渲染到紋理很直觀。簡單地綁定幀緩存,然后像往常一樣畫場景。輕松搞定! ~~~ // Render to our framebuffer glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); glViewport(0,0,1024,768); // Render on the whole framebuffer, complete from the lower left corner to the upper right ~~~ fragment shader只需稍作調整: ~~~ layout(location = 0) out vec3 color; ~~~ 這意味著每當修改變量“color”時,實際修改了0號渲染目標;這是因為之前調用了`glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0); 注意:最后一個參數表示mipmap的級別,這個0和GL_COLOR_ATTACHMENT0沒有任何關系。 ## 使用渲染出的紋理 我們將畫一個簡單的鋪滿屏幕的四邊形。需要buffer、shader、ID…… ~~~ // The fullscreen quad's FBO GLuint quad_VertexArrayID; glGenVertexArrays(1, &quad_VertexArrayID); glBindVertexArray(quad_VertexArrayID); static const GLfloat g_quad_vertex_buffer_data[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, }; GLuint quad_vertexbuffer; glGenBuffers(1, &quad_vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW); // Create and compile our GLSL program from the shaders GLuint quad_programID = LoadShaders( "Passthrough.vertexshader", "SimpleTexture.fragmentshader" ); GLuint texID = glGetUniformLocation(quad_programID, "renderedTexture"); GLuint timeID = glGetUniformLocation(quad_programID, "time"); ~~~ 現在想渲染到屏幕上的話,必須把glBindFramebuffer的第二個參數設為0。 ~~~ // Render to the screen glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0,0,1024,768); // Render on the whole framebuffer, complete from the lower left corner to the upper right ~~~ 我們用下面這個shader來畫全屏的四邊形: ~~~ #version 330 core in vec2 UV; out vec3 color; uniform sampler2D renderedTexture; uniform float time; void main(){ color = texture( renderedTexture, UV + 0.005*vec2( sin(time+1024.0*UV.x),cos(time+768.0*UV.y)) ).xyz; } ~~~ 這段代碼只是簡單地采樣紋理,加上一個隨時間變化的微小偏移。 ## 結果 ![wavvy-1024x793](https://box.kancloud.cn/2015-11-02_5636f308caa98.png) ## 進一步探索 ## 使用深度 在一些情況下,使用已渲染的紋理可能需要深度。本例中,像下面這樣,簡單地渲染到紋理中: ~~~ glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT24, 1024, 768, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0); ~~~ (“24”是精度。你可以按需從16,24,32中選。通常24剛好) 上面這些已經足夠您起步了。課程源碼中有完整的實現。 運行可能有點慢,因為驅動無法使用[Hi-Z](http://developer.amd.com/media/gpu_assets/Depth_in-depth.pdf)這類優化。 下圖的深度層次已經經過手動“優化”。通常,深度紋理不會這么清晰。深度紋理中,近 = Z接近0 = 顏色深; 遠 = Z接近1 = 顏色淺。 ![wavvydepth-1024x793](https://box.kancloud.cn/2015-11-02_5636f30901503.png) ## 多重采樣 能夠用多重采樣紋理來替代基礎紋理:只需要在C++代碼中將glTexImage2D替換為[glTexImage2DMultisample](http://www.opengl.org/sdk/docs/man3/xhtml/glTexImage2DMultisample.xml),在fragment shader中將`sampler2D/texture`替換為`sampler2DMS/texelFetch`。 但要注意:`texelFetch`多出了一個參數,表示采樣的數量。換句話說,就是沒有自動“濾波”(在多重采樣中,正確的術語是“分辨率(resolution)”)功能。 所以需要你自己解決多重采樣的紋理,另外,非多重采樣紋理,是多虧另一個著色器。 沒有什么難點,只是體積龐大。 ## 多重渲染目標 你可能需要同時寫多個紋理。 簡單地創建若干紋理(都要有正確、一致的大小!),調用glFramebufferTexture,為每一個紋理設置一個不同的color attachement,用更新的參數(如`(2,{GL_COLOR_ATTACHMENT0,GL_COLOR_ATTACHMENT1,GL_DEPTH_ATTACHMENT})`一樣)調用glDrawBuffers,然后在片斷著色器中多添加一個輸出變量: ~~~ layout(location = 1) out vec3 normal_tangentspace; // or whatever ~~~ 提示1:如果真需要在紋理中輸出向量,浮點紋理也是有的,可以用16或32位精度代替8位……看看[glTexImage2D](http://www.opengl.org/sdk/docs/man/xhtml/glTexImage2D.xml)的參考手冊(搜GL_FLOAT)。提示2:對于以前版本的OpenGL,請使用glFragData[1] = myvalue。 ## 練習 - 試使用`glViewport(0,0,512,768)`代替`glViewport(0,0,1024,768)`;(幀緩存、屏幕兩種情況都試試) - 在最后一個fragment shader中嘗試一下用其他UV坐標 - 試用一個真正的變換矩陣變換四邊形。首先用硬編碼方式。然后嘗試使用`controls.hpp`里面的函數,觀察到了什么現象? > ? [http://www.opengl-tutorial.org/](http://www.opengl-tutorial.org/) > Written with [StackEdit](https://stackedit.io/).
                  <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>

                              哎呀哎呀视频在线观看