2D纹理与3D模型共存时的渲染问题
在XNA开发3D游戏过程中不可避免会用到2D纹理渲染,比如做游戏的主界面、背景图、选项框或者物品库等等,一般使用SpriteBatch方法渲染2D Texture,但这样会导致你的3D模型出错:变透明或是虚化或是UV贴图错误,如果在3D空间中还有2D的图片(如作为空间内地板或者墙壁之用),这部分内容也将比例失常。
究其原因是在SpriteBatch.begin()渲染完2D精灵(图片)以后你的3D图形管理器不再能正确使用,SpriteBatch 改变了一些驱动设备的渲染状态值,而这些值修改后令你的3D渲染不能正常工作。
实际上,在使用SpriteBatch方法渲染2D 材质时,我们注意下SpriteBatch.Begin()默认方法
//Begins a sprite batch operation using deferred sort and default state objects (BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullCounterClockwise).
SpriteBatch.Begin();
很显然,在3D模型绘制时,根据需要重新设置下驱动设备的渲染参数。
RasterizerState rs = new RasterizerState();
rs.CullMode = CullMode.None; /*关闭消隐模式*/
gd.RasterizerState = rs;
gd.BlendState = BlendState.AlphaBlend;
gd.DepthStencilState = DepthStencilState.Default;
gd.SamplerStates[0] = SamplerState.LinearWrap;/*Wrap模式*/
我们这里很少绘制2D纹理,一旦绘制则出现模型的UV贴图、背面消隐错误,因此, 可以在2D材质的渲染时使用改方法spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.None, RasterizerState.CullNone);3D模型绘制时不需要再修改图形设备参数。
UV显示错误
UV显示正确
我们看下Direct3D的纹理寻址模式
Direct3D定义了4种纹理寻址模式来处理纹理坐标超出[0, 1]范围的纹理映射方法,它们分别是重叠映射寻址(wrap texture address mode)、镜像纹理寻址(mirror texture address mode)、夹取纹理寻址(clamp texture address mode)、边框颜色纹理寻址(border color texture address mode)。
重叠纹理寻址模式
使用重叠纹理寻址模式时,Direct3D会在每个整数纹理坐标连接处自动重复纹理。例如,应用程序创建了一个正方形图元,并指定4个顶点的纹理坐标为(0.0, 0.0)、(0.0, 3.0)、(3.0, 3.0)、(3.0, 0.0)。使用重叠纹理寻址,Direct3D就会在u、v方向各复制3遍原始纹理,如下图所示:
重叠纹理寻址是Direct3D中缺省的寻址模式,也是三维系统中最常用的寻址模式之一。在渲染具有诸如砖墙之类纹理的物体时,如果使用包含一整张砖墙的纹理贴图会占用较多的内存,通常只需载入一张具有一块或多块砖瓦的较小的纹理贴图,再把它按照重叠纹理寻址模式在物体表面映射多次,就可以达到和使用整张砖墙贴图同样的效果。
镜像纹理寻址模式
使用镜像纹理寻址模式时,Direct3D会在每个整数纹理坐标连接处自动复制并翻转纹理。例如,应用程序创建了一个正方形图元,并指定4个顶点的纹理坐标为(0.0, 0.0)、(0.0, 3.0)、(3.0, 3.0)、(3.0, 0.0)。采用镜像纹理寻址模式,Direct3D就会在u、v方向各复制3遍并翻转原始纹理图,所有的行和列都是前一行或列的镜像,如下图所示:
夹取纹理寻址模式
夹取纹理寻址模式将纹理坐标夹取在[0.0, 1.0]范围之内。也就是说,它将纹理复制一遍,然后将纹理边缘像素的颜色延伸。例如,应用程序创建了一个正方形图元,并指定4个顶点的纹理坐标为(0.0, 0.0)、(0.0, 3.0)、(3.0, 3.0)、(3.0, 0.0)。将u、v方向上的纹理寻址模式都设置为夹取纹理寻址模式时的效果如下图所示:
原纹理 |
使用夹取纹理寻址模式后的效果图 |
用枚举类型D3DTEXTUREADDRESS的成员D3DTADDRESS_CLAMP指定夹取纹理寻址模式。下面的示例代码设置纹理层0的u、v方向寻址模式为夹取纹理寻址模式:
边框颜色纹理寻址模式
边框颜色纹理寻址模式用枚举类型D3DTEXTUREADDRESS的成员D3DTADDRESS_BORDER指定,当纹理坐标超出[0.0, 1.0]范围时,Direct3D使用边框颜色代替纹理颜色。
边框颜色通过调用函数IDirect3DDevice9::SetSamplerState()设置,第一个参数设为纹理层序号,第二个参数设为D3DSAMP_BORDERCOLOR,第三个参数设为所需的边框颜色,为D3DCOLOR类型,以32位整数表示A、R、G、B颜色。下面的示例代码指定边框颜色为红色,并设置纹理层0的u、v方向寻址模式为边框颜色纹理寻址模式。
g_device->SetSamplerState(0, D3DSAMP_BORDERCOLOR, 0xFFFF0000); g_device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); g_device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
渲染的结果如下图所示:
原纹理 |
使用边框颜色纹理寻址模式后的效果图 |