C++小项目:directx11图形程序(七):modelclass

时间:2022-11-13 19:47:44

模型类是世界空间中的表示物体的类,那么他的所做的事就是加载模型,移动模型,渲染模型

modelclass.h

 #pragma once

 #include <d3d11.h>
#include <d3dcompiler.h>
#include <D3DX11.h>
#include <xnamath.h>
#include<fstream>
using namespace std;
#pragma comment(lib,"d3dx11.lib")
#pragma comment(lib,"d3d11.lib")
#pragma comment(lib,"d3dcompiler.lib")
class modelclass
{
public:
modelclass();
~modelclass(); void Render(ID3D11DeviceContext* context,XMMATRIX& viewmatrix, XMMATRIX& promatrix, D3D11_PRIMITIVE_TOPOLOGY geometry,
ID3D11VertexShader* vertexshader, ID3D11PixelShader* pixelshader);
bool Initialize(ID3D11Device *device, LPCWSTR model, LPCWSTR texture);
void Setposition(float x, float y, float z);
void RotationAxis(XMVECTOR axis, float angle);
void Shutdown(); private:
bool Loadmodel(LPCWSTR file);
bool Loadtexture(LPCWSTR file, ID3D11Device* device); struct vertex
{
XMFLOAT3 pos;
XMFLOAT2 tex;
}; struct constantBuffer
{
XMMATRIX world;
XMMATRIX view;
XMMATRIX pro;
}; ID3D11Buffer *m_vertexBuffer, *m_indexBuffer;
ID3D11Buffer *m_constantBuffer;
int m_vertexCount, m_indexCount;
ID3D11ShaderResourceView* m_Texture;
ID3D11SamplerState *m_samplerstate;
vertex* m_vertexlist;
XMMATRIX m_worldMatrix;
};

他的公共方法如前所述:Render()渲染模型,Initialize()初始化(加载模型),Setposition()移动模型,RotationAxis()绕轴旋转。

两个私有数据结构,顶点和常量缓存,分别是用来构造顶点缓存和常量缓存的。

私有成员:顶点缓存,索引缓存,常量缓存,顶点个数,索引个数,纹理源视图,取样器状态,顶点列表,及世界变换矩阵。

