分享到新浪微博 分享到QQ空间 打印

[原创改版教程] nds 3D游戏hack入门(4) 纹理篇

nds 3D游戏hack入门(4) 纹理篇

nds 3D游戏hack入门(4) 纹理篇
纹理的英文是texture,所以中文也有材质这样的翻译
纹理贴图这种东西,比多边形有实感多了,NDS的纹理贴图都以2D图片的形式进行存储
白金版的npc形象就是纹理贴图,修改这些东西就是修改纹理贴图啦,纹理贴图是3D系统中最贴近大家的一块了

纹理参数设置
对应的I/O寄存器
引用:
40004A8h - Cmd 2Ah - TEXIMAGE_PARAM - 设置纹理参数(W)
  0-15  纹理在显存中的偏移,除以8后存储
  16    在横轴方向上重复纹理贴图 (0=不重复, 1=重复)
  17    在纵轴方向上重复纹理贴图 (0=不重复, 1=重复)
  18    在横轴方向上水平翻转纹理贴图 (0=禁用, 1=为2的倍数的纹理翻转) (开启bit16的重复)
  19    在纵轴方向上垂直翻转纹理贴图 (0=禁用, 1=为2的倍数的纹理翻转) (开启bit17的重复)
  20-22 纹理的宽度 (0到7,分别对应2^3到2^10,也就是8到1024)
  23-25 纹理的高度 (0到7,分别对应2^3到2^10,也就是8到1024)
  26-28 纹理格式 (0到7,一共8种,见下)
  29    4/16/256色调色板的背景色(color 0) (0=启用, 1=保持透明)
  30-31 纹理坐标转换方式(0到3,见下,涉及到纹理矩阵)
首先是纹理在显存中的偏移,在第一章的显存控制中,我们知道,nds的显存最多可以给纹理贴图分配512k的空间,从slot 0到slot 3
bit0-bit15记录纹理的偏移地址除以8的值,也就是说,纹理贴图的存储地址必须为8的倍数
结合第一章可知,当bit0-bit15的取值范围在0x0000-0x3fff的时候,贴图的起始地址在slot 0,0x4000-0x7fff的时候,在slot 1,
slot2就是0x8000-0xbfff,slot3就是0xc000-0xffff
贴图可以跨slot界限存储,这个值只是记录了起始地址

如果要跟踪纹理贴图,得先确认纹理贴图的slot分配,然后把显存的模式切换到LCDC模式,接着计算地址,然后下断点找
下面用空之探险队来做说明,下面有些东西在显存分配篇就讲过了,就不重复了,有需要请查阅那篇的资料
先在3D查看器中确认到纹理贴图属性的信息

偏移是0x3E00,放置在slot0,然后看一下slot0是哪个

显然,只有VramD是存放3D纹理的,所以VramD就是slot0
接着计算地址0x6860000+0x3E00*0x8 = 0x687F000
然后切换到LCDC模式,编写一段简单的代码,调用相关的API就行了

好了,下断点然后逆向吧

SDK内有提供专门的纹理贴图载入API,如下
复制内容到剪贴板
代码:
void GX_BeginLoadTex(void);
void GX_LoadTex(const void *pSrc, u32 destSlotAddr, u32 szByte);
void GX_EndLoadTex(void);
此外,一般还搭配DC_FlushRange这个API使用

接下来是纹理重复跟纹理翻转的问题,翻转这个东西,NO$GBA的3D查看器没有直观地体现出来
纹理重复跟纹理翻转用的其实也不多,但毕竟本系列教程是以作为NDS 3D游戏hack的基础参考资料为目标编写的,所以还是得介绍一下
这里的重复跟翻转并不体现在纹理贴图的“内部”,而是体现在“外部”
NDS的纹理坐标的取值范围相当大,在±2048之间,下面会做更具体的介绍,配合矩阵做几何变换,可以更大,而纹理贴图的大小最大不超过1024x1024
如果访问到超过这个范围的坐标,会怎么样呢,答案是,取决于是否纹理贴图是否重复
讲到这里,我想应该有人明白重复是怎么一回事了吧
没有明白也没关系,下面简单介绍一下

这是空之探险队对话框的3D纹理贴图,128x32,横轴上重复纹理贴图就会像下面这样


开启水平翻转会像这样


纵轴跟垂直翻转的话,也跟上面差不多,就是方向变了一下

纹理格式

接下来介绍一下格式,NDS的纹理贴图支持8种格式
格式0,无纹理贴图,这个很好理解
格式2,4色调色板索引的纹理贴图,在ct2中用vb 2bpp的方式查看并导出导入
格式3,16色调色板索引的纹理贴图,在ct2中用gba 4bpp的方式查看并导出导入
格式4,256色调色板索引的纹理贴图,在ct2中用gba 8bpp的方式查看并导出导入
格式7,16位非调色板索引的纹理贴图,在ct2中用RGBa 16bpp的方式查看并导出导入

看到这里有人可能要问了,为什么我不按顺序介绍,因为我觉得这样的分类比较好,以上的那些可以通过ct2导出导入
但是以下的3种,虽然可以用ct2查看,但是不能用ct2导出导入,需要另外编写工具,理解它为什么不能用ct2导出导入,将是本小节的难点

