DirectX3D开发之绘制流水线(一)

欢迎来到EasyLiu的博客 !

参考:directxtutorial.com   DirectX.9.0.3D游戏开发编程基础

In the last lesson you built a simple, flat triangle lit with simple diffuse lighting. This triangle was not 3D, it was flat. If you managed to change it, you found it was a 2D triangle drawn
in screen coordinates. The triangle you made was pre-transformed, meaning you took no action to convert it from 3D coordinates to screen coordinates, but just gave Direct3D the screen coordinates.

翻译:在上一节课中我们建立了一个简单的,具有简单漫反射光的平面三角形。这个三角形不是3D的,它是平面的。如果你想改变它,你会发现它是一个平面坐标下的二维三角形。你画的这个三角形是预先经过转换的,意思是你并没有采取任何措施而将它从三维坐标变换成了屏幕坐标,而是直接把三角形的屏幕坐标给了Direct3D进行绘制。

In this lesson, you will learn to transform vertices, or convert them from 3D coordinates to screen coordinates. You will also learn to position the 3D camera, set the 3D "lens", and put your triangle
into a 3D world with other 3D objects in it.

翻译:在这节课,我们将学习顶点的转换或者三维坐标到屏幕坐标的转换。我们也将学习放置3D摄像头,设置3D“透镜”,并且把你的三角形放入具有其它三维物体的世界中。

绘制流水线

一个简单的绘制流水线如下图所示:需要经过坐标变换、背面消隐、光照、裁剪、投影、视口坐标系、光栅化等过程,这里主要讲一下局部坐标系到世界坐标系的转换(世界变换)、世界坐标系到观察坐标系的转换(取景变换)、投影(投影变换)。

The Geometry Pipeline(几何管道)

Before we get into the actual transformation code, let‘s take a look at everything that happens to translate something from 3D coordinates to a flat image. There
is a sequence of actions which must occur before an object appears on the screen properly. This sequence of actions is known as theGeometry Pipeline. It is called a pipeline because vertices are put through each step one at a time, and at
each step along the "pipe", the vertex is rendered into its flat image form.

When a model first starts out, it is generally centered on the origin, meaning the center of the object is at (0, 0, 0). This also means that all the objects in your game will be in the exact center
of the world, all piled up on top of each other, which doesn‘t make a very excellent game. The first step is to sort out the new positions of all the models in relation to each other.This is called World Transformation.

Once all the objects in the world have been sorted out and the vertices‘ positions have been altered to represent world coordinates, then we have to change the entire coordinate system to create
a virtual camera. What this means is that we have to change the direction of each axis, in order to position everything in the most efficient way for the video card. This process is known as View Transformation.

After the coordinate system has been rearanged, then it is time to convert all the 3D models into 2D images. In this step, the 3D coordinates are converted into screen coordinates. This process is
known as Projection Transformation.

上面介绍了世界转换、视图转换(取景变换)以及投影变换的概念以及为什么要进行这些变换,下图代表了变换的过程:

World Transformation(世界变换概述)

   World
Transformation, in essence, changes coordinates from model space to world space. In other words, it places a model in a world at an exact point defined by coordinates. Following is an overhead demonstration of how this works:

This
is known as translation. Translation refers to the movement of a vertex along a coordinate system axis. For example, the above diagram shows movement of a tree along the x and y axes. Of course, we could also translate the tree along the z-axis, but our ground
here is flat, and having trees floating ten feet high just outside the local village tends to scare the tourists away (not to mention the players).

Of course, being able to move an object into world space is always useful, but it can get rather limiting if your model is always facing the same direction. A spaceship that can only face East is rather dull and does not elicit much thrill or adrenaline (or
so I find).

And so another part of World Transformation is rotation(世界变换的另一部分是旋转). Rotation is the process of spinning 3D objects along an axis. Like translation, it can be done along multiple axes simultaneously, allowing you to position
your model as desired.

Another important part of World Transformation is scaling(世界变换中另外一个重要的变换是缩放). Scaling is the action of making a 3D object larger or smaller. When an object is scaled, each vertex in the object is multiplied by a given number. These numbers can be different
for each axis, resulting in various stretching effects.

位于局部坐标系中的物体通过世界变换的运算变换到世界坐标系中,该变换通常包括平移、旋转以及比例运算。世界变换通过一个矩阵来表示,并由Direct3D通过SetTransform(D3DTS_WORLD, &matWorld)方法来加以应用,第二个参数表示所采用的世界变换矩阵。例如,我们想要一个立方体的中心位于世界坐标系中的的点(-3,2,6),让一个球体的中心位于点(5,0,-2),可以这样实现:

        D3DXMATRIXA16 cubeWorldMatrix;
	D3DXMatrixTranslation(&cubeWorldMatrix, -3.0f, 2.0f, 6.0f);

	D3DXMATRIXA16 sphereWorldMatrix;
	D3DXMatrixTranslation(&sphereWorldMatrix, 5.0f, 0.0f, -2.0f);

	g_pd3dDevice->SetTransform(D3DTS_WORLD, &cubeWorldMatrix);
	//绘制立方体
	g_pd3dDevice->SetTransform(D3DTS_WORLD, &sphereWorldMatrix);
	//绘制球体

