上一篇中介绍的DirectxApp类给整个应用搭建了一个框架,而这篇文章涉及的CubeRenderer类则是负责填充框架,呈现实际内容:一个旋转的彩色立方体。CubeRenderer类中的方法通过名称就很容易理解,但是它们之间的联系和功能实现比较复杂,而且CubeRenderer类的成员较多,涉及到DirectX的基本原理和概念,看上去无从下手。没办法,打算按照代码的顺序去看,遇到哪里不明白就去查找对应的原理。看下CubeRenderer.h头文件就转到CubeRenderer.cpp,想了解下整个绘制过程。主要研究下这个文件。首先自然是包含头文件和使用命名空间,然后是构造函数。

#include "pch.h"
#include "CubeRenderer.h"using namespace DirectX;
using namespace Microsoft::WRL;
using namespaceWindows::Foundation;
using namespaceWindows::UI::Core;CubeRenderer::CubeRenderer():m_loadingComplete(false),m_indexCount(0)
{
}

接着就是一个100多行的CreateDeviceResources方法,它实现创建设备资源的功能。CubeRenderer类继承自Direct3Dbase类,CreateDeviceResources方法首先调用基类的CreateDeviceResources方法,然后读入生成的顶点着色器和像素着色器文件。注意ReadDataAsync方法中的Async表明这是一个异步方法。

Direct3DBase::CreateDeviceResources();auto loadVSTask =DX::ReadDataAsync("SimpleVertexShader.cso");auto loadPSTask =DX::ReadDataAsync("SimplePixelShader.cso");

这里涉及到DirectX编程很重要的三个概念:顶点着色器、像素着色器和异步编程。

顶点着色器SimpleVertexShader可以看成是一个以顶点作为输入输出数据的方法,只不过这个方法会由显示硬件去执行。每个将要绘制的顶点都会通过顶点着色器,可以概念性地认为在显示硬件上执行了如下代码:

for(UINT i = 0; i <numVertices; ++i)outputVertex[i] = SimpleVertexShader(inputVertex[i]);

之所以单独提出这个着色器是因为顶点着色器方法可在GPU上运行,执行速度非常快。

像素着色器SimplePixelShader则用来渲染像素片段,它的输入是与顶点着色器的输出对应的。

异步编程简单的说就是异步方法会立即返回,但返回的不是结果,其代码会在后台运行直至结束,因此不影响其他线程的操作。不过异步操作的返回时间不确定,为保证内容的同步,需要一些控制,then方法就是其中一种。then方法包括的部分会在调用它的任务成功完成后执行,看代码时暂时把then去掉,方便理解。关于以上概念的详细介绍见附注。

auto createVSTask =loadVSTask.then([this](Platform::Array<byte>^fileData) {DX::ThrowIfFailed(m_d3dDevice->CreateVertexShader(fileData->Data,fileData->Length,nullptr,&m_vertexShader));constD3D11_INPUT_ELEMENT_DESC vertexDesc[] ={{ "POSITION", 0,DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },{ "COLOR",    0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12,D3D11_INPUT_PER_VERTEX_DATA, 0 },};DX::ThrowIfFailed(m_d3dDevice->CreateInputLayout(vertexDesc,ARRAYSIZE(vertexDesc),fileData->Data,fileData->Length,&m_inputLayout));});

以上的代码就是在载入顶点着色器成功后,依照其说明数据创建顶点着色器,之后创建输入布局InputLayout来描述顶点着色器的分量结构,让DirectX知道如何使用其中的每个分量。接着是创建像素着色器和一个来保存模型、视图和投影矩阵的常量缓冲区,代码如下:

auto createPSTask =loadPSTask.then([this](Platform::Array<byte>^fileData) {DX::ThrowIfFailed(m_d3dDevice->CreatePixelShader(fileData->Data,fileData->Length,nullptr,&m_pixelShader));CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer),D3D11_BIND_CONSTANT_BUFFER);DX::ThrowIfFailed(m_d3dDevice->CreateBuffer(&constantBufferDesc,nullptr,&m_constantBuffer));});

