公告

Locations of visitors to this page
<2010年2月>
31123456
78910111213
14151617181920
21222324252627
28123456
78910111213

统计

  • 随笔 - 35
  • 文章 - 0
  • 评论 - 86
  • 引用 - 0

常用链接

留言簿(6)

随笔分类

随笔档案

相册

Game Dev

搜索

  •  

最新评论

阅读排行榜

评论排行榜

2010年1月20日

可编程管道下的剪裁平面

作者:Bill Hsu

主页:http://www.graptor.com

剪裁平面 (Clip Plane) 在图形学领域有着重要的作用,比如水面模拟中,渲染折射纹理时,我们就必须将水面以上的顶点通过剪裁平面剪裁掉。

在过去的固定渲染管道时代,剪裁平面的实现较为简单,比如在 DirectX 9 中,可以先设定剪裁平面在世界坐标系下的方程 (ax+by+cz+d=0) ,再调用 SetClipPlane(DWORD Index,CONST float * pPlane) 这个 API 函数就可以了。

 

附上例子程序:

vPosition=D3DXVECTOR3(0,0,0); // 平面上一个点
vNormal=D3DXVECTOR3(0,1,0); // 法向量
D3DXPlaneFromPointNormal( &clipplane, &vPosition, &vNormal ); // 生成剪裁平面

m_pDevice()->SetClipPlane( 0, (
float *)clipplane); 

 

然而,在现在的可编程管道 (programmable pipeline) 下,设置的剪裁平面会被在剪裁坐标系下处理,而不是在世界坐标系下。

解决这个问题的方法有:

1)  给要剪裁的顶点做标记,在Pixel Shader中把它剪裁掉。

2)  使用近斜平面裁剪(Oblique Near-Plane Clipping),即修改投影矩阵,将要剪裁的顶点放在视截体之外,从而避免了该顶点的绘制。

3)  修改平面方程,使之从世界坐标系转换到剪裁坐标系。


上述方法中,第一种和第二种效率并不高:在
Pixel Shader中剪裁没有减少任何不必要的顶点处理,而计算近斜平面裁剪矩阵较为繁琐。所以,方法三是最佳选择。

 要将一个平面从世界坐标系转换到剪裁坐标系,必须求出这个变换矩阵。

设平面方程ax+by+cz+d=0,用一个4维向量来n表示(a,b,c,d),设平面上有个点p:(x,y,z,1)。根据平面方程的定义,有:


nTp = ax + by + cz + d = 0

设矩阵R可以让点P从世界坐标系转换到剪裁坐标系,矩阵Q可以让平面n实现同样的变换。那么,有:

p'= Rp
n'= Qn

其中p'n'分别是转换后的点与平面。


n'Tp'= 0
(Qn)T (Rp) = 0
nTQTRp = 0


如果:QTR = I

那么:

nTQTRp = nTIp = nTp = 0

于是:

QT = R-1
Q
= (R-1)T

DirectX 3D中,将一个点从世界坐标系转换到剪裁坐标系,所用的矩阵为观察矩阵与投影矩阵的乘积,即:

D3DXMATRIX  TranMatrix = matView*matProj;

(TranMatrix为所求的变换矩阵,matViewmatProj分别为观察矩阵与投影矩阵)

 

附上在D3D中变换的完整代码:

D3DXPLANE tempPlane = clipplane;
D3DXPlaneNormalize(&tempPlane, &tempPlane);

D3DXMATRIX  TranMatrix = matView*matProj;
D3DXMatrixInverse(&TranMatrix, NULL, &TranMatrix);
D3DXMatrixTranspose(&TranMatrix, &TranMatrix);
D3DXPlaneTransform(&tempPlane, &tempPlane, &TranMatrix);

参考资料:

1.Back Face Culling Notes ,Jordan Smith (University of California, Berkeley)

http://www.cs.berkeley.edu/~ug/slide/pipeline/assignments/backfacecull.shtml 

