程序的天空

我的学习心得

导航

DX10 SDK 例子讲解(1)--基础

Posted on 2008-08-18 03:29  帕托  阅读(2206)  评论(1)    收藏  举报
前言

     这几年,图形技术有了巨大的发展.先是Windows Vista界面部分抛弃了古董级的GDI,将DirectX9 API作为成熟的API使用,并在用户模式层增加了DirectX9的函数功能,通过新的驱动模型(WDDM)处理和内核模式的图形处理驱动交互,这样,就有了Vista的Aero界面和更好的图形处理能力.

     不久,DirectX 10出世了,事实上DX9被Vista直接使用,Vista真正的目标是DX10,DX10比DX9有了更多的改变,说起来我能想到的包括:更强的图形处理硬件支持,取消固定流水线,统一的着色器(Shader)架构,统一的资源管理,新的几何着色器的引入,功能强大的Shader Model 4.0,和所有的和现代游戏引擎相贴近的API...

      Direct10的设计让我们好像可以摸到图形处理的每个环节一样,为了试手,打开最新的DirectX SDK,看一下DX10的例子程序.这几节,我就来概述一下这几个例子程序.

      遗憾的是,我的笔记本还不支持DX10,不过编译运行例子是足够了(当然是用参考模式),我们开始吧.

 

例子简介:(tutorial1-tutorial2)

 

1.Direct3D 10 Basics            //创建一个Direct3D程序需要的最少元素


      设置Direct3D 10设备          //要应用DX功能,先创建一个设备

 

               DXGI_SWAP_CHAIN_DESC sd;       //一个swap_chain描述符,swap_chain译过来就是"交换链"

                                                                 //把像素写到后缓存,再送到前缓存显示,前缓存又作为新的后缓存,这就是交换链
         ZeroMemory( &sd, sizeof(sd) );
         sd.BufferCount = 1;                //只有一个缓存
         sd.BufferDesc.Width = 640;
         sd.BufferDesc.Height = 480;
         sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
         sd.BufferDesc.RefreshRate.Numerator = 60;
         sd.BufferDesc.RefreshRate.Denominator = 1;
         sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;         //用途:渲染目标的输出
         sd.OutputWindow = g_hWnd;               //输出窗口
         sd.SampleDesc.Count = 1;               //过滤器,也就是Sampler
         sd.SampleDesc.Quality = 0;
         sd.Windowed = TRUE;

          //创建,成功的话我们就有了一个交换链和设备(参考模式)
         if( FAILED( D3D10CreateDeviceAndSwapChain( NULL, D3D10_DRIVER_TYPE_REFERENCE, NULL,
                     0, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice ) ) )
         {
             return FALSE;
         }

      创建渲染目标视图              //我们要渲染到哪里?

 

          // Create a render target view
         ID3D10Texture2D *pBackBuffer;               //找一块缓存作为渲染的目标

               //这块目标当然是交换链的缓存(我们的交换链只有一个缓存)
         if( FAILED( g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID*)&pBackBuffer ) ) )
             return FALSE;

               //设备把这块缓存作为我们的渲染目标视图(资源-视图模式在DX10中很常见)
         hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView );
         pBackBuffer->Release();


         if( FAILED( hr ) )
             return FALSE;

               //设备把我们得到的渲染目标视图设置到输出(注意到OM了吗?表示Output Merger,我们最终的输出阶段)
         g_pd3dDevice->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL );


      创建视口               //渲染目标视图(一般是一个矩形),我们能看到它的多大?

 

          D3D10_VIEWPORT vp;
         vp.Width = 640;               //宽,高
         vp.Height = 480;
         vp.MinDepth = 0.0f;          //深度
         vp.MaxDepth = 1.0f;
         vp.TopLeftX = 0;
         vp.TopLeftY = 0;
         g_pd3dDevice->RSSetViewports( 1, &vp );          //设置我们的视口(看到全部),RS表示Render State

      开始渲染               //齐了,我们可以往我们的渲染目标视图中画东西了

 

          void Render()
    {
        //
        // Clear the backbuffer,设备用一种指定的颜色先清空我们的渲染目标视图
        //
        float ClearColor[4] = { 0.0f, 0.125f, 0.6f, 1.0f }; // RGBA,定义一个颜色


        g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
   
        g_pSwapChain->Present( 0, 0 );          //交换链开始它的工作,把设备画好的缓存(后端缓存)送到我们的眼前(前端缓存)
    }

 

