Effect框架简述
之前我们已经提到过HLSL文件。并且我还编写程序编译它,加载它,使用它。但是那样使用未免有点复杂。需要绘制复杂图形的时候,我们可以直接使用Effect框架来加载.fx文件.这里提到的.fx文件和我们之前提到的.HLSL文件差不多,语法上基本相同。我们把它编译之后是与一个ID3DX11Effect接口关联在一起,被关联的接口就成为了它的经纪人,把外界的数据传递给它,比如设置各种常量矩阵。我们通过ID3DX11EffectTechnique来调用其中的着色器。着色器的设置在.fx文件中完成
定义与外部交互的变量
在Effect文件与外部交互的变量通常定义在cbuffer中,或者也可以像HLSL文件那样直接定义在全局。如下所示:
cbuffer MatrixBuffer
{
matrix World;
matrix View;
matrix Projection;
float4 EyePosition;
};
Texture2D Texture;
外部程序通过设置这些变量,供着色器在渲染的时候使用.
Technique
每个Effect文件至少包含一个Technique,每个Technique至少包含一个通道.定义方式如下:
technique11 TexTech
{
pass P0
{
SetVertexShader(CompileShader(vs_5_0,VSMain()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_5_0,PSMain()));
}
}
顶点着色器和像素着色器就很好编写了.编写好直接使用即可.
Effect框架的使用
在Direct3D11中,Effect框架由两个接口管理着,一个就是经纪人,一个就是执行者.它们分别是
ID3DX11Effect *g_pEffect = NULL;
ID3DX11EffectTechnique *g_pEffectTechnique = NULL;
ID3DX11Effect就是充当着经纪人的角色,沟通着Effect程序内部与外部程序.而ID3DX11EffectTechnique则管理着通道.负责对顶点进行渲染.
编译Effect文件
编译Effect文件与之前编译.HLSL文件相同,都是通过D3DX11CompileFromFile来完成.不过这里要注意的是,之前使用的着色器模型要改成fx_5_0.
之前提到有一个flag2,在MSDN上说明了,建议设为0比较好。那就用0吧。
下面给出一个调用实例:
hr = D3DX11CompileFromFile(L"SimpleShader.fx", NULL, NULL, NULL,
"fx_5_0", D3DCOMPILE_ENABLE_STRICTNESS, 0,
NULL, &pTechBlob, NULL, NULL);
if (FAILED(hr)) {
::MessageBox(NULL, L"fx 载入失败", L"Error", MB_OK);
return hr;
}
创建Effect
Effect文件编译成功之后,它的字节码就保存在内存当中。我们要从内存创建Effect接口对象,也就是聘用一个经纪人来管理它.
通过调用D3DX11CreateEffectFromMemory来完成.该函数的原型如下
HRESULT D3DX11CreateEffectFromMemory(
void *pData,
SIZE_T DataLength,
UINT FXFlags,
ID3D11Device *pDevice,
ID3DX11Effect **ppEffect
);
- void *pData:一个指针,指向Effect数据所在内存段的首地址
- SIZE_T DataLength:数据段长度
- UINT FXFlags:目前暂时没有flags,设置为0即可
- ID3D11Device *pDevice:很明显,Direct3D设备接口
- ID3DX11Effect **ppEffect:Effect接口,就是我们之前说的经纪人.
获取ID3DX11EffectTechnique接口
ID3DX11EffectTechnique接口是通过ID3DX11Effect的GetTechniqueByName或者GetTechniqueByIndex方法得到的,这两个方法的使用都很简单,只需要传入相应的参数就行.
GetTechniqueByName指的就是根据名字寻找Technique
GetTechniqueByIndex就是根据索引号来寻找Technique
创建输入布局
创建Effect的输入布局,必须提前获取通道的描述信息,以便在创建输入布局的时候要用到.
前面说过,ID3DX11EffectTechnique就是负责管理通道的接口,可以通过调用它的GetPassByIndex或者GetPassByName来获取类型为ID3DX11EffectPass的通道接口对象.通过该接口的GetDesc就可以获取到通道的相关参数信息.
GetDesc只有一个D3DX11_PASS_DESC指针的参数,它的原型如下:
HRESULT GetDesc(
_Out_ D3DX11_PASS_DESC *pDesc
);
而提到D3DX11_PASS_DESC就顺便把该结构体的内部信息展示出来:
struct D3DX11_PASS_DESC
{
LPCSTR Name; // Name of this pass (nullptr if not anonymous)
uint32_t Annotations; // Number of annotations on this pass
uint8_t *pIAInputSignature; // Signature from VS or GS (if there is no VS)
// or nullptr if neither exists
size_t IAInputSignatureSize; // Singature size in bytes
uint32_t StencilRef; // Specified in SetDepthStencilState()
uint32_t SampleMask; // Specified in SetBlendState()
FLOAT BlendFactor[4]; // Specified in SetBlendState()
};
其中的注释已经相当清楚,就不再做过多的解释了.
下面是一个调用示例:
g_technique = g_effect->GetTechniqueByName("TexTech");
D3DX11_PASS_DESC PassDesc;
g_technique->GetPassByIndex(0)->GetDesc(&PassDesc);
当调用了GetDesc得到通道的参数信息之后,可以通过D3D11_INPUT_ELEMENT_DESC结构体数组来描述输入的元素特征。接着通过设备接口调用CreateInputLayout即可获得输入布局.
下面创建的示例代码:
hr = g_pd3dDevice->CreateInputLayout(
layout,
numElements,
PassDesc.pIAInputSignature,
PassDesc.IAInputSignatureSize,
&g_vertexLayout);
输入布局创建成功基本上就完成了初始化的工作。在后续的渲染操作中需要使用到输入布局的时候,只需要通过设备上下文接口来设置一下.
Effect的使用
游戏中每个顶点都不会是一成不变的。我们在Effect文件中通常会定义一些变量,用于和外部程序沟通。我们可以从外部程序设置这些变量的值.
明星都不会直接与你打交道的,都是经纪人在打点这一切。所以Effect程序也是相当地高贵,我们只能通过ID3DX11Effect接口对象来设置变量的值.
我们可以通过ID3DX11Effect接口对象的GetVariableByName或者GetVariableByIndex或者GetVariableBySemantic方法来获取变量接口:ID3DX11EffectVariable.
通过ID3DX11EffectVariable接口可以将得到的变量解读为某一种类型的接口.如若要解释为矩阵,则调用它的AsMatrix方法即可.然后通过SetMatrix方法来将值设置到变量中.
设置完成之后,就需要对顶点进行着色。这是ID3DX11EffectPass接口对设备上下文接口的一次调用,很明显,在设备上下文接口中应该已经设置好了顶点缓存,或者顶点缓存+索引缓存.接着通过ID3DX11EffectPass接口的Apply方法即可把顶点作为着色器的输入参数,输出结果顶点.
这一过程的示例代码如下:
//设置世界坐标系
g_effect->GetVariableByName("World")->AsMatrix()->SetMatrix((float*)&world);
//设置观察坐标系
g_effect->GetVariableByName("View")->AsMatrix()->SetMatrix((float*)&view);
//设置投影坐标系
g_effect->GetVariableByName("Projection")->AsMatrix()->SetMatrix((float*)&projection);
//定义一个D3DX11_TECHNIQUE_DESC对象来描述technique
//D3DX11_TECHNIQUE_DESC techDesc;
//g_technique->GetDesc(&techDesc);//获取techinique的描述
//获取通道Pass,把它设置到执行上下文中
g_technique->GetPassByIndex(0)->Apply(0, g_pImmediateContext);
//绘制立方体,注意,这里调用的是DrawIndexed
g_pImmediateContext->DrawIndexed(36, 0, 0);
g_pSwapChain->Present(0, 0);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
旋转立方体代码
Cube.fx
cbuffer ConstantBuffer
{
matrix WORLD
matrix VIEW
matrix PROJECTION
}
struct VS_INPUT
{
float4 Pos:SV_POSITION
float4 Color:COLOR
}
VS_INPUT VS(float4 Pos:POSITION, float4 Color : COLOR)
{
VS_INPUT input = (VS_INPUT)0
input.Pos = mul(Pos, WORLD)
input.Pos = mul(input.Pos, VIEW)
input.Pos = mul(input.Pos, PROJECTION)
input.Color = Color
return input
}
float4 PS(VS_INPUT input):SV_TARGET
{
return input.Color
}
technique11 CubeTex
{
pass P0 {
SetVertexShader(CompileShader(vs_5_0, VS()))
SetGeometryShader(NULL)
SetPixelShader(CompileShader(ps_5_0, PS()))
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
Cube.h
#pragma once
#include"dxUtil.h"
struct Vertex
{
XMFLOAT3 Position;
XMFLOAT4 Color;
};
class Cube
{
private:
ID3DX11Effect *m_pEffect;
ID3DX11EffectTechnique *m_pTechnique;
ID3D11InputLayout *m_pInputLayout;
ID3D11Buffer *m_pVertexBuffer;
UINT m_uStrid;
UINT m_uOffset;
ID3D11Buffer *m_pIndexBuffer;
XMFLOAT4X4 m_world;
public:
Cube()
:m_pEffect(NULL),m_pTechnique(NULL),m_pInputLayout(NULL),m_pVertexBuffer(NULL),m_pIndexBuffer(NULL)
{
XMStoreFloat4x4(&m_world, XMMatrixIdentity());
}
HRESULT Init(DirectSystem* d3dSys) {
HRESULT hr;
ID3DBlob *effectFileBlob = NULL;
hr=D3DX11CompileFromFile(L"Cube.fx", NULL, NULL, NULL, "fx_5_0", NULL, 0, NULL, &effectFileBlob, NULL, NULL);
if (FAILED(hr))
{
return hr;
}
hr = D3DX11CreateEffectFromMemory(
effectFileBlob->GetBufferPointer(),
effectFileBlob->GetBufferSize(),
0, d3dSys->D3DDevice(),
&m_pEffect,
NULL
);
m_pTechnique = m_pEffect->GetTechniqueByName("CubeTex");
D3D11_INPUT_ELEMENT_DESC layout[] = {
{
"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0
},
{
"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0
}
};
UINT numLayoutSize = ARRAYSIZE(layout);
D3DX11_PASS_DESC passDesc;
m_pTechnique->GetPassByIndex(0)->GetDesc(&passDesc);
d3dSys->D3DDevice()->CreateInputLayout(layout, numLayoutSize, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &m_pInputLayout);
Vertex vertices[]=
{
{ XMFLOAT3(-1.0f,1.0f,-1.0f),XMFLOAT4(0.0f,0.0f,1.0f,1.0f) },
{ XMFLOAT3(1.0f,1.0f,-1.0f),XMFLOAT4(0.0f,1.0f,0.0f,1.0f) },
{ XMFLOAT3(1.0f,1.0f,1.0f),XMFLOAT4(0.0f,1.0f,1.0f,1.0f) },
{ XMFLOAT3(-1.0f,1.0f,1.0f),XMFLOAT4(1.0f,0.0f,1.0f,1.0f) },
{ XMFLOAT3(-1.0f,-1.0f,-1.0f),XMFLOAT4(1.0f,0.0f,1.0f,1.0f) },
{ XMFLOAT3(1.0f,-1.0f,-1.0f),XMFLOAT4(1.0f,1.0f,0.0f,1.0f) },
{ XMFLOAT3(1.0f,-1.0f,1.0f),XMFLOAT4(1.0f,1.0f,1.0f,1.0f) },
{ XMFLOAT3(-1.0f,-1.0f,1.0f),XMFLOAT4(0.0f,0.0f,0.0f,1.0f) }
};
D3D11_BUFFER_DESC vertexDesc;
::ZeroMemory(&vertexDesc, sizeof(D3D11_BUFFER_DESC));
vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexDesc.ByteWidth = sizeof(Vertex) * 8;
vertexDesc.CPUAccessFlags = 0;
vertexDesc.MiscFlags = 0;
vertexDesc.StructureByteStride = sizeof(Vertex);
vertexDesc.Usage = D3D11_USAGE_DEFAULT;
D3D11_SUBRESOURCE_DATA vertexData;
::ZeroMemory(&vertexData,sizeof(D3D11_SUBRESOURCE_DATA));
vertexData.pSysMem = vertices;
d3dSys->D3DDevice()->CreateBuffer(&vertexDesc, &vertexData, &m_pVertexBuffer);
m_uStrid = sizeof(Vertex);
m_uOffset = 0;
WORD indexs[] = {
3,1,0,
2,1,3,
0,5,4,
1,5,0,
3,4,7,
0,4,3,
1,6,5,
2,6,1,
2,7,6,
3,7,2,
6,4,5,
7,4,6
};
UINT numElements = ARRAYSIZE(indexs);
D3D11_BUFFER_DESC indexDesc;
indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexDesc.ByteWidth = sizeof(WORD)*numElements;
indexDesc.CPUAccessFlags = 0;
indexDesc.MiscFlags = 0;
indexDesc.StructureByteStride = sizeof(WORD);
indexDesc.Usage = D3D11_USAGE_DEFAULT;
D3D11_SUBRESOURCE_DATA indexData;
indexData.pSysMem = indexs;
d3dSys->D3DDevice()->CreateBuffer(&indexDesc, &indexData, &m_pIndexBuffer);
}
VOID Update(float deltaTime)
{
static float angle = 0.0f;
angle += deltaTime;
if (angle >= 6.28f)
angle = 0.0f;
XMMATRIX mov = XMMatrixTranslation(3, 0, 0);
XMVECTOR axis = XMVectorSet(0, 1, 0, 0);
XMMATRIX rotAxis = XMMatrixRotationAxis(axis, angle);
XMMATRIX rot = XMMatrixRotationY(angle);
XMMATRIX world = rotAxis*mov*rot;
XMStoreFloat4x4(&m_world, world);
}
HRESULT Draw(DirectSystem* d3dSys)
{
d3dSys->D3DDeviceContext()->IASetVertexBuffers(0, 1, &m_pVertexBuffer,&m_uStrid,&m_uOffset);
d3dSys->D3DDeviceContext()->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
d3dSys->D3DDeviceContext()->IASetInputLayout(m_pInputLayout);
d3dSys->D3DDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
XMMATRIX world;
world=XMLoadFloat4x4(&m_world);
XMMATRIX view;
XMMATRIX projection;
view = d3dSys->GetViewMatrix();
projection = d3dSys->GetProjectionMatrix();
m_pEffect->GetVariableByName("WORLD")->AsMatrix()->SetMatrix((float*)&world);
m_pEffect->GetVariableByName("VIEW")->AsMatrix()->SetMatrix((float*)&view);
m_pEffect->GetVariableByName("PROJECTION")->AsMatrix()->SetMatrix((float*)&projection);
m_pTechnique->GetPassByIndex(0)->Apply(0, d3dSys->D3DDeviceContext());
d3dSys->D3DDeviceContext()->DrawIndexed(36, 0, 0);
return S_OK;
}
~Cube() {
SAFE_RELEASE(m_pTechnique);
SAFE_RELEASE(m_pEffect);
SAFE_RELEASE(m_pVertexBuffer);
SAFE_RELEASE(m_pIndexBuffer);
}
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
Main.cpp核心部分
MSG msg = { 0 };
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg,NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
static float lastTime = 0.0f;
float currentTime = (float)timeGetTime();
float deltaTime = (currentTime - lastTime)*0.001;
g_pCube->Update(deltaTime);
g_pDirect->Direct3D_Clear();
g_pCube->Draw(g_pDirect);
g_pDirect->Direct3D_Present();
lastTime = currentTime;
}
}