之前一篇文章讲了如何初始化DirectX 11,现在在此基础上绘制一个Cube,总体可概括为以下几个步骤:

  1. 定义Cube顶点数据结构
  2. 创建Vertex Buffer和Index Buffer
  3. 编写应用于Cube的effect file
  4. 读取effect,编译创建
  5. 根据顶点数据结构,创建input layout,将顶点与effect中VS的input signature关联
  6. 开始绘制,clear掉render target view和depth stencil view
  7. 设置若干IA参数,input layout,primitive toplogy,vertex buffer,index buffer
  8. 将一些必要参数设置给effect的cbuffer中,如worldViewProjMatrix
  9. 将effect的每个pass依次apply到context中,进行绘制
  10. 绘制提交,结束绘制

定义Cube顶点数据结构

当前只需要顶点的position和color属性,position是三维向量,color是四维向量,定义如下:

	struct Vertex
{
XMFLOAT3 position;
XMFLOAT4 color;
};

这里用的是DirectXmath.h中的XMFLOAT3XMFLOAT4,也可以用自定义的向量类。

创建Vertex Buffer和Index Buffer

HRESULT CreateBuffer(
const D3D11_BUFFER_DESC *pDesc,
const D3D11_SUBRESOURCE_DATA *pInitialData,
ID3D11Buffer **ppBuffer
);

主要用到的是ID3D11Device::CreateBuffer这一函数。其中,pDesc主要设置要创建的buffer大小,用途,是否cpu可访问等等,D3D11_BIND_VERTEX_BUFFER用于创建vertex buffer,D3D11_BIND_INDEX_BUFFER用于创建index buffer;pInitialData存放的是初始化数据。

编写应用于Cube的effect file

这个effect效果很简单,就是将Cube变换到正确的屏幕空间位置,设置为插值后的颜色。大致包括的内容如下:

cbuffer cbPerObject
{
float4x4 gWorldViewProj;
}; struct VertexIn
{
float3 posL : POSITION;
float4 color : COLOR;
}; struct VertexOut
{
float4 posH : SV_POSITION;
float4 color : COLOR;
}; VertexOut VS(VertexIn vIn)
{
VertexOut vOut;
vOut.posH = mul(float4(vIn.posL, 1.0f), gWorldViewProj);
vOut.color = vIn.color; return vOut;
} float4 PS(VertexOut pIn) : SV_TARGET
{
return pIn.color;
} technique11 ColorTech
{
pass P0
{
SetVertexShader(CompileShader(vs_5_0, VS()));
SetPixelShader(CompileShader(ps_5_0, PS()));
}
}

cBuffer存放的是要从外部读取的数据,这里就是个MVP矩阵了。

读取effect,编译创建

HRESULT D3DX11CompileFromFile(
_In_ LPCTSTR pSrcFile,
_In_ const D3D10_SHADER_MACRO *pDefines,
_In_ LPD3D10INCLUDE pInclude,
_In_ LPCSTR pFunctionName,
_In_ LPCSTR pProfile,
_In_ UINT Flags1,
_In_ UINT Flags2,
_In_ ID3DX11ThreadPump *pPump,
_Out_ ID3D10Blob **ppShader,
_Out_ ID3D10Blob **ppErrorMsgs,
_Out_ HRESULT *pHResult
);

这里,我们要编译整个effect而不是某个shader,因而将pFunctionName设置为nullptr。得到编译后的effect后:

HRESULT D3DX11CreateEffectFromMemory(
void *pData,
SIZE_T DataLength,
UINT FXFlags,
ID3D11Device *pDevice,
ID3DX11Effect **ppEffect
);

effect创建完成。

创建input layout

input layout将定义的顶点结构与effect中VS的input结构关联,为VS中的input指定输入来源。

HRESULT CreateInputLayout(
const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs,
UINT NumElements,
const void *pShaderBytecodeWithInputSignature,
SIZE_T BytecodeLength,
ID3D11InputLayout **ppInputLayout
);