View Transformation(取景变换)

在世界坐标中,几何体和摄像机是相对世界坐标系定义的。但是当摄像机的位置和朝向任意时,投影变换以及其他类型的变换就略显困难或者效率不高。为了简化运算,我们将摄像机变换至世界坐标系的原点,并将其旋转,使得摄像头的光轴与世界坐标系的Z轴正方向一致。同时,世界坐标系中的所有几何体随着摄像头一同进行变换,保证摄像头的视场恒定,变换称为取景变换,我们称变换后的几何体位于观察坐标系中,如下图所示:

Project Transformation(投影变换)

投影变换定义了视域体,并负责将视域体中的几何体投影到投影窗口中。投影矩阵比较复杂,可以使用如下函数:

// Build a perspective projection matrix. (right-handed)

D3DXMATRIX* WINAPI D3DXMatrixPerspectiveFovRH( D3DXMATRIX *pOut, FLOAT fovy, FLOAT Aspect, FLOAT zn, FLOAT zf );

其中pOut代表投影之后的矩阵,Aspect代表横纵比(投影窗口中的几何体最终会变换到屏幕显示区,从方形(投影窗口)到矩形的显示屏的的变换会导致拉伸畸变,所谓纵横比就是显示屏纵横两维尺寸的比率,长用于校正由正方形到矩形的映射而引发的畸变,纵横比=屏幕宽度/屏幕高度),其余的三个参数的含义如下图所示:fovy代表观察范围夹角,zn代表投影中心距离近平面的距离,zf代表投影中心距离远平面的距离。

下面实现一个效果:使一个三角形绕Y轴一直旋转。主要函数是自定义的一个函数SetupMatrices,用于设定世界、观察、投影变换矩阵,代码如下所示:

VOID SetupMatrices()
{
	// For our world matrix, we will just rotate the object about the y-axis.
	D3DXMATRIXA16 matWorld;

	// Set up the rotation matrix to generate 1 full rotation (2*PI radians)
	// every 1000 ms. To avoid the loss of precision inherent in very high
	// floating point numbers, the system time is modulated by the rotation
	// period before conversion to a radian angle.
	UINT iTime = timeGetTime() % 1000;//获取当前时间
	FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f;//1000ms旋转360度
	D3DXMatrixRotationY(&matWorld, fAngle);//旋转矩阵
	g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);//设置世界变换

	// Set up our view matrix. A view matrix can be defined given an eye point,
	// a point to lookat, and a direction for which way is up. Here, we set the
	// eye five units back along the z-axis and up three units, look at the
	// origin, and define "up" to be in the y-direction.
	D3DXVECTOR3 vEyePt(0.0f, 3.0f, -5.0f);//观察点,摄像头的位置
	D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);//朝原点看,代表摄像头朝向
	D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);//垂直方向为y轴
	D3DXMATRIXA16 matView;
	D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
	g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);

	// For the projection matrix, we set up a perspective transform (which
	// transforms geometry from 3D view space to 2D viewport space, with
	// a perspective divide making objects smaller in the distance). To build
	// a perpsective transform, we need the field of view (1/4 pi is common),
	// the aspect ratio, and the near and far clipping planes (which define at
	// what distances geometry should be no longer be rendered).
	D3DXMATRIXA16 matProj;
	D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f);
	g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}

同时在初始化里面关闭背面消隐以及关闭光照:

// Turn off culling, so we see the front and back of the triangle
	g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

	// Turn off D3D lighting, since we are providing our own vertex colors
	g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);</span>

最后,Render()函数:

VOID Render()
{
	// Clear the backbuffer to a black color
	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

	// Begin the scene
	if (SUCCEEDED(g_pd3dDevice->BeginScene()))
	{
		// Setup the world, view, and projection matrices
		SetupMatrices();

		// Render the vertex buffer contents
		g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
		g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
		g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 1);

		// End the scene
		g_pd3dDevice->EndScene();
	}

	// Present the backbuffer contents to the display
	g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}

效果如下:由于是动态的,从图片看不出什么效果。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-09-30 19:45:31

DirectX3D开发之绘制流水线(一)的相关文章

DirectX3D开发之绘制第一个图形

