--------------------------------------------------------------------------------
author: hjjdebug
date: 2012-07-04
--------------------------------------------------------------------------------
该文档不是一个入门教程。 而是一个描述D3D 底层关键技术的概要文档。
但尽量使得它通俗易懂。 具体的实现细节,你可能需要阅读代码或其它文献。
1. 创建d3d 对象和 获得d3d 设备能力
CComPtr<IDirect3D9> d3d(Direct3DCreate9(D3D_SDK_VERSION));
hr=d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &dc);
2. 创建d3d 设备 (独占模式,窗口模式),适配器模式(长,宽等)设备参数等在m_d3dpp 中
FAIL_RET(m_d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,m_hWnd,vertexProcessing,&m_d3dpp,&m_pD3DDev.p));
3. 设定d3d 状态
//设置剔出模式为不剔出任何面,显示正面和反面
//关闭光照处理, 默认情况下启用光照处理
// 不打开Z buffer缓存
// 不打开模板缓冲
//设置着色模式
//设置填充模式
//设置纹理寻址模式
//设置纹理过滤模式
// 设置纹理混合层
//指定alpha 资源
// 启用alpha 混合模式
4. 创建d3d 画布 (关联3 个对象)
if( SUCCEEDED( D3DXCreateTexture(m_pD3DDev,CANVAS_WIDTH,CANVAS_HEIGHT,1,D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&m_pCanvTexture) ) ) // texture
m_pCanvTexture->GetSurfaceLevel(0,&m_pCanvSurface); //surface
D3DXCreateRenderToSurface(m_pD3DDev,CANVAS_WIDTH,CANVAS_HEIGHT,D3DFMT_A8R8G8B8,TRUE,D3DFMT_D24S8,&m_pCanvRS); //render
核心函数:DrawTexture
HRESULT CD3DCanvas::DrawTexture (int x,int y,SIZE const *pDstSize,IDirect3DTexture9 *pTexture,RECT const *pTexRect,D3DCOLOR color)
HRESULT Dx2DDraw::DrawTexture(RECT const *pDstRect,IDirect3DTexture9 *pTexture, RECT const *pTexRect, D3DCOLOR color, U32 z)
// 计算纹理坐标
drawVertexs.v[0].tu
drawVertexs.v[0].tv
drawVertexs.v[1].tu
drawVertexs.v[1].tv
drawVertexs.v[2].tu
drawVertexs.v[2].tv
drawVertexs.v[3].tu
drawVertexs.v[3].tv
// 画..
FAIL_RET(m_pD3Device->SetTexture( 0,pTexture));
memcpy(&VertArray_[nPrim_*NSPRIM_QUADS],drawVertexs.v, sizeof(CUSTOMVERTEX)*NSPRIM_QUADS);
5. 批量渲染模式
HRESULT Dx2DDraw::CreateVertexAndIndex() // 创建定点缓冲区和索引缓冲区
HRESULT Dx2DDraw::RenderBatch(bool EndScence)
hr=m_pD3Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, nPrim_<<2, 0, nPrim_<<1);
6. Draw Target: 分为设定层次,画模板,画图形操作
case TARGET_GRAPH:
DrawGraph();
break;
case TARGET_TEMPLATE_PUSH:
templateDepth++;
DrawTemplatePush();
break;
case TARGET_TEMPLATE_POP:
templateDepth--;
if(templateDepth < 0)
printf("error template depth!\n");
DrawTemplatePop();
break;
case TARGET_GRAPH_TEMPLATE:
DrawClipGraph();
所有操作仅仅对应 m_pD3Device->SetRenderState(。。。)
例如DrawGraph() 对应
FAIL_RET(m_pD3Device->SetRenderState(D3DRS_ALPHABLENDENABLE, ALPHABLENDVALUE));
FAIL_RET(m_pD3Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA));
FAIL_RET(m_pD3Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA));
FAIL_RET(m_pD3Device->SetRenderState( D3DRS_STENCILENABLE, false));
7. 设备丢失和重建工作...
8. 绘画层的概念(驱动层,非驱动层)及批量绘画概念(beginPaint, endPaint(render),drawCmds)
#define DCTY_INVALID 0
#define DCTY_DCDRAWRESIMAGE 1
//世界坐标变换
#define TRTY_MATRIXWORLD 2
// 绘画目标
#define DCTY_DRAWTARGET 3
#define DCTY_DCSETDRAWCOLOR 4
#define DCTY_DCSETBKGNDCOLOR 5
#define DCTY_DCDRAWTEXT 6
DCTY_DCDRAWRESIMAGE 对应以下子类型
union{
DCDrawImage dcDrawImage;
DCDrawText dcDrawText;
DCSetDrawColor dcDrawColor;
DCSetBkGndColor dcBkGndColor;
DCDrawTarget dcDrawTarget;
};
9. 结果集提交
FAIL_RET(RenderLayerDrawCmds(target)); // --> 画布(surface)
FAIL_RET(RenderCanvas()); // 到 backbuffer
FAIL_RET(Present()); // backbuffer -> 屏幕
10. 3D 矩阵
SetupViewMatrix(); //眼睛, 观察点(原点),上法线, 必须要恰当设置,否则图像或大,或小,或看不见
SetupProjMatrix(); // 投射矩阵,三维向二维的转换。符合远小近大的视觉效果。(45度或90度)
视口概念: 视口也是一个矩阵,他是把屏幕大小映射到(-1,1)的一个矩阵变换。
10.1 两个简单接口。 给定平面上两点, 计算夹角及缩放比例
// 返回旋转参数, 角度的正负值已包含
void GetRotateAngle2(Point2D u1, Point2D u2, Point2D v1, Point2D v2, float &angle)
// 返回缩放系数
void GetScaleEfficient(Point2D u1, Point2D u2, Point2D v1, Point2D v2, float &scale)
10.2: 折扇动画的底层支持
bool Dx3DDraw::GetMatrixWolrd_FromPoint(TransPoints &transPs, D3DXMATRIX &matWorld)
注意:缩放是相对于屏幕中心点进行的,如果不是已以屏幕中心点为中心的矩形,三角形,线段,需要将中心点移回(底层考虑)。
//折扇动画需要调用: (2维平面)
// 输入: 起点矢量,终点矢量,
// 输出: matrix
// input transPs.u1, transPs.u2; transPs.v1, transPs.v2;
// output transPs.retP matWorld;
// 注:当一条与坐标轴平行的线仅做缩放时,将不能判断线在那个平面内 ?
// 简单说, 三点决定一个平面,而两点不能决定一个平面,此时默认是 Y轴,Z轴,X轴
核心运算:
1. 转换屏幕坐标到d3d 坐标
2. 获取缩放系数,
3. 获取旋转系数
4. 找到偏移
4. 加入世界变换,
6. 得到最终变换矩阵
over! thanks!
author: hjjdebug
date: 2012-07-04
--------------------------------------------------------------------------------
该文档不是一个入门教程。 而是一个描述D3D 底层关键技术的概要文档。
但尽量使得它通俗易懂。 具体的实现细节,你可能需要阅读代码或其它文献。
1. 创建d3d 对象和 获得d3d 设备能力
CComPtr<IDirect3D9> d3d(Direct3DCreate9(D3D_SDK_VERSION));
hr=d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &dc);
2. 创建d3d 设备 (独占模式,窗口模式),适配器模式(长,宽等)设备参数等在m_d3dpp 中
FAIL_RET(m_d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,m_hWnd,vertexProcessing,&m_d3dpp,&m_pD3DDev.p));
3. 设定d3d 状态
//设置剔出模式为不剔出任何面,显示正面和反面
//关闭光照处理, 默认情况下启用光照处理
// 不打开Z buffer缓存
// 不打开模板缓冲
//设置着色模式
//设置填充模式
//设置纹理寻址模式
//设置纹理过滤模式
// 设置纹理混合层
//指定alpha 资源
// 启用alpha 混合模式
4. 创建d3d 画布 (关联3 个对象)
if( SUCCEEDED( D3DXCreateTexture(m_pD3DDev,CANVAS_WIDTH,CANVAS_HEIGHT,1,D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&m_pCanvTexture) ) ) // texture
m_pCanvTexture->GetSurfaceLevel(0,&m_pCanvSurface); //surface
D3DXCreateRenderToSurface(m_pD3DDev,CANVAS_WIDTH,CANVAS_HEIGHT,D3DFMT_A8R8G8B8,TRUE,D3DFMT_D24S8,&m_pCanvRS); //render
核心函数:DrawTexture
HRESULT CD3DCanvas::DrawTexture (int x,int y,SIZE const *pDstSize,IDirect3DTexture9 *pTexture,RECT const *pTexRect,D3DCOLOR color)
HRESULT Dx2DDraw::DrawTexture(RECT const *pDstRect,IDirect3DTexture9 *pTexture, RECT const *pTexRect, D3DCOLOR color, U32 z)
// 计算纹理坐标
drawVertexs.v[0].tu
drawVertexs.v[0].tv
drawVertexs.v[1].tu
drawVertexs.v[1].tv
drawVertexs.v[2].tu
drawVertexs.v[2].tv
drawVertexs.v[3].tu
drawVertexs.v[3].tv
// 画..
FAIL_RET(m_pD3Device->SetTexture( 0,pTexture));
memcpy(&VertArray_[nPrim_*NSPRIM_QUADS],drawVertexs.v, sizeof(CUSTOMVERTEX)*NSPRIM_QUADS);
5. 批量渲染模式
HRESULT Dx2DDraw::CreateVertexAndIndex() // 创建定点缓冲区和索引缓冲区
HRESULT Dx2DDraw::RenderBatch(bool EndScence)
hr=m_pD3Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, nPrim_<<2, 0, nPrim_<<1);
6. Draw Target: 分为设定层次,画模板,画图形操作
case TARGET_GRAPH:
DrawGraph();
break;
case TARGET_TEMPLATE_PUSH:
templateDepth++;
DrawTemplatePush();
break;
case TARGET_TEMPLATE_POP:
templateDepth--;
if(templateDepth < 0)
printf("error template depth!\n");
DrawTemplatePop();
break;
case TARGET_GRAPH_TEMPLATE:
DrawClipGraph();
所有操作仅仅对应 m_pD3Device->SetRenderState(。。。)
例如DrawGraph() 对应
FAIL_RET(m_pD3Device->SetRenderState(D3DRS_ALPHABLENDENABLE, ALPHABLENDVALUE));
FAIL_RET(m_pD3Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA));
FAIL_RET(m_pD3Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA));
FAIL_RET(m_pD3Device->SetRenderState( D3DRS_STENCILENABLE, false));
7. 设备丢失和重建工作...
8. 绘画层的概念(驱动层,非驱动层)及批量绘画概念(beginPaint, endPaint(render),drawCmds)
#define DCTY_INVALID 0
#define DCTY_DCDRAWRESIMAGE 1
//世界坐标变换
#define TRTY_MATRIXWORLD 2
// 绘画目标
#define DCTY_DRAWTARGET 3
#define DCTY_DCSETDRAWCOLOR 4
#define DCTY_DCSETBKGNDCOLOR 5
#define DCTY_DCDRAWTEXT 6
DCTY_DCDRAWRESIMAGE 对应以下子类型
union{
DCDrawImage dcDrawImage;
DCDrawText dcDrawText;
DCSetDrawColor dcDrawColor;
DCSetBkGndColor dcBkGndColor;
DCDrawTarget dcDrawTarget;
};
9. 结果集提交
FAIL_RET(RenderLayerDrawCmds(target)); // --> 画布(surface)
FAIL_RET(RenderCanvas()); // 到 backbuffer
FAIL_RET(Present()); // backbuffer -> 屏幕
10. 3D 矩阵
SetupViewMatrix(); //眼睛, 观察点(原点),上法线, 必须要恰当设置,否则图像或大,或小,或看不见
SetupProjMatrix(); // 投射矩阵,三维向二维的转换。符合远小近大的视觉效果。(45度或90度)
视口概念: 视口也是一个矩阵,他是把屏幕大小映射到(-1,1)的一个矩阵变换。
10.1 两个简单接口。 给定平面上两点, 计算夹角及缩放比例
// 返回旋转参数, 角度的正负值已包含
void GetRotateAngle2(Point2D u1, Point2D u2, Point2D v1, Point2D v2, float &angle)
// 返回缩放系数
void GetScaleEfficient(Point2D u1, Point2D u2, Point2D v1, Point2D v2, float &scale)
10.2: 折扇动画的底层支持
bool Dx3DDraw::GetMatrixWolrd_FromPoint(TransPoints &transPs, D3DXMATRIX &matWorld)
注意:缩放是相对于屏幕中心点进行的,如果不是已以屏幕中心点为中心的矩形,三角形,线段,需要将中心点移回(底层考虑)。
//折扇动画需要调用: (2维平面)
// 输入: 起点矢量,终点矢量,
// 输出: matrix
// input transPs.u1, transPs.u2; transPs.v1, transPs.v2;
// output transPs.retP matWorld;
// 注:当一条与坐标轴平行的线仅做缩放时,将不能判断线在那个平面内 ?
// 简单说, 三点决定一个平面,而两点不能决定一个平面,此时默认是 Y轴,Z轴,X轴
核心运算:
1. 转换屏幕坐标到d3d 坐标
2. 获取缩放系数,
3. 获取旋转系数
4. 找到偏移
4. 加入世界变换,
6. 得到最终变换矩阵
over! thanks!