OpenGL ES 3.0之Texturing紋理詳解(二),opengltexturing
Texture Filtering and Mipmapping 紋理過濾與多級紋理
前面我們已經講了單個2D映像的2D紋理的介紹,這篇文章主要講解多級紋理。紋理座標是用於產生一個2D索引,當放大和縮小設定為GL_NEAREST時,將發生一個單一紋理將匹配到紋理座標位置中,這是一個最近點的採樣。
當使用一個多級紋理時,我們可以設定過濾模式,,為了達到螢幕像素和紋理圖片像素更合適的比例,減少鋸齒。因為多級紋理貼圖的成功過濾,當在更遠處觀察時,我們向貼圖鏈後移動,鋸齒減少,實現高品質的映像。
// Load mipmap level 0glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height,0, GL_RGB, GL_UNSIGNED_BYTE, pixels);level = 1;prevImage = &pixels[0];while(width > 1 && height > 1){ int newWidth, newHeight; // Generate the next mipmap level GenMipMap2D( prevImage, &newImage, width, height, &newWidth, &newHeight); // Load the mipmap level glTexImage2D(GL_TEXTURE_2D, level, GL_RGB, newWidth, newHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, newImage); // Free the previous image free(prevImage); // Set the previous image for the next iteration prevImage = newImage; level++; // Half the width and height width = newWidth; height = newHeight;}free(newlmage);
GenMipMap2D用於用於實現多級紋理。紋理過濾有2種:放大和縮小。當螢幕上設計的多邊形的大小小於紋理映像時,我們使用縮小紋理。反之使用放大。使用過濾類型由具體硬體自動選擇,但是API也提供了過濾控制,放大處理是不相關的,因為我們總是使用最大
可用的層級。對於縮小,有各種的取樣模式可以使用。哪種模式的使用選擇基於你需要實現的可視品質和你想要實現多大效能的紋理過濾來決定的。過濾模式使用glTexParameter[i|f][v]來指定。
放大過濾可以是GL_NEAREST 或 GL_LINEAR。在GL_NEAREST 放大過濾模式,紋理最近的單點將做紋理座標。在GL_LINEAR 模式,雙線性(四個點平均)作為紋理座標。
縮小過濾可以是下列值:
•• GL_NEAREST—Takes a single point sample from the texture nearest to the texture coordinate.
•• GL_LINEAR—Takes a bilinear sample from the texture nearest to the texture coordinate.
•• GL_NEAREST_MIPMAP_NEAREST—Takes a single point sample from the closest mip level chosen.
•• GL_NEAREST_MIPMAP_LINEAR—Takes a sample from the two closest mip levels and interpolates between those samples.
•• GL_LINEAR_MIPMAP_NEAREST—Takes a bilinear fetch from the closest mip level chosen.
•• GL_LINEAR_MIPMAP_LINEAR—Takes a bilinear fetch from each of the two closest mip levels and then interpolates between them. This last mode, which is typically referred to as trilinear filtering, produces the best quality of all modes.
GL_NEAREST 和 GL_LINEAR 是唯一不需要完整多級紋理的縮小過濾模式,其他都需要完整的多級處理。
GL_NEAREST 和GL_LINEAR_MIPMAP_LINEAR的過濾設定。
值得一提的是一些效能將影響你選擇的紋理過濾模式。對於大多數硬體來說,使用多級紋理是最好的選擇。
Seamless Cubemap Filtering
它是3.0新特性。當一個線性過濾核心在一個立方體紋理的邊框時,這個過濾只發生線上所在立方體的一面中。你不需要設定Seamless Cubemap Filtering,線性過濾會自動使用它。
自動多級紋理產生
前面我們已經建立了一個level為0的多級紋理,這是一種方法。另外也提供了自動多級紋理產生函數 glGenerateMipmap。
我們隊綁定的紋理對象調用glGenerateMipmap,它會為我們產生從原始映像到level為0的多級紋理鏈。當你使用framebuffer對象時,自動多級紋理產生變得尤為重要。當渲染一個紋理時,我們不想將紋理讀回CPU中產生多級紋理。glGenerateMipmap可以解決這個問題。
Texture Coordinate Wrapping
當紋理座標超過了範圍[0.0, 1.0] 時,使用紋理封裝來實現。紋理封裝模式使用glTexParameter[i|f][v]來指定。
紋理封裝模式能被獨立的設定為s座標和t座標。GL_TEXTURE_WRAP_S模式定義s 座標超出範圍[0.0, 1.0]的情況,GL_TEXTURE_WRAP_T 設定t 座標超出範圍[0.0, 1.0]的情況。有三種封裝模式供選擇
注意,紋理封裝模式對過濾行為有影響。例如紋理座標是邊緣時,雙線性過濾將掃描紋理的邊緣。這時封裝模式將決定哪個紋理是紋理邊緣的外面而應用於過濾演算法。如果你不想要任何形式的重複,應該使用GL_CLAMP_TO_EDGE。
是使用紋理繪製正方形在三種封裝模式中的
//void Draw ( ESContext *esContext ){ UserData *userData = esContext->userData; GLfloat vVertices[] = { -0.3f, 0.3f, 0.0f, 1.0f, // Position 0 -1.0f, -1.0f, // TexCoord 0 -0.3f, -0.3f, 0.0f, 1.0f, // Position 1 -1.0f, 2.0f, // TexCoord 1 0.3f, -0.3f, 0.0f, 1.0f, // Position 2 2.0f, 2.0f, // TexCoord 2 0.3f, 0.3f, 0.0f, 1.0f, // Position 3 2.0f, -1.0f // TexCoord 3 }; GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; // Set the viewport glViewport ( 0, 0, esContext->width, esContext->height ); // Clear the color buffer glClear ( GL_COLOR_BUFFER_BIT ); // Use the program object glUseProgram ( userData->programObject ); // Load the vertex position glVertexAttribPointer ( 0, 4, GL_FLOAT, GL_FALSE, 6 * sizeof ( GLfloat ), vVertices ); // Load the texture coordinate glVertexAttribPointer ( 1, 2, GL_FLOAT, GL_FALSE, 6 * sizeof ( GLfloat ), &vVertices[4] ); glEnableVertexAttribArray ( 0 ); glEnableVertexAttribArray ( 1 ); // Bind the texture glActiveTexture ( GL_TEXTURE0 ); glBindTexture ( GL_TEXTURE_2D, userData->textureId ); // Set the sampler texture unit to 0 glUniform1i ( userData->samplerLoc, 0 ); // Draw quad with repeat wrap mode glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); glUniform1f ( userData->offsetLoc, -0.7f ); glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices ); // Draw quad with clamp to edge wrap mode glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glUniform1f ( userData->offsetLoc, 0.0f ); glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices ); // Draw quad with mirrored repeat glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT ); glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT ); glUniform1f ( userData->offsetLoc, 0.7f ); glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );}