日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

创建mip纹理链

發(fā)布時(shí)間:2023/12/10 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 创建mip纹理链 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

(1)

我們要做的是,根據(jù)原始紋理T0創(chuàng)建一系列的紋理(通常使用平均濾波):T1、T2…Tn,其中每個(gè)紋理的大小都是前一個(gè)紋理的1/4,即長度和寬度減半,如圖12.40所示。

要根據(jù)前一個(gè)mip紋理計(jì)算當(dāng)前紋理中紋素的值,可以使用平均濾波器,即在RGB空間中,計(jì)算紋素(x,y)、(x+1,y)、(x+1,y+1)和(x,y+1)的平均值,然后將結(jié)果寫入到當(dāng)前紋理中,如圖12.41所示。

(點(diǎn)擊查看大圖)圖12.40? 根據(jù)原始紋理創(chuàng)建Mip紋理鏈
(點(diǎn)擊查看大圖)圖12.41? 用于創(chuàng)建mip紋理的平均濾波器

創(chuàng)建Mip紋理鏈時(shí)需要遵守一些規(guī)則。首先,所有紋理都必須是方形的,且邊長為2的冪。這樣,可以在兩個(gè)軸上按相同的比例縮小,Mip紋理鏈末尾的最后一個(gè)紋理總是1×1的。另一個(gè)約定是,原始紋理為mip等級(jí)0,然后依次為mip等級(jí)1、2、3、4…n。例如,如果原始紋理的大小為256×256,則mip鏈中各個(gè)紋理的大小如表12.4所示。

表12.4?原始紋理為256×256時(shí),各個(gè)Mip紋理的大小

Mip紋理

紋理大小

Mip紋理

紋理大小

T0

256×256

T5

8×8

T1

128×128

T6

4×4

T2

64×64

T7

2×2

T3

32×32

T8

1×1

T4

16×16

?

?

除原始紋理外,mip等級(jí)數(shù)為log2T0的邊長。

在這個(gè)例子中,為log2256 = 8。要計(jì)算總紋理數(shù),只需將上述結(jié)果加1。因此計(jì)算總紋理數(shù)的公式為:log2T0的邊長+1。在這個(gè)例子中,總紋理數(shù)為9。

(2)

這里紋理要占用多少內(nèi)存呢?圖12.42是實(shí)際的mip紋理,其中每個(gè)紋理的大小都是前一個(gè)紋理的1/4。由于每次都將紋理縮小到原來的1/4,因此占用的內(nèi)存很少。下面計(jì)算在前一個(gè)例子中,紋理需要占用多少內(nèi)存。

圖12.42? 實(shí)際的mip紋理

初始紋理的大小為256×256,需要占用2562個(gè)字。Mip紋理鏈需要的內(nèi)存量如下:

要計(jì)算x為原始紋理所需內(nèi)存量的多少倍,將其除以2562:

?

?

換句話說,加上mip紋理時(shí),每個(gè)紋理需要的內(nèi)存量只增加33%,代價(jià)很小,收益卻很高。

知道如何創(chuàng)建mip紋理以及它們占用的內(nèi)存量后,需要拿出一種將其加入到引擎中的方法。作者苦思悶想,考慮過再次修改物體/多邊形數(shù)據(jù)結(jié)構(gòu),最后終于柳暗花明:只需將紋理指針指向mip紋理鏈而不是單個(gè)紋理即可。然而,在每個(gè)多邊形中設(shè)置一個(gè)Mipmapping標(biāo)記,并在渲染多邊形時(shí),將紋理指針視為執(zhí)行位圖數(shù)組的指針,而不是單個(gè)位圖的指針。這樣,便可以使用原來的數(shù)據(jù)結(jié)構(gòu)。請看圖12.43,以理解這里討論的方法。

??
圖12.43? 支持mip紋理鏈的紋理指針數(shù)組

?

需要對紋理進(jìn)行Mipmapping時(shí),原來的texture指針指向0級(jí)別mip紋理。據(jù)此分兩步創(chuàng)建mip紋理鏈:首先,分配一個(gè)位圖指針數(shù)組,并將原來的texture指針指向該數(shù)組;然后為每個(gè)mip紋理分配內(nèi)存、生成mip紋理,并將位圖指針數(shù)組中的每個(gè)元素指向相應(yīng)mip紋理的位圖。看起來令人迷惑,其實(shí)并非如此。

