• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            C++ Programmer's Cookbook

            {C++ 基礎} {C++ 高級} {C#界面,C++核心算法} {設計模式} {C#基礎}

            Managed DirectX start !

            DirectX 首次出現在 1995 年,當時稱為“GameSDK”。在其原始形式中,針對的目標是使用 C 和 C++ 的開發人員。只有在 2002 年 12 月該 API 的第一個托管版本 (9.0) 發布以來,才可以使用 C# 或 VB.NET 開發 DirectX(實際上,如果您希望,那么可以使用任何符合 CLR 的語言)。

            雖然與非托管版本相比,關于托管 DirectX 的性能爭論很多,但商業游戲已使用托管 DirectX 進行創建的事實應該能夠從根本上平息這樣的爭論。雖然某些需要極高性能的游戲可能需要使用非托管代碼,但大多數游戲可以使用托管代碼或者結合使用托管和非托管代碼進行創建。編寫托管代碼使開發人員的效率更高,從而編寫出更多的代碼,生成更安全的代碼。

            安裝 DirectX SDK 之后,在 C:\WINDOWS\Microsoft.NET\Managed DirectX 應該有一個目錄,在機器上安裝的每個版本的 SDK 都有一個子目錄。我機器上使用的已經是第四版了,因此我有四個子目錄。在每個子目錄中應該有九個 DLL 和九個 XML 文件。由于托管環境中的 .NET 允許同一臺機器上的同一個 DLL 文件有多個版本,而不會引起以前被稱為 DLL Hell 的問題,所以我們可以使用多版本的托管 DirectX 庫。這就允許您在安裝新版本之后輕松地回滾到以前的版本。

            如果您以前有在 Windows 下處理 DLL 文件的經驗,您可能會擔心在同一臺計算機上安裝同一個文件的多個版本會產生問題。自從 .NET 引入并行版本控制,這些版本控制問題就不復存在了。這意味著當新版本的 SDK 發布時,您可以使用多個版本來檢查兼容性問題,而不必強迫自己進行升級。

            九個 DLL 文件大致對應于 DirectX 中的十個命名空間。在創建游戲時,我們使用其中的大量命名空間來提供對輸入設備、聲音、網絡播放(當然還有 3D 圖形)的支持。

            命名空間 描述

            Microsoft.DirectX

            公共類和數學結構

            Microsoft.DirectX.Direct3D

            3D 圖形和助手庫

            Microsoft.DirectX.DirectDraw

            Direct Draw 圖形 API。這是舊式命名空間,您不需要使用它。

            Microsoft.DirectX.DirectPlay

            用于多玩家游戲的網絡 API

            Microsoft.DirectX.DirectSound

            聲音支持

            Microsoft.DirectX.DirectInput

            輸入設備支持(例如,鼠標和游戲桿)

            Microsoft.DirectX.AudioVideoPlayback

            播放視頻和音頻(例如,在 PC 上播放 DVD)

            Microsoft.DirectX.Diagnostics

            疑難解答

            Microsoft.DirectX.Security

            訪問安全性

            Microsoft.DirectX.Security.Permissions

            訪問安全權限



            HEL和HAL

              在圖5.2中,可以看到在DirectX下有兩個層面,分別是HEL(硬件模擬層)和HAL(硬件抽象層)。這是一個約定:DirectX是一種非常有遠見的設計思路,它假定可以通過硬件來實現高級性能。但是,如果硬件并不支持某些性能,那怎么辦呢?這就是HAL和HEL雙重模式設計思路的基礎。
              HAL(硬件抽象層)是接近硬件的底層。它直接和硬件交流。該層通常有設備生產商提供的設備驅動程序。可以通過常規DirectX調用直接和硬件進行聯系。使用HAL要求硬件能夠直接支持所要求的性能,這時使用HAL,就能夠提高性能。例如,當繪制一個位圖時,使用硬件要比軟件更勝任該項工作。
              當硬件不支持所要求的性能時,使用HEL(硬件仿真層)。我們以使用視頻卡旋轉一個位圖為例來說明。如果硬件不支持旋轉動作,則使用HEL,軟件算法取代硬件。很明顯這樣做速度要慢一些,但關鍵是這樣做至少不會中斷應用程序,應用程序仍然在運行,僅僅是速度慢一些而已。另外,HAL和HEL之間的切轉是透明的。如果要求DirectX做某工作,而HAL直接處理該工作,也就是硬件直接處理該項工作。否則,HEL將調用軟件仿真來處理該工作。



            Section 1 – Introduction

            Section 1.1 – What is DirectX?

            DirectX is the name given to a series of API for running and displaying multimedia rich applications. Using it, you can have graphics, video, 3D animation, surround sound and so on. The different API’s available in DirectX are Direct Graphics, Direct Input, Direct Sound, Direct Play and Direct Show.

            Direct Graphics deals with everything related to graphics. With it you can load 3D meshes, render textures, animate 3D models, light your scene, add particle effects and much more. It is concentrated more towards 3D making it ideal for rendering 3D graphics, although it will also work just as well doing 2D graphics too.
            Direct Input is the API that allows you to use many different kinds of input devices such as keyboards, mice, joysticks, joy pads and so on. It gives you much more control than the Win32 API does, and is ideal for games.
            Direct Sound does everything you could ever want to do with audio. You can play midi files and wav files and other types of music. You can add special effects such as an echo or flanging. You can also add 3D surround sound effects by telling Direct Sound to apply special 3D algorithms and so on. Again, this is ideal for games.
            Direct Play is the networking API used mainly in games. If you wish to make a game run over a network then you can use DirectPlay?. There isn’t much more to say about that really.
            Direct Show can be used for all kinds of multimedia tasks such as video playback. It is ideal for audio or video recording, editing and manipulation.


            Section 1.2 - Assumptions

            Readers should have a basic understanding of the C# language and should have at least enough experience using it to understand the examples. The code examples are fairly simple and don’t use anything overly complicated, but you should still have a firm grasp of the language nevertheless. If you have any experience with using previous versions of DirectX in other languages then this would certainly help, but isn’t a requirement. The tutorial assumes you’ve never used DirectX before.
            I will be using the .Net framework version 1.1. Readers using the new .Net 2.0 Framework that comes with Microsoft Visual C# 2005 Express Edition should be able to convert the code without too much trouble. Most of it should be compatibl. I will be using the Microsoft Visual Studio .Net 2003 IDE so any screenshots or descriptions will explain how to perform the task in that IDE. If you are using a different IDE such as Sharp Develop, Borland C# Builder or Microsoft Visual C# 2005 Express Edition, then I assume that you’re competent enough in it’s use that you can understand how to do the tasks in your own IDE. You should at least know how to create a new project, add references to your project, add files and code to your project, save it, and build it. Obviously knowing how to do other important things such as use the debugger would be a strong advantage.
            I will use the DirectX Summer Update 2004 SDK. That is: version 1.0.1901.0. There may be some slight incompatibilities with previous versions, but they shouldn’t be too hard to fix if you’re using a previous version. I suggest you get the update though if you don’t already have it.
            Note that I won’t be using the DirectX wizards or any template files in my project. I’ll be showing you how to do everything yourself so that we can gain a deeper understanding of what’s actually going on and what we’re actually writing.



            Section 2 – Creating a New DirectX Project


            Section 2.1 – Creating a New Project

            Start up your IDE. As I mentioned above, I use Microsoft Visual Studio .Net 2003. Start a new project, and save it. Choose either “Windows Application” or “Console Application” depending on which type of project you wish to make. If you installed DirectX9? properly then you should be able to create a new DirectX project, which has a wizard to guide you through creating a simple application. As I mentioned, I won’t be using this. I prefer to write the code myself to gain a deeper understanding of what is actually going on in my project.


            Section 2.2 – Adding the DirectX References

            In order to use DirectX in your applications, you must add a reference to the assemblies. To do this in Microsoft Visual Studio .Net 2003 you can click the project menu and click “Add Reference”, or right click on the “References” section in the project explorer, and click “Add Reference”.
            Now you should be presented with the “Add Reference” dialog. Make sure the “.Net” tab is selected, and scroll down to “Microsoft.DirectX”. You will see that there are several entries. At the very least, add “Microsoft.DirectX”. The other assembly names reflect quite clearly what they contain. For example “Microsoft.DirectX.Direct3D” is the 3D graphics API, “Microsoft.DirectX.DirectSound” is the Direct Sound API and so on. Go ahead and add whichever ones you require.
            Some of you may notice that you have 2 versions of each assembly with different versions. You will have this if you installed the Summer 2004 Update. I have one set using version 1.0.1901.0 and another set using version 1.0.900.0. I will be adding the assemblies with the newer version: 1.0.1901.0.

            Image


            Adding the DirectX references in Microsoft Visual Studio .Net 2003.


            Section 2.3 – The “using” Directives

            You may wish to add some “using” directives for the namespaces in DirectX. You should know what the “using” directive does. Here are some simple ones for using Direct3D:

            using Microsoft.DirectX;
            using Microsoft.DirectX.Direct3D;


            Section 3 – Direct Graphics Enumeration


            Section 3.1 – Enumerating Adapters and Display Modes

            An adapter is basically a graphics card. Most systems will have just 1 adapter. Systems with multiple monitors may have more than 1 adapter. If you wish to support systems with multiple adapters then you will have to enumerate them, otherwise you can just use the default one. The code to enumerate and choose an adapter is incredibly simple though, so it’s worth the little bit of extra effort.
            An adapter is described by an AdapterInformation? class located inside the Microsoft.DirectX.Direct3D namespace. This class has some useful properties such as the CurrentDisplayMode? property, which funnily enough, returns the current display mode; the AvailableDisplayModes? property that returns a list of supported display modes, which can be enumerated using a foreach loop; and an Information property, which returns an AdapterDetails? class. This class contains several useful properties which you can use to identify individual cards and so on. One of the most useful properties of this class is the Description property. This gives you a human readable description of the graphics card such as “NVIDIA GeForce2? MX/MX 400” (My old crappy card). There are many other properties and methods inside the AdapterInformation? class too. Explore the properties and methods using the tooltips and the intellisense (Intellisense is the name given to the lists that pop up in the code editor containing all the accessible members of an object for those of you who don’t know what that is).
            To actually enumerate an adapter, we use the Manager class located inside the Microsoft.DirectX.Direct3D namespace. You don’t create a new instance of this class as all of it’s methods are static. The Manager class contains a static property called “Adapters” which returns a list of AdapterInformation? classes described above, that you can enumerate using a foreach loop. It really is that simple. If you wish to use the default adapter, or just want to know what it is at least, then you can get that simply by using Manager.Adapters.Default.
            Here’s an example program showing the main things we’ve learned so far:

            using System;
            using Microsoft.DirectX;
            using Microsoft.DirectX.Direct3D;
            
            
            class AdapterEnumeration
            {
            static void Main(string[] args)
            {
            	foreach(AdapterInformation adapter in Manager.Adapters)
            	{
            	// Check whether or not this is the default adapter
            		if(adapter.Equals(Manager.Adapters.Default))
            		{
            			Console.WriteLine("This is the default adapter\n");
            		}
            		
            		// Write out some information about the adapter
            		Console.WriteLine("" + adapter.Information.ToString() + 
            					"\n\nDisplay Modes:\n");
            			
            		// Write out each display mode
            		foreach(DisplayMode display in adapter.SupportedDisplayModes)
            		{
            			Console.WriteLine("{0}x{1} : {2} @ {3} Hz", 
            					display.Width,
            					display.Height,
            					display.Format,
            					display.RefreshRate);
            		}
            			
            		// Write out the current display mode
            		Console.WriteLine ("\nCurrent Display Mode: {0}x{1} : {2} @ {3} Hz", 
            					adapter.CurrentDisplayMode.Width,
            					adapter.CurrentDisplayMode.Height,
            					adapter.CurrentDisplayMode.Format,
            					adapter.CurrentDisplayMode.RefreshRate);
            			
            		Console.WriteLine("\n\n");
            	}
            
            	Console.ReadLine();
            }
            }




            That’s extremely simple, I think you’ll agree. The output isn’t the nicest looking output in the world, but it shows you how to do it. You can make it look pretty quite easily. In a windows application you can add each adapter description to a combo box or some other suitable control. When an adapter in the combo box is selected, you could add information about that adapter to a listview, and add it’s available display modes to another combo box, selecting the current display mode by default. That’s how I usually do it, and that’s an example of the kind of things you can do with the very simple code above.
            As a by the way, you can get a handle to the monitor associated with each adapter using the following code:

            IntPtr MonitorHandle = Manager.GetAdapterMonitor(adapter.Adapter);



            I’m not quite sure what you could do with that handle, but I’m sure it’s useful somewhere, such as with some Win32 API functions that return information about the monitor or something like that. Note that the “Adapter” property of the AdapterInformation? class is the “adapter ordinal” which is just a fancy name for the adapter number. The first one has ordinal 0, the second ordinal 1 and so on. Usually there will be just one default adapter with an adapter ordinal of 0.


            Section 3.2 – Device Capabilities (Caps)

            Device Caps is one of those terms you will hear a lot with DirectX programming. Caps is simply short for Capabilities. The Device Caps are therefore just what the device is and isn’t capable of doing. There are literally hundreds of things you can check. Retrieving device capabilities is very simple. Again, you use the Manager class to do this. Here is a short snippet of code showing you how to do it:

            AdapterInformation ai = Manager.Adapters.Default;
            Caps caps = Manager.GetDeviceCaps(ai.Adapter, DeviceType.Hardware);



            There’s nothing hard there, is there? The only thing that might confuse you is the DeviceType?. The 2 main types are “DeviceType.Hardware” and “DeviceType.Reference”. There is also another device type called a Software Device, but this is very rarely used. I think it’s something to do with plugging in your own software renderer or something. Using the hardware device type will query the capabilities of the graphics adapter. Using the reference device type will query the capabilities of software emulation, basically. A lot of drivers will be able to make up for lack of hardware features by providing software emulation. A common difference for example, is that the hardware will only usually be able to do a few active lights such as 8 or 16 whereas the reference device may be able to do an unlimited amount. The software device will be able to do pretty much everything, but it’s much slower than the hardware.
            Anyway, back to the point. You can probably figure out how to use the Caps class by looking at the intellisense again. This is a very powerful way to learn about classes. Most of it should be fairly self explanatory. You can test for all kinds of things. The tooltips will explain what all of the properties mean. For example, if you want to see whether or not textures must be square, you can test that using the following code:

            if(caps.TextureCaps.SupportsSquareOnly)
            {
            	Console.WriteLine("Square textures only are supported");
            }



            As I mentioned, there are literally hundreds of things you can check for. They are all organised into sensible properties. For example, all texture capabilities are stored inside the TextureCaps? property, vertex processing capabilities are inside the VertexProcessingCaps? property and so on. You can explore it using the object browser as well as the intellisense. (Press F2 in Visual Studio .Net 2003 to open the object browser):

            Image
            Exploring the Caps class inside the object browser.

            Section 3.3 – Adapter Formats and BackBuffer? Formats

            There are 3 main questions I will answer in this section: What is a format? What is a backbuffer (format), and what is an adapter format?
            In answer to the first question, the format is just the way that pixel data is encoded. For example, you may have 5 bits to store the amount of red, 6 bits to store the amount of green and another 5 bits to store the amount of blue. This adds up to 16 bits, or 2 bytes per pixel. As a by the way, we give green more bits for 2 reasons. Firstly, to make the pixel data up to 2 bytes without wasting a pixel, and secondly, we chose the green component because our eyes are more sensitive to green and can therefore distinguish between more shades of green than they can red or blue, so it makes sense to give the green component the extra bit. The 2 most common formats are 16 bit and 32 bit. There is a 24 bit format and there are 8 bit formats, but these are rarely used. Some formats have some bits set aside for an “alpha” component. This is to do with something called alphablending, which is a type of transparency. You don’t need to know what that is exactly right now, but just bear in mind that some formats have an extra alpha component. Yet other formats have unused bits, denoted by “X”. For example, there is a 32 bit mode called “X8R8G8B8” which means that the red, green and blue components are all 8 bits each, and there is an unused 8 bits to round the format up to 4 bytes per pixel. An example of a format with an alpha component is one called “A8R8G8B8” which has the same as the other format, but instead of having an unused 8 bits, it uses the extra 8 bits for the alpha component.
            Now in order to explain what the backbuffer format is, I suppose I better mention briefly what a backbuffer is. When you draw things on the screen, they aren’t all drawn at the same time obviously. So you may draw a tree, then draw a bush, then draw another tree, then draw a character, then draw a house for example. They are all drawn one after the other. There is a phenomena called “artifacts” where the screen encounters a vertical resync (a refresh) while you’re in the middle of drawing your scene on to the screen. This results in flickering graphics where you can briefly see things being drawn on the screen. The way this is fixed is we draw everything offscreen to an area of memory, and only once the scene is finished, we draw this entire area of memory onto the screen at once. This way you don’t see each individual part being drawn. This area of memory where you do your drawing is called a “backbuffer” and the process of drawing the backbuffer onto the screen is called “flipping” or “presenting”. Hopefully the term “backbuffer format” should be quite clear now that I’ve explained what a backbuffer is, and what a format is.
            Now for the adapter format, this is basically just your display mode. The format of the pixels on the main screen. One question may arise from this – why aren’t the backbuffer format and the adapter format the exact same? Well the answer to that is in most cases they are. Although there is one difference. In a backbuffer you can have an alpha component, but you can’t have an alpha component in the adapter format. This is why they may differ.


            Section 3.4 – Device Types

            This is quite a short section. I’ve already mentioned device types before, but here it is again. There are 3 device types: Hardware, Software and Reference. Hardware means use the graphics card where possible, reference means use software emulation. And the software device is rarely used. It’s something to do with writing your own software renderer I think. Now you may be wondering why you would ever want to use software instead of hardware. Well there is actually a good reason. Because the reference device supports absolutely everything. You would need to fork out a huge amount of money to get a graphics card that can come anywhere near close to being able to do everything. I’m talking about a top of the range card – the best you can get. The problem with software is that it’s painfully slow compared to using hardware. So if you just want to test out some features in your game that your graphics card doesn’t support, you can switch to software emulated mode and check that it works. Or if you just really want to use some feature not supported by the hardware so much that you’re willing to slow down everything to a crawl to get it to work then you can use software emulation for that. You probably wouldn’t want to do that in a game unless you want a frame rate of about 0.5 frames per second. That would be for an application such as a 3D rendering application, where you really want to have some special effect in your scene, and don’t care if it takes an extra hour to render (These things take hours anyway).


            Section 3.5 – Using Manager.CheckDeviceType

            At this point I’ve explained the following things to you: how to enumerate adapters, how to enumerate display modes, device types and backbuffer and adapter formats. Now you need to begin choosing them. So choose an adapter, a device type, an adapter format (from your list of display modes), a backbuffer format, and a device type. Now you need to choose one more thing: whether or not you want to run this application in a window, or in full screen mode. You will need all of these to create a device (which I’ll explain later. Lets just say for now that it’s incredibly important). So now you’ve chosen all of these things. Unless you know what you’re doing or you got pretty lucky, they’re probably all incompatible with each other and wouldn’t work. Ideally you want to present a list of adapters to the user. Once they choose an adapter, you would then want to present a list of device types compatible with that adapter to them, and have them choose one of those. Once they’ve chosen an adapter and a device type, you would like them to choose a display mode (the important part being the format, for the adapter format). Once they’ve chosen that, you would then ideally like to present them with a list of backbuffer formats which are compatible with the adapter format to choose from. And finally, you want to present them with the option of fullscreen or windowed mode, if that’s still there.
            The best way to do this is to check every possibly combination of the following: adapters, device types, available adapter formats, backbuffer formats, whether or not to use windowed or full screen mode. By checking all the combinations of the above, you’ll get a list of all the compatible combinations which you can present to the user whatever way you see fit. The method used to check these is Manager.CheckDeviceType. The following code snippet shows you how you can check all possible combinations. When you get a valid combination, you can add that to your combo boxes or list boxes or your arrays or whatever method of storing the combinations you choose.


            DeviceType[] deviceTypes = new DeviceType[] 
            {DeviceType.Hardware, DeviceType.Software, DeviceType.Reference};
            		
            Format[] backBufferFormats = new Format[] 
            {Format.A8R8G8B8, Format.X8R8G8B8, Format.A2R10G10B10,
            Format.R5G6B5, Format.A1R5G5B5, Format.X1R5G5B5};
            		
            bool[] windowModes = new bool[] {true, false};
            		
            // For each adapter
            foreach (AdapterInformation adapter in Manager.Adapters)
            {
            	ArrayList adapterFormats = new ArrayList();
            			
            	// Build the list of adapter formats
            	foreach (DisplayMode dispMode in adapter.SupportedDisplayModes) {
            		if (!adapterFormats.Contains (dispMode.Format))
            			adapterFormats.Add (dispMode.Format);
            	}
            	
            	foreach (DeviceType deviceType in deviceTypes) {
            		foreach (Format adapterFormat in adapterFormats) {
            			foreach (Format backBufferFormat in backBufferFormats) {
            				foreach (bool windowMode in windowModes) {
            					if (Manager.CheckDeviceType (
            						adapter.Adapter,
            						deviceType,
            						adapterFormat,
            						backBufferFormat,
            						windowMode)) {
            						// *** This combination is valid!
            						}
            				} // windowMode	
            			} // backBufferFormat
            		} // adapterFormat
            	} // deviceType
            } // adapter




            Section 3.6 – Vertex Processing

            The last thing we need before we can create a device (As I said earlier, this will be explained. Just know that it’s important. This is the main object we use for all our rendering) is a vertex processing type. I assume you’ve used something similar to the above code to enumerate all the possible combinations of adapters, device types, adapter/backbuffer formats and windowed or not and chosen one of each. Now before we can build a device, we need this vertex processing method. Basically the vertex processing method is just telling Direct3D where to do all of the vertex processing. How much should the hardware be involved, and how much should the software be involved, basically. Most cards these days should support hardware vertex processing. Lower end ones will support mixed vertex processing, where the processing is done by both hardware and software. Software only vertex processing will always work, but is slower. We can go through some methods to determine which type of processing is available like this:


            Caps caps = Manager.GetDeviceCaps(Manager.Adapters.Default.Adapter, 
            						DeviceType.Hardware);
            
            	if (caps.DeviceCaps.SupportsHardwareTransformAndLight)
            	{
            		if (caps.DeviceCaps.SupportsPureDevice)
            		{
            			Console.WriteLine ("Pure Device");
            		}
            			
            		Console.WriteLine ("Hardware Vertex Processing");
            		Console.WriteLine ("Mixed Vertex Processing");
            	}
            		
            	Console.WriteLine ("Software Vertex Processing");




            You can see that first we get the device capabilities, as we use them to check the vertex processing available. Then we check if the device supports hardware processing. If it does, we know that at least it supports hardware and mixed processing. If it supports hardware processing, then we check if it supports the “pure device” which means it also supports resterization and shading as well as just lighting and transformation. We know that software vertex processing will always be available so that’s a given.
            Now you have everything you need to create a device. You can enumerate and choose an adapter, and a display mode, and a backbuffer format and a device type and finally you can choose whether or not to use windowed mode or full screen mode if it’s compatible with everything else you’ve chosen.


            Section 3.7 – Enumerating Depth Stencil Formats

            There is one other main thing you will need to be able to enumerate – depth stencil formats. Don’t worry about what these actually are, you will learn later. I’m just putting this in the enumeration section because that’s where it belongs – it is afterall enumeration. Just know how to do it. You already know what a format is. This is done quite easily. We first just check the format is valid for the device, then check if it’s compatible with the backbuffer format. If so, then we can use it (You’ll see what it’s for later).


            DepthFormat[] depthStencilFormats = new DepthFormat[]
            {
            DepthFormat.D16,
            		DepthFormat.D15S1,
            		DepthFormat.D24X8,
            		DepthFormat.D24S8,
            		DepthFormat.D24X4S4,
            		DepthFormat.D32,
            };
            
            foreach (DepthFormat depthStencilFormat in depthStencilFormats)
            {
            if(Manager.CheckDeviceFormat(adapter, deviceType, adapterFormat, 
            		Usage.DepthStencil, ResourceType.Surface, depthStencilFormat))
            	{
            if (Manager.CheckDepthStencilMatch(adapter, deviceType,
            			adapterFormat, backbufferFormat, depthStencilFormat))
            		{
            			// This depth stencil format is compatible
            		}
            	}
            }




            Section 3.8 – Final Word on Enumeration

            Note that I’ve covered more than enough on enumeration for you to get started. There is plenty more that you can figure out on your own though. Also remember all the stuff in the device capabilities (device caps) classes that can be checked. You check that stuff as you need it though. Unfortunately, enumeration is quite boring. I should have probably told you that at the start. We’ll start doing some more interesting stuff in the next section.


            Section 4 – Rendering Something


            Section 4.1 – Creating the Device

            Finally we get on to this device I’ve mentioned so much in the enumeration section. What is a device? The device is the object we use in almost everything. It’s a representation of our actual adapter (well, in reality it’s driver). You will use the device to do all of the rendering (drawing, if I haven’t mentioned that yet) and lighting and so on. You can’t do very much without a device. So I think I’ve stressed just how important it is. Now to actually create a device is a little bit trickier than anything we’ve seen yet, but it’s still fairly trivial. Especially with all our enumeration done above.

            // Assumes you have:
            	// 
            	// AdapterInformation	adapter;
            	// DeviceType		deviceType;
            	// CreateFlags		createFlags;
            	// DisplayMode		displayMode;
            	// Format		backbufferFormat;
            	// bool			windowed;
            		
            	PresentParameters presentation = new PresentParameters();
            		
            	presentation.BackBufferFormat	= backbufferFormat;
            	presentation.BackBufferWidth	= displayMode.Width;
            	presentation.BackBufferHeight	= displayMode.Height;
            	presentation.SwapEffect		= SwapEffect.Flip;
            	presentation.Windowed		= windowed;
            		
            	Device device = new Device(
            			adapter.Adapter, 
            			deviceType, 
            			this,
            			createFlags,
            			presentation);



            So first you need to choose an adapter, a device type, a vertex processing type (this is the createFlags variable) a display mode, a backbuffer format, and whether or not to use windowed mode. All of these are stored in the variables mentioned above. One you’ve chosen these, you then create a new PresentParameters? object. This stores information about the backbuffer, and the display mode, and other important presentation information. You can change things like the number of back buffers to use and so on. We just change the backbuffer format, width and height as appropriate. Then we change the swap effect. The swap effect is just how the backbuffer is presented to the screen. We just tell it to flip the backbuffer and the screen around so that the backbuffer now becomes drawn on the screen, and what was previously on the screen now becomes the backbuffer. Lastly, we set whether or not we want to use windowed mode or not. Now to finally create the device, you pass first the adapter ordinal, then the device type. The next parameter, “this”, must be a windows forms control! So this won’t work in console mode obviously. You must write the above code in a windows forms application. Using “this” will just draw onto the form. You could also draw onto a picturebox or something else if you pleased. The next parameter is the create flags, or the vertex processing type that I talked about a lot above in the enumeration section. And lastly, you pass the presentation parameters. This should hopefully give us a working device.


            Section 4.2 – Rendering Something

            Now we get to the fun part – actually rendering! Don’t get too excited yet though, we’re only going to clear the window with a color. First we need to know where to actually render though. You could override the OnPaint? event and render everything in there. For a game or something, you will need a loop though. This is usually called “the game loop”. This game loop usually goes after all the initialization code. Just remember to show your form before entering the loop. So now we know roughly where to put our rendering code, how do we actually write it? Well, we’ll learn 2 new methods of the Device object: Clear and Present. The “Clear” method simply clears the entire drawing area with your chosen color. The “Present” method performs the “flip”, drawing the backbuffer to the screen. That’s all we’ll use right now. So here’s the code for a typical rendering loop:

            while (Running)
            {
            	device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);
            	device.Present();
            	Application.DoEvents();
            }



            Notice that we have a variable, Running. This would be a boolean that you would set to true if your initialization was successful. Then when you want to end the loop, for example when the escape key is pressed, or the form is closing, then you set the Running variable to false. Notice that we also use Application.DoEvents to continue processing messages.


            Section 4.3 – A Complete Sample Application


            using System;
            using System.Drawing;
            using System.Windows.Forms;
            using Microsoft.DirectX;
            using Microsoft.DirectX.Direct3D;
            
            public class MainForm : Form
            {
            	Device device = null;
            
            	/// <summary>
            	///	When the form is clicked, we close it and stop
            	///	the application
            	/// </summary>
            	protected override void OnClick(EventArgs e)
            	{
            		this.Close();
            		base.OnClick (e);
            	}
            
            	
            	/// <summary>
            	///	In the constructor we initialize the device using
            	///	the default adapter and the current display mode
            	/// </summary>
            	public MainForm()
            	{
            		AdapterInformation adapter = Manager.Adapters.Default;
            	
            		PresentParameters presentation = new PresentParameters ();
            		presentation.BackBufferFormat = adapter.CurrentDisplayMode.Format;
            		presentation.BackBufferWidth = adapter.CurrentDisplayMode.Width;
            		presentation.BackBufferHeight = adapter.CurrentDisplayMode.Height;		
            		presentation.SwapEffect	= SwapEffect.Flip;
            		presentation.Windowed = false;
            		
            		// Place it in a try catch block just 
            		//in case it goes wrong for
            		// some reason.
            		try
            		{
            			// To make things simple, we'll just 
            			//use the reference device, and
            			// software vertex processing. 
            			//Although this will be extrelemly slow
            			// it doesn't matter in this case.
            			// It will definetly work on 
            			// all machines, so it saves us doing 
            			//enumeration for now.
            			device = new Device (adapter.Adapter, 
            						DeviceType.Reference,
            						this,
            						CreateFlags.SoftwareVertexProcessing,
            						presentation);
            		}
            		catch (DirectXException e)
            		{
            			MessageBox.Show (e.Message);
            			return;
            		}
            	}
            
            
            	/// <summary>
            	///	Clear the screen with a blue color
            	/// </summary>
            	public void Render()
            	{
            		device.Clear(ClearFlags.Target, Color.Blue, 1.0f, 0);
            		device.Present();
            	}
            
            
            	/// <summary>
            	///	The entry point where the main render loop goes
            	/// </summary>
            	static void Main() 
            	{
            		using (MainForm form = new MainForm())
            		{
            			form.Show();
            			
            			while (form.Created)
            			{
            				form.Render();
            				Application.DoEvents();
            			}
            		}
            	}
            }




            As a simple exercise you could try changing the application so that it exits when the escape key is pressed instead of clicked. Also, try changing the color to red. And if you like you can try making the program run in windowed mode by commenting all the backbuffer parameters in the presentation parameters and just change the Windowed property to true.

            posted on 2006-04-19 13:56 夢在天涯 閱讀(2533) 評論(6)  編輯 收藏 引用 所屬分類: DirectX

            評論

            # re: DirectX start ! 2006-04-19 16:23 小銀子

            繼續深入...  回復  更多評論   

            # re: Managed DirectX start ! 2006-06-14 18:12 夢在天涯

            托管的 D3DX 庫
            托管的 D3DX 實用工具庫具有用來處理網格、紋理、Shader、效果、文本和動畫的類。但是,與非托管的 D3DX 庫不同的是,它沒有數學類,如矩陣、矢量和四元組類。在托管 DirectX 中,數學類是 DirectX 庫的一部分。

            用來處理網格的類包括 Mesh、SimplificationMesh、ProgressiveMesh、SkinMesh 和 PatchMesh。Mesh 和 ProgressiveMesh 從 BaseMesh 類繼承。BaseMesh 管理內存(包括頂點和索引緩沖區)中的網格表示形式,并提供用來呈現網格的 DrawSubset 方法。其他方法包括用來復制網格的 Clone 方法,以及用來計算頂點法線并獲取相鄰項信息的方法。

            Mesh 類使用可將網格保存到 .X 文件(標準的 DirectX 文件類型)或二進制流中并從中加載網格的方法來擴展 BaseMesh。還提供了用來生成表示以下圖形的網格的方法:n 邊形、圓柱、球形、圓環、給定字體的 3D 文本或者甚至是茶壺。用戶可以網格化網格以獲得更光滑的對象(通過將每個三角形解釋為 N-patch),簡化網格(通過減少三角形的數量)、優化網格(通過對三角形重新排序,以便利用硬件中的頂點緩存并提高性能)或者執行與網格的光交叉。

            SimplificationMesh 對象是從 Mesh 構造的,它具有可減少表面(三角形)或頂點數量的方法,從而可產生比初始網格簡單但是質量更低的網格形式。ProgressiveMesh 對象是從 Mesh 構造的。它允許實時簡化網格,以便在網格對象和照相機之間的距離增大時,最小化所呈現三角形的數量。SkinMesh 類(由主干制作動畫的網格)提供的方法可用來從 .X 文件數據對象加載外觀網格。包含了用來公開基礎網格和外觀的信息(如每根骨頭對結構的影響)的屬性。

            PatchMesh 類表示更高階的表面,如 N-Patch、Triangle Patch 或 Rectangle Patch 表面。PatchMesh 包括用來執行如下操作的方法:從 Mesh 對象創建 N-Patch 網格、從 .X 文件加載 PatchMesh、網格化 PatchMesh 等。用來處理紋理的類主要包括:前面介紹的 TextureLoader 類、RenderToEnvironmentMap 類和 RenderToSurface 類。RenderToEnvironmentMap 和 RenderToSurface 類用來在運行時創建立方體環境貼圖和紋理。如果在運行時呈現到紋理中,則允許您獲得特殊效果,如讓類似于鏡面的物體反射布景中的其他物體,或者制造雙窗格呈現效果。用來處理文本的類主要包括 Font 類,Font 類可以從 System.Drawing.Font 對象實例化,并且具有可以在支持 Direct3D 的設備上呈現文本的方法。用來處理動畫的類由 KeyFrameInterpolator 類組成,KeyFrameInterpolator 類具有用來以內插值替換對象的縮放、旋轉和/或平移的方法。內插值替換是通過使用一組 3D 矢量(用來縮放和平移)和四元組項(用于旋轉)來執行的。

              回復  更多評論   

            # re: Managed DirectX start ! 2006-06-14 18:13 夢在天涯

            與幾何形狀相關的類
            Direct3D 中的幾何形狀被定義為頂點定義的數組。不同的圖形算法需要存儲在每個頂點的不同信息,了解這一點很重要。這些頂點組分需要由應用程序進行聲明,具體情況取決于程序員希望實現的效果。例如,如果程序員希望將紋理映射到 Direct3D 將呈現的幾何形狀,則程序員必須進行如下聲明:在每個頂點,都將有 tu 和 tv 值(紋理坐標)。托管的 Direct3D 提供了兩種頂點定義機制:VertexFormats 和 VertexDeclarations。使用這些機制,可以在每個頂點定義其他數據,如顏色、混合權重、紋理坐標或應用程序定義的任何用法。作為一種方便的方法,為經常使用的頂點格式定義提供了 CustomVertex helper 類。CustomVertex 類提供 11 種不同的頂點定義,這些定義經常用于 Direct3D 應用程序中。

            在托管的 Direct3D 中,應用程序用來定義其頂點布局的頂點格式由 Device 類的讀和寫 VertexFormat 屬性來訪問。VertexFormat 屬性訪問 VertexFormats 枚舉的元素,并且只需通過以下方法來實現:針對 IDirect3DDevice9 接口使用 GetFVF 和 SetFVF 方法,調用內部的非托管 Direct3D Device COM 對象。托管的 VertexFormats 枚舉映射到在 d3dtypes.h 中定義的 VertexFormat 常量位,如下所示:

            public struct Vertex
            {
            public Vector3 position;
            public float tu, tv;
            public static readonly VertexFormats Format =
            VertexFormats.Position | VertexFormats.Texture1;
            };
            // From a typical managed Direct3D applications Render() method.
            device.VertexFormat = Vertex.Format;

            在使用可編程的管線時,需要自定義的頂點聲明。與使用靈活的頂點格式定義的頂點緩沖區不同,自定義頂點聲明可以通過使用多個流來定義,從而可節省帶寬:

            VertexElement[] declaration = new VertexElement[]
            {
            new VertexElement(
            0, // short stream
            0, // short offset
            DeclarationType.Float2, // DeclarationType declType
            DeclarationMethod.Default, // DeclarationMethod declMethod
            DeclarationUsage.Position, // DeclarationUsage declUsage
            0 // byte usageIndex
            ),
            VertexElement.VertexDeclarationEnd
            };
            VertexDeclaration declaration = new VertexDeclaration(device,
            declaration);

            托管 Direct3D 中的幾何形狀通常是通過處理 VertexBuffer.Created 事件來創建的。圖 5 顯示了從 SDK 中的 Tutorial2 示例提取的簡單三角形形狀,并說明了預定義的自定義頂點 (CustomVertex.TransformedColored) 的用法。

              回復  更多評論   

            # re: Managed DirectX start ! 2006-06-14 18:13 夢在天涯

            圖形狀態類
            如前所述,非托管代碼的圖形狀態是通過 IDirect3DDevice9 接口的方法來配置的。例如,在非托管代碼中,變換狀態可通過 GetTransform 和 SetTransform 方法直接訪問,這兩種方法都使用 D3DTRANSFORMTYPE 類型的枚舉值。

            // From unmanaged IDirect3DDevice9 interface:
            HRESULT GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX *pMatrix);
            HRESULT SetTransform(D3DTRANSFORMSTATETYPE State,
            CONST D3DMATRIX *pMatrix);

            托管的 Direct3D 為非托管層提供一些抽象,這會使客戶端代碼變得更簡潔。下面顯示的 Device 類說明了一組只讀屬性:

            public class Device : MarshalByRefObject, IDisposable
            {
            // Additional properties, methods and events.
            public Transforms Transform { get; }
            public RenderStates RenderState { get; }
            public SamplerStates SamplerState { get; }
            public TextureStates TextureState { get; }
            }

            這些屬性返回 Transforms、RenderStates、SamplerStates 和 TextureStates 類的實例。這些實例隨后用于配置托管 Direct3D 的圖形狀態。例如,Device 類不直接公開使用枚舉值的 Transform 屬性。Device 托管類提供可返回 Transforms 對象的屬性。Transforms 對象隨后公開一組可用來訪問當前世界、視圖和投影矩陣的屬性,這些屬性本身是 TransformType 托管枚舉的元素。

            RenderStates 類提供了大量的屬性來配置為光柵化階段選擇的特定算法。下面的客戶端代碼顯示了如何設置 Direct3D 托管管線的狀態。

            // cull, spec, dither states.
            device.RenderState.CullMode = Cull.None;
            device.RenderState.SpecularEnable = false;
            device.RenderState.DitherEnable = false;
            // Filter states.
            device.SamplerState[0].MagFilter = TextureFilter.Linear;
            device.SamplerState[0].MinFilter = TextureFilter.Linear;

            請注意,使用索引器來訪問取樣器狀態的多紋理層疊所在的階段。

            取樣器狀態指定用于特定階段的篩選、平鋪和紋理尋址模式,這些模式可通過 Sampler 類的屬性來公開。篩選功能用于指定如何將圖像映射到特定的 Direct3D 基元。根據圖像(紋理)的大小以及它需要映射到的屏上基元的大小,可能需要放大或縮小圖像。Direct3D 提供了三種篩選方法:MipFilter、MinFilter 和 MagFilter,每種方法都具有可由 TextureFilter 枚舉配置的模式。平鋪功能用于將一組單個的紋理匯集成單個紋理并減少切換紋理的需要。平鋪功能是通過 Sampler 類的一組屬性獲得支持的。最后,紋理尋址模式通過 TextureAddress 枚舉的元素為 [0,1] 邊界外部的紋理坐標定義操作:

            public class SamplerStates
            {
            private Sampler[] m_lpTex;
            private bool pureDevice;
            public Sampler get_SamplerState(int index);
            internal SamplerStates(Device dev, bool pure);
            public Sampler this[int index] { get; }
            }

            TextureStates 和 SamplerStates 類提供只讀索引器,該索引器可返回特定階段的 TextureState 實例。TextureState 類定義的屬性可獲得或指定特定紋理階段狀態的元素。諸如 ColorArgumentn 或 AlphaArgumentn(其中 n 可以是 0、1 或 2)屬性可以是 TextureArgument 枚舉的元素,而 ColorOperation 或 AlphaOperation 可以屬于 TextureOperation 枚舉,如下所示:

            // color = tex mod diffuse.
            device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;
            device.TextureState[0].ColorOperation = TextureOperation.Modulate;
            device.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;
            // alpha = select texture alpha.
            device.TextureState[0].AlphaArgument1 = TextureArgument.TextureColor;
            device.TextureState[0].AlphaOperation = TextureOperation.SelectArg1;
            device.TextureState[0].AlphaArgument1 = TextureArgument.Diffuse;

              回復  更多評論   

            # re: Managed DirectX start ! 2006-06-14 18:13 夢在天涯

            設備類
            托管的 Direct3D 提供了基于類的設備抽象,該抽象是通過使用非托管的 IDirect3DDevice9 接口實現的。編寫 Direct3D 托管代碼的程序員使用 Device 類的方法來訪問其他 Direct3D 對象,以便設置各種圖形狀態并呈現幾何形狀。為了執行這些函數,Device 類提供了許多屬性、方法和事件。圖 2 列出了 Device 類最重要的方法,這些方法由 3D 應用程序調用。

            談到對象激活,一種觀點認為,非托管的 Direct3D 之所以使用工廠方法,只是因為 COM 不支持新運算符。COM 的標準激活模式是基于工廠的構造。CoCreateInstance 函數模仿 COM 的新運算符,但它只是一個在內部使用 COM 工廠的包裝。使用工廠(相對于新運算符)的另一個原理就是,在使用新運算符時,需要將對象的特定實現綁定到客戶端的代碼中;因此,如果大量使用新運算符,可能會導致版本控制問題。工廠方法通常用于將代碼的客戶端或用戶與代碼的創建者去耦。非托管的 COM IDirect3DDevice9 接口提供 14 種顯式工廠方法,以便創建在使用 Direct3D 時需要的對象(如像素和頂點 Shader 以及頂點和索引緩沖區)。

            目前,托管的 Direct3D 在很大程度上依賴于使用新運算符來構造類。盡管 Device 托管類只提供三種工廠方法,但是,一個值得注意的有趣現象是,非托管的 IDirect3DDevice9 工廠方法和由 Device 類公開的公共屬性之間存在一對一關聯。以下代碼行說明了由 Device 托管類公開的三種工廠方法,每種方法都使用多個參數:

            public Surface CreateRenderTarget(...);
            public Surface CreateDepthStencilSurface(...);
            public Surface CreateOffscreenPlainSurface(...);

            在托管的 Direct3D 中大量使用方法重載。下面的代碼示例說明了非托管的 Device.ColorFill 方法及其托管的重載包裝:

            typedef DWORD D3DCOLOR;

            // Methods from the unmanaged IDirect3DDevice9 interface.
            HRESULT ColorFill(IDirect3DSurface9 *pSurface, CONST RECT *pRect,
            D3DCOLOR color);

            // Methods from the managed Device class.
            public void ColorFill(Surface surface, Rectangle rect, Color color);
            public void ColorFill(Surface surface, Rectangle rect, int color);

            與傳統的圖形系統一樣,非托管的 Direct3D 需要將顏色值作為 32 位整數值在內部傳遞。另一方面,Microsoft .NET Framework 顯式提供用來處理 ARGB 顏色值的 System.Drawing.Color 類,其中包含幾種用來在不同表示形式之間進行轉換的方法。為方便那些已習慣于使用整數值來表示顏色的程序員,托管的 Direct3D 在需要顏色參數時使用這兩種表示形式來提供方法重載。

            非托管的 IDirect3DDevice9 接口既公開只讀屬性,又公開讀寫屬性,這兩種屬性都可以帶參數,也可以不帶參數。在最新版本的 .NET Framework 中,屬性不帶參數。因此,在將非托管的 Direct3D 映射到托管的 Direct3D 時,不使用參數的屬性可以很好地映射到 C# 屬性,而使用參數的 Direct3D 非托管屬性只作為 Get 和 Set 方法公開。圖 3 列出了 Device 類的一些最重要的屬性。

            最后,Direct3D Device 托管類提供了五個用來與設備進行交互的顯式事件。基于 Direct3D 的應用程序可以通過以下方法來將事件作為 Device 的來源:啟動應用程序、調整窗口的大小、從窗口模式更改到全屏模式或者退出應用程序。一個有趣的發現是由 Direct3D 使用的基于 .NET 委托的事件模式。對于 Device 類的每個事件聲明,提供了添加、刪除和引發方法,以及用來存儲事件處理程序的私有實例變量。在 C# 中,客戶端事件注冊和注銷的語法形式分別是通過 += 和 -= 運算符來提供的(請參閱圖 4)。
              回復  更多評論   

            # re: Managed DirectX start ! 2006-06-14 18:15 夢在天涯

            紋理類
            在托管的 Direct3D 中,與紋理相關的類從抽象類 Resource 繼承,并且在極大程度上在與紋理相關的非托管接口上建立層。托管的 Direct3D 有三個紋理類:Texture、CubeTexture 和 VolumeTexture。Texture 類表示可映射到基元上的圖像,用于呈現或用于凹凸貼圖、法線貼圖或其他效果。紋理的基本函數用于將一對紋理坐標映射到某個值(通常是顏色值),但是可以通過其他方式進行解釋。紋理坐標通常是頂點數據的一部分。紋理坐標到顏色或其他值的映射是在呈現管線的像素處理階段完成的。Direct3D 允許一次最多使用八個紋理。CubeTexture 類是用于立方體環境貼圖的特殊種類的紋理,立方體環境貼圖這種技術允許環境(如室內或外景)由反光物體反射出來,這是通過以下方法來實現的:使用紋理來為立方體周圍的六個面各定義一個圖像,并由所呈現的物體來反射。VolumeTexture 類表示存在于三維矩形空間中的顏色或其他值。同樣,它將紋理坐標的三元組映射到顏色或其他值。這些類最重要的方面是,它們都支持一組用于鎖定和取消鎖定紋理的重載方法。

            經常用于加載和保存紋理的類是 TextureLoader。TextureLoader 類包含用來從文件或流加載紋理、立方體紋理或體積紋理的方法。TextureLoader 類的其他用法包括填充和篩選紋理以及計算法線貼圖。用來創建紋理的有用的 helper 方法由 GraphicsUtility 類提供:文件的 GraphicsUtility.CreateTexture 方法只是查找指定紋理的路徑,然后調用 TextureLoader.FromFile 方法以加載它。以下代碼說明了 GraphicsUtility 類的用法:

            Texture texture = GraphicsUtility.CreateTexture(device,"banana.bmp");

              回復  更多評論   

            公告

            EMail:itech001#126.com

            導航

            統計

            • 隨筆 - 461
            • 文章 - 4
            • 評論 - 746
            • 引用 - 0

            常用鏈接

            隨筆分類

            隨筆檔案

            收藏夾

            Blogs

            c#(csharp)

            C++(cpp)

            Enlish

            Forums(bbs)

            My self

            Often go

            Useful Webs

            Xml/Uml/html

            搜索

            •  

            積分與排名

            • 積分 - 1804603
            • 排名 - 5

            最新評論

            閱讀排行榜

            伊人久久大香线蕉成人| 久久久久99精品成人片| 久久久噜噜噜www成人网| 国产精品美女久久久| 国产精品成人99久久久久| 亚洲伊人久久成综合人影院| 亚洲国产精品无码久久一线| 成人免费网站久久久| 久久这里有精品| 国产91色综合久久免费| 亚洲午夜无码AV毛片久久| 国产精品久久毛片完整版| 一本大道久久东京热无码AV| 国产精品久久毛片完整版| 日韩中文久久| 国产成人精品久久亚洲高清不卡| 国产精品一区二区久久精品涩爱 | 狠狠色婷婷久久一区二区三区| 99久久99久久精品国产| 久久午夜伦鲁片免费无码| 亚洲人AV永久一区二区三区久久 | 亚洲精品综合久久| 国产精品岛国久久久久| 国产亚洲精久久久久久无码77777| 91精品国产综合久久香蕉| 久久国产免费观看精品3| 2020国产成人久久精品| 日韩精品无码久久一区二区三| 国产激情久久久久影院小草| 久久99精品久久久久久动态图| 亚洲乱码中文字幕久久孕妇黑人| 怡红院日本一道日本久久 | 亚洲精品无码久久千人斩| 久久无码人妻精品一区二区三区| 91精品无码久久久久久五月天| 日本欧美久久久久免费播放网| 少妇熟女久久综合网色欲| 久久久黄色大片| 午夜精品久久久久久毛片| 久久男人Av资源网站无码软件| 亚洲va久久久噜噜噜久久|