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

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 第十四課: 渲染到紋理 # 第十四課:渲染到紋理 “渲染到紋理”是一系列特效方法之一。基本思想是:像通常那樣渲染一個場景——只是這次是渲染到可以重用的紋理中。 應用包括:游戲(in-game)相機、后期處理(post-processing)以及你能想象到一切. ## 渲染到紋理 我們有三個任務:創建要渲染的紋理對象;將紋理渲染到對象上;使用生成的紋理。 ## 創建渲染目標(Render Target) 我們要渲染的對象叫做幀緩存。它像一個容器,用來存紋理和一個可選的深度緩沖區(depth buffer)。在OpenGL中我們可以像創建其他對象一樣創建它: ``` <pre class="calibre16">``` <span class="token2">// The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer.</span> GLuint FramebufferName <span class="token">=</span> <span class="token6">0</span><span class="token1">;</span> <span class="token3">glGenFramebuffers</span><span class="token1">(</span><span class="token6">1</span><span class="token1">,</span> <span class="token">&</span>amp<span class="token1">;</span>FramebufferName<span class="token1">)</span><span class="token1">;</span> <span class="token3">glBindFramebuffer</span><span class="token1">(</span>GL_FRAMEBUFFER<span class="token1">,</span> FramebufferName<span class="token1">)</span><span class="token1">;</span> ``` ``` 現在需要創建紋理,紋理中包含著色器的RGB輸出。這段代碼非常的經典: ``` <pre class="calibre16">``` <span class="token2">// The texture we're going to render to</span> GLuint renderedTexture<span class="token1">;</span> <span class="token3">glGenTextures</span><span class="token1">(</span><span class="token6">1</span><span class="token1">,</span> <span class="token">&</span>amp<span class="token1">;</span>renderedTexture<span class="token1">)</span><span class="token1">;</span> <span class="token2">// "Bind" the newly created texture : all future texture functions will modify this texture</span> <span class="token3">glBindTexture</span><span class="token1">(</span>GL_TEXTURE_2D<span class="token1">,</span> renderedTexture<span class="token1">)</span><span class="token1">;</span> <span class="token2">// Give an empty image to OpenGL ( the last &quot;0&quot; )</span> <span class="token3">glTexImage2D</span><span class="token1">(</span>GL_TEXTURE_2D<span class="token1">,</span> <span class="token6">0</span><span class="token1">,</span>GL_RGB<span class="token1">,</span> <span class="token6">1024</span><span class="token1">,</span> <span class="token6">768</span><span class="token1">,</span> <span class="token6">0</span><span class="token1">,</span>GL_RGB<span class="token1">,</span> GL_UNSIGNED_BYTE<span class="token1">,</span> <span class="token6">0</span><span class="token1">)</span><span class="token1">;</span> <span class="token2">// Poor filtering. Needed !</span> <span class="token3">glTexParameteri</span><span class="token1">(</span>GL_TEXTURE_2D<span class="token1">,</span> GL_TEXTURE_MAG_FILTER<span class="token1">,</span> GL_NEAREST<span class="token1">)</span><span class="token1">;</span> <span class="token3">glTexParameteri</span><span class="token1">(</span>GL_TEXTURE_2D<span class="token1">,</span> GL_TEXTURE_MIN_FILTER<span class="token1">,</span> GL_NEAREST<span class="token1">)</span><span class="token1">;</span> ``` ``` 同時還需要一個深度緩沖區(depth buffer)。這是可選的,取決于紋理中實際需要畫的東西;由于我們渲染的是小猴Suzanne,所以需要深度測試。 ``` <pre class="calibre16">``` <span class="token2">// The depth buffer</span> GLuint depthrenderbuffer<span class="token1">;</span> <span class="token3">glGenRenderbuffers</span><span class="token1">(</span><span class="token6">1</span><span class="token1">,</span> <span class="token">&</span>amp<span class="token1">;</span>depthrenderbuffer<span class="token1">)</span><span class="token1">;</span> <span class="token3">glBindRenderbuffer</span><span class="token1">(</span>GL_RENDERBUFFER<span class="token1">,</span> depthrenderbuffer<span class="token1">)</span><span class="token1">;</span> <span class="token3">glRenderbufferStorage</span><span class="token1">(</span>GL_RENDERBUFFER<span class="token1">,</span> GL_DEPTH_COMPONENT<span class="token1">,</span> <span class="token6">1024</span><span class="token1">,</span> <span class="token6">768</span><span class="token1">)</span><span class="token1">;</span> <span class="token3">glFramebufferRenderbuffer</span><span class="token1">(</span>GL_FRAMEBUFFER<span class="token1">,</span> GL_DEPTH_ATTACHMENT<span class="token1">,</span> GL_RENDERBUFFER<span class="token1">,</span> depthrenderbuffer<span class="token1">)</span><span class="token1">;</span> ``` ``` 最后,配置frameBuffer。 ``` <pre class="calibre16">``` <span class="token2">// Set "renderedTexture" as our colour attachement #0</span> <span class="token3">glFramebufferTexture</span><span class="token1">(</span>GL_FRAMEBUFFER<span class="token1">,</span> GL_COLOR_ATTACHMENT0<span class="token1">,</span> renderedTexture<span class="token1">,</span> <span class="token6">0</span><span class="token1">)</span><span class="token1">;</span> <span class="token2">// Set the list of draw buffers.</span> GLenum DrawBuffers<span class="token1">[</span><span class="token6">2</span><span class="token1">]</span> <span class="token">=</span> <span class="token1">{</span>GL_COLOR_ATTACHMENT0<span class="token1">}</span><span class="token1">;</span> <span class="token3">glDrawBuffers</span><span class="token1">(</span><span class="token6">1</span><span class="token1">,</span> DrawBuffers<span class="token1">)</span><span class="token1">;</span> <span class="token2">// "1" is the size of DrawBuffers</span> ``` ``` 這個過程中可能出現一些錯誤,取決于GPU的性能;下面是檢查的方法: ``` <pre class="calibre16">``` <span class="token2">// Always check that our framebuffer is ok</span> <span class="token4">if</span><span class="token1">(</span><span class="token3">glCheckFramebufferStatus</span><span class="token1">(</span>GL_FRAMEBUFFER<span class="token1">)</span> <span class="token">!=</span> GL_FRAMEBUFFER_COMPLETE<span class="token1">)</span> <span class="token4">return</span> <span class="token6">false</span><span class="token1">;</span> ``` ``` ## 渲染到紋理 渲染到紋理很直觀。簡單地綁定幀緩存,然后像往常一樣畫場景。輕松搞定! ``` <pre class="calibre16">``` <span class="token2">// Render to our framebuffer</span> <span class="token3">glBindFramebuffer</span><span class="token1">(</span>GL_FRAMEBUFFER<span class="token1">,</span> FramebufferName<span class="token1">)</span><span class="token1">;</span> <span class="token3">glViewport</span><span class="token1">(</span><span class="token6">0</span><span class="token1">,</span><span class="token6">0</span><span class="token1">,</span><span class="token6">1024</span><span class="token1">,</span><span class="token6">768</span><span class="token1">)</span><span class="token1">;</span> <span class="token2">// Render on the whole framebuffer, complete from the lower left corner to the upper right</span> ``` ``` fragment shader只需稍作調整: ``` <pre class="calibre16">``` <span class="token3">layout</span><span class="token1">(</span>location <span class="token">=</span> <span class="token6">0</span><span class="token1">)</span> out vec3 color<span class="token1">;</span> ``` ``` 這意味著每當修改變量“color”時,實際修改了0號渲染目標;這是因為之前調用了`glFramebufferTexture(GL\_FRAMEBUFFER, GL\_COLOR\_ATTACHMENT0, renderedTexture, 0); 注意:最后一個參數表示mipmap的級別,這個0和GL\_COLOR\_ATTACHMENT0沒有任何關系。 ## 使用渲染出的紋理 我們將畫一個簡單的鋪滿屏幕的四邊形。需要buffer、shader、ID…… ``` <pre class="calibre16">``` <span class="token2">// The fullscreen quad's FBO</span> GLuint quad_VertexArrayID<span class="token1">;</span> <span class="token3">glGenVertexArrays</span><span class="token1">(</span><span class="token6">1</span><span class="token1">,</span> <span class="token">&</span>quad_VertexArrayID<span class="token1">)</span><span class="token1">;</span> <span class="token3">glBindVertexArray</span><span class="token1">(</span>quad_VertexArrayID<span class="token1">)</span><span class="token1">;</span> static const GLfloat g_quad_vertex_buffer_data<span class="token1">[</span><span class="token1">]</span> <span class="token">=</span> <span class="token1">{</span> <span class="token">-</span><span class="token6">1.0</span>f<span class="token1">,</span> <span class="token">-</span><span class="token6">1.0</span>f<span class="token1">,</span> <span class="token6">0.0</span>f<span class="token1">,</span> <span class="token6">1.0</span>f<span class="token1">,</span> <span class="token">-</span><span class="token6">1.0</span>f<span class="token1">,</span> <span class="token6">0.0</span>f<span class="token1">,</span> <span class="token">-</span><span class="token6">1.0</span>f<span class="token1">,</span> <span class="token6">1.0</span>f<span class="token1">,</span> <span class="token6">0.0</span>f<span class="token1">,</span> <span class="token">-</span><span class="token6">1.0</span>f<span class="token1">,</span> <span class="token6">1.0</span>f<span class="token1">,</span> <span class="token6">0.0</span>f<span class="token1">,</span> <span class="token6">1.0</span>f<span class="token1">,</span> <span class="token">-</span><span class="token6">1.0</span>f<span class="token1">,</span> <span class="token6">0.0</span>f<span class="token1">,</span> <span class="token6">1.0</span>f<span class="token1">,</span> <span class="token6">1.0</span>f<span class="token1">,</span> <span class="token6">0.0</span>f<span class="token1">,</span> <span class="token1">}</span><span class="token1">;</span> GLuint quad_vertexbuffer<span class="token1">;</span> <span class="token3">glGenBuffers</span><span class="token1">(</span><span class="token6">1</span><span class="token1">,</span> <span class="token">&</span>quad_vertexbuffer<span class="token1">)</span><span class="token1">;</span> <span class="token3">glBindBuffer</span><span class="token1">(</span>GL_ARRAY_BUFFER<span class="token1">,</span> quad_vertexbuffer<span class="token1">)</span><span class="token1">;</span> <span class="token3">glBufferData</span><span class="token1">(</span>GL_ARRAY_BUFFER<span class="token1">,</span> <span class="token3">sizeof</span><span class="token1">(</span>g_quad_vertex_buffer_data<span class="token1">)</span><span class="token1">,</span> g_quad_vertex_buffer_data<span class="token1">,</span> GL_STATIC_DRAW<span class="token1">)</span><span class="token1">;</span> <span class="token2">// Create and compile our GLSL program from the shaders</span> GLuint quad_programID <span class="token">=</span> <span class="token3">LoadShaders</span><span class="token1">(</span> <span class="token5">"Passthrough.vertexshader"</span><span class="token1">,</span> <span class="token5">"SimpleTexture.fragmentshader"</span> <span class="token1">)</span><span class="token1">;</span> GLuint texID <span class="token">=</span> <span class="token3">glGetUniformLocation</span><span class="token1">(</span>quad_programID<span class="token1">,</span> <span class="token5">"renderedTexture"</span><span class="token1">)</span><span class="token1">;</span> GLuint timeID <span class="token">=</span> <span class="token3">glGetUniformLocation</span><span class="token1">(</span>quad_programID<span class="token1">,</span> <span class="token5">"time"</span><span class="token1">)</span><span class="token1">;</span> ``` ``` 現在想渲染到屏幕上的話,必須把glBindFramebuffer的第二個參數設為0。 ``` <pre class="calibre16">``` <span class="token2">// Render to the screen</span> <span class="token3">glBindFramebuffer</span><span class="token1">(</span>GL_FRAMEBUFFER<span class="token1">,</span> <span class="token6">0</span><span class="token1">)</span><span class="token1">;</span> <span class="token3">glViewport</span><span class="token1">(</span><span class="token6">0</span><span class="token1">,</span><span class="token6">0</span><span class="token1">,</span><span class="token6">1024</span><span class="token1">,</span><span class="token6">768</span><span class="token1">)</span><span class="token1">;</span> <span class="token2">// Render on the whole framebuffer, complete from the lower left corner to the upper right</span> ``` ``` 我們用下面這個shader來畫全屏的四邊形: ``` <pre class="calibre16">``` #version <span class="token6">330</span> core <span class="token4">in</span> vec2 UV<span class="token1">;</span> out vec3 color<span class="token1">;</span> uniform sampler2D renderedTexture<span class="token1">;</span> uniform float time<span class="token1">;</span> void <span class="token3">main</span><span class="token1">(</span><span class="token1">)</span><span class="token1">{</span> color <span class="token">=</span> <span class="token3">texture</span><span class="token1">(</span> renderedTexture<span class="token1">,</span> UV <span class="token">+</span> <span class="token6">0.005</span><span class="token">*</span><span class="token3">vec2</span><span class="token1">(</span> <span class="token3">sin</span><span class="token1">(</span>time<span class="token">+</span><span class="token6">1024.0</span><span class="token">*</span>UV<span class="token1">.</span>x<span class="token1">)</span><span class="token1">,</span><span class="token3">cos</span><span class="token1">(</span>time<span class="token">+</span><span class="token6">768.0</span><span class="token">*</span>UV<span class="token1">.</span>y<span class="token1">)</span><span class="token1">)</span> <span class="token1">)</span><span class="token1">.</span>xyz<span class="token1">;</span> <span class="token1">}</span> ``` ``` 這段代碼只是簡單地采樣紋理,加上一個隨時間變化的微小偏移。 ## 結果 ![](https://box.kancloud.cn/2015-11-02_5636f308caa98.png) ## 進一步探索 ## 使用深度 在一些情況下,使用已渲染的紋理可能需要深度。本例中,像下面這樣,簡單地渲染到紋理中: ``` <pre class="calibre16">``` <span class="token3">glTexImage2D</span><span class="token1">(</span>GL_TEXTURE_2D<span class="token1">,</span> <span class="token6">0</span><span class="token1">,</span>GL_DEPTH_COMPONENT24<span class="token1">,</span> <span class="token6">1024</span><span class="token1">,</span> <span class="token6">768</span><span class="token1">,</span> <span class="token6">0</span><span class="token1">,</span>GL_DEPTH_COMPONENT<span class="token1">,</span> GL_FLOAT<span class="token1">,</span> <span class="token6">0</span><span class="token1">)</span><span class="token1">;</span> ``` ``` (“24”是精度。你可以按需從16,24,32中選。通常24剛好) 上面這些已經足夠您起步了。課程源碼中有完整的實現。 運行可能有點慢,因為驅動無法使用[Hi-Z](http://developer.amd.com/media/gpu_assets/Depth_in-depth.pdf)這類優化。 下圖的深度層次已經經過手動“優化”。通常,深度紋理不會這么清晰。深度紋理中,近 = Z接近0 = 顏色深; 遠 = Z接近1 = 顏色淺。 ![](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,然后在片斷著色器中多添加一個輸出變量: ``` <pre class="calibre16">``` <span class="token3">layout</span><span class="token1">(</span>location <span class="token">=</span> <span class="token6">1</span><span class="token1">)</span> out vec3 normal_tangentspace<span class="token1">;</span> <span class="token2">// or whatever</span> ``` ``` 提示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/> > 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>

                              哎呀哎呀视频在线观看