2.Rendering a Triangle                         //怎样画一个三角形?
      

      顶点排列               //要画一个三角形,需要定义三个顶点,我们定义顶点格式,排列它们,交给设备

          

     // Define the input layout,定义输入排列

     //在一般游戏引擎中,顶点有声明(Declaration),其中每个声明又包含若干个元素(Element)

     //下面的代码设置我们的顶点有一个元素,它的语义为"位置"


          D3D10_INPUT_ELEMENT_DESC layout[] =
          {
              { L"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },  
          };
     UINT numElements = sizeof(layout)/sizeof(layout[0]);

 

     // Create the input layout,创建输入排列

     //DX10中,顶点的定义无疑是我们的输入.由于Dx10去掉了固定功能流水线,我们的顶点就需要又Shader来处理

     //我们在工程中写一个fx文件做为我们的Shader

     //在现代游戏引擎中,特效Effect包括若干个Technique,Technique又包含若干个Pass,

     //每个Pass就是GPU的Shader编译的模块,用在图形处理流水线中,Techinque和Effect是多个Pass的组织方式.

     //由于我们的输入是由Pass来处理的,因此创建输入排列也需要Pass的一些信息


     D3D10_PASS_DESC PassDesc;
     g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );      //得到pass的描述符


     if( FAILED( g_pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature
             PassDesc.IAInputSignatureSize, &g_pVertexLayout ) ) )    //这两处用到了Pass信息
         return FALSE;
     // Set the input layout


     g_pd3dDevice->IASetInputLayout( g_pVertexLayout );     //设置我们的输入排列,IA表示Input Assembler

      创建顶点缓存             //顶点格式,输入排列,还需要什么?需要顶点缓存来存放我们的数据

     

      // Create vertex buffer
     SimpleVertex vertices[] =             //我们定义的三个顶点
     {
         D3DXVECTOR3( 0.0f, 0.5f, 0.5f ),      //位置
         D3DXVECTOR3( 0.5f, -0.5f, 0.5f ),
         D3DXVECTOR3( -0.5f, -0.5f, 0.5f ),
     };


     D3D10_BUFFER_DESC bd;               //缓存描述符
     bd.Usage = D3D10_USAGE_DEFAULT;
     bd.ByteWidth = sizeof( SimpleVertex ) * 3;               //缓存大小?容纳3个顶点
     bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;          //要绑定到顶点缓存
     bd.CPUAccessFlags = 0;
     bd.MiscFlags = 0;
     D3D10_SUBRESOURCE_DATA InitData;          //SubResource?子资源数据?是的,它是我们创建缓存的子资源(缓存也是资源)
     InitData.pSysMem = vertices;          //我们定义的顶点

 

       //创建顶点缓存,里面包括了我们的顶点数据
     if( FAILED( g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer ) ) )
         return FALSE;

     // Set vertex buffer,通知设备,设置设备的顶点缓存
     UINT stride = sizeof( SimpleVertex );
     UINT offset = 0;

     g_pd3dDevice->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );

      设置图元拓扑                    //图元拓扑表示我们的顶点以什么方式被渲染,点?线?三角形? 

     // Set primitive topology,三角形列表      
     g_pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );


      渲染三角形         //开始渲染

 

     // Render a triangle
     D3D10_TECHNIQUE_DESC techDesc;
     g_pTechnique->GetDesc( &techDesc );
     for( UINT p = 0; p < techDesc.Passes; ++p )        //对Technique中的每个pass
     {
         g_pTechnique->GetPassByIndex( p )->Apply(0);          //应用Pass
         g_pd3dDevice->Draw( 3, 0 );          //设备画我们的三角形(3个顶点)
     }

 

     先讲这两节,通过代码我们可以看出图形流水线处理的过程,Direct3D的内容并不算多,通过例子我们可以熟悉3D图形的一些相关概念和编程方式,看看图形硬件给我们编程带来了哪些功能.了解了这些,我们就可以学习游戏引擎了(游戏引擎在DX之上).