欢迎访问EasyLiu的博客! 在前一章节我们已经创建了我们的第一个DirectX3D项目,但是只是显示一个灰色的窗口而已,并没有进行相应的 绘图操作.那么今天,我们就来让窗口变得更漂亮一些. 今天主要讲通过顶点缓冲区绘制图形.什么是顶点缓冲区?顶点缓冲区就是用来保存顶点数据的内存缓冲区,在DirectX3D中由COM接口IDirectVertexBuffer9表示,顶点缓冲区中顶点的数据就决定了渲染到屏幕上的效果. LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; /

HTML5 2D平台游戏开发——地图绘制篇

此前已经完成了一部分角色的动作,现在还缺少可以交互的地图让游戏看起来能玩.不过在开始之前应当考虑清楚使用什么类型的地图,就2D平台游戏来说,一般有两种类型的地图,Tile-based和Art-based,即基于瓦片风格和美术风格两种.Tile-based的典型代表是<Super Mario>(超级马里奥),Art-based记不太清楚了,能够回想起来的是去年出的一款叫做<Owlboy>(猫头鹰男孩)的游戏.      Super Mario  Owlboy 由于Art-based的

IOS开发中绘制地图线路

地图应用经常会涉及到线路的绘制问题,ios下可以使用MKMapView进行地图开发,使用 MKOverlayView进行线路的绘制. 使用MKMapView添加MKMap.framework 和CoreLocation.framework并导入 MapKit.h头文件. 新建一个基于视图的工程,修改头文件: 1 #import <UIKit/UIKit.h> 2 #import <MapKit/MapKit.h> 3 #import "CloMKAnnotation.h&

DirectX3D开发之开发第一个DirectX3D项目

欢迎访问EasyLiu的博客!此博客为博主原创,未经允许不得转载! 开发环境:WIN764+VS2013+DirectX SDK(June 2010) 首先提供DirectX3D软件包下载地址:http://pan.baidu.com/s/16WItw. 下载下来之后直接双击安装就行,默认安装目录为:C:\Program Files (x86)\Microsoft DirectX SDK (June 2010). 下面就开始我们的第一个DirectX3D项目. 1.新建一个空的win32应用程序

IOS开发 图形绘制,绘制线条,矩形,和垂直和居中绘制文字

概述 吐槽下IOS下 的图形绘图,代码冗长,不得不自己重新封装方法.整理形成本文. 绘制线 // 绘制直线 + (void)toDrawLineFromX:(CGFloat)x1 Y:(CGFloat)y1 toX:(CGFloat)x2 toY:(CGFloat)y2 context:(CGContextRef)con{ CGContextMoveToPoint(con, x1, y1); CGContextAddLineToPoint(con, x2, y2); CGContextSetLi

iOS 开发 - 绘制辉光效果

如何使曲线有辉光(荧光?)效果(glow)? 试了各种方法,最终有一点效果,觉得值得记录一下,如下. 1.最开始,我想是不是用shadow可以实现,事实证明,shadow 太淡,不醒目,如果多次shadow叠加,可加重一点,但性能不好,放弃: 2.然后想是不是可以用图片沿着path绘制,结果效果也不理想(也许是图片做的不好),性能也不好 3.Spritekit 中 skshapenode 可以设置辉光,而且可以设置用texture绘制,貌似可以解决问题,但是当线段之间夹角太小时,结合部位的辉光可

iOS开发 - Quartz2D绘制小黄人

Quartz2D绘制小黄人 - (void)drawRect:(CGRect)rect { // 1.上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.身体 drawBody(ctx, rect); // 3.嘴(微笑) drawMouth(ctx, rect); // 4.画眼睛 drawEyes(ctx, rect); } /** * 眼睛 */ void drawEyes(CGContextRef ctx, CGRect

OC开发_Storyboard——绘制和视图

1.绘制 不要调用drawRect.调用setNeedsDisplay相当于告知系统视图需要重绘, 它会去调用drawRect,更新屏外缓冲器 2.UIBezierPath绘制图形,   设置图像opaque属性=no,根据透明度一层层合成视图,比直接修改比特值的开销会大很大多,消耗性能   如果只是显示的问题可以通过设置hidden 3.UIGestureRecognizer setNeedDisplay是为了让有人修改时重绘 ,据目标大小,选择合适尺寸 现在利用绘制做一个小demo,效果如下

iOS开发-Quartz2D绘制时定时器选择

NSTimer定时器 [NSTimer scheduledTimerWithTimeInterval:0.025 target:self selector:@selector(update) userInfo:nil repeats:YES]; //如果我们使用NSTimer定时器. 设置的执?行时间为0.025秒, 假如屏幕刷新时间为0.035.中间就会等待0.010//绘制图形的时候不建议使用该方法 CADisplayLink定时器 补充知识: drawRect方法是在view将要显示,已经