两天学会DirectX 3D

环境配置以及背景知识

环境
Windows 8.1 64bit
VS2013
Microsoft DirectX SDK (June 2010)
NVDIA Geforce GT755

环境的配置参考VS2008整合DirectX9.0开发环境


一些背景知识

DirectX的和应用层与硬件层的关系如下

REF设备允许开发人员测试那些Direct3D提供了但未被图形设备所实现的功能。

COM(Component Object Model)是一项可使DirectX独立于编程语言,并具备向下兼容的技术。基本思想是将大而复杂的应用软件分为一系列的可现行实现,易于开发,理解复用和调整的软件单元。

COM组件是遵循COM规范编写,以Win32动态链接库(dll)或者可执行文件形式发布的可执行二进制代码(exe)。

COM的优点:

  • 与开发语言无关
  • 通过接口有效保证了组件的复用性
  • 组件运行效率高,便于使用和管理

下面可以正式开始今天的学习了。

绘制一个三角形

用到的DxUtility类在VS2008整合DirectX9.0开发环境已经实现了,可以直接去看。主要修改一下渲染的几个函数。

#include "dxutility.h"
#include <windows.h>
#include <iostream>

//
// Globals
//

IDirect3DDevice9* Device = 0;
D3DXMATRIX World;
IDirect3DVertexBuffer9 * VB = 0;

const int Width = 800;
const int Height = 600;

struct Vertex{
    Vertex(){};
    Vertex(float _x, float _y, float _z)
    {
        x = _x;
        y = _y;
        z = _z;
    }

    float x, y, z;
    static const DWORD FVF;
};

const DWORD Vertex::FVF = D3DFVF_XYZ;

//
// Framework Functions
//

bool Setup()
{
    Device->CreateVertexBuffer(
        3 * sizeof(Vertex),
        D3DUSAGE_WRITEONLY,
        Vertex::FVF,
        D3DPOOL_MANAGED,
        &VB,
        0);

    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();

    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(
        &proj,                        // result
        D3DX_PI * 0.5f,               // 90 - degrees
        (float)Width / (float)Height, // aspect ratio
        1.0f,                         // near plane
        1000.0f);                     // far plane
    Device->SetTransform(D3DTS_PROJECTION, &proj);

    Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

    return true;
}

void Cleanup()
{
    Dx::Release<IDirect3DVertexBuffer9*>(VB);
}

bool Display(float timeDelta)
{
    if (Device) // Only use Device methods if we have a valid device.
    {
        Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
        Device->BeginScene();

        Device->SetStreamSource(0, VB, 0, sizeof(Vertex));
        Device->SetFVF(Vertex::FVF);

        // Draw one triangle.
        Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

        Device->EndScene();
        Device->Present(0, 0, 0, 0);
    }

    return true;
}

//
// WndProc
//
LRESULT CALLBACK Dx::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY:
        ::PostQuitMessage(0);
        break;

    case WM_KEYDOWN:
        if (wParam == VK_ESCAPE)
            ::DestroyWindow(hwnd);
        break;
    }
    return ::DefWindowProc(hwnd, msg, wParam, lParam);
}

//
// WinMain
//
int WINAPI WinMain(HINSTANCE hinstance,
    HINSTANCE prevInstance,
    PSTR cmdLine,
    int showCmd)
{
    if (!Dx::InitDx(hinstance,
        Width, Height, true, D3DDEVTYPE_HAL, &Device))
    {
        ::MessageBox(0, "InitD3D() - FAILED", 0, 0);
        return 0;
    }

    if (!Setup())
    {
        ::MessageBox(0, "Setup() - FAILED", 0, 0);
        return 0;
    }
    Dx::EnterMsgLoop(Display);

    Cleanup();

    Device->Release();

    return 0;
}

最终效果

给三角形加上颜色
数据结构定义


