【DirecX 教程】Lesson 8:渲染帧

本文介绍 Direct3D 的基本渲染流程,包括如何配置渲染目标、设置视口及渲染单帧等内容。通过实例演示了如何创建空白帧,并详细解释了相关函数的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



Lesson 8:渲染帧

课程一览

Direct3D一旦初始化就该做一些实际的渲染了。渲染本身很简单,但是需要一点准备工作。这节课我么会配置好每件事情以备一遍又一遍地渲染一个空白帧。

相关设置很简单。有两个东西要做。首先,我们需要告诉GPU在内存的哪里创建最终图像(对与我们,它是个空白缓冲)。第二,我们需要告诉GPU我们需要在后台缓冲的哪里绘图。

设置渲染目标

让我们从渲染到哪里开始。逻辑上你会说,“废话,当然是后台缓冲!”。但是事实上Direct3D此时并不知道。可能你不希望立刻渲染到后台缓冲。例如很多游戏是渲染到模型表面再渲染模型到后台缓冲。这个技术可以产生很多特效。如果你玩过Portal(传送门)这个游戏,你会看到一个这方面的例子。在Portal中,游戏引擎首先渲染传送门,然后以传送门图像渲染完整场景。

当在Direct3D中渲染的时候,你必须建立渲染目标。这是个简单的COM对象,它包含了你要渲染到显存的位置。大多数情况下这个位置就是后台缓冲。

下面是我们的做法:

ID3D11RenderTargetView *backbuffer;    // global declaration

// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{
    // Direct3D initialization
    // ...

    // get the address of the back buffer
    ID3D11Texture2D *pBackBuffer;
    swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

    // use the back buffer address to create the render target
    dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
    pBackBuffer->Release();

    // set the render target as the back buffer
    devcon->OMSetRenderTargets(1, &backbuffer, NULL);
}

这里我们做了3件事情。第一,确定后台缓冲的地址。第二,创建COM对象代表渲染目标。第三,设置该对象为活动渲染目标。

ID3D11RenderTargetView *backbuffer;

这个变量是个指向包含有渲染目标信息的对象的指针。

ID3D11Texture2D *pBackBuffer;

在3D渲染中,纹理是图片的另一个名字。一个ID3D11Texture2D是一个存储了平面图像的对象。像任何COM对象一样,我们首先定义指针,然后用函数创建对象。

swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

你肯定不相信我,但是这个命令真的好简单。GetBuffer()函数做的就是找到交换链中的后台缓冲并用它创建pBackBuffer纹理对象。

第一个参数是获得的后台缓冲个数。我们仅用一个后台缓冲#0。所以第一个参数值是0.

第二个参数是一个标识ID3D11Texture2D COM对象的数字。每种类型的COM对象都有它自己的ID,用来获得关于对象的信息。为了得到这个ID,我们必须使用_uuidof运算符。我们这样做的原因是GetBuffer()函数知道它应该创建什么类型的对象。

第三个参数,void*是个指向没有特定类型的指针,可以指向任何东西。它可以转换成任意其它的指针类型。

dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);

这个函数创建渲染目标对象。

第一个参数是个指向纹理的指针。在我们的程序中它是‘pBacjBuffer’。

第二个参数是一个描述渲染目标的结构。我们不需要填充它,给个NULL就好。

第三个参数是对象指针的地址。指针名是‘backbuffer’,所以我么用‘&backbuffer’。

pBackBuffer->Release();

这个Release()函数释放所有的内存并关闭使用COM对象的线程。注意它并不销毁后台缓冲,它仅关闭我们曾访问的纹理对象。

devcon->OMSetRenderTargets(1, &backbuffer, NULL);

上面的函数实际上用来设置渲染目标。更确切的说它设置多渲染目标。

第一个参数是要设置的渲染目标数量。通常是1。

第二个参数是个指针指向渲染目标视图对象。我们只用一个所以仅是渲染目标对象(&backbuffer)的地址。

第三个参数很高级,我们稍后再讨论,现在先设置为NULL。

这部分代码复杂而重要,确定你已经弄清楚了,以便后边的Direct3D编程中多次对它进行使用和修改。

设置视口

一个视口是把像素坐标转换为标准化坐标。下面的图显示了两者的不同。

单词normalized含义是适配一个值直到它等价1.

-1,-1和1,1实际等价于什么由视口决定。视口是使我们在像素坐标中在哪里设置-1,-1和1,1的结构。

设置视口的代码如下:

// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{
    // Direct3D initialization
    // ...

    // Set the render target
    // ...

    // Set the viewport
    D3D11_VIEWPORT viewport;
    ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = 800;
    viewport.Height = 600;

    devcon->RSSetViewports(1, &viewport);
}

需要解释的可能只有最后一行。

RSSetViewports()是激活视口结构的函数。第一个参数是使用的视口数量,第二个参数是指向视口结构指针列表的地址。

在某些高级情况下使用多视口会很方便,但是我们现在用1和‘&viewport’就已经适合参数了。

渲染帧

接下里创建一个窗口渲染一个单帧,这个帧只有一个蓝色背景。当然你可以改变成你想要的颜色。

// this is the function used to render a single frame
void RenderFrame(void)
{
    // clear the back buffer to a deep blue
    devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));

    // do 3D rendering on the back buffer here

    // switch the back buffer and the front buffer
    swapchain->Present(0, 0);
}

Nice!让我们讨论一下它们做了什么。

devcon->ClearRenderTargetView()

这个指令用一个特定的颜色填充渲染目标缓冲。在我们的程序中目标是后台缓冲。它很简单,有两个参数。

第一个是渲染目标对象地址,这里是‘backbuffer’

第二个参数是你想用来填充后台缓冲的颜色。为了做到这点,我们用一个简单的叫做D3DXCOLOR结构。四个构造函数参数用于构建的颜色(红色、绿色、蓝色值和透明值)。

swapchain->Present()

这个函数出现在所有的东西都绘制到后台缓冲后。它的工作主要是在交换链中执行‘交换’,这样后台缓冲就变成了前台缓冲。

这两个参数都设置为0,因为在课程中并不会用到。

Obligatory Cleanup

上节课我们通过释放每个被创建的COM对象关闭Direct3D。大多数COM对象都有Release()函数,在我们完成后就要调用它们。渲染目标对象也不例外。

// this is the function that cleans up Direct3D and COM
void CleanD3D()
{
    // close and release all existing COM objects
    swapchain->Release();
    backbuffer->Release();
    dev->Release();
    devcon->Release();
}

完成项目

极好的!我们已经使Direct3D运行了并得到一个简单的渲染到窗口的空白帧。我们进步很大。

下面是Main.cpp代码,我们会得到一个蓝色窗口!




Ready...Set...

问题

1.渲染目标是啥?什么函数可以创建渲染目标?

2.哪两个函数渲染了空白的蓝色帧?这些函数具体做了些什么?

3.什么是标准化坐标(normalized coordinates)?

练习

1.看你能在程序运行的时候改变颜色。使它从蓝色淡出为黑色。

2.改变视口看发生了什么。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值