這種方案存在的唯一問題是,我們強(qiáng)行將物體/多邊形的位圖圖像指針指向了一個(gè)位圖指針數(shù)組。因此,必須非常小心,避免不知道紋理已被mipmap化的函數(shù)將0級(jí)紋理視為普通紋理;而知道紋理已被mipmap化的函數(shù)必須從mip紋理鏈中選擇正確的紋理。

(3)

int Generate_Mipmaps(BITMAP_IMAGE_PTR source, // 原始紋理 BITMAP_IMAGE_PTR *mipmaps, // 指向mip紋理數(shù)組的指針 float gamma) // gamma修正因子 { // 這個(gè)函數(shù)創(chuàng)建一個(gè)mip紋理鏈 // 調(diào)用該函數(shù)時(shí),mipmap指向原始紋理 // 該函數(shù)退出時(shí),mipmap指向一個(gè)指針數(shù)組,其中包含指向各個(gè)mip級(jí)紋理的指針 // 另外,該函數(shù)返回mip等級(jí)數(shù),如果發(fā)生錯(cuò)誤,則返回-1 // 最后一個(gè)參數(shù)gamma用于提高mip紋理的亮度,因?yàn)槠骄鶠V波器會(huì)降低亮度 // 1.01通常是不錯(cuò)的選擇 // 該參數(shù)大于1.0時(shí),將提高亮度;小于1.0時(shí)將降低亮度;為1.0時(shí)沒有影響 BITMAP_IMAGE_PTR *tmipmaps; // 局部變量,指向指針數(shù)組的指針 // 第一步:計(jì)算mip等級(jí)數(shù) int num_mip_levels = logbase2ofx[source->width] + 1; // 為指針數(shù)組分配內(nèi)存 tmipmaps = (BITMAP_IMAGE_PTR *)malloc(num_mip_levels * sizeof(BITMAP_IMAGE_PTR) ); // 將元素0指向原始紋理 tmipmaps[0] = source; // 設(shè)置寬度和高度(它們相同) int mip_width = source->width; int mip_height = source->height; // 使用平均濾波器生成各個(gè)mip紋理 for (int mip_level = 1; mip_level < num_mip_levels; mip_level++) { // 計(jì)算下一個(gè)mip紋理的大小 mip_widthmip_width = mip_width / 2; mip_heightmip_height = mip_height / 2; // 為位圖對象分配內(nèi)存 tmipmaps[mip_level] = (BITMAP_IMAGE_PTR)malloc(sizeof(BITMAP_IMAGE) ); // 創(chuàng)建用于存儲(chǔ)mip紋理的位圖 Create_Bitmap(tmipmaps[mip_level],0,0, mip_width, mip_height, 16); // 讓位圖可用于渲染 SET_BIT(tmipmaps[mip_level]->attr, BITMAP_ATTR_LOADED); // 遍歷前一個(gè)mip紋理,使用平均濾波器創(chuàng)建當(dāng)前mip紋理 for (int x = 0; x < tmipmaps[mip_level]->width; x++) { for (int y = 0; y < tmipmaps[mip_level]->height; y++) { // 需要計(jì)算4個(gè)紋素的平均值,這些紋素在前一個(gè)mip紋理中的位置如下: // (x*2, y*2)、(x*2+1, y*2)、(x*2,y*2+1)、(x*2+1,y*2+1) // 然后將計(jì)算結(jié)果寫入到當(dāng)前mip紋理的(x, y)處 float r0, g0, b0, // 4個(gè)樣本紋素的R、G、B分量 r1, g1, b1, r2, g2, b2, r3, g3, b3; int r_avg, g_avg, b_avg; // 用于存儲(chǔ)平均值 USHORT *src_buffer = (USHORT *)tmipmaps[mip_level-1]->buffer, *dest_buffer = (USHORT *)tmipmaps[mip_level]->buffer; // 提取每個(gè)紋素的R、G、B值 _RGB565FROM16BIT( src_buffer[(x*2+0) + (y*2+0)*mip_width*2] , &r0, &g0, &b0); _RGB565FROM16BIT( src_buffer[(x*2+1) + (y*2+0)*mip_width*2] , &r1, &g1, &b1); _RGB565FROM16BIT( src_buffer[(x*2+0) + (y*2+1)*mip_width*2] , &r2, &g2, &b2); _RGB565FROM16BIT( src_buffer[(x*2+1) + (y*2+1)*mip_width*2] , &r3, &g3, &b3); // 計(jì)算平均值,并考慮gamma參數(shù) r_avg = (int)(0.5f + gamma*(r0+r1+r2+r3)/4); g_avg = (int)(0.5f + gamma*(g0+g1+g2+g3)/4); b_avg = (int)(0.5f + gamma*(b0+b1+b2+b3)/4); // 根據(jù)5.6.5格式,對R、G、B值進(jìn)行截取 if (r_avg > 31) r_avg = 31; if (g_avg > 63) g_avg = 63; if (b_avg > 31) b_avg = 31; // 寫入數(shù)據(jù) dest_buffer[x + y*mip_width] = _RGB16BIT565(r_avg,g_avg,b_avg); } // end for y } // end for x } // end for mip_level // 讓mipmaps指向指針數(shù)組 *mipmaps = (BITMAP_IMAGE_PTR)tmipmaps; // 成功返回 return(num_mip_levels); } // end Generate_Mipmaps

(4)

該函數(shù)接受三個(gè)參數(shù),它們有些棘手。第一個(gè)參數(shù)是位圖指針source,可以是指向任何有效BITMAP_IMAGE對象的指針,切記它是一個(gè)指針。第二個(gè)參數(shù)要復(fù)雜些:

  • BITMAP_IMAGE_PTR?*mipmaps;?
  • 這是一個(gè)指向BITMAP_IMAGE指針的指針。假設(shè)物體(或多邊形)有一個(gè)texture指針,它指向一個(gè)BITMAP_IMAGE。現(xiàn)在的問題是,當(dāng)mip紋理函數(shù)生成所有的mip紋理時(shí),我們要將該指針指向mip紋理鏈本身,為此,需要知道該指針的地址,以便能夠修改它,因此需要一個(gè)** BITMAP_IMAGE。這就是需要一個(gè)指向指針的指針作為參數(shù)的原因。我們將讓該參數(shù)指向mip紋理指針數(shù)組。

    這個(gè)函數(shù)提供了這樣的靈活性:可以將同一個(gè)對象作為參數(shù)source和mipmap。對于source參數(shù),將其設(shè)置為指向該對象的指針;對于參數(shù)mipmaps,需要將其設(shè)置為指向該對象的指針的地址,這樣函數(shù)才能對其進(jìn)行修改。假設(shè)您這樣調(diào)用該函數(shù):

  • Generate_Mipmaps(obj->texture,?(BITMAP_IMAGE_PTR?*)&obj->texture,1.01);?
  • 其中obj的類型為OBJECT4DV2_PTR,它有一個(gè)texture字段,該字段是一個(gè)指向BITMAP_IMAGE的指針(BITMAP_IMAGE_PTR)。仔細(xì)查看上述調(diào)用可以發(fā)現(xiàn):我們將該指針作為第一個(gè)參數(shù),同時(shí)將其地址作為第二個(gè)參數(shù),因此對第二個(gè)參數(shù)進(jìn)行修改時(shí),將修改obj->texture指向的實(shí)際值,從而丟失它指向的原始數(shù)據(jù)。但事實(shí)上,并不會(huì)丟失任何數(shù)據(jù),我們將把obj->texture指向的原始位圖用作mip紋理鏈中的第一個(gè)紋理。在刪除mip紋理鏈時(shí),我們重新將該指針指向原始位圖。圖12.44說明了整個(gè)處理過程。

    (點(diǎn)擊查看大圖)圖12.44? 讓obj.texture指向mip紋理鏈和重新指向T0

    回到mip紋理生成函數(shù)--它創(chuàng)建mip紋理鏈:為紋理指針數(shù)組分配內(nèi)存;然后計(jì)算下一個(gè)mip等級(jí)的大小,為該mip等級(jí)分配內(nèi)存,在RGB空間使用平均濾波器來創(chuàng)建該mip等級(jí)。這一過程不斷重復(fù),直到mip等級(jí)的大小為1×1為止,然后函數(shù)結(jié)束。該函數(shù)的最后一個(gè)參數(shù)(默認(rèn)值為1.01)用于設(shè)置gamma值。使用平均過濾器來不斷縮小圖像時(shí),其亮度會(huì)逐漸降低;因此通常使用gamma因子來提高每個(gè)mip等級(jí)的亮度,確保所有mip等級(jí)的亮度一致。為說明這一點(diǎn),作者編寫了一個(gè)演示程序,名為DEMOII12_10.CPP|H。用戶可以選擇不同的紋理圖,該程序?qū)?dòng)態(tài)地創(chuàng)建mip紋理,并顯示它們,如圖12.45所示。另外,用戶還可以修改gamma值,以查看其影響。該程序的控制方式如下:

    圖12.45? mip紋理實(shí)時(shí)生成程序的屏幕截圖
    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

    總結(jié)

    以上是生活随笔為你收集整理的创建mip纹理链的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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