D3D9 简单图形的绘制以及显示
程序截图所示:
要想完成这样的程序,首先咱们先得知道以下几点才能进行绘制并且显示:
一、了解什么是D3D9的绘制流水线:
1.局部坐标系:
主要用于在使用3D建模时,所使用的坐标系,无需考虑它相对于场景中其他物体的位置,大小。通常在创建模型时,建模人员都会将模型围绕原点进行建模,那样将有助于坐标变换,比如让模型旋转起来,在我们将坐标变换时将会进行描述。
2.世界坐标系:
将每个模型的所在的局部坐标组织在一起就变成了世界坐标系。然而位于局部坐标系的物体通过一个称为世界变换的运算才能变换到世界坐标系中,通常包括平移(translation),旋转(rotation),以及比例运算(scaling)。
世界变换用一个矩阵来表示,通过IDirect3DDevice9::SetTransform函数便可加以应用,第一个参数表示要变换的类型。
如:
Device->SetTransform(D3DTS_WORLD,&xx);
3.观察坐标系:
在世界空间中,世界坐标系定义了虚拟的3D空间,物体都被放置到这个空间中,在3D游戏中,世界空间中所有的几何体都随着摄像机一同进行,以保证摄像机的视场恒定。一般称为取景变换(view space transformation)。
取景变换(view space transformation)也是用IDirect3DDevice9::SetTransform函数来进行设定。
Device->SetTransform(D3DTS_VIEW,&XX);
4.背面消隐:
由于场景中的大多数物体都是封闭体,而且摄像机是进入不了物体内部的实体空间的,并且在游戏中,如果该场景在渲染过程中多边形越多,要进行处理的内容就越多,就越消费计算机的处理能力,所以背面消隐就很重要了,只看见它的正面,后背面进行渲染时进行跳过,这将减少大约一半的渲染量,提高了游戏的运行速度。
以2D俯视图为例:
一般通过修改绘制状态(render state)D3DRS_CULLMODE来达到目的。
Device->SetRenderState(D3DRS_CULLMODE,Value);
Value的值可以取:
D3DCULL_NONE 完全禁用背面消隐
D3DCULL_CW 只对顺时针绕序的三角形进行消隐
D3DCULL_CCW 对逆时针绕序的三角形进行消隐
顺时针绕序:Direct3D中认定顶点的排列顺序在“观察坐标系”中的三角形单元是正面朝向的,那就消隐它的背面,反之逆时针绕序一样。
5.光照:
光源是在世界坐标系中定义的,但必须经过取景变换到观察坐标系方可使用。光照可以照亮场景中的物体,从而可以获得比较逼真的显示效果。
目前本程序没使用光照。
6.裁剪:
将位于视域体之外的几何体进行剔除。
7.投影:
将所得到的3D场景,进行2D表示。
投影的方法:
使用D3DX函数,根据视域体中的信息创建一个投影矩阵。
D3DXMATRIX * D3DXMatrixPerspectiveFovLH(D3DXMATRIX & pOut, //最终生成的投影变换矩阵FLOAT fovY, //视域角度,角度越大,映射到投影窗口的图像就越小FLOAT Aspect, //屏幕显示区的纵横比(aspect ratio)=屏幕宽度(screen width)/屏幕高度(screen height)FLOAT zn, //表示视域体中近裁面FLOAT zf //表示视域体中远裁面
);
//例如:D3DXMATRIX proj;D3DXMatrixPerspectiveFovLH(&proj,D3DX_PI/4,Aspect,1.0f,1000.0f);Device->SetTransform(D3DTS_PROJECTION,&proj);
8.视口变换:
将顶点坐标从投影窗口转换到屏幕的程序窗口中。
在Direct3D中,视口用结构D3DVIEWPORT9来表示,定义如下:
typedef struct D3DVIEWPORT9{DWORD X, //所表示窗口相对于父窗口的X坐标DWORD Y, //所表示窗口相对于父窗口的Y坐标DWORD Width, //表示窗口的宽度DWORD Height, //表示窗口的高度DWORD MinZ, //深度缓存的最小值DWORD MaxZ; //深度缓存的最大值
}D3DVIEWPORT9;
如:D3DVIEWPORT9 vp={0,0,640,480,0,1};Device->SetViewport(&vp);
typedef struct D3DVIEWPORT9{DWORD X, //所表示窗口相对于父窗口的X坐标DWORD Y, //所表示窗口相对于父窗口的Y坐标DWORD Width, //表示窗口的宽度DWORD Height, //表示窗口的高度DWORD MinZ, //深度缓存的最小值DWORD MaxZ; //深度缓存的最大值
}D3DVIEWPORT9;
如:D3DVIEWPORT9 vp={0,0,640,480,0,1};Device->SetViewport(&vp);
9.光栅化:
计算所构成图形中每个三角形单元的每个像素的颜色值。
终于告一段落了,休息会。
二、顶点缓存与索引缓存:
简介:
在Direct3D中,顶点缓存与索引缓存(vertex/index buffer)是两个比较相似的接口。顶点缓存是一个包含顶点数据的连续内存空间;索引缓存是一个包含索引数据的连续内存空间。而且存储的位置比较随意,既可以存在内存中,也可以存在显卡的显存中(video memory),存在显存中,可以在绘制时,使用显存中的数据将会比使用系统内存中的数据快得多许多。
1.创建顶点缓存和索引缓存:
顶点缓存的结构体格式:
HRESULT IDirect3DDevice9::CreateVertexBuffer(UINT Length, //缓存分配的字节数DWORD Usage, //关于缓存的附加属性DWORD FVF, //灵活顶点格式D3DPOOL Pool, //缓存的内存池IDirect3DVertexBuffer9 ** ppVertexBuffer, //接收所创建的顶点缓存的指针HANDLE* pSharedHandle //为保留参数,一般设为0或NULL
);//索引缓存的结构体格式HRESULT IDirect3DDevice9::CreateIndexBuffer(UINT Length, DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DIndexBuffer9** ppIndexBuffer,HANDLE * pSharedHandle
);
可以看出两个缓存的结构体格式都是大同小异的
注意:
创建缓存时,设置缓存的附加属性时,如果不需要频繁更新缓存中的内容,就将其设置为动态缓存D3DUSAGE_DYNAMIC,反之就设为静态缓存。
USAGE的相关值:
//调用://创建静态顶点缓存IDirect3DVertexBuffer9 * vb; Device->CreateVertexBuffer(8*sizeof(Vertex), //8个顶点0, //无附加属性D3DFVF_XYZ, D3DPOOL_MANAGED,&vb,0);//创建动态索引缓存IDirect3DIndexBuffer9* ib;Device->CreateIndexBuffer(36* sizeof(WORD), D3DUSAGE_DYNAMIC|D3DUSAGE WRITEONLY, //动态缓存和只写模式D3DFMT_INDEX16, //16位索引大小D3DPOOL_MANAGED,&ib,0);
//调用://创建静态顶点缓存IDirect3DVertexBuffer9 * vb; Device->CreateVertexBuffer(8*sizeof(Vertex), //8个顶点0, //无附加属性D3DFVF_XYZ, D3DPOOL_MANAGED,&vb,0);//创建动态索引缓存IDirect3DIndexBuffer9* ib;Device->CreateIndexBuffer(36* sizeof(WORD), D3DUSAGE_DYNAMIC|D3DUSAGE WRITEONLY, //动态缓存和只写模式D3DFMT_INDEX16, //16位索引大小D3DPOOL_MANAGED,&ib,0);
2.访问缓存内容:
要进行访问缓存内容就要借助Lock与Unlock两个方法进行操作。
注意:
如果在创建缓存的时候将它的属性设置为只写(D3DUSAGE_WRITEONLY)的话,那就无法进行访问我们的缓存内容。
在Direct3D中,顶点缓存与索引缓存的Lock/Unlock(死锁/解锁)函数完全一致。
Lock函数:
HRESULT IDirect3DVertexBuffer9::Lock(UINT OffsetToLock, //缓存的起点位置的偏移量UINT SizeToLock, //所要锁定的字节数BYTE* ppbData, //指向被锁定的存储区起始位置的指针DWORD Flags //描述锁定的方式);
HRESULT IDirect3DVertexBuffer9::Lock(UINT OffsetToLock, //缓存的起点位置的偏移量UINT SizeToLock, //所要锁定的字节数BYTE* ppbData, //指向被锁定的存储区起始位置的指针DWORD Flags //描述锁定的方式);
Flags 表示锁定的方式,可以取以下三种值:
D3DLOCK_DISCARD: 仅用于动态缓存。
D3DLOCK_NOOVERWRITE: 仅用于动态缓存
D3DLOCK_READONLY: 所锁定的缓存只可读而不可写
调用例子:
Vertex* vertices;_vb->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);_vb->Unlock();
Vertex* vertices;_vb->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);_vb->Unlock();
3.获取缓存当中的信息:
通过D3DVERTEXBUFFER_DESC和D3DINDEXBUFFER_DESC结构体创建实例对象,再通过调用GetDesc函数从而获取信息。
如:
D3DVERTEXBUFFER_DESC vbDescription;vertexBuffer->GetDesc(&vbDescription); //获取顶点缓存的信息D3DINDEXBUFFER_DESC ibDescription;inDescription->GetDesc(&ibDescription); //获取索引缓存的信息
D3DVERTEXBUFFER_DESC vbDescription;vertexBuffer->GetDesc(&vbDescription); //获取顶点缓存的信息D3DINDEXBUFFER_DESC ibDescription;inDescription->GetDesc(&ibDescription); //获取索引缓存的信息
4.进行图形的绘制:
首先是IDirect3DDevice9::SetStreamSource方法,将几何体的信息传输到绘制流水线中。
HRESULT IDirect3DDevice9::SetStreamSource(UINT StreamNumber, //用于指定与该顶点缓存建立连接的数据流IDirect3DVertexBuffer9* pStreamData, //包含顶点数据的顶点缓存指针UINT OffsetInBytes, //数据流当中的偏移量UINT Stride //顶点缓存中每个顶点结构的大小
);//调用例子:g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(CUSTOMVERTEX) ); 最后一步利用顶点缓存和索引缓存进行绘制,所调用的函数是IDirect3DDevice9::DrawPrimitive。函数原型为:HRESULT IDirect3Ddevice9::DrawPrimitive(D3DPRMITIVETYPE PrimitiveType, //所需要绘制的图元类型UINT StartVertex, //用于指定从顶点缓存中读取顶点数据的起始索引位置UINT PrimitiveCount //所要绘制的图元数量
);
HRESULT IDirect3DDevice9::SetStreamSource(UINT StreamNumber, //用于指定与该顶点缓存建立连接的数据流IDirect3DVertexBuffer9* pStreamData, //包含顶点数据的顶点缓存指针UINT OffsetInBytes, //数据流当中的偏移量UINT Stride //顶点缓存中每个顶点结构的大小
);//调用例子:g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(CUSTOMVERTEX) ); 最后一步利用顶点缓存和索引缓存进行绘制,所调用的函数是IDirect3DDevice9::DrawPrimitive。函数原型为:HRESULT IDirect3Ddevice9::DrawPrimitive(D3DPRMITIVETYPE PrimitiveType, //所需要绘制的图元类型UINT StartVertex, //用于指定从顶点缓存中读取顶点数据的起始索引位置UINT PrimitiveCount //所要绘制的图元数量
);
调用实例: g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 8 );
终于告一段落了,再休息一会。
哎呦,不错哦。
三、最后一步了,进行颜色的上色。
在Direct3D中,颜色使用RGB三原色来表示,分解为红色(Red),绿色(Green),蓝色(Blue)。RGB数据可以用两种不同的结构来保存,第一种是D3DCOLOR,它实际上与DWORD类型完全相同,共32位,且可分为四个8位项,每项存储一种颜色的分量的亮度值,R,G,B各占8位,剩下8位,一个字节分配给Alpha分量,Alpha分量主要用于后面的融合;第二种结构是D3DCOLORVALUE,该结构中,用单精度浮点数来度量每个颜色分量的亮度值,而亮度值的取值范围为0~1.
D3DCOLORVALUE的函数结构:
Typedef struct D3DCOLORVALUE{float r; //redfloat g; //green;float b; //bluefloat a; //alpha
}D3DCOLORVALUE;
Typedef struct D3DCOLORVALUE{float r; //redfloat g; //green;float b; //bluefloat a; //alpha
}D3DCOLORVALUE;
开始着色:
在光栅化的过程中,有两种着色模式(shading mode):平面着色(flat shading)与Gouraud着色也称为(smooth shading)。
在绘制状态调用函数里面便可进行着色的设置:
如:
//平面着色(flat shading)Device->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_FLAT);//Gouraud着色(smooth shading)Device->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_GOURAUD);
样例:
四边形的简单绘制和上色:点击打开链接
截图所示:
D3D9 简单图形的绘制以及显示相关推荐
- 【OpenGL】计算机图形学实验一:OpenGL基础实验(实验环境的熟悉、简单图形的绘制和输出)
实验一:OpenGL基础实验 (实验环境的熟悉.简单图形的绘制和输出) 1.实验目的和要求 学习基本的OpenGL图形绘制和输出函数,掌握使用基于C++ OpenGL开发图形程序的流程. 2.实验设 ...
- SurfaceView简单理解,Android混淆,Android openGl开发详解简单图形的绘制,
SurfaceView允许你在非ui线程中去绘制. SurfaceView的帧率可以操作60FPS 在要求实时性比较高的游戏开发中,显然,view的ondraw是满足不了你的,这时候只能是用Surfa ...
- python绘制简单图形-python绘制数学图形(堪比matlab)
在开始之前,我要对latex做一点补充. 上一篇文章中提到了latex绘制流程图,文中给出了一个实例,在具体的应用上也很简单.下面两个网页可能会比较有用,特别是在流程图的绘制上(各类shapes汇总) ...
- FxCAD实验一 简单图形的绘制
实验一.绘制一个简单矩形 绘制的图形如下: 第1步: 在解决方案里找到"ToolWindowHost.cs" 双击打开后如图: 添加一个按钮(矩形),ID设置为 btnBox 双击 ...
- Windows编程 GDI简单图形的绘制 简单实现锁帧效果
版本:VS2015 语言:C++ 快要到9月份了,天气渐渐凉了,没有空调的我终于渐渐看到了光明. 现在书的进度进入都最后一章的Windows编程,嘛,和作者的态度差不多,Windows编程实在是枯燥乏 ...
- FLASH鼠绘入门教程,主要让大家熟悉一下简单图形的绘制!
初学者练习,有基础的朋友可以跳过,不过希望刚开始学的想学的朋友配合交份作业.我现在也是只菜鸟,我也是在学习中,想和大家一起学,不知道有没有人愿意和我一起学.不啰嗦了,开始进入主题吧,今天要画的是叶子, ...
- Python之Turtle库绘制简单图形
Python之Turtle库绘制简单图形 来绘制正方形.三角形.五边形.五角形 import turtle #引入turtle库pen=turtle.Turtle() #创建turtle类型的画笔 # ...
- java编程打印以下图形,分享java打印简单图形的实现代码
我们平时都是使用的画图工具进行简单图形的绘制,今天我们使用java打印一些简单的图形 实现代码如下 package test; /** * * @author hanzel * @打印图形 * */ ...
- java打印 好看的图形_分享java打印简单图形的实现代码
我们平时都是使用的画图工具进行简单图形的绘制,今天我们使用java打印一些简单的图形 实现代码如下 package test; /** * * @author hanzel * @打印图形 * */ ...
- OpenCv Java 简单的图形轮廓绘制 (5)
初学Opencv实现一点点的功能都感觉很是吃力,所以不得不写点东西记忆一下,不然明天又忘记了 好记星不如烂笔头 我就想能不能处分出图片中的正方形和圆形,标记出来,我们这边就绘制器图像,下一步就是认识图 ...
最新文章
- 换硬币c语言编程_如何才能成为编程高手?别人都不告诉你的东西,我来说给你听...
- ASP.NET MVC 2示例Tailspin Travel UI层分析
- dbcp、c3p0、proxool、Bonecp等连接池对比
- 理解CSS3中的background-size(对响应性图片等比例缩放)
- 如何在arm平台移植ubuntu系统(转)
- java 调用.net webservice axis2_java利用axis2调用.net写的webservice,传递自定义的实体类参数...
- php函数大全 pdf,php常用函数.pdf
- 证券基金行业IT运维“远景”如何应对?
- 腾讯联手华为!将让腾讯游戏越跑越快
- EDA实验课课程笔记(四)——TCL脚本语言的学习2
- OCTO-RPC集成 Thrift 0.11.0
- matlab-博弈演化
- ansys命令流——坐标系与工作平面(基础操作)
- comsol通直流电_COMSOL 在电力行业中的 10 种实际用途
- cesium 旋转图片
- 服务器怎么设置自动拨号,打造全自动的拨号上网服务器
- html添加悬浮图片,HTML5和jQuery制作网页灰度图片悬浮效果_js
- iOS上架appstore详细教材
- 中国叉车行业发展现状及趋势分析,无人叉车将成为未来发展趋势「图」
- 腾讯笔试04-24 题目二
热门文章
- 自己的联想Y450笔记本无法连接无线网络的解决办法
- 数据挖掘——无量纲化
- Google Code Jam 2010 Qualification Round 资格赛 Problem A. Snapper Chain 问题A.按扣链条
- 【深度学习之美】一入侯门“深”似海,深度学习深几许(入门系列之一)
- 朋友,我真诚的劝你别网贷
- 即时通讯,2022即时通讯IM厂商介绍
- 计算机专业的浪漫情话,计算机学科的告白情话
- 学习java的第十九天,static关键字、隐匿代码块的学习
- 6.2.1.1UE maximum output power - EIRP and TRP——翻译
- python后端工程师学什么_成为后端工程师需要学习什么