青浦网络公司网站广告公司网页页面设计模板
青浦网络公司网站,广告公司网页页面设计模板,自己开发的app如何上线,如何做视频网站赚钱(1)
我们要做的是#xff0c;根据原始纹理T0创建一系列的纹理#xff08;通常使用平均滤波#xff09;#xff1a;T1、T2…Tn#xff0c;其中每个纹理的大小都是前一个纹理的1/4#xff0c;即长度和宽度减半#xff0c;如图12.40所示。
要根据前一个mip纹理计算当前纹…(1)
我们要做的是根据原始纹理T0创建一系列的纹理通常使用平均滤波T1、T2…Tn其中每个纹理的大小都是前一个纹理的1/4即长度和宽度减半如图12.40所示。
要根据前一个mip纹理计算当前纹理中纹素的值可以使用平均滤波器即在RGB空间中计算纹素(xy)、(x1y)、(x1y1)和(xy1)的平均值然后将结果写入到当前纹理中如图12.41所示。
点击查看大图图12.40 根据原始纹理创建Mip纹理链
点击查看大图图12.41 用于创建mip纹理的平均滤波器
创建Mip纹理链时需要遵守一些规则。首先所有纹理都必须是方形的且边长为2的幂。这样可以在两个轴上按相同的比例缩小Mip纹理链末尾的最后一个纹理总是1×1的。另一个约定是原始纹理为mip等级0然后依次为mip等级1、2、3、4…n。例如如果原始纹理的大小为256×256则mip链中各个纹理的大小如表12.4所示。
表12.4 原始纹理为256×256时各个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等级数为log2T0的边长。
在这个例子中为log2256 8。要计算总纹理数只需将上述结果加1。因此计算总纹理数的公式为log2T0的边长1。在这个例子中总纹理数为9。
2
这里纹理要占用多少内存呢图12.42是实际的mip纹理其中每个纹理的大小都是前一个纹理的1/4。由于每次都将纹理缩小到原来的1/4因此占用的内存很少。下面计算在前一个例子中纹理需要占用多少内存。
图12.42 实际的mip纹理
初始纹理的大小为256×256需要占用2562个字。Mip纹理链需要的内存量如下 要计算x为原始纹理所需内存量的多少倍将其除以2562 换句话说加上mip纹理时每个纹理需要的内存量只增加33代价很小收益却很高。
知道如何创建mip纹理以及它们占用的内存量后需要拿出一种将其加入到引擎中的方法。作者苦思闷想考虑过再次修改物体/多边形数据结构最后终于柳暗花明只需将纹理指针指向mip纹理链而不是单个纹理即可。然而在每个多边形中设置一个Mipmapping标记并在渲染多边形时将纹理指针视为执行位图数组的指针而不是单个位图的指针。这样便可以使用原来的数据结构。请看图12.43以理解这里讨论的方法。 图12.43 支持mip纹理链的纹理指针数组需要对纹理进行Mipmapping时原来的texture指针指向0级别mip纹理。据此分两步创建mip纹理链首先分配一个位图指针数组并将原来的texture指针指向该数组然后为每个mip纹理分配内存、生成mip纹理并将位图指针数组中的每个元素指向相应mip纹理的位图。看起来令人迷惑其实并非如此。
这种方案存在的唯一问题是我们强行将物体/多边形的位图图像指针指向了一个位图指针数组。因此必须非常小心避免不知道纹理已被mipmap化的函数将0级纹理视为普通纹理而知道纹理已被mipmap化的函数必须从mip纹理链中选择正确的纹理。
3
int Generate_Mipmaps(BITMAP_IMAGE_PTR source, // 原始纹理 BITMAP_IMAGE_PTR *mipmaps, // 指向mip纹理数组的指针 float gamma) // gamma修正因子
{
// 这个函数创建一个mip纹理链
// 调用该函数时mipmap指向原始纹理
// 该函数退出时mipmap指向一个指针数组其中包含指向各个mip级纹理的指针
// 另外该函数返回mip等级数如果发生错误则返回-1
// 最后一个参数gamma用于提高mip纹理的亮度因为平均滤波器会降低亮度
// 1.01通常是不错的选择
// 该参数大于1.0时将提高亮度小于1.0时将降低亮度为1.0时没有影响 BITMAP_IMAGE_PTR *tmipmaps; // 局部变量指向指针数组的指针 // 第一步计算mip等级数
int num_mip_levels logbase2ofx[source-width] 1; // 为指针数组分配内存
tmipmaps (BITMAP_IMAGE_PTR *)malloc(num_mip_levels * sizeof(BITMAP_IMAGE_PTR) ); // 将元素0指向原始纹理
tmipmaps[0] source; // 设置宽度和高度它们相同
int mip_width source-width;
int mip_height source-height; // 使用平均滤波器生成各个mip纹理
for (int mip_level 1; mip_level num_mip_levels; mip_level) { // 计算下一个mip纹理的大小 mip_widthmip_width mip_width / 2; mip_heightmip_height mip_height / 2; // 为位图对象分配内存 tmipmaps[mip_level] (BITMAP_IMAGE_PTR)malloc(sizeof(BITMAP_IMAGE) ); // 创建用于存储mip纹理的位图 Create_Bitmap(tmipmaps[mip_level],0,0, mip_width, mip_height, 16); // 让位图可用于渲染 SET_BIT(tmipmaps[mip_level]-attr, BITMAP_ATTR_LOADED); // 遍历前一个mip纹理使用平均滤波器创建当前mip纹理 for (int x 0; x tmipmaps[mip_level]-width; x) { for (int y 0; y tmipmaps[mip_level]-height; y) { // 需要计算4个纹素的平均值这些纹素在前一个mip纹理中的位置如下: // (x*2, y*2)、(x*21, y*2)、(x*2,y*21)、(x*21,y*21) // 然后将计算结果写入到当前mip纹理的(x, y)处 float r0, g0, b0, // 4个样本纹素的R、G、B分量 r1, g1, b1, r2, g2, b2, r3, g3, b3; int r_avg, g_avg, b_avg; // 用于存储平均值 USHORT *src_buffer (USHORT *)tmipmaps[mip_level-1]-buffer, *dest_buffer (USHORT *)tmipmaps[mip_level]-buffer; // 提取每个纹素的R、G、B值 _RGB565FROM16BIT( src_buffer[(x*20) (y*20)*mip_width*2] , r0, g0, b0); _RGB565FROM16BIT( src_buffer[(x*21) (y*20)*mip_width*2] , r1, g1, b1); _RGB565FROM16BIT( src_buffer[(x*20) (y*21)*mip_width*2] , r2, g2, b2); _RGB565FROM16BIT( src_buffer[(x*21) (y*21)*mip_width*2] , r3, g3, b3); // 计算平均值并考虑gamma参数 r_avg (int)(0.5f gamma*(r0r1r2r3)/4); g_avg (int)(0.5f gamma*(g0g1g2g3)/4); b_avg (int)(0.5f gamma*(b0b1b2b3)/4); // 根据5.6.5格式对R、G、B值进行截取 if (r_avg 31) r_avg 31; if (g_avg 63) g_avg 63; if (b_avg 31) b_avg 31; // 写入数据 dest_buffer[x y*mip_width] _RGB16BIT565(r_avg,g_avg,b_avg); } // end for y } // end for x } // end for mip_level // 让mipmaps指向指针数组
*mipmaps (BITMAP_IMAGE_PTR)tmipmaps;
// 成功返回
return(num_mip_levels); } // end Generate_Mipmaps
4
该函数接受三个参数它们有些棘手。第一个参数是位图指针source可以是指向任何有效BITMAP_IMAGE对象的指针切记它是一个指针。第二个参数要复杂些 BITMAP_IMAGE_PTR *mipmaps;
这是一个指向BITMAP_IMAGE指针的指针。假设物体或多边形有一个texture指针它指向一个BITMAP_IMAGE。现在的问题是当mip纹理函数生成所有的mip纹理时我们要将该指针指向mip纹理链本身为此需要知道该指针的地址以便能够修改它因此需要一个** BITMAP_IMAGE。这就是需要一个指向指针的指针作为参数的原因。我们将让该参数指向mip纹理指针数组。
这个函数提供了这样的灵活性可以将同一个对象作为参数source和mipmap。对于source参数将其设置为指向该对象的指针对于参数mipmaps需要将其设置为指向该对象的指针的地址这样函数才能对其进行修改。假设您这样调用该函数 Generate_Mipmaps(obj-texture, (BITMAP_IMAGE_PTR *)obj-texture,1.01);
其中obj的类型为OBJECT4DV2_PTR它有一个texture字段该字段是一个指向BITMAP_IMAGE的指针BITMAP_IMAGE_PTR。仔细查看上述调用可以发现我们将该指针作为第一个参数同时将其地址作为第二个参数因此对第二个参数进行修改时将修改obj-texture指向的实际值从而丢失它指向的原始数据。但事实上并不会丢失任何数据我们将把obj-texture指向的原始位图用作mip纹理链中的第一个纹理。在删除mip纹理链时我们重新将该指针指向原始位图。图12.44说明了整个处理过程。
点击查看大图图12.44 让obj.texture指向mip纹理链和重新指向T0
回到mip纹理生成函数--它创建mip纹理链为纹理指针数组分配内存然后计算下一个mip等级的大小为该mip等级分配内存在RGB空间使用平均滤波器来创建该mip等级。这一过程不断重复直到mip等级的大小为1×1为止然后函数结束。该函数的最后一个参数默认值为1.01用于设置gamma值。使用平均过滤器来不断缩小图像时其亮度会逐渐降低因此通常使用gamma因子来提高每个mip等级的亮度确保所有mip等级的亮度一致。为说明这一点作者编写了一个演示程序名为DEMOII12_10.CPP|H。用户可以选择不同的纹理图该程序将动态地创建mip纹理并显示它们如图12.45所示。另外用户还可以修改gamma值以查看其影响。该程序的控制方式如下
图12.45 mip纹理实时生成程序的屏幕截图
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/91120.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!