DX9实现天空盒

对于天空盒如何制作,我这里就不介绍了,网上有好些制作天空盒的资料,也可看我的其它转载关于天空盒的资料。这里只讲一种简单的方法实现天空盒。这种方法的基于,网上http://blog.csdn.net/xoyojank/article/details/1628932这里提出的用D3DFVF_XYZRHW实现天空盒的想法。不过有个问题,D3DFVF_XYZRHW本身会跳过坐标变换的阶段,也就是说它不会传入VertexShader和视口变换阶段,然而我们的纹理坐标却要在VertexShader中生成,因为在PixelShader中不能使用POSITION,这就很麻烦,于是想用D3DFVF_XYZW,可惜的也是会跳过VertexShader阶段。所以没办法,自能自己用编码实现类D3DFVF_XYZW的功能了,其实弄下来是很简单的,没有那么麻烦。

好了,开始了:

(1)首先准备一张CUBE纹理图

(2)声明顶点坐标

              struct Vertex{

                     float x,y,z;//注意只要这几个坐标即可,无需纹理坐标,因为纹理坐标会在VertexShader去生成的

                     static const DWORD FVF;         

                  }

 const DWORD Vertex::FVF=D3DFVF_XYZ;

(3)装入纹理图

IDirect3DCubeTexture9 *g_pBoxCubeTexture=NULL;

char szCubePath[64]="sky_box0.dds";
 D3DXCreateCubeTextureFromFile(Device,szCubePath,&g_pBoxCubeTexture);

 

(4)这一步很重要,对与顶点的部署,因为天空盒是铺满整个屏幕的,所以我们要渲染的几个三角形要把屏幕铺满,在最简单的情况下只要两个三角形凑成的矩形即可把屏幕覆盖,而且在无穷远处,但是我们的相机里的远裁剪面就知道,不能有所谓的无穷远,如何来构成无穷远呢?我们知道在透视变换之后x,y在(-1.0f,1.0f),而z在(0.0f,1.0f)直接之间,这就是说在Z-Buffer中,最近的是z=0.0f处,最远在z=1.0f处,其实这也是D3DFVF_XYZRHW的效果,所以我们只要保持我们的覆盖矩阵z=1.0f即可。我们要仿照的D3DFVF_XYZRHW也要仿照D3DFVF_XYZW,我们要是我们输入的图形覆盖掉屏幕,那么类似D3DFVF_XYZRHW,但我们要经过VertexShader,这里就和D3DFVF_XYZRHW不同了,假如我们经过了VertexShader,那么也要经过视口变换,所以,我们输入的顶点坐标要不能是视口(屏幕)坐标,而只是透视坐标中覆盖的屏幕,由于我们前面知道透视坐标的范围,所以也很容易得出,下面我给出顶点:

g_pDevice->CreateVertexBuffer(6*sizeof(Vertex),D3DUSAGE_WRITEONLY,Vertex::FVF,D3DPOOL_MANAGED,&g_pSkyBox,NULL);

 Vertex *pV=NULL;
 g_pSkyBox->Lock(0,0,(void **)&pV,0);
 pV[0]=Vertex(-1.0f,1.0f,1.0f);//(注意在透视坐标下,屏幕中心是(0.0f,0.0f),向上为y正轴,右为x正轴,和我们几何里的坐标轴一样)
 pV[1]=Vertex(1.0f,1.0f,1.0f);//(所以,右上角为(-1.0f,1.0f),右下角为(-1.0f,-1.0f),左上角及右下角自己推)
 pV[2]=Vertex(1.0f,-1.0f,1.0f);//(我们这里的z一定要是1.0f,这才能表示它处于视觉的最末尾处,而且才能被我们场景覆盖)

 pV[3]=Vertex(-1.0f,1.0f,1.0f);
 pV[4]=Vertex(1.0f,-1.0f,1.0f);
 pV[5]=Vertex(-1.0f,-1.0f,1.0f);

 g_pSkyBox->Unlock();

 

(5)下面是处理天空盒的效果文件

/*

 作者:秋风扫落叶
 时间:2012/5/19 11:30
*/

/*
 此effect完成天空盒渲染
*/ 

