DX11 纹理
目录
题目&要求
-
题目
-
- 给一个立方体六个面贴不同的纹理,并且使用方向光光照
-
- 利用纹理数组实现2D纹理动画(09项目中的火焰动画)
-
- 给一个立方体六个面贴上同一个纹理,这个纹理利用给定的两张纹理进行合成,并且实现纹理在立方体面上的旋转(提示:顶点着色器),关闭光照,还可以利用上上一节课所写的代码来操控立方体的旋转
-
要求
-
- 以上三个作业写在同一个项目中,并且利用数字键盘进行切换。
存在问题
- 从这次作业发现,前面基础非常不扎实,从而导致这次作业推迟交。
- 对imgui暂时没有实现。
- 利用纹理数组实现2D纹理动画,一个数组索引没有找出来,所以…后面会回头处理。
学习情况&整体思路
- 学习情况
-
- 现在大概明白的整体实现的流程,但是还有许多细节没办法处理。
- 可能到现在,基础不是很扎实,基础薄弱。
- 这次作业对纹理有了个基本的认识,同时加深了渲染管线的印象。
- 整体思路
-
- 1、首先处理纹理坐标的顶点结构体,然后是对HLSL代码的处理,接下来就是创建着色器了,着色器有4个,两个顶点布局,在InitEffect()函数中实现。
-
- 2、然后是对网络模型初始化ResetMesh(meshData),设置设置常量缓冲区,新建用于VS和PS的常量缓冲区,初始化纹理(3个作业的纹理初始化), 初始化采样器状态。初始化常量缓冲区的值,更新PS常量缓冲区资源。然后就是给渲染管线各个阶段绑定好所需资源啦。
-
- 3、基本的完成后,就是GameApp::DrawScene()的绘制几何模型和绘制Direct2D部分。
-
- 4、最后是GameApp::UpdateScene(float dt),播放动漫和实现了。
一、顶点输入布局
虽然渲染管线的那篇文章说过,但也是简单的提了一下,现在就这详细说一下
来看看Geometry.h中的模板实现各种几何体的方法,这里就正方体来说一下
1、首先是输入布局的描述
struct VertexData
{
DirectX::XMFLOAT3 pos;//顶点 (0,12)//字节
DirectX::XMFLOAT3 normal;//法线 (12,24)
DirectX::XMFLOAT4 tangent;//切线(24,40)
DirectX::XMFLOAT4 color;//颜色 (40,56)
DirectX::XMFLOAT2 tex;//纹理 (56,64)
};
//input 基础元素
//使用D3D11_INPUT_ELEMENT_DESC结构体来描述待传入结构体中每个成员的具体信息
//(语义名,语义索引,数据格式,输入槽索引(0-15),初始位置(字节偏移量),输入类型,忽略)
//通过语义、数据类型和起始偏移量,我们就可以建立起C++顶点缓冲区数据和HLSL顶点之间的联系(1)
typedef struct D3D11_INPUT_ELEMENT_DESC {
LPCSTR SemanticName; //语义名
UINT SemanticIndex; //语义索引
DXGI_FORMAT Format; //数据格式
UINT InputSlot; //输入槽索引(0-15)
UINT AlignedByteOffset //初始位置(字节偏移量)
D3D11_INPUT_CLASSIFICATION InputSlotClass; //输入类型
UINT InstanceDataStepRate; //目前指定为0;其他值只用于高级实例技术。
} D3D11_INPUT_ELEMENT_DESC;
const D3D11_INPUT_ELEMENT_DESC VertexPosNormalTex::inputLayout[3] = {
{
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{
"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{
"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
struct VertexPosNormalTex
{
float3 PosL : POSITION;
float3 NormalL : NORMAL;
float2 Tex : TEXCOORD;
};
来看看是怎么联系起来的
这是一种通过语义名和语义索引提供了一种将顶点元素映射为顶点着色器参数的方法
-
在来看看第五个参数AlignedByteOffset初始位置(字节偏移量)
-
AlignedByteOffset:对于单个输入槽来说,该参数表示从顶点结构体的起始位置到顶点元素的起始位置之间的字节偏移量。例如在下面的顶点结构体中,元素Pos的字节偏移量为0,因为它的起始位置与顶点结构体的起始位置相同;元素Normal的字节偏移量为12,因为必须跳过由Pos占用的字节才能到达Normal的起始位置;元素tangent的字节偏移量为24,因为必须跳过由Pos和Normal占用的字节才能到达tangent的起始位置;其他以此类推下去
struct VertexData { DirectX::XMFLOAT3 pos;//顶点 (0,12)//字节 DirectX::XMFLOAT3 normal;//法线 (12,24) DirectX::XMFLOAT4 tangent;//切线(24,40) DirectX::XMFLOAT4 color;//颜色 (40,56) DirectX::XMFLOAT2 tex;//纹理 (56,64) };
2、接下来就是在设备创建输入布局
// 创建顶点布局(3D)
// ([In]输入布局描述,[In]上述数组元素个数,[In]顶点着色器字节码,[In]顶点着色器字节码长度,[out]获取的输入布局)
HR(m_pd3dDevice->CreateInputLayout(VertexPosNormalTex::inputLayout, ARRAYSIZE(VertexPosNormalTex::inputLayout),
blob->GetBufferPointer(), blob->GetBufferSize(), m_pVertexLayout3D.GetAddressOf()));
3、数据输入对不对,来看这一章的CreateBox
template<class VertexType, class IndexType>
inline MeshData<VertexType, IndexType> CreateBox(float width, float height, float depth, const DirectX::XMFLOAT4 & color)
{
using namespace DirectX;
// 网格数据
//template<class VertexType = VertexPosNormalTex, class IndexType = DWORD>
//struct MeshData
//{
// std::vector<VertexType> vertexVec; // 顶点数组
// std::vector<IndexType> indexVec; // 索引数组
//};
MeshData<VertexType, IndexType> meshData;
meshData.vertexVec.resize(24);
// struct VertexData
// {
// DirectX::XMFLOAT3 pos;//顶点
// DirectX::XMFLOAT3 normal;//法线
// DirectX::XMFLOAT4 tangent;//切线
// DirectX::XMFLOAT4 color;//颜色
// DirectX::XMFLOAT2 tex;//纹理
// };
Internal::VertexData vertexDataArr[24];
float w2 = width / 2, h2 = height / 2, d2 = depth / 2;
//可能这里你要问了,为什么需要写这么多的顶点,上一次不是说了索引吗
//那是因为
//对于棱角分明的物体,如立方体,一共由12个三角形组成,2个三角形的4个顶点构成一个面。由于该面的4个顶点要求法向量朝向一致,而一个顶点虽然与立方体的三个面邻接,但是法向量只有一个,因此需要分化出3个包含不同法向量的顶点。最终用于绘制该立方体的顶点数就需要24个,是立方体顶点数的3倍!
//就是因为下面有法线和切线的赋值,每一个顶点都不一样
// 右面(+X面)
vertexDataArr[0].pos = XMFLOAT3(w2, -h2, -d2);
vertexDataArr[1].pos = XMFLOAT3(w2, h2, -d2);
vertexDataArr[2].pos = XMFLOAT3(w2, h2, d2);
vertexDataArr[3].pos = XMFLOAT3(w2, -h2, d2);
// 左面(-X面)
vertexDataArr[4].pos = XMFLOAT3(-w2, -h2, d2);
vertexDataArr[5].pos = XMFLOAT3(-w2, h2, d2);
vertexDataArr[6].pos = XMFLOAT3(-w2, h2, -d2);
vertexDataArr[7].pos = XMFLOAT3(-w2, -h2, -d2);
// 顶面(+Y面)
vertexDataArr[8].pos = XMFLOAT3(-w2, h2, -d2);
vertexDataArr[9].pos = XMFLOAT3(-w2, h2, d2);
vertexDataArr[10].pos = XMFLOAT3(w2, h2, d2);
vertexDataArr[11].pos = XMFLOAT3(w2, h2, -d2);
// 底面(-Y面)
vertexDataArr[12].pos = XMFLOAT3(w2, -h2, -d2);
vertexDataArr[13].pos = XMFLOAT3(w2, -h2, d2);
vertexDataArr[14].pos = XMFLOAT3(-w2, -h2, d2);
vertexDataArr[15].pos = XMFLOAT3(-w2, -h2, -d2);
// 背面(+Z面)
vertexDataArr[16].pos = XMFLOAT3(w2, -h2, d2);
vertexDataArr[17].pos = XMFLOAT3(w2, h2, d2);
vertexDataArr[18].pos = XMFLOAT3(-w2, h2, d2);
vertexDataArr[19].pos = XMFLOAT3(-w2, -h2, d2);
// 正面(-Z面)
vertexDataArr[20].pos = XMFLOAT3(-w2, -h2, -d2);
vertexDataArr[21].pos = XMFLOAT3(-w2, h2, -d2);
vertexDataArr[22].pos = XMFLOAT3(w2, h2, -d2);
vertexDataArr[23].pos = XMFLOAT3(w2, -h2, -d2);