pInputElementDescs可以被当作是两者关联的桥梁,现在顶点只有positioncolor两个属性,pInputElementDescs定义如下:

D3D11_INPUT_ELEMENT_DESC VertexDesc[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
};

D3D11_APPEND_ALIGNED_ELEMENT这个宏省去了自己计算每个分量偏移的麻烦。

绘制

首先,清空back buffer和depth/stencil buffer;

void ClearRenderTargetView(
ID3D11RenderTargetView *pRenderTargetView,
const FLOAT [4] ColorRGBA
);
void ClearDepthStencilView(
ID3D11DepthStencilView *pDepthStencilView,
UINT ClearFlags,
FLOAT Depth,
UINT8 Stencil
);

接下来,设置若干IA参数,这里我们需要的就是input layout关联,绘制基本primitive的类型,还有设置vertex buffer和index buffer。

void IASetInputLayout(
ID3D11InputLayout *pInputLayout
);
void IASetPrimitiveTopology(
D3D11_PRIMITIVE_TOPOLOGY Topology
);
void IASetVertexBuffers(
UINT StartSlot,
UINT NumBuffers,
ID3D11Buffer * const *ppVertexBuffers,
const UINT *pStrides,
const UINT *pOffsets
);
void IASetIndexBuffer(
ID3D11Buffer *pIndexBuffer,
DXGI_FORMAT Format,
UINT Offset
);

值得一提的是,vertex buffer可以存在多个,index buffer只能存在一个。不同的vertex buffer会分配到不同的input slots中去,这里只用到了一个vertex buffer,暂时不考虑多个input slots的情况。

在effect渲染之前,往往存在需要设置一些参数给effect的情况,比如我们这个例子,就需要把MVP矩阵传给effect:

		XMMATRIX worldViewProj = world * view * proj;
shaderMVP->SetMatrix(reinterpret_cast<float*>(&worldViewProj));

然后就到了正式的绘制阶段,将effect的每个pass依次apply到context中,进行绘制:

		D3DX11_TECHNIQUE_DESC techDesc;
shaderTech->GetDesc(&techDesc);
for (UINT i = 0; i < techDesc.Passes; ++i)
{
shaderTech->GetPassByIndex(i)->Apply(0, mD3dImmediateContext);
mD3dImmediateContext->DrawIndexed(36, 0, 0);
}

一个Cube有6个面,描述一个面需要6个index,所以总共是36个index。

最后不要忘记将绘制内容提交:

mSwapChain->Present(0, 0);

运行效果如图:

