DirectX9:基础篇 第五章 绘制流水线
一.简介
绘制流水线也称为渲染管线,在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; }
六.简化版