//由于CUBETexture是使用向量来表示纹理坐标的,具体为什么经过逆变换之后可以获取纹理坐标这里不讲,请查看推荐的那篇文章,或留言
matrix invWorldViewProj;//逆向转换矩阵,因为我们用的是变换过的坐标,这里的矩阵并不是World,View,Proj相乘的逆矩阵,后面在主控程序区会说


texture SkyBoxTexture;//纹理对象,是我们的CubeTexture

//我们的纹理采样器

samplerCUBE skyboxCube=sampler_state
{
 Texture=(SkyBoxTexture);
 MinFilter=Linear;
 MagFilter=Linear;
 AddressU=Clamp;//注,这里不能是Wrap,因为立方体纹理,无此
 AddressV=Clamp;
 AddressW=Clamp;
};

//顶点输入结构

struct VS_INPUT{
 float4 pos:POSITION; 
};

//顶点输出结构,注意虽然在输入结构中没有纹理坐标,但是在输出中可以有纹理坐标

struct VS_OUTPUT{
 float4 pos:POSITION;
 float3 texcoord:TEXCOORD; 
};

VS_OUTPUT VSMain(VS_INPUT input){
 VS_OUTPUT output=(VS_OUTPUT)0;

//这里,因为我们的坐标就是在透视平面中所以没有所谓的变换,直接放到下游进行视口变换
 output.pos=input.pos;

//获取纹理坐标
 output.texcoord=normalize(mul(input.pos,invWorldViewProj));
 
 return output;
}

vector PSMain(VS_OUTPUT input):COLOR
{

//获取像素颜色
 return texCUBE(skyboxCube,input.texcoord);
}

 

//technique

technique SkyBox{
 pass p0
 {
  VertexShader=compile vs_2_0 VSMain();
  PixelShader=compile ps_2_0 PSMain();
 }
}

 

(6)我们要编译效果文件,假定你会编译

我们如何渲染呢

//在此之前要设置好矩阵,g_mWorld是世界矩阵,g_mView是相机,g_mProj是透视矩阵

void RenderSkyBox(IDirect3DDevice9 *pDevice)
{

//关闭关照
 pDevice->SetRenderState(D3DRS_LIGHTING,false);


  D3DXMATRIX view;
 D3DXMATRIX mInvWorldViewProj;
 

//获取相机矩阵,这里不用g_mView是不想破坏矩阵
 pDevice->GetTransform(D3DTS_VIEW,&view); 

//这里是最重要的,一定不能有平移,我们要保证视点在原点,因为我们的天空盒矩形位置没有变过,而纹理坐标是视点到各顶点(天空盒)的向量,接入视点改变,那么,顶点上的纹理坐标会扭曲。(这里很重要,所以大家请思考)
 view._41=0.0f;
 view._42=0.0f;
 view._43=0.0f;

//获取逆矩阵
 D3DXMatrixInverse(&mInvWorldViewProj,NULL,&(g_mWorld*view*g_mProj));

 //设置相关效果文件常量
 g_pEffect->SetMatrix("invWorldViewProj",&mInvWorldViewProj);
 g_pEffect->SetTexture("SkyBoxTexture", g_pBoxCubeTexture);//设置纹理,这一句可以放在初始化中

//渲染天空盒
 D3DXHANDLE hTechnique=g_pEffect->GetTechniqueByName("SkyBox");
 g_pEffect->SetTechnique(hTechnique);

 UINT passNum;
 g_pEffect->Begin(&passNum,0);
  for(UINT iPass=0;iPass<passNum;iPass++)
 {

  g_pEffect->BeginPass(iPass);
  
  pDevice->SetStreamSource(0,g_pSkyBox,0,sizeof(Vertex));
  pDevice->SetFVF(Vertex::FVF);

  pDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,2);
  g_pEffect->EndPass();
 }

 g_pEffect->End();
 pDevice->SetRenderState(D3DRS_LIGHTING,true);
}

 

到此就完成了,可惜的是会有明显的分割线,所以还需改进,或者获取一张质量更好的天空盒图片

下面是截图:

DX9实现天空盒 - 995116752 - 秋风扫落叶的博客

DX9实现天空盒 - 995116752 - 秋风扫落叶的博客

DX9实现天空盒 - 995116752 - 秋风扫落叶的博客

DX9实现天空盒 - 995116752 - 秋风扫落叶的博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值