用DirectX 11绘制一个Cube的更多相关文章

  1. 用DirectX12绘制一个Cube

    之前一篇文章讲了DirectX12的初始化流程,现在来看看在此基础上如何绘制一个Cube. 首先,我们要为这个Cube准备一个shader,来告诉GPU绘制的具体流程,DirectX中的shader使 ...

  2. Unity3d修炼之路:用Mesh绘制一个Cube

    #pragma strict function Awake(){ var pMeshFilter : MeshFilter = gameObject.AddComponent(typeof(MeshF ...

  3. DX11 Without DirectX SDK--03 渲染一个立方体

    回到 DirectX11--使用Windows SDK来进行开发 一个立方体有8个顶点,然而绘制一个立方体需要画12个三角形,如果按照前面的方法绘制的话,则需要提供36个顶点,而且这里面的顶点数据会重 ...

  4. {转自MC}NVIDIA DirectX 11演示DEMO详解

    http://tieba.baidu.com/p/1960826986 图形技术无论如何发展,最终都要落到实际的应用中才有效果.在个人电脑上,图形技术最大的用户除了显示UI和操作界面外,就是呈现美轮美 ...

  5. DirectX 文本绘制

    在Direct中进行文本绘制,可以通过Win32程序框架实现,也可以通过DXUT进行绘制. 基于第一篇的Win32框架入门实现非常简单,只需要添加数行代码即可.主要说需要修改的地方. #pragma  ...

  6. Introduction to 3D Game Programming with DirectX 11 翻译--开篇

    Direct3D 11简介 Direct3D 11是一个渲染库,用于在Windows平台上使用现代图形硬件编写高性能3D图形应用程序.Direct3D是一个windows底层库,因为它的应用程序编程接 ...

  7. CAD绘制一个单行文字(com接口VB语言)

    主要用到函数说明: _DMxDrawX::DrawText 绘制一个单行文字.详细说明如下: 参数 说明 DOUBLE dPosX >文字的位置的X坐标 DOUBLE dPosY 文字的位置的Y ...

  8. CAD绘制一个对齐标注(com接口VB语言)

    主要用到函数说明: _DMxDrawX::DrawDimAligned 绘制一个对齐标注.详细说明如下: 参数 说明 DOUBLE dExtLine1PointX 第一条界线开始点X值 DOUBLE ...

  9. CAD绘制一个角度标注(com接口VB语言)

    主要用到函数说明: _DMxDrawX::DrawDimAngular 绘制一个角度标注.详细说明如下: 参数 说明 DOUBLE dAngleVertexX 角度标注的顶点的X值 DOUBLE dA ...

随机推荐

  1. 移动端调试Web页面

    移动端调试Web页面 虽然可以在PC下,通过开发者工具,模拟移动端,但是这样只能模拟页面样式,对于代码的执行情况是无法模拟的,所以在此结合实际调试经验,针对安卓与IOS设备,进行总结. IOS 安卓 ...

  2. 如何用MathType 7输入x的一阶导数

    物理学.几何学.经济学等学科中的一些重要概念都可以用导数来表示.如,导数可以表示运动物体的瞬时速度和加速度.可以表示曲线在一点的斜率.还可以表示经济学中的边际和弹性.那么作为专业的公式编辑器,如何输入 ...

  3. css3系列之伪类选择器

    Pseudo-Classes Selectors(伪类选择器) E:not(s) E:root E:target E:first-child E:last-child E:only-child E:n ...

  4. 蓝桥杯——字母阵列(2018JavaC组第3题)

    字母阵列(18JavaC3) 标题:字母阵列 仔细寻找,会发现:在下面的8x8的方阵中,隐藏着字母序列:"LANQIAO". SLANQIAO ZOEXCCGB MOAYWKHI ...

  5. C++基础知识篇:C++ 运算符

    运算符是一种告诉编译器执行特定的数学或逻辑操作的符号.C++ 内置了丰富的运算符,并提供了以下类型的运算符: 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 杂项运算符 本章将逐一介绍算术运 ...

  6. 盘点腾讯Linux、 C++后台开发面试题,做好充足准备,不怕被Pass

    一.C/C++   ​ const 多态 什么类不能被继承 二.网络   ​ 网络的字节序 网络知识 TCP三次握手 各种细节 timewait状态 TCP与UDP的区别 概念 适用范围 TCP四次挥 ...

  7. jmp使用

    jps -l jmap 36429 jmap -heap 36429 jmap -histo:live 36429 jmap -clstats 36429 jmap  -finalizerinfo 3 ...

  8. sentinel整合dubbo

    <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-dubbo-a ...

  9. Ajax Status(状态码) & readyState()

    Ajax Status & readyState readyState(状态值) 是指运行AJAX所经历过的几种状态,论访问是否成功都将响应的步骤,可以理解成为AJAX运行步骤,使用" ...

  10. gsap基础一[from,to,fromTo]

    学了几天基础了,感觉总算有点入了一个门的感觉啦,gasp不难,想想一年前我看着官网跟天文一样,今年真的进步很大,在外网发现学习的新世界, 自己的获取知识和查看api源码的能力也增强了许多,现在国内的气 ...