2.GameDev Forum

http://www.gamedev.net/community/forums/topic.asp?topic_id=402381

3.Oblique Near-Plane Clipping with Orthographic Camera ,Aras

http://aras-p.info/texts/obliqueortho.html

posted @ 2010-01-20 22:00 Bill Hsu 阅读(1165) | 评论 (0)编辑 收藏

2009年12月11日

矩阵求逆代码

12-12-2009更新:加入图形化界面

程序下载(含使用说明):http://www.cppblog.com/Files/billhsu/MatInv.rar

感觉线性代数作业里一直少不了矩阵求逆,

写个带输出算逆矩阵的步骤的矩阵求逆程序,希望给即将或正在学线代的同学一点方便。

代码写的不好,大家见谅。

/* ==================================
 *
 *  Copyright (C) Bill Hsu 
 *   
http://hi.baidu.com/probill
 *  2009-12-11
 **********************************
*/
#include  
< iostream >
#include  
< vector >
#include  
< math.h >
using     namespace   std;

typedef vector  
< float >   s_line;  //  用来表示一行
s_line line;

typedef vector  
< s_line >   s_matrix;  //  用来表示一个矩阵
s_matrix matrix;
s_matrix mat;
int   nSize;  //  矩阵维数
int   nSign;  //  标记行列式正负
void   outprint(s_matrix  &   _mat);
void   printstep(s_matrix  &   _mat);
int   step  =   0  ;
void   line_add(s_matrix  &   _mat,  int   a,  int   b,  float   k  =   1.0f  )  //  第b行乘k加到第a行
{
int   size  =  _mat[  0  ].size();

for  (  int   i  =   0  ;i  <  size;  ++  i)
{
_mat[a][i] 
+=  _mat[b][i]  *  k;

//  end for
}



void   work1(s_matrix  &   _mat)  //  主计算函数
{

for  (  int   i  =   1  ;i  <  nSize;  ++  i)
{

if  (fabs(_mat[i  -   1  ][i  -   1  ])  <   0.000001 )
{
int   mm;
for  (mm  =  i;mm  <  nSize;  ++  mm)
{
if  (fabs(_mat[mm  -   1  ][i  -   1  ])  >   0.000001  )   break  ;
//  end for
line_add(_mat,i  -   1  ,mm  -   1  );
//  end if

for  (  int   j  =  i;j  <  nSize;  ++  j)
{
line_add(_mat,j,i 
-   1  ,  -  _mat[j][i  -   1  ]  /  _mat[i  -   1  ][i  -   1  ]);

//  end for j
printstep(_mat);
//  end for i

}


void   work2(s_matrix  &   _mat)  //  第二部计算
{
for  (  int   i  =  nSize  -   2  ;i  >=   0  ;  --  i)
{
for  (  int   j  =  i;j  >=   0  ;  --  j)
{
line_add(_mat,j,i 
+   1  ,  -  _mat[j][i  +   1  ]  /  _mat[i  +   1  ][i  +   1  ]);
}
printstep(_mat);
}

}


void   makeunit(s_matrix  &   _mat)  //  单位化
{

mat.clear();

for  (  int   i  =   0  ;i  <  nSize;  ++  i)
{
line.clear();
for  (  int   j  =   0  ;j  <  nSize  *   2  ;  ++  j)
{
float   tmp  =  _mat[i][j]  /  _mat[i][i];
if  (fabs(tmp)  <   0.000001  ) tmp  =   0  ;
line.push_back(tmp);
}
mat.push_back(line);
//  cout<<endl;
}
_mat 
=  mat;
}

void   printstep(s_matrix  &   _mat)  //  显示求的过程
{
cout 
<<   "  第   "   <<++  step  <<   "  步  "   <<  endl;
for  (  int   i  =   0  ;i  <  nSize;  ++  i)
{

for   (  int   j  =   0  ;j  <   2   *  nSize;  ++  j)
{
if  (fabs(_mat[i][j])  <   0.000001 ) _mat[i][j]  =   0  ;
cout 
<<  _mat[i][j]  <<   "     "  ;
if  (j  ==  nSize  -   1  )cout   <<   "   |   "  ;
}
cout 
<<  endl;
}
cout 
<<  endl;

}

void   outprint(s_matrix  &   _mat)  //  输出函数
{
for  (  int   i  =   0  ;i  <  nSize;  ++  i)
{

for   (  int   j  =  nSize;j  <   2   *  nSize;  ++  j)
{
cout 
<<  _mat[i][j]  <<   "     "  ;
}
cout 
<<  endl;
}


}

int   main()
{
step 
=   0  ;
matrix.clear();
line.clear();
cout 
<<   "  *********矩阵 求逆*********  "   <<  endl;
cout 
<<   "  *********Bill  Hsu*********  "   <<  endl;
cout 
<<   "  http://hi.baidu.com/probill  "   <<  endl  <<  endl;

cout 
<<   "  请输入矩阵维数(输入0退出):  "  ; 
cin 
>>  nSize;
if  (nSize  <=   0  )   return     0  ;
for  (  int   i  =   0  ;i  <  nSize;  ++  i)
{
line.clear(); 
cout 
<<   "  输入第  "   <<  i  +   1   <<   "   行:   "   <<  endl;
for   (  int   j  =   0  ;j  <  nSize;  ++  j) 
{
float   tmp;
cin 
>>  tmp;
line.push_back(tmp);  
//  压入一个数到某行
}

for   (  int   j  =   0  ;j  <  nSize;  ++  j) 
{
if  (i  ==  j) line.push_back(  1.0f  );
else   line.push_back(  0.0f  );
}


matrix.push_back(line);  
//  压入一行到矩阵
}

cout  
<<  endl;
work1(matrix);
work2(matrix);
makeunit(matrix);
cout 
<<  endl  <<   "  ########################  "   <<  endl
<<   "  求逆结果:  "   <<  endl;
outprint(matrix);
cout 
<<   "  ########################  "   <<  endl;

main();


return     0  ;    
}

有图有真相:

输入矩阵数据

计算步骤

计算结果

执行文件下载:http://www.cppblog.com/Files/billhsu/%E7%9F%A9%E9%98%B5%E6%B1%82%E9%80%86.rar

.

posted @ 2009-12-11 22:23 Bill Hsu 阅读(1069) | 评论 (3)编辑 收藏

2009年11月25日

发日志纪念~~第一次写导出插件

今天终于把模型导出插件最基本的功能--导出网格给写好了。

c++和max sdk一起用的感觉很怪,系统崩溃了N次,不过,总算能导出网格了~

 

有图有真相,截图纪念

(注意:模型是从value的csol中弄出来的)

在d3d中渲染导出的模型­

在d3d中渲染导出的模型­


我的模型导出插件­

导出数据样本:

[这是一个带贴图的立方体的导出数据]

 

8//  8个顶点
-6.70302 -21.2068 -5.46039
17.1883 -6.46757 0.162097
-22.4049 2.22378 -0.162097
1.48644 16.963 5.46039
-8.48039 -28.3257 20.7542
15.411 -13.5865 26.3767
-24.1823 -4.89514 26.0525
-0.290929 9.84411 31.675

12//  12个纹理坐标
0 1 0
1 1 0
0 0 0
1 0 0
0 1 0
1 1 0
0 0 0
1 0 0
0 1 0
1 1 0
0 0 0
1 0 0

12//  12个面引索
0 9 2 11 3 10
3 10 1 8 0 9
4 8 5 9 7 11
7 11 6 10 4 8
0 4 1 5 5 7
5 7 4 6 0 4
1 0 3 1 7 3
7 3 5 2 1 0
3 4 2 5 6 7
6 7 7 6 3 4
2 0 0 1 4 3
4 3 6 2 2 0

posted @ 2009-11-25 19:25 Bill Hsu 阅读(68) | 评论 (2)编辑 收藏

2009年11月8日

最酷的排序算法演示

真的很形象啊( ⊙ o ⊙ )!

posted @ 2009-11-08 00:08 Bill Hsu 阅读(105) | 评论 (0)编辑 收藏

2009年10月17日

DirectX 3D 设备丢失(lost device)的处理

低手交流,高手勿入

当初觉得DX中设备丢失很讨厌,差点就投奔OpenGL了。
不过现在发现其实也没那么麻烦啦,写点东西,给不清楚
设备丢失怎么处理的同学参考下。

在创建时使用D3DPOOL_MANAGED标志的资源可以不需要重新载入,但D3DPOOL_DEFAULT加载的资源就需要先释放,后重建。

通常需要这样处理的有ID3DXFont和ID3DXSprite,而.X模型什么的就不需要。
在发现设备丢失时,我们要调用 OnLostDevice(void)函数让D3DPOOL_DEFAULT加载的资源释放掉。
好在ID3DXFont和ID3DXSprite有设备丢失处理函数,直接调用就好了

void OnLostDevice(void)
{
    m_sprite->OnLostDevice();
    m_font->OnLostDevice();
}

可是,怎么知道设备丢失了呢?
如果设备丢失,Present()函数就会“出问题”,返回值是D3DERR_DEVICELOST。
m_pIDirect3DDevice->EndScene();

HRESULT hr;
hr 
= m_pIDirect3DDevice->Present(NULL, NULL, NULL, NULL);
if(hr == D3DERR_DEVICELOST)
{
   
if(m_pIDirect3DDevice->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
    {
        OnLostDevice();
        OnResetDevice();
    }
}
TestCooperativeLevel()== D3DERR_DEVICENOTRESET时,就可以恢复设备了。
于是,我们调用
OnLostDevice()让D3DPOOL_DEFAULT加载的资源释放掉,之后,调用OnResetDevice()来恢复设备就可以了。

怎么恢复设备呢?
void OnResetDevice(void)
{
    
if(FAILED(m_pIDirect3DDevice->Reset(&d3dpp)))
    {
        
return;
    }

    m_sprite
->OnResetDevice();
    m_font
->OnResetDevice();

    InitDevice();
}
先让D3D设备reset,然后调用
ID3DXFont和ID3DXSprite的恢复函数,最后,需要把D3D设备中的状态啊,矩阵变换啊这些重新设置下就完成了,也就是调用InitDevice()。

void InitDevice()
{
m_pIDirect3DDevice
->SetRenderState( D3DRS_ZENABLE, TRUE );

m_pIDirect3DDevice
->SetRenderState( D3DRS_AMBIENT, 0xffffffff );

m_pIDirect3DDevice
->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
m_pIDirect3DDevice
->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
m_pIDirect3DDevice
->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

D3DXMatrixPerspectiveFovLH( 
&matProj, D3DX_PI/41.0f1.0f1000.0f );
m_pIDirect3DDevice
->SetTransform( D3DTS_PROJECTION, &matProj );

vEyeVec
=D3DXVECTOR3(0.0f,0.0f,-1.0f);
vLookatVec
=D3DXVECTOR3(0.0f,0.0f,0.0f);
vUpVec
=D3DXVECTOR3(0.0f,1.0f,0.0f);
D3DXMatrixLookAtLH( 
&matView, &vEyeVec, &vLookatVec, &vUpVec );
m_pIDirect3DDevice
->SetTransform( D3DTS_VIEW, &matView );

}



啊,这样设备丢失就处理好了

//
tag:DirectX 3D  d3d lost device TestCooperativeLevel OnLostDevice 恢复设备 设备丢失 DeviceLost

posted @ 2009-10-17 13:10 Bill Hsu 阅读(982) | 评论 (2)编辑 收藏
仅列出标题  下一页