DirectX9:基础篇 第五章 绘制流水线
一.简介
绘制流水线也称为渲染管线,在DirectX的固定渲染管线中有九个步骤
用来创建3D世界几何描述的2D图像,并且设定一个虚拟摄像机把其中需要的部分透视投影到屏幕上
绘制流水线的流程:局部坐标系->世界坐标系->观察坐标系->背面消隐->光照->投影->裁剪->视口坐标系->光栅化
三维图形的显示和绘制流水线对照可以发现,观察坐标系和光照步骤是可以省略的,而背面消隐也可以省略,它属于优化作用,并不是必须的
二.三大坐标系
1.局部坐标系
局部坐标就是模型本身的坐标
2.世界坐标系
D3DXMATRIX matWorld;
pd3dDevice->GetTransform(D3DTS_WORLD,&matWorld);
3.观察坐标系
观察坐标系就是摄像机的位置
DirectX是左手坐标系,以屏幕为基准,该坐标系X轴指向右,Y轴指向上,Z轴指向屏幕里面
1 2 3 4 5 6 7 8 9 10 | //建立虚拟摄影机,相当于渲染视角 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.背面消隐
背面消隐就是消除背面朝向相机的多边形,因为一个物体人眼看过去有正面也有背面,把背面剔除可以优化渲染性能
背面拣选状态也分为三种情况
1 2 3 | 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 //最远的平面
);
1 2 3 4 5 6 7 8 9 10 11 | //获得投影矩阵 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;
1 2 | 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 //绘制图元个数
);
1 2 3 4 5 6 7 8 9 10 11 12 13 | //绑定资源流 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.三角形绘制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | 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.正方形绘制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | 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 ; } |
六.简化版
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)