struct ColorVertex{
    ColorVertex(float _x, float _y, float _z, D3DCOLOR c)
    {
        x = _x;
        y = _y;
        z = _z;
        color = c;
    }
    float x, y, z;
    D3DCOLOR color;
    static const DWORD FVF;
};
const DWORD ColorVertex::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;

创建Buffer

    Device->CreateVertexBuffer(
        3 * sizeof(ColorVertex),
        D3DUSAGE_WRITEONLY,
        ColorVertex::FVF,
        D3DPOOL_MANAGED,
        &VB,
        0);

    ColorVertex *v;
    VB->Lock(0, 0, (void**)&v, 0);
    v[0] = ColorVertex(-1.0f, 0.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0));
    v[1] = ColorVertex(0.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(0, 255, 0));
    v[2] = ColorVertex(1.0f, 0.0f, 2.0f, D3DCOLOR_XRGB(0, 0, 255));

    VB->Unlock();

在绘制函数中设置使用Ground插值进行三角形绘制

bool Display(float timeDelta)
{
    if (Device) // Only use Device methods if we have a valid device.
    {
        std::cout << "Display" << std::endl;
        Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
        Device->BeginScene();

        Device->SetStreamSource(0, VB, 0, sizeof(ColorVertex));
        Device->SetFVF(ColorVertex::FVF);

        Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
        Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

        Device->EndScene();
        Device->Present(0, 0, 0, 0);
    }

    return true;
}

渲染结果

绘制一个旋转的正方体

生成Vertex Buffer和Index Buffer

    Device->CreateVertexBuffer(
        8 * sizeof(ColorVertex),
        D3DUSAGE_WRITEONLY,
        ColorVertex::FVF,
        D3DPOOL_MANAGED,
        &VB,
        0);
    Device->CreateIndexBuffer(
        36 * sizeof(WORD),
        D3DUSAGE_WRITEONLY,
        D3DFMT_INDEX16,
        D3DPOOL_MANAGED,
        &IB,
        0);

    ColorVertex *v;
    VB->Lock(0, 0, (void**)&v, 0);
    v[0] = ColorVertex(-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255, 0, 0));
    v[1] = ColorVertex(-1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0, 255, 0));
    v[2] = ColorVertex(1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0, 0, 255));
    v[3] = ColorVertex(1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255, 255, 0));
    v[4] = ColorVertex(-1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0));
    v[5] = ColorVertex(-1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255));
    v[6] = ColorVertex(1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 255));
    v[7] = ColorVertex(1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0));

    VB->Unlock();

    WORD* indices = 0;
    IB->Lock(0, 0, (void**)&indices, 0);
    // front side
    indices[0] = 0; indices[1] = 1; indices[2] = 2;
    indices[3] = 0; indices[4] = 2; indices[5] = 3;

    // back side
    indices[6] = 4; indices[7] = 6; indices[8] = 5;
    indices[9] = 4; indices[10] = 7; indices[11] = 6;

    // left side
    indices[12] = 4; indices[13] = 5; indices[14] = 1;
    indices[15] = 4; indices[16] = 1; indices[17] = 0;

    // right side
    indices[18] = 3; indices[19] = 2; indices[20] = 6;
    indices[21] = 3; indices[22] = 6; indices[23] = 7;

    // top
    indices[24] = 1; indices[25] = 5; indices[26] = 6;
    indices[27] = 1; indices[28] = 6; indices[29] = 2;

    // bottom
    indices[30] = 4; indices[31] = 0; indices[32] = 3;
    indices[33] = 4; indices[34] = 3; indices[35] = 7;

    IB->Unlock();

绘制函数,让正方体旋转起来