上面准备工作完成后,开始创建一个正方体的模型。首先定义模型的顶点。正方体有八个顶点,所以顶点数组有八个元素,包含各顶点的位置和颜色信息。

 auto createCubeTask= (createPSTask && createVSTask).then([this] () {VertexPositionColor cubeVertices[] ={{XMFLOAT3(-0.5f, -0.5f, -0.5f),XMFLOAT3(0.0f, 0.0f, 0.0f)},{XMFLOAT3(-0.5f, -0.5f,  0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f)},{XMFLOAT3(-0.5f,  0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f)},{XMFLOAT3(-0.5f,  0.5f, 0.5f), XMFLOAT3(0.0f, 1.0f, 1.0f)},{XMFLOAT3( 0.5f, -0.5f, -0.5f),XMFLOAT3(1.0f, 0.0f, 0.0f)},{XMFLOAT3( 0.5f, -0.5f,  0.5f), XMFLOAT3(1.0f, 0.0f, 1.0f)},{XMFLOAT3( 0.5f,  0.5f, -0.5f), XMFLOAT3(1.0f, 1.0f, 0.0f)},{XMFLOAT3( 0.5f,  0.5f, 0.5f), XMFLOAT3(1.0f, 1.0f, 1.0f)},};D3D11_SUBRESOURCE_DATA vertexBufferData ={0};vertexBufferData.pSysMem = cubeVertices; //指明数据存储位置vertexBufferData.SysMemPitch = 0;vertexBufferData.SysMemSlicePitch = 0;CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices),D3D11_BIND_VERTEX_BUFFER); //缓冲区格式描述DX::ThrowIfFailed(m_d3dDevice->CreateBuffer(&vertexBufferDesc,&vertexBufferData,&m_vertexBuffer));

绘制一个正方体,光有顶点还不够,DirectX不知道是要绘制一个正方体还是两个交叉的平面,所以如何连接各顶点绘制六个面需要进行说明,这个说明就由索引缓冲区完成。因为DirectX只绘制三角形,所以一个正方形面需要两个三角形拼接。

   unsigned short cubeIndices[] ={0,2,1, // -x1,2,3,4,5,6, // +x5,7,6,0,1,5, // -y0,5,4,2,6,7, // +y2,7,3,0,4,6, // -z0,6,2,1,3,7, // +z1,7,5,};m_indexCount = ARRAYSIZE(cubeIndices);D3D11_SUBRESOURCE_DATA indexBufferData ={0};indexBufferData.pSysMem = cubeIndices;indexBufferData.SysMemPitch = 0;indexBufferData.SysMemSlicePitch = 0;CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices),D3D11_BIND_INDEX_BUFFER);DX::ThrowIfFailed(m_d3dDevice->CreateBuffer(&indexBufferDesc,&indexBufferData,&m_indexBuffer));});createCubeTask.then([this] () {m_loadingComplete = true;});
}

完成这些工作后,资源创建完成,进入下一阶段的处理。

附注:

关于顶点着色器和像素着色器可以参考博文

C++Directx11开发笔记四:着色器之顶点着色器和像素着色器

更详细的介绍可以看《Directx 10 3D游戏编程入门》的第5章

游戏编程入门系列最新的是介绍DirectX 11,可惜是英文版,刚接触有些概念理解不好。这本书虽然介绍的是DirectX10,但是它和DirectX 11的许多内容是相通的,可以参考。我并没有找到这本书的印刷版,好像没有正式出版,只能在此对译者汤毅表示感谢,如果有一天这本书正式出版,一定买一本支持。

异步编程推荐

使用 C++ 异步编程(Metro 风格应用)

2012.11.26更新:

顶点着色器文件SimpleVertexShader.cso和像素着色器文件SimplePixelShader.cso是由SimpleVertexShader.hlsl和SimplePixelShader.hlsl编译而成,在GPU上运行。在Direct3D 11中,GPU必须包含一个正确的顶点和像素着色器。这里不做任何更改,保持默认。感谢liuwumiyuhuiping提出的问题。

Windows 8 Directx 开发学习笔记(二)建立模型及初始化设备相关推荐

  1. Windows 8 Directx开发学习笔记(一)应用基本框架

    Windows 8系统10月25日就要正式发布,其应用可与Windows Phone 8应用兼容,所以打算转到Windows 8系列的开发.之前虽然开发过应用,但对游戏开发更感兴趣,随意开始学习Met ...

  2. Windows 8 Directx 开发学习笔记(十一)地形纹理贴图

    前一篇实现木箱贴图时,木箱的六个面都正好用一整张纹理图,即六个面的纹理坐标均在[0,1]内.然而在为比较大的模型贴图时,像山峰河谷模型,如果只用一张纹理图,那么每个三角形只得到几个纹理元素,无法为提供 ...

  3. Windows 8 Directx 开发学习笔记(十二)利用混合实现浮在水面的木箱

    在场景中绘制多个不透明物体时很简单,哪个物体离得近,看到的就是哪个物体.但如果加入一个透明的物体,像玻璃,如何渲染就有些麻烦.拿一块红色的玻璃挡住眼睛,看到的物体都偏红,换成蓝色的玻璃,物体都偏蓝.D ...

  4. Windows 8 Directx 开发学习笔记(七)水波纹的实现

    使用DirectX实际开发中,模型的形状不可能都是一成不变,只依靠移动摄像机去实现动画.这里用实时更新顶点缓冲的方式生成一个水波模型,最终效果类似向水面扔石子时出现的水波纹.有了上一篇建立好的模型,实 ...

  5. Windows 8 DirectX 开发学习笔记(十六)使用Terragen生成自然环境贴图

    DirectX 游戏编程入门中提到一个Terragen软件可以生成环境贴图,所以登陆它的官方网站看了下.没想到Terragen生成的图片和照片一样,效果非常好,很多电影里有用到,所以下载免费版尝试一下 ...

  6. Windows 8 DirectX 开发学习笔记(十五)使用Billboard实现树木贴图

    要使用DirectX来获得三维效果,一般首先要生成一个三维模型,然后计算它在可视空间中的投影.这样得到的二维图像十分真实,但是计算量也很大.在大规模场景渲染中,随着模型精度的提高,这样的处理方式十分消 ...

  7. Windows 8 Directx 开发学习笔记(十四)使用几何着色器实现三角形细分

    几何着色器是从DirectX 10才引入的着色器,是一个可选阶段,位于顶点着色器和像素着色器阶段之间.顶点着色器以顶点作为输入数据,而几何着色器以完整的图元作为输入数据,像点.直线.三角形等.之所以引 ...

  8. Windows 8 Directx 开发学习笔记(十三)利用模板实现木箱镜像

    假设墙上有一面镜子,镜子前面有个木箱.如果观察角度合适,整个木箱镜像都会在镜子里,计算起来还比较简单:而变换个角度,木箱的镜像可能只有一部分在镜子里,这时单纯依靠计算来实现就很麻烦.DirectX提供 ...

  9. Windows 8 Directx 开发学习笔记(十)纹理贴图实现旋转的木箱

    纹理贴图映射(texturemapping)是可以显著提高场景细节和真实感的一种技术,基本原理是将图像数据映射到3D三角形表面(之前的文章提到过,三维模型其实是由很多个三角形拼接而成).当使用纹理资源 ...

最新文章

  1. 【转】推荐给初级Java程序员的3本进阶书
  2. android oom 全解析
  3. java垃圾回收根对象_Java垃圾回收怎么理解?
  4. python相同key合并value_python之入门
  5. mysql enum_MySQL数据库中关于ENUM类型的详细解释
  6. Linux多线程开发-线程同步-读写锁pthread_rwlock_t
  7. Linux下jdk配置环境变量
  8. pivotx的entry和page内容里的日期格式修改
  9. html网页毕业论文,HTML网页设计毕业论文.pdf
  10. 网站无法打开显示阻断页面的解决方法
  11. 修复pdf字体嵌入问题
  12. html计算梯形的面积,梯形的面积计算
  13. 学习单片机必须要学的八大知识点,你知道吗?
  14. CTP接口开发案例(内附源码)
  15. 推荐计算机 在线使用方法,在线记笔记平台推荐:如何优雅地用电脑记笔记
  16. 编程实现linux中的who命令功能,Linux who命令简介及使用方法详解
  17. ildasm + ilasm + ilmerge 小试牛刀
  18. apicloud 不干胶标签打印模块及开发
  19. 生产者消费者模式解决强耦合问题
  20. 山东省第五届省赛题C Colorful Cupcakes(五维数组+记忆化搜索)

热门文章

  1. dubbo几种协议_Dubbo面试(简)
  2. kotlin 添加第一个 集合_kotlin 集合的操作
  3. 前端 鼠标一次移动半个像素_今天来说说鼠标的DPI该怎么设置
  4. python基础笔记_python基础笔记
  5. 251f与ips屏显示器对比_8百左右预算,2020年PS平面设计/摄影后期显示器推荐/选购指南(全高清+高色域屏)...
  6. 判断一个整数的奇偶性php,【算法】- 判断一个整数是否是奇数
  7. unity已存在,您无法加载相同的版本
  8. 超详细 | 接口自动化测试总结与分享入门篇
  9. 派尼数据库连接池配置
  10. Intellij IDEA 识别不了@Slf4j和log的问题