格式1,32色调色板索引带透明通道的纹理贴图,这个格式是8bit的,其中5bit存储调色板索引,3bit存储alpha
其中,3bit的alpha转换成5bit的alpha,参照这个公式,(Alpha*4)+(Alpha/2)
因为这个格式是8bit存储一像素,是可以在ct2中通过gba 8bpp的方式查看的
但是,不能导出导入,因为gba 8bpp,是8bit都用来存储调色板索引,而格式1只用5bit存储调色板索引,另外3bit是alpha

格式6,8色调色板索引带透明通道的纹理贴图,这个格式也是8bit的,其中3bit存储调色板索引,5bit存储alpha
同上,也可以通过gba 8bpp的方式查看

格式5,这个格式估计是NDS最变态的格式了,重点讲这个,这个格式的英文是4x4-Texel Compressed
名字内带有compressed,不过并不是lz77那种压缩,而是能把高画质的纹理贴图以4色的方式存储
有人要问了,那样的话,不是很容易失真吗?
呵呵,你太小看任天堂了,虽说是4色,但这种格式额外地带有一个调色板信息
额外的调色板信息丰富了该格式能显示的颜色,我们接下来就来看看这个格式的奥秘吧

首先这个格式是可以在ct2中查看的,方式是vb 2bpp,此外要把宽高设置为4x4,举个栗子,就像下面这样


嗯,由4x4的图块构成,每个图块都带有一个调色板信息,调色板信息是这个格式的核心,也是相当奇葩的部分

调色板信息有2字节,其中低14bit存储调色板偏移,高2bit存储模式
调色板偏移换算成具体的地址,就是调色板的基地址+调色板偏移*4,关于调色板基地址的计算,下面会做更具体的介绍
模式一共有4种,这4种模式会决定调色板的最终内容

4色图的调色板,有4种颜色,下文以color 0 .. 3来说明
复制内容到剪贴板
代码:
  Texel  Mode 0       Mode 1             Mode 2         Mode 3
  0      Color 0      Color0             Color 0        Color 0
  1      Color 1      Color1             Color 1        Color 1
  2      Color 2      (Color0+Color1)/2  Color 2        (Color0*5+Color1*3)/8
  3      Transparent  Transparent        Color 3        (Color0*3+Color1*5)/8
很奇葩吧,出现了乘除运算,4种模式的共同点在于,color0跟color1直接使用调色板中的颜色
其中模式2是最正常的,color2跟color3也使用调色板的颜色,模式1跟模式3仅使用color0跟color1
模式0跟模式1中,color3都是作为透明色用,计算的话,要把RGB分开来计算,具体的代码,参考desmume中的texcache.cpp的代码

有人估计又要问了,这种格式该如何编辑,呵呵,这种格式目前只有用任天堂官方的photoshop插件才能修改,这个插件我改天放出


纹理坐标

设置纹理坐标
复制内容到剪贴板
代码:
4000488h - Cmd 22h - TEXCOORD - 设置纹理坐标 (W)
  参数 1, Bit 0-15   S坐标 (理解为纹理贴图中的X坐标也行)
  参数 2, Bit 16-31  T坐标 (理解为纹理贴图中的Y坐标也行)
这个命令跟顶点坐标设置命令一样,使用频率非常高,它的重要性在于:能将纹理贴图与多边形关联起来,形成丰富多彩的3D建模
参数的格式是4bit带符号的定点数
绘制3D建模的时候,按照纹理坐标->法向量->顶点坐标的顺序绘制是最快,如下


不过这里传进去的纹理坐标,并不一定成为最终的纹理坐标,而是可能要经过一次变换才行

纹理坐标变换

还记得第二章提到的纹理矩阵吗?纹理坐标的变换就基于此,结合上面提到的纹理参数设置的bit30-31,一共有4种模式,分别是
Transform
TexCoord source
Normal source
Vertex source

Transform模式就是直接赋值,最常见的就是这个

TexCoord source遵循如下公式
复制内容到剪贴板
代码:
                                     | m[0]  m[1]  |
  ( S' T' )  =  ( S  T 1/16 1/16 ) * | m[4]  m[5]  |
                                     | m[8]  m[9]  |
                                     |_m[12] m[13]_|
S T作为向量的x y分量 1/16作为z w分量,这个矩阵就是纹理矩阵,不过并没有全部使用,而是仅使用了左侧的2列进行运算
如果把缩放、平移、旋转矩阵写入到纹理矩阵中,可实现对纹理坐标的缩放、平移、旋转等变换

Normal source遵循如下公式
复制内容到剪贴板
代码:
                                     | m[0]  m[1]  |
  ( S' T' )  =  ( Nx  Ny  Nz 1.0 ) * | m[4]  m[5]  |
                                     | m[8]  m[9]  |
                                     |_S     T    _|
其中,向量( Nx  Ny  Nz 1.0 )是法向量,可用于球面纹理映射,不过gbatek对此没有过多的解释

在设置完法向量时执行

Vertex source如下
复制内容到剪贴板
代码:
                                     | m[0]  m[1]  |
  ( S' T' )  =  ( Vx  Vy  Vz 1.0 ) * | m[4]  m[5]  |
                                     | m[8]  m[9]  |
                                     |_S     T    _|
其中,( Vx  Vy  Vz 1.0 )是顶点坐标
在设置顶点坐标时执行,可以设置texture scrolls

[ 本帖最后由 enler 于 2013-5-6 10:47 编辑 ]
附件: 您所在的用户组无法下载或查看附件

TOP

占楼,差纹理混合

TOP

求纹理混合啊,楼主不能这样弃了

TOP

楼主为何不更了。

TOP