//
        // spin the cube:
        //
        D3DXMATRIX Rx, Ry;

        // rotate 45 degrees on x-axis
        D3DXMatrixRotationX(&Rx, 3.14f / 4.0f);

        // incremement y-rotation angle each frame
        static float y = 0.0f;
        D3DXMatrixRotationY(&Ry, y);
        y += timeDelta;

        // reset angle to zero when angle reaches 2*PI
        if (y >= 6.28f)
            y = 0.0f;

        // combine x- and y-axis rotation transformations.
        D3DXMATRIX p = Rx * Ry;

        Device->SetTransform(D3DTS_WORLD, &p);

        Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
        Device->BeginScene();

        Device->SetStreamSource(0, VB, 0, sizeof(ColorVertex));
        Device->SetIndices(IB);
        Device->SetFVF(ColorVertex::FVF);

        Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);

        Device->EndScene();
        Device->Present(0, 0, 0, 0);


在屏幕上显示FPS信息
首先初始化文字

    D3DXFONT_DESC d3dFont;

    memset(&d3dFont, 0, sizeof(d3dFont));
    d3dFont.Height = 25; // in logical units
    d3dFont.Width = 12; // in logical units
    d3dFont.Weight = 500;// boldness, range 0(light) - 1000(bold)
    d3dFont.Italic = FALSE;
    d3dFont.CharSet = DEFAULT_CHARSET;
    strcpy_s(d3dFont.FaceName, "Times New Roman");
    if (FAILED(D3DXCreateFontIndirect(Device, &d3dFont, &font)))
    {
        ::MessageBox(0, "D3DXCreateFontIndirect() - FAILED", 0, 0);
        ::PostQuitMessage(0);
    }

声明几个变量

ID3DXFont* font = 0;
DWORD FrameCnt = 0;
float TimeElapsed = 0;
float FPS = 0;
char FPSString[16];

FPS的计算

FrameCnt++;
TimeElapsed += timeDelta;
if (TimeElapsed >= 1.0f)
{
    FPS = (float)FrameCnt / TimeElapsed;
    sprintf_s(FPSString, "FPS:%f", FPS);
    FPSString[15] = ‘\0‘; // mark end of string
    TimeElapsed = 0.0f;
    FrameCnt = 0;
}

文字的渲染

Device->BeginScene();
RECT rect = { 0, 0, Width, Height };
font->DrawText(
    m_pSprite,
    FPSString,
    -1, // size of string or -1 indicates null terminating string
    &rect, // rectangle text is to be formatted to in windows coords
    DT_TOP | DT_LEFT, // draw in the top left corner of the viewport
    0xff000000);      // black text

Device->EndScene();

记住最后要Clear掉COM对象

void Cleanup()
{
    Dx::Release<IDirect3DVertexBuffer9*>(VB);
    Dx::Release<IDirect3DIndexBuffer9*>(IB);
    Dx::Release<ID3DXFont*>(font);
}

运行结果

参考

Introduction to 3D Game Programming with DirectX® 9.0

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

时间: 2024-08-07 15:16:23

两天学会DirectX 3D的相关文章

两天学会DirectX 3D之第二天

提要 前几天很简单地跑了一个DirectX 9 程序,以为DirectX就那么绘制,事实证明有点Naive了. 之前的那个程序最多也就是个固定流水线的东西.但是今天要用DirectX11来写一个小的框架. 龙书就不要看了,看Introduction to 3D GAME PROGRAMMING WITH DIRECTX®11 几个重要的类 ID3D11Device : 一个虚拟适配器:它被用于运行渲染和创建资源. ID3D11DeviceContext:  represents a device

两分钟学会Unity3D布娃娃的使用

在RPG游戏中,为了让人物的死亡更加真实,unity创建布娃娃系统,搞的跟真的一样,尼玛我差点就相信那是真的了. 1.首先打开unity,创建地形,导入已经准备好的人物模块. 2.project下选中该模型,再为该模型添加布娃娃属性:GameObject->Create Other->RagDoll 3.在弹出的框中将布娃娃的各个结点设置进去 4.一定要去掉该人物的Box Collider属性,运行程序,就可以看到人物的死亡效果啦. 两分钟学会Unity3D布娃娃的使用,布布扣,bubuko.

两分钟学会Android平台NDK编程(无须Eclipse和cygwin,可使用命令行打包多个so)

