当前位置: 代码迷 >> 综合 >> Effect框架
  详细解决方案

Effect框架

热度:44   发布时间:2023-09-30 08:54:32.0

Effect框架简述

??之前我们已经提到过HLSL文件。并且我还编写程序编译它,加载它,使用它。但是那样使用未免有点复杂。需要绘制复杂图形的时候,我们可以直接使用Effect框架来加载.fx文件.这里提到的.fx文件和我们之前提到的.HLSL文件差不多,语法上基本相同。我们把它编译之后是与一个ID3DX11Effect接口关联在一起,被关联的接口就成为了它的经纪人,把外界的数据传递给它,比如设置各种常量矩阵。我们通过ID3DX11EffectTechnique来调用其中的着色器。着色器的设置在.fx文件中完成

定义与外部交互的变量

??在Effect文件与外部交互的变量通常定义在cbuffer中,或者也可以像HLSL文件那样直接定义在全局。如下所示:

cbuffer MatrixBuffer
{matrix World;   //世界坐标变换矩阵matrix View;    //观察坐标变换矩阵matrix Projection; //投影坐标变换矩阵float4 EyePosition;//视点距离
};Texture2D Texture;  //纹理变量
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

??外部程序通过设置这些变量,供着色器在渲染的时候使用.

Technique

??每个Effect文件至少包含一个Technique,每个Technique至少包含一个通道.定义方式如下:

//
//定义Techinique
/
technique11 TexTech
{pass P0{SetVertexShader(CompileShader(vs_5_0,VSMain()));SetGeometryShader(NULL);SetPixelShader(CompileShader(ps_5_0,PSMain()));}
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

??顶点着色器和像素着色器就很好编写了.编写好直接使用即可.

Effect框架的使用

??在Direct3D11中,Effect框架由两个接口管理着,一个就是经纪人,一个就是执行者.它们分别是

ID3DX11Effect *g_pEffect = NULL;
ID3DX11EffectTechnique *g_pEffectTechnique = NULL;
  
  • 1
  • 2

??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;}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

创建Effect

??Effect文件编译成功之后,它的字节码就保存在内存当中。我们要从内存创建Effect接口对象,也就是聘用一个经纪人来管理它.
??通过调用D3DX11CreateEffectFromMemory来完成.该函数的原型如下

HRESULT D3DX11CreateEffectFromMemory(void          *pData,SIZE_T        DataLength,UINT          FXFlags,ID3D11Device  *pDevice,ID3DX11Effect **ppEffect
);
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 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);
  
  • 1
  • 2
  • 3

??而提到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 passuint8_t *pIAInputSignature;     // Signature from VS or GS (if there is no VS)// or nullptr if neither existssize_t IAInputSignatureSize;    // Singature size in bytes                                uint32_t StencilRef;            // Specified in SetDepthStencilState()uint32_t SampleMask;            // Specified in SetBlendState()FLOAT BlendFactor[4];           // Specified in SetBlendState()
};
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

??其中的注释已经相当清楚,就不再做过多的解释了.
??下面是一个调用示例:

    g_technique = g_effect->GetTechniqueByName("TexTech");D3DX11_PASS_DESC PassDesc;g_technique->GetPassByIndex(0)->GetDesc(&PassDesc);
  
  • 1
  • 2
  • 3


??当调用了GetDesc得到通道的参数信息之后,可以通过D3D11_INPUT_ELEMENT_DESC结构体数组来描述输入的元素特征。接着通过设备接口调用CreateInputLayout即可获得输入布局.
??下面创建的示例代码:

hr = g_pd3dDevice->CreateInputLayout(layout,         //上面定义的D3D11_INPUT_ELEMENT_DESC数组numElements,    //D3D11_INPUT_ELEMENT_DESC数组的元素个数PassDesc.pIAInputSignature,//Effect Pass描述的输入标识PassDesc.IAInputSignatureSize,//Effect Pass描述的输入标识的大小&g_vertexLayout);//返回生成的输入布局对象
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

??输入布局创建成功基本上就完成了初始化的工作。在后续的渲染操作中需要使用到输入布局的时候,只需要通过设备上下文接口来设置一下.

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);//绘制立方体,注意,这里调用的是DrawIndexedg_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;/*创建Effect*/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 world = XMLoadFloat4x4(&m_world);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;}}