一.简介
绘制流水线也称为渲染管线,在DirectX的固定渲染管线中有九个步骤
用来创建3D世界几何描述的2D图像,并且设定一个虚拟摄像机把其中需要的部分透视投影到屏幕上
绘制流水线的流程:局部坐标系->世界坐标系->观察坐标系->背面消隐->光照->投影->裁剪->视口坐标系->光栅化
三维图形的显示和绘制流水线对照可以发现,观察坐标系和光照步骤是可以省略的,而背面消隐也可以省略,它属于优化作用,并不是必须的
二.三大坐标系
1.局部坐标系
局部坐标就是模型本身的坐标
2.世界坐标系
D3DXMATRIX matWorld;
pd3dDevice->GetTransform(D3DTS_WORLD,&matWorld);
3.观察坐标系
观察坐标系就是摄像机的位置
DirectX是左手坐标系,以屏幕为基准,该坐标系X轴指向右,Y轴指向上,Z轴指向屏幕里面
//建立虚拟摄影机,相当于渲染视角
D3DXVECTOR3 position(0.0f,0.0f,-5.0f); //摄像机的位置
D3DXVECTOR3 target(0.0f,0.0f,0.0f); //观察点的位置
D3DXVECTOR3 up(0.0f,1.0f,0.0f); //向上的坐标系
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V,&position,&target,&up); //计算观察矩阵
Device->SetTransform(D3DTS_VIEW,&V); //绑定观察矩阵
三.摄像机采集数据
1.背面消隐
背面消隐就是消除背面朝向相机的多边形,因为一个物体人眼看过去有正面也有背面,把背面剔除可以优化渲染性能
背面拣选状态也分为三种情况
Device->SetRenderState(D3DRS_CULLMODE,DDCULL_NONE); //禁用背面消隐
Device->SetRenderState(D3DRS_CULLMODE,DDCULL_CW); //只对顺时针绕序的三角形消隐
Device->SetRenderState(D3DRS_CULLMODE,DDCULL_CCW); //默认值,只对逆时针绕序的三角形消隐
2.光照
D3D有默认的光照,也可以自定义光照系统,如果没有光照就无法看见物体
3.投影
在3D图形学中有两种基本的投影方式,平行投影(正投影,orthographic projection)和透视投影(perspective projection)
平行投影中,三维物体的坐标沿平行线投影到观察平面上,保持物体的比例不变
透视投影中,基于物体相对于投影平面的距离来确定投影的大小,不保持物体的比例.
DirectX采用透视投影(Perspective Projection),从视锥体投影到平面上
投影就是从3D空间投影到2D笛卡尔坐标来表示
D3DXMATRIX* D3DMatrixPerspectiveFovLH(
D3DXMATRIX* pOut, //获得的投影矩阵
FLOAT fovy, //y轴向上的视角,角度越大视野也越远
FLOAT Aspect, //显示的高宽比
FLOAT zn, //最近的平面
FLOAT zf //最远的平面
);
//获得投影矩阵
D3DXMATRIX porj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI*0.5f, //直角
(float)Width/(float)Height, //宽高比例
1.0f, //前裁面为1
1000.0f); //后裁面为1000
Device->SetTransform(D3DTS_PROJECTION,&proj);
4.裁剪
裁剪就是把相机范围之外的物体去除掉,不进行处理,相机只能看到一个锥形范围内的物体.
可视体由可视角度和前剪裁面(Near Plane)与后剪裁面(Far Plane)决定
裁剪分为三种情况:
完全包含:三角形完全在可视体内
完全在外:三角形完全在可视体外部
部分在内:三角形一部分在可视体内,一部分在可视体外
四.摄像机显示
1.视口坐标系
视口变换就是将投影过后的2D笛卡尔坐标转化为屏幕上的实际坐标,它把剪裁区域映射到窗口区域
视口坐标系是以桌面窗口左上角为原点(0,0),横轴X向右为正,纵轴Y轴向下为正
typedef struct _D3DVIEWPORT9 {
DWORD X;
DWORD Y;
DWORD Width;
DWORD Height;
DWORD MinZ; //最小深度缓冲值
DWORD MaxZ; //最大深度缓冲值
} D3DVIEWPORT9;
D3DVIEWPORT9 vp={0,0,screenWidth,screenHeight,0,1};
Device->SetViewport(&vp);
2.光栅化
光栅化就是将一个多边形光栅化为一个个像素,进行着色处理.
图元(Graphics Output Primitive)是用来描述几何图元,图元是组成图像的基本单元,比如三维模型中的点/线/面等
HRESULT IDirect3DDevice9::SetStreamSource(
UINT StreamNumber,
IDirect3DVertexBuffer9* pStreamData,
UINT OffsetInBytes,
UINT Stride
);
HRESULT IDirect3DDevice9::DrawPrimitive(
D3DPRIMITIVETYPE PrimitiveType, //图元类型
UINT StartVertex, //起始点的索引位置
UINT PrimitiveCount //绘制图元个数
);
//绑定资源流
Device->SetStreamSource(0, vb, 0, sizeof(Vertex));
//设置顶点格式
Device->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
//设置索引缓冲区
Device->SetIndices(ib);
//绘制图元方式
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,8,0,12);
Device->Present(0,0,0,0);
五.完整版
参考代码->DirectX2D/3D--9.0:初始化,代码都不变,添加了一些新代码
1.三角形绘制
IDirect3DVertexBuffer9* Triangle=0;
//struct Vertex{
Vertex(){}
Vertex(float x,float y,float z){
_x=x;_y=y;_z=z;
}
float _x,_y,_z;
static const DWORD FVF;
}
const DWORD Vertex::FVF=D3DFVF_XYZ;
bool Setup(){
//
//Create the vertex buffer
//
Device->CreateVertexBuffer(
3*sizeof(Vertex), //size in bytes
D3DUSAGE_WRITEONLY, //flags
Vertex::FVF, //vertex format
D3DPOOL_MANAGED, //managed memory pool
&Triangle, //return create vertex buffer
0);
//
//Fill the buffers with the triangle data
//
Vertex* vertices;
Triangle->Lock(0,0,(void**)&vertices,0);
vertices[0]=Vertex(-1.0f,0.0f,2.0f);
vertices[1]=Vertex(0.0f,1.0f,2.0f);
vertices[2]=Vertex(1.0f,0.0f,2.0f);
Triangle->Unlock();
//
//Set the projection matrix
//
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI*0.5f,
(float)Width/(float)Height,
1.0f,
1000.0f);
Device->SetTransform(D3DTS_PROJECTION,&proj);
//
//Set wireframe mode render state
//
Device->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
return true;
}
void Cleanup(){
d3d::Release<IDirect3DVertexBuffer9*>(Triangle);
}
bool Display(float timeDelta){
if(Device){
Device->Clear(0,0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0xffffffff,1.0f,0);
Device->BeginScene();
Device->SetStreamSource(0,Triangle,0,sizeof(Vertex));
Device->SetFVF(Vertex::FVF);
//Draw one triangle
Device->DrawPrimitive(D3DPI_TRIANGLELIST,0,1);
Device->EndScene();
Device->Present(0,0,0,0);
}
return true;
}
2.正方形绘制
IDirect3DVertexBuffer9* VB=0;
IDirect3DIndexBuffer9* IB=0;
struct Vertex{
Vertex(){}
Vertex(float x,float y,float z){
_x=x;_y=y;_z=z;
}
float _x,_y,_z;
static const DWORD FVF;
};
const DWORD Vertex::FVF=D3DFVF_XYZ;
bool Setup(){
Device->CreateVertexBuffer(
8*sizeof(Vertex),
D3DUSAGE_WRITEONLY,
Vertex::FVF,
D3DPOOL_MANAGED,
&VB,
0);
Device->CreateIndexBuffer(
36*sizeof(WORD),
D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&IB,
0);
Vertex* vertices;
VB->Lock(0,0,(void**)&vertices,0);
vertices[0]=Vertex(-1.0f,-1.0f,-1.0f);
vertices[1]=Vertex(-1.0f,1.0f,-1.0f);
vertices[2]=Vertex(1.0f,1.0f,-1.0f);
vertices[3]=Vertex(1.0f,-1.0f,-1.0f);
vertices[4]=Vertex(-1.0f,-1.0f,1.0f);
vertices[5]=Vertex(-1.0f,1.0f,1.0f);
vertices[6]=Vertex(1.0f,1.0f,1.0f);
vertices[7]=Vertex(1.0f,-1.0f,1.0f);
VB->Unlock();
WORD* indices=0;
IB->Lock(0,0,(void**)&indices,0);
//front side
indices[0]=0;indices[1]=1;indices[2]=2;
indices[3]=0;indices[4]=2;indices[5]=3;
//back side
indices[6]=4;indices[7]=6;indices[8]=5;
indices[9]=4;indices[10]=7;indices[11]=6;
//left side
indices[12]=4;indices[13]=5;indices[14]=1;
indices[15]=4;indices[16]=1;indices[17]=0;
//right side
indices[18]=3;indices[19]=2;indices[20]=6;
indices[21]=3;indices[22]=6;indices[23]=7;
//top
indices[24]=1;indices[25]=5;indices[26]=6;
indices[27]=1;indices[28]=6;indices[29]=2;
//bottom
indices[30]=4;indices[31]=0;indices[32]=3;
indices[33]=4;indices[34]=3;indices[35]=7;
IB->Unlock();
D3DXVECTOR3 position(0.0f,0.0f,-5.0f);
D3DXVECTOR3 target(0.0f,0.0f,0.0f);
D3DXVECTOR3 up(0.0f,1.0f,0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V,&position,&target,&up);
Device->SetTransform(D3DTS_VIEW,&V);
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI*0.5f,
(float)Width/(float)Height,
1.0f,
1000.0f);
Device->SetTransform(D3DTS_PROJECTION,&proj);
Device->SetRenderState(D3DRS_FILEMODE,D3DFILL_WIREFRAME);
return true;
}
void Cleanup(){
d3d::Release<IDirect3DVertexBuffer9*>(VB);
d3d::Release<IDirect3DIndexBuffer9*>(IB);
}
bool Display(float timeDelta){
if(Device){
D3DXMATRIX Rx,Ry;
D3DXMatrixRotationX(&Rx,3.14f/4.0f);
static float y=0.0f;
D3DXMatrixRotationY(&Ry,y);
y+=timeDelta;
if(y>=6.28f)
y=0.0f;
D3DXMATRIX p=Rx*Ry;
Device->SetTransform(D3DTS_WORLD,&p);
Device->Clear(0,0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0xffffffff,1.0f,0);
Device->BeginScene();
Device->SetStreamSource(0,VB,0,sizeof(Vertex));
Device->SetIndices(IB);
Device->SetFVF(Vertex::FVF);
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,8,0,12);
Device->EndScene();
Device->Present(0,0,0,0);
}
return true;
}
六.简化版