在第二章的纹理程序基础上做简单的修改就可以显示旋转立方体效果如下:
做以下几点修改:
3D顶点坐标数据
我们从vertex.txt文件读取顶点数据与纹理,数据结构如下
typedef struct _VertexData
{
XMFLOAT4 position;
XMFLOAT2 uv;
}VertexData;
这个立方体的3D坐标位置与纹理可以自已构建的(比较复杂模型由别人提供),这里为了简化代码从文件中读取,CVertexData类负责加载数据。代码:
typedef struct _VertexData
{
XMFLOAT4 position;
XMFLOAT2 uv;
}VertexData;
typedef struct _SceneConstantBuffer
{
XMFLOAT4X4 m_ModelViewProject;
XMFLOAT4 offset;
float padding[44];
}SceneConstantBuffer;
class CVertexData
{
public:
void LoadData(const wchar_t*path);
void* VertexDataPtr()
{
return m_listVertexData.data();
}
void* IndexDataPtr()
{
return m_listIndexData.data();
}
int VertexSize()
{
return m_listVertexData.size() * sizeof(VertexData);
}
int IndexSize()
{
return m_listIndexData.size() * sizeof(UINT32);
}
int IndexNumber()
{
return m_listIndexData.size();
}
private:
vector<VertexData> m_listVertexData;
vector<UINT32> m_listIndexData;
};
增加常量缓冲区视图 (CBV) 资源
存放3D模型数据, Cpu修改 世界空间模型,由于沿Y旋转, 改变角度达到自转目的。GPU-Shader读值,进行最后的运算。3D模型数据结构,数据对齐256,所以加float padding[44]
typedef struct _SceneConstantBuffer
{
XMFLOAT4X4 m_ModelViewProject;
XMFLOAT4 offset;
float padding[44];
}SceneConstantBuffer;
创建代码:
void CD3D12Cube::CreateConstantBuffer(UINT64 bufferOffset, ComPtr<ID3D12Device>device, ComPtr<ID3D12Heap> uploadHeap, ComPtr<ID3D12DescriptorHeap>srvcbvHeap, ComPtr<ID3D12Resource>& cbvResource)
{
UINT64 wSize = UPPER_ALING_DIV(sizeof(SceneConstantBuffer), 256);
bufferOffset = UPPER_ALING_DIV(bufferOffset + wSize, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
CreatePlacedResource(device
, uploadHeap.Get()
, bufferOffset
, &CD3DX12_RESOURCE_DESC::Buffer(wSize)
, D3D12_RESOURCE_STATE_GENERIC_READ
, cbvResource);
ThrowIfFailed(cbvResource->Map(0, nullptr, reinterpret_cast<void**>(&m_constantBufferData)));
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
cbvDesc.BufferLocation = cbvResource->GetGPUVirtualAddress();
cbvDesc.SizeInBytes = wSize;
UINT nSRVSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
D3D12_CPU_DESCRIPTOR_HANDLE stCPUCBVHandle = srvcbvHeap->GetCPUDescriptorHandleForHeapStart();
stCPUCBVHandle.ptr += nSRVSize;
m_device->CreateConstantBufferView(&cbvDesc, stCPUCBVHandle);
}
cbvResource->Map(,), 相连到内存,直接修改m_constantBufferData可以了。
3D模型转换
详情见第三章
裁剪空间 是我们最终目标
本地空间
本地空间 就是 顶点坐标
观察空间
XMMATRIX view = XMMatrixLookAtLH(m_vCameraPos, m_vLookAt, m_vUpDir); 自己构建,给特定值,写死的。
世界空间
XMMATRIX model = XMMatrixRotationY(static_cast<float>(m_dYAngle)); 给旋转角度。
观察空间
XMMATRIX view = XMMatrixLookAtLH(m_vCameraPos, m_vLookAt, m_vUpDir); 自己构建,给特定值,写死的。
投影空间
正射投影
正射投影矩阵定义了一个类似立方体的平截头箱,它定义了一个裁剪空间,在这空间之外的顶点都会被裁剪掉。创建一个正射投影矩阵需要指定可见平截头体的宽、高和长度。在使用正射投影矩阵变换至裁剪空间之后处于这个平截头体内的所有坐标将不会被裁剪掉。
透视投影
如果你曾经体验过实际生活给你带来的景象,你就会注意到离你越远的东西看起来更小。这个奇怪的效果称之为透视(Perspective)。这里用 透视投影.
XMMATRIX projection = XMMatrixPerspectiveFovLH(XM_PIDIV4, (FLOAT)m_nW / (FLOAT)m_nH, 0.1f, 1000.0f)
矩阵相乘
XMMATRIX xmModelViewProject = XMMatrixMultiply(XMMatrixMultiply(model, view), projection);
XMStoreFloat4x4(&m_constantBufferData->m_ModelViewProject, xmModelViewProject);
UI刷新代码
void CD3D12Cube::OnRender(void)
{
UpdateConstantBufferData();
PopulateCommandList();
}
//clip= projection*view*model*local
void CD3D12Cube::UpdateConstantBufferData()
{
ULONGLONG n64tmCurrent = ::GetTickCount64();
m_dYAngle += ((n64tmCurrent - m_n64tmFrameStart) / 1000.0f) * m_dbPalstance;
m_n64tmFrameStart = n64tmCurrent;
if (m_dYAngle > XM_2PI)
{
m_dYAngle = fmod(m_dYAngle, XM_2PI);
}
XMMATRIX model = XMMatrixRotationY(static_cast<float>(m_dYAngle));
XMMATRIX view = XMMatrixLookAtLH(m_vCameraPos, m_vLookAt, m_vUpDir);
XMMATRIX projection = XMMatrixPerspectiveFovLH(XM_PIDIV4, (FLOAT)m_nW / (FLOAT)m_nH, 0.1f, 1000.0f);
// 从左向右读这个乘法
// 1.XMMatrixMultiply(model, view) 读法-> (model * view)
// 2. ((model *view ) )* projection
// 3. XMMatrixMultiply 人性化了
XMMATRIX xmModelViewProject = XMMatrixMultiply(XMMatrixMultiply(model, view), projection);
XMStoreFloat4x4(&m_constantBufferData->m_ModelViewProject, xmModelViewProject);
}
HelloCube.hlsl程序
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
cbuffer SceneConstantBuffer : register(b0)
{
float4x4 m_ModelViewProject;
float4 offset;
float padding[48];
};
struct PSInput
{
float4 position : SV_POSITION;
float2 uv : TEXCOORD;
};
Texture2D g_texture : register(t0);
SamplerState g_sampler : register(s0);
PSInput VSMain(float4 position : POSITION, float4 uv : TEXCOORD)
{
PSInput result;
//裁剪空间 = ModelViewProject 矩阵 乘 本地空间
// 从左向右读这个乘法 position(本地空间) 乘 ModelViewProject 矩阵
result.position = mul(position, m_ModelViewProject);
result.uv = uv;
return result;
}
float4 PSMain(PSInput input) : SV_TARGET
{
return g_texture.Sample(g_sampler, input.uv);
}
注意
本章用CreatePlacedResource()替换CreateCommittedResource()分配资源
感谢大家的支持,如要问题欢迎提问指正。