之前在进行cocos2dx开发时,已经详细介绍了如何将win32的c++代码移植到Android平台,当再次回顾时,发现一些基础的东西理解并不是很彻底,今天使用Android NDK提供的一个例子做一个简单的移植.在进行该demo前,请确认你已经配置了Android开发环境和安装了最新的Android NDK. 1.创建Android项目 创建一个Android项目 , 包名是com.example.hellojni,创建一个Activity作为程序进入的Acitivity,命名为HelloJn

两周“学会”bootstrap搭建一个移动站点

一直想着用bootstrap搭建网站,它的自适应.元素封装完善.现成的Glyphicons字体图标,省去很多的css.js.ui的工作,可以快速搭建一个客户需要的站点.ytkah自己有一些div+css的基础知识,所以上手bootstrap相对会比较快一些,从入手到完成项目只用了两周“学会”bootstrap搭建一个企业站,中间还有其他的一些事需要处理.当然做得比较粗糙,效果图在文章尾部. 国内的企业站一般都喜欢这样的版式:头部导航.幻灯片banner.次导航.文章列表.tag标签.转化引导.主

最近找到了一个免费的python教程,两周学会了python开发【内附学习视频】

原文链接:https://blog.csdn.net/weixin_41052734/article/details/86528541 最近找到了一个免费的python教程,两周学会了python开发.推荐给大家,希望召集更多的朋友一起学习python. 最近开始整理python的资料,博主建立了一个qq群,希望给大家提供一个交流的同平台: 78486745 ,欢迎大家加入共同交流学习. 本套教程学习时间15天 第一阶段(1-8天) 该阶段我们正式进入Python这门语言的学习,首先通过了解Py

【公众号系列】两分钟学会SAP F1技巧

公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[公众号系列]两分钟学会SAP F1技巧 写在前面 这是以前写的一篇文章,但这个技巧可能有些人还是不太会用,拿出来和大家分享一下.做SAP系统的朋友应该都会和IMG打交道,无论是技术顾问还是业务顾问,F1是必备技能之一,有效的利用系统提供的方法,会减少很多麻烦,也会提高工作效率.还有一篇相关性技巧的文章,请在文末查看推荐阅读. 今天来简单说一个F

DirectX 3D 之C#开发

C#下进行directX的3D开发,一个旋转的4棱锥的例子. 建议看两个文档<Managed DirectX 9图形和游戏编程简略中文文档>和<Managed DirectX 9 SDK 中文文档>. 另外最好下载个DirectX SDK (August 2007).rar.里面有些范例还是非常好的. 一.首先在电脑上装了DirectX. 二.建立一个C#的Windows应用程序,添加两个引用Microsoft.DirectX和Microsoft.DirectX.Direct3D;

两天学会css基础(二)

接上一篇博客,还有css中的两个重要知识点没有说到,就是元素的浮动与定位. 第三部分:元素的浮动与清除 这部分的内容之前的博客已总结过.请查看css中的浮动与三种清除浮动的方法这篇文章. 浮动在网页中也用的和普遍,特别要注意清除浮动的方法. 第四部分:元素的定位 元素的定位在实际开发中会经常用到,特别是涉及到精确定位的时候. 默认情况下元素的position属性值为static static: 对象遵循常规流.此时4个定位偏移属性不会被应用. relative: 对象遵循常规流,并且参照自身在常

DirectX 3d 取景变换

在世界坐标系中,几何体和摄像机都是相对于世界坐标系定义的.但是当摄像机的位置和朝向任意时,投影变换及其它类型的变的就略显困难或效率不高.为了简化运算,我们将摄像机变的至世界坐标系原点,并将其旋转,使摄像机的光轴与世界坐标系z轴正方向一致.同时,世界空间中的所有几何几都随着摄像机一同进行变换,以保证摄像机视声恒定.这种变换称之为取景变换(view space transformation),我们称变换后的几何体位于观察坐标系中(view space). 假定摄像机位于(5,3,-10),其观察点为