译pixelpoint
在DirectX 8 中进行2D渲染
Background
背景
I have been reading alot of questions lately related to DirectX 8 and the exclusion of DirectDraw from the new API. Many people have fallen back to DX7. I can understand people using DX7 if they have alot of experience with that API, but many of the questions seem to be coming from people who are just learning DX, and they are stuck learning an old API. People have argued that many people don't have 3D hardware, and therefore D3D would be a bad alternative for DirectDraw. I don't believe this is true - 2D rendering in D3D requires very little vertex manipulation, and everything else boils down to fillrate. In short, 2D rendering in D3D on 2D hardware should have pretty much the same performance as DirectDraw, assuming decent fillrate. The advantage is that the programmer can learn the newest API, and performance on newer hardware should be very good. This article will present a framework for 2D re
ndering in DX8 to ease the transition from DirectDraw to Direct3D. In each section, you may see things that you don't like ("I'm a 2D programmer, I don't care about vertices!"). Rest assured, if you implement this simple framework once, you'll never think about these things again.
最近,我看到很多关于DirectX8在最新的API中摒弃DirectDraw的问题。很多人回到了以前的DX7.1中。我可以理解那些在DX7.1中有很多开发经验的人为什么
这样做,但是有很多问题却是来自于那些刚学DX,还没有学过以前的API的初学者。人们争辩说很多人没有3D硬件,因此D3D对于DirectDraw是个错误的选择。我不相信那是真的,在D3D中进行2D渲染只需要做一点顶点操作,而其他的事
情都可以被精简来提高填充率。简言之,在D3D中使用2D硬件进行2D渲染,可以做到和DirectDraw一样好的性能,有很好的填充率。而优点是,程序员可以学习最新的API,并且在更新的硬件中获得更好的性能。这篇文章将给出一个在DX8中进行2D渲染的框架,以便于从DirectDraw到Direct3D的转变。在每一节里,你会看到一些你不喜欢的东西(“我是一个2D程序员,我不用关心顶点!”)。但是,请放心,只要你将这个简单的框架实现一次,你就再也不会考虑那些了。
Getting Started
开始
Assuming you have the DX8 SDK, there are a couple tutorials that present how to create a D3D device and set up a render loop, so I don't want to spend alot of
time on that. For the purposes of this article, I'll talk about the tutorial found in [DX8SDK]samplesMultimediaDirect3DTutorialsTut01_CreateDevice, although you can add it to anything. To that sample, I'll add the following functions:
假设你已经有DX8 SDK,那儿有一组指南讲述了如何创建一个D3D设备,如何放置渲染循环,因此我不想再在这上面花费时间。按照这篇文章的意图,我将谈论位于[DX8SDK]samplesMultimediaDirect3DTutorialsTut01_CreateDevice目录里的指南,你可能将它放到了任何地方。在那个例子中,我将加入以下函数:
void PostInitialize(float WindowWidth, float WindowHeight)
- this function is called by the app after everything else is set up. You've created your device and initialized everything. If you're following along with the Tutorial code, WinMain looks like this:
- 其他所有事情都设置完之后,这个函数被app调用,你已经创建了你的设备并且所有东西都已经初始化了。如果你跟着往下看指南里的代码,你会看到WinMain 是这样的:
.
..
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
PostInitialize(200.0f, 200.0f); // This is my added line. The values of
// 200.0f were chosen based on the sizes
// used in the call to CreateWindow.
ShowWindow( hWnd, SW_SHOWDEFAULT );
...
void Render2D()
- This function is called each time you want to render your scene. Again, the Render function of the Tutorial now looks like this:
- 这个函数当你渲染你的场景时会被调用,指南里的Render函数现在看起来是这样的:
VOID Render()
{
if( NULL == g_pd3dDevice )
return;
// Clear the backbuffer to a blue color
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
// Begin the scene
g_pd3dDevice->BeginScene();
Render2D(); //My
// End the scene
g_pd3dDevice->EndScene();
// Present the backbuffer contents to the display
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
OK, that's our shell of an application. Now for the
好了,这就是我们的程序外壳,现在来准备好的内容填充它吧...
Setting Up for 2D drawing in D3D
为在D3D中进行2D绘制进行设置
NOTE: This is where we start talking about some of the nasty math involved with D3D. Don't be alarmed - if you want to, you can choose to ignore most of the details?/I> Most Direct3D drawing is controlled by three matrices: the projection matrix, the world matrix, and the view matrix. The first one we'll talk about is the projection matrix. You can think of the projection matrix as defining the properties
of the lens of your camera. In 3D applications, it defines things like perspective, etc. But, we don't want perspective - we are talking about 2D!! So, we can talk about orthogonal projections. To make a long story very short, this allows us to draw in 2D without all the added properties of 3D drawing. To create an orthogonal matrix, we need to call D3DXMatrixOrthoLH and this will create a matrix for us. The other matrices (view and world) define the position of the camera and the position of the world (or an object in the world). For our 2D drawing, we don't need to move the camera, and we don't want to move the world for now, so we'll use an identity matrix, which basically sets the camera and world in a default position. We can create identity matrices with
D3DXMatrixIdentity. To use the D3DX functions, we need to add:
注意:从这儿开始我们就要谈论一些和D3D相关的令人讨厌的数学知识了。不要被吓倒了---如果你愿意,你可以选择乎略大多数细节。大多数Direct3D绘制都受三个矩阵控制:投影矩阵,世界矩阵,观察矩阵。我们将谈论的第一个矩阵是投影矩阵。你可以认为投影矩阵定义了你的摄像机的镜头属性。在3D应用里,它定义了象透视方法,等等的东西。但是我们用不着透视---我们正在谈论2D!!所以我们只谈论正交投影。简短得说,就是让我们进行2D绘制而不用考虑那些附加在
3D绘制中的属性。为了创建一个正交投影矩阵,我们需要调用D3DXMatrixOrthoLH 函数,它将为我们
创建一个矩阵。其他的矩阵(观察矩阵和世界矩阵)定义了摄像机的位置和世界(或一个在世界里的对象)的位置。为了我们的2D绘制,我们不需要移动摄像机,也不用想移动世界,所以我们将使用一个单位矩阵,将摄像机和世界放置在缺省的位置。我们可以用D3DXMatrixIdentity函数来创建单位矩阵。我们需要加入下面的头文件,以使用D3DX函数。
#include <d3dx8.h>
and add d3dx8dt.lib to the list of linked libraries. Once that was set up, the PostInitialize function now looks like this:
并且加入d3dx8dt.lib到连接库列表里。当那些设置了之后,PostInitialize函数现在是这样子的:
float upvoid PostInitialize(float WindowWidth, float WindowHeight)
{
D3DXMATRIX Ortho2D;
D3DXMATRIX Identity;
D3DXMatrixOrthoLH(&Ortho2D, WindowWidth, WindowHeight, 0.0f, 1.0f); D3DXMatrixIdentity(&Identity);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &Identity);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &Identity);
}
We are now set up for 2D drawing, now we need something to draw. The way things are set up, our drawing area goes from -WindowWidth/2 to WindowWidth/2 and -WindowHeight/2 to WindowHeight/2. One thing to note, in this code, the width and the height are being specified in pixels. This allows us to think about everything in terms of pixels, but we could have set the width and height to say 1.0 and that would have allowed us to specify sizes, etc. in terms of percentages of the screen space, which would be nice for supporting multiple resolutions easily. Changing the matrix allows for all sorts of neat things, but for simplicity, we'll talk about pixels for now?
我们现在正在为2D绘制进行设置,我们需要绘制些东西。这样设置了之后,我们的绘制区域就是从-Win
dowWidth/2 到WindowWidth/2和从-WindowHeight/2 到WindowHeight/2。要注意的一件事是,在代码里,宽度和高度都是用象素为单位指定的。这允许我们用象素来考虑所有的事情,但我们也能设置宽度和高度为1.0,然后允许我们用屏幕空间的百分比来指定大小,这样就很容易的支持了多分辨率的情况。改变矩阵就能够支持各种各样的巧妙的事情,但为了简单起见,我们现在将谈论象素。
Setting Up a 2D "Panel"
设置一个2D“面板”
When I draw in 2D, I have a class called CDX8Panel that encapsulates everything I need to draw a 2D rectangle. For simplicity, and it avoid a C++ explanation, I have pulled out the code here. However, as we build up our code to draw a panel,
you'll probably see the value of such a class or higher level API if you don't use C++. Also, we are about to recreate much that goes on in the ID3DXSprite interface. I'm explaining the basics here to show the way things work, but you may want to use the sprite interface if it suits your needs.
当我进行2D绘制时,我有一个叫CDX8Panel的类,它装封了所有我绘制2D矩形所需要的东西。简单起见,它消除了C++说明,我已经将代码拿了出来了。无论如何,当我们建造我们的一个绘制面板的代码
时,你将可能看到一个类的价值,或者如果你不使用C++时一个更高层的API的价值。同样,依靠ID3DXSprite接口,我们也可得以更加悠闲。我将在这儿解释最基本的东西,以展显事情工作的方法,但是如果Sprite接口适合你的需要,你也可以使用它。
My definition of a panel is simply a 2D textured rectangle that we are going to draw on the screen. Drawing a panel will be extremely similar to a 2D blit. Experienced 2D programmers may think that this is a lot of work for a blit, but that work pays off with the amount of special effects that it enables. First, we have to think about the geometry of our rectangle. This involves thinking about vertices. If you have 3D hardware, the hardware will process these vertices extremely quickly. If you have 2D hardware, we are talking about so few vertices that they will be processed very quickly by the CPU. First, let's define our vertex format. Place the following code near the #includes:
我的面板定义是一个简单的2D纹理矩形,我们将会把它绘制到屏幕上。绘制一个面板非常类似于2D的blit操作。有经验的2D程序员可能会想一个blit操作会有大量的工作,但是这些工作完成了很多允许的特效。首先,我们不得不考虑我们的矩形的几何结构。这样就包括了关于顶点的思想。如果你有3D硬件,硬件将非常快地处理这些顶点。如果你只有2D硬件,我们所谈论的如此少的顶点也将很快的被CPU处理完成。首先,让我们定义我们的顶点格式。将以下的代码放置到靠近#include:的地方
struct PANELVERTEX
{
FLOAT x, y, z;
DWORD color;
FLOAT u, v;
};
#define D3DFVF_PANELVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
This structure and Flexible Vertex Format (FVF) specify that we are talking about a vertex that has a position, a color, and a set of texture coordinates.
这个结构和灵活的顶点格式(FVF)定义了我们所谈论的包含位置,颜和一组纹理坐标的顶点。
Now we need a vertex buffer. Add the following line of code to the list of globals. Again, for simplicity, I'm making it global - this is not a demonstration of good
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论