modelclass.cpp

 #include "modelclass.h"

 modelclass::modelclass()
{
m_worldMatrix = XMMatrixIdentity();
} modelclass::~modelclass()
{
} bool modelclass::Initialize(ID3D11Device* device,LPCWSTR model,LPCWSTR texture)
{
HRESULT hr = S_OK;
bool m=Loadmodel(model);
bool t=Loadtexture(texture,device); D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(vertex)* m_vertexCount;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = ;
D3D11_SUBRESOURCE_DATA InitData;
InitData.pSysMem = m_vertexlist;
hr = device->CreateBuffer(&bd, &InitData, &m_vertexBuffer);
if (FAILED(hr))
{
return false;
} WORD *indices = new WORD[m_indexCount];
for (int i = ; i < m_indexCount; i++)
{
indices[i] = i;
}
D3D11_BUFFER_DESC bd1;
ZeroMemory(&bd1, sizeof(bd1));
bd1.Usage = D3D11_USAGE_DEFAULT;
bd1.ByteWidth = sizeof(WORD)* m_indexCount;
bd1.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd1.CPUAccessFlags = ;
D3D11_SUBRESOURCE_DATA InitData1;
InitData1.pSysMem = indices;
hr = device->CreateBuffer(&bd1, &InitData1, &m_indexBuffer);
if (FAILED(hr))
{
return false;
} D3D11_BUFFER_DESC bd2;
ZeroMemory(&bd2, sizeof(bd2));
bd2.Usage = D3D11_USAGE_DEFAULT;
bd2.ByteWidth = sizeof(constantBuffer);
bd2.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd2.CPUAccessFlags = ;
hr = device->CreateBuffer(&bd2, NULL, &m_constantBuffer);
if (FAILED(hr))
{
return false;
} D3D11_SAMPLER_DESC sampDesc;
ZeroMemory(&sampDesc, sizeof(sampDesc));
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = ;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
device->CreateSamplerState(&sampDesc, &m_samplerstate); delete[] indices;
indices = ; return true;
} bool modelclass::Loadmodel(LPCWSTR file)
{
ifstream fin;
char input; fin.open(file);
if (fin.fail())
{
return false;
} fin.get(input);
while (input != ':')
{
fin.get(input);
} fin >> m_vertexCount; m_indexCount = m_vertexCount; m_vertexlist = new vertex[m_vertexCount];
if (!m_vertexlist)
{
return false;
} fin.get(input);
while (input != ':')
{
fin.get(input);
}
fin.get(input);
fin.get(input); for (int i = ; i<m_vertexCount; i++)
{
fin >> m_vertexlist[i].pos.x >> m_vertexlist[i].pos.y >> m_vertexlist[i].pos.z;
fin >> m_vertexlist[i].tex.x >> m_vertexlist[i].tex.y;
} fin.close();
return true;
} bool modelclass::Loadtexture(LPCWSTR file,ID3D11Device* device)
{
D3DX11CreateShaderResourceViewFromFile(device, file, NULL, NULL, &m_Texture, NULL);
return true;
} void modelclass::Render(ID3D11DeviceContext* context, XMMATRIX& viewmatrix, XMMATRIX& pro, D3D11_PRIMITIVE_TOPOLOGY geometry,
ID3D11VertexShader* vertexshader,ID3D11PixelShader* pixelshader)
{
UINT stride = sizeof(vertex);
UINT offset = ;
context->IASetVertexBuffers(,,&m_vertexBuffer,&stride,&offset);
context->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R16_UINT, );
context->IASetPrimitiveTopology(geometry); constantBuffer cb;
XMMATRIX worldmatrix = m_worldMatrix;
XMMATRIX promatrix = pro;
cb.world = XMMatrixTranspose(worldmatrix);
cb.view = XMMatrixTranspose(viewmatrix);
cb.pro = XMMatrixTranspose(promatrix); context->UpdateSubresource(m_constantBuffer, , NULL, &cb, , ); context->VSSetShader(vertexshader, NULL, );
context->VSSetConstantBuffers(, , &m_constantBuffer);
context->PSSetShader(pixelshader, NULL, ); context->PSSetShaderResources(, , &m_Texture);
context->PSSetSamplers(, , &m_samplerstate);
context->DrawIndexed(m_vertexCount, , );
} void modelclass::Setposition(float x, float y, float z)
{
m_worldMatrix = XMMatrixTranslation(x, y, z);
} void modelclass::RotationAxis(XMVECTOR axis, float angle)
{
m_worldMatrix *= XMMatrixRotationAxis(axis, angle);
} void modelclass::Shutdown()
{
if (m_samplerstate)
{
m_samplerstate->Release();
}
if (m_constantBuffer)
{
m_constantBuffer->Release();
}
if (m_indexBuffer)
{
m_indexBuffer->Release();
}
if (m_vertexBuffer)
{
m_vertexBuffer->Release();
}
if (m_Texture)
{
m_Texture->Release();
}
if (m_vertexlist)
{
delete[] m_vertexlist;
m_vertexlist = ;
}
}

initialize():

  • 调用私有方法加载模型和纹理。加载完模型后,顶点列表,顶点个数已经有值了;加载完纹理后,纹理资源视图也有值了。
  • 填充顶点缓存描述数据结构,将顶点列表填充到源数据数据结构的pSysmem字段,然后根据顶点描述数据结构和源数据数据结构创建顶点缓存
  • for循环填充索引,填充索引缓存描述数据结构,填充源数据数据结构,创建索引缓存
  • 填充常量缓存描述数据结构,并创建常量缓存
  • 填充取样器描述数据结构,并创建取样器状态

私有方法Loadmodel():

从磁盘读取一个文件,该文件包含顶点信息,顶点个数该文件如下

Vertex Count: 

Data:

-1.0 -1.0 0.0 0.0 1.0
-1.0 1.0 0.0 0.0 0.0
1.0 -1.0 0.0 1.0 1.0
-1.0 1.0 0.0 0.0 0.0
1.0 1.0 0.0 1.0 0.0
1.0 -1.0 0.0 1.0 1.0

这是一个txt文件,有6个顶点,每个顶点有3个位置坐标信息和2个纹理坐标信息。

这个方法很简单,就不多做叙述了。

Render():

  • 设置创建好的顶点缓存
  • 设置创建好的索引缓存
  • 设置图形绘制方式
  • 将世界转换矩阵,观察矩阵,投影矩阵填充在常量缓存里的各个字段中,并更新常量缓存
  • 设置顶点着色器
  • 设置常量缓存
  • 设置像素着色器
  • 设置纹理源
  • 设置取样器的取样方式
  • 绘制各个顶点

Setposition(),RotationAxis():

这两个方法只是作用于世界转换矩阵,没什么好说的,他们就是用来将模型翻转或平移的