点+ index(三角形)->mesh
各种法线、亮度->材质
这些都在CPU阶段 ,渲染管线开始时由CPU提交给GPU进行绘图
自定义渲染管线:
1.点映射到屏幕空间(变换)(GPU)
2.将屏幕空间的点图元化,如果需要对三角形细分则在图元化后细分,裁剪(硬件进行),深度测试等(此时还没映射到屏幕)(GPU)
此阶段前还可以读取CPU传来的代码(对GPU的语言:shader),逐个顶点操作
3.光栅化:映射到屏幕,并对像素操作(GPU)
在这个光栅化阶段后,也可以读取CPU传来的代码,逐个像素操作,再进行光栅化
4.深度测试并将最好结果合并放入后缓冲区,交给交换链进行下一步操作
DX12渲染管线
应用程序阶段——CPU(内存)
几何阶段——变换
光栅阶段——图元装配、光栅化和插值、像素操作、帧缓冲区
流输出阶段
1.输入装配阶段:顶点、索引(几何元素/几何图元)
2.顶点着色阶段:顶点着色器(顶点数据、变换、光照、纹理贴图——法线和置换)(Shader)
3.外壳着色阶段:单个表面分解为许多三角形 *
4.曲面细分阶段:细化三角形
5.域着色阶段:各个域样本对于的顶点位置 (Shader)
6.几何着色阶段(可选):点或者线扩展为四边形
7.光栅化阶段:将三角形生成像素
8.像素着色阶段:针对像素进行编程处理 (Shader)
装配阶段
基类
储存顶点信息和面(Index)的结构体
struct FVertex
{
FVertex(const XMFLOAT3& InPos, const XMFLOAT4& InColor);
XMFLOAT3 Position;
XMFLOAT4 Color;
XMFLOAT3 Normal;
XMFLOAT3 UTangent;
};
struct FMeshRenderingData
{
vector<FVertex> VertexData;
vector<uint16_t> IndexData;
};
Rendering基类:提供渲染接口,实现解耦合
#pragma once
#include"../../Core/Engine.h"
#include"Engine/EngineMinimal.h"
class IRenderingInterface
{
friend class FWindowsEngine;
public:
IRenderingInterface();
virtual ~IRenderingInterface();
virtual void Draw(float DeltaTime);
bool operator ==(const IRenderingInterface& tmp)
{
return guid_equal(&Guid, &tmp.Guid);
}
simple_c_guid GetGuid() { return Guid; }
protected:
ComPtr<ID3D12Device> GetD3D12Device();
ComPtr<ID3D12GraphicsCommandList> GetGraphicsCommandList();
ComPtr<ID3D12Resource> ConstructDefaultBuffer(ComPtr<ID3D12Resource>& OutTmpBuffer,const void* InData,UINT64 DataSize);
private:
static vector<IRenderingInterface*> RenderingInterface;
simple_c_guid Guid;
};
Mesh基类:继承Rendering,是所以模型的基类。对顶点缓冲区和索引缓冲区初始化
#pragma once
#include"../../Rending/Core/Rendering.h"
#include"MeshType.h"
class FRenderingResoucesUpdate;
struct FObjectTrasformation
{
FObjectTrasformation();
XMFLOAT4X4 World;
};
class FMesh :public IRenderingInterface
{
public:
FMesh();
virtual void Init();
virtual void BuildMesh(const FMeshRenderingData* InMeshRenderingData);
virtual void Draw(float DeltaTime);
static FMesh* CreateMesh(const FMeshRenderingData* InMeshRenderingData);
D3D12_VERTEX_BUFFER_VIEW GetVertexBufferView();
D3D12_INDEX_BUFFER_VIEW GetIndexBufferView();
//Vertex & Index args
protected:
UINT VertexSizeInBytes;
UINT VertexStrideInBytes;
UINT IndexSizeInBytes;
DXGI_FORMAT IndexFormat;
UINT IndexSize;
protected:
ComPtr<ID3DBlob> CPUVertexBufferPtr;
ComPtr<ID3DBlob> CPUIndexBufferPtr;
ComPtr<ID3D12Resource> GPUVertexBufferPtr;
ComPtr<ID3D12Resource> GPUIndexBufferPtr;
ComPtr<ID3D12Resource> VertexBufferTmpPtr;
ComPtr<ID3D12Resource> IndexBufferTmpPtr;
shared_ptr<FRenderingResoucesUpdate> ObjectConstants;
ComPtr<ID3D12DescriptorHeap> CBVHeap;
};
//常量缓冲区的信息
class FRenderingResoucesUpdate :public enable_shared_from_this <FRenderingResoucesUpdate >
{
public:
FRenderingResoucesUpdate();
~FRenderingResoucesUpdate();
void Init(ComPtr<ID3D12Device> InDevice, UINT InDataSize, UINT InDataCount);
void Update(UINT Index, const void* InData);
UINT GetConstantBufferBytesSize(UINT InBytesSize);
UINT GetConstantBufferBytesSize();
ID3D12Resource* GetBuffer() { return UpdateBuffer.Get(); }
private:
ComPtr<ID3D12Resource> UpdateBuffer;
BYTE* Data;
UINT ElementSize;
};
常量缓冲区
常量缓冲区是GPU资源(ID3D12Resource),其数据内容可以在着色器程序中引用,方便了C++和Shader的通信。
创建常量缓冲区
//常量缓冲区
// CBV 栈创建
D3D12_DESCRIPTOR_HEAP_DESC CBVDescriptorHeapDesc;
CBVDescriptorHeapDesc.NumDescriptors = 1;
CBVDescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
CBVDescriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
CBVDescriptorHeapDesc.NodeMask = 0;//默认
ANALYSIS_HRESULT(GetD3D12Device()->CreateDescriptorHeap(
&CBVDescriptorHeapDesc,
IID_PPV_ARGS(CBVHeap.GetAddressOf())));
///
ObjectConstants = make_shared<FRenderingResoucesUpdate>();
ObjectConstants->Init(GetD3D12Device().Get(),sizeof(FObjectTrasformation),1);
D3D12_GPU_VIRTUAL_ADDRESS GPUVADD = ObjectConstants.get()->GetBuffer()->GetGPUVirtualAddress();
D3D12_CONSTANT_BUFFER_VIEW_DESC ConstantBVD;
ConstantBVD.BufferLocation = GPUVADD;
ConstantBVD.SizeInBytes = ObjectConstants->GetConstantBufferBytesSize();
GetD3D12Device()->CreateConstantBufferView(
&ConstantBVD,
CBVHeap->GetCPUDescriptorHandleForHeapStart()
);
根签名
帮着色器提供在渲染流水线需要的所有资源
根参数可以是 根常量、根描述符、描述符表(可以装CBV)
这里使用描述符表
//构建根签名
CD3DX12_ROOT_PARAMETER RootParam[1];
//CBV描述表
/* D3D12_DESCRIPTOR_RANGE_TYPE_SRV = 0,
D3D12_DESCRIPTOR_RANGE_TYPE_UAV = (D3D12_DESCRIPTOR_RANGE_TYPE_SRV + 1),//无序访问视图
D3D12_DESCRIPTOR_RANGE_TYPE_CBV = (D3D12_DESCRIPTOR_RANGE_TYPE_UAV + 1),//常量缓冲区的视图
D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER = (D3D12_DESCRIPTOR_RANGE_TYPE_CBV + 1)*/
CD3DX12_DESCRIPTOR_RANGE DescRangeCBV;
DescRangeCBV.Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV,1,0);//0:0号着色器
RootParam[0].InitAsDescriptorTable(1, &DescRangeCBV);
/* D3D12_ROOT_SIGNATURE_FLAG_NONE = 0,
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT = 0x1,//为当前程序输入汇编器,顶点缓存绑定在输入布局
D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS = 0x2,//拒接顶点着色器访问的根签名
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS = 0x4,//拒接外壳着色器访问的根签名
D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS = 0x8,//拒接域着色器访问的根签名
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS = 0x10,//拒接几何着色器访问的根签名
D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS = 0x20,//拒接像素着色器访问的根签名
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT = 0x40,//流输出有关
D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE = 0x80,//和光线追踪着色器一起使用,不能和其他的结合使用
D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS = 0x100,//拒接放大着色器访问的根签名
D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS = 0x200,//拒接顶点着色器访问的根签名拒绝网格着色器
D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED = 0x400,
D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED = 0x800*/
CD3DX12_ROOT_SIGNATURE_DESC RootSignatureDesc(
1, RootParam, 0, nullptr,D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
//创建二进制的 根签名
ComPtr<ID3DBlob> SerializeRootSignature;
ComPtr<ID3DBlob> ErrorBlob;
D3D12SerializeRootSignature(
&RootSignatureDesc,
D3D_ROOT_SIGNATURE_VERSION_1,
SerializeRootSignature.GetAddressOf(),
ErrorBlob.GetAddressOf()
);
if (!ErrorBlob)
{
Engine_Error("%s", (char*)ErrorBlob->GetBufferPointer());
}
//创建根签名
//nodemask:操作GPU顶点下表,只有一个GPU时,写0:单个GPU
GetD3D12Device()->CreateRootSignature(
0,
SerializeRootSignature->GetBufferPointer(),
SerializeRootSignature->GetBufferSize(),
IID_PPV_ARGS(&RootSignature)
);
Shader
//h
#pragma once
#include"Engine/EngineMinimal.h"
class FShader
{
public:
//InFileName:Shader保存位置
//InEntryFunName:入口函数名,Shader进入函数顶点名称,相当于Main
void BuildShader(const wstring& InFileName, const string& InEntryFunName, const string& InShaderVersion);
protected:
ComPtr<ID3DBlob> ShaderCode;
};
//cpp
#include"Shader.h"
void FShader::BuildShader(const wstring& InFileName, const string& InEntryFunName, const string& InShaderVersion)
{
ComPtr< ID3DBlob> ErrorBlobMsg;
D3DCompileFromFile(
InFileName.c_str(),
NULL,
D3D_COMPILE_STANDARD_FILE_INCLUDE,
InEntryFunName.c_str(),
InShaderVersion.c_str(),
#if _DEBUG
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION
#else
0
#endif
, 0, &ShaderCode, &ErrorBlobMsg
);
if (!ErrorBlobMsg)
{
Engine_Error("%s", (char*)ErrorBlobMsg->GetBufferPointer());
}
}
h
FShader VShader;
FShader IShader;
/* LPCSTR SemanticName:着色器输入的签名中与这个元素关联的HLSL语法
UINT SemanticIndex;//元素语义索引
DXGI_FORMAT Format;//指向元素顶点格式
UINT InputSlot;//当前汇编程序的整数值:0-15
UINT AlignedByteOffset;//可选,顶点到此元素的偏移量
D3D12_INPUT_CLASSIFICATION InputSlotClass;
UINT InstanceDataStepRate//默认是0,每个实例绘制的步数
*/
vector<D3D12_INPUT_ELEMENT_DESC> InputElementDesc;
cpp
//构建Shader
HLSL
VShader.BuildShader(L"../../../Shader/Hello.hlsl","VertexShaderMain","vs_5_0");
IShader.BuildShader(L"../../../Shader/Hello.hlsl", "PixelShaderMain", "vs_5_0");
InputElementDesc = {
{"Position",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0},
{"Color",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,12,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,0}
};
HLSL
输入输出点信息(映射到齐次剪裁面)
cbuffer ConstBuffer : register(b0) //b0->b14
{
float1x4 World;
}
struct MeshVertexIn
{
float3 Position : POSITIONT;
float4 Color : COLOR;
};
struct MeshVertexOut
{
float3 Position : SV_POSITIONT;
float4 Color : COLOR;
};
MeshVertexOut VertexShaderMain(MeshVertexIn MV)
{
MeshVertexOut Out;
//投影到齐次剪裁面
Out.Position = mul(float4(MV.Position, 1.f), World);
Out.Color = MV.Color;
return Out;
}
float4 PixelShaderMain(MeshVertexOut MVOut):SV_TARGET
{
return MVOut.Color;
}
PSO
流水线状态对象
//PSO
D3D12_GRAPHICS_PIPELINE_STATE_DESC GPSDesc;
memset(&GPSDesc, 0, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));//必须初始化为0,否则崩溃
//绑定输入层元素
GPSDesc.InputLayout.NumElements = (UINT)InputElementDesc.size();
GPSDesc.InputLayout.pInputElementDescs = InputElementDesc.data();
//绑定根签名
GPSDesc.pRootSignature = RootSignature.Get();
// 绑定顶点Shader
GPSDesc.VS.BytecodeLength = VShader.GetBufferSize();
GPSDesc.VS.pShaderBytecode = reinterpret_cast<BYTE*>(VShader.GetBufferData());
//绑定像素Shader
GPSDesc.PS.BytecodeLength = PShader.GetBufferSize();
GPSDesc.PS.pShaderBytecode = PShader.GetBufferData();
//配置光栅化
/* FillMode = D3D12_FILL_MODE_SOLID;//绘制实物(D3D12_FILL_MODE_WIREFRAME:绘制线框)
CullMode = D3D12_CULL_MODE_BACK;//剔除三角形后的图元(D3D12_CULL_MODE_NONE:不剔除)
FrontCounterClockwise = FALSE;//FALSE:根据三角形顶点顺时针绘制。TRUE:逆时针绘制
DepthBias = D3D12_DEFAULT_DEPTH_BIAS;//像素的深度值:0
DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;//像素最大深度偏差:0.0
SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;//像素在斜率上的标量
DepthClipEnable = TRUE;//是否启用距离(深度)裁剪
MultisampleEnable = FALSE;//true:线性抗锯齿,false:Alpha抗锯齿
AntialiasedLineEnable = FALSE;//是否开始行抗锯齿
ForcedSampleCount = 0;//采样强计数,主要用于UAV渲染,有效值:0 1 2 4 8 16. 0:不采用。>0:不要绑定深度模板视图且,禁用深度测试,确保着色器不输出深度
ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;//表示当前光栅化是否打开
*/
GPSDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
//1111...000:1代表采样哪个样本
GPSDesc.SampleMask = UINT_MAX;//混合状态下的视力模板。多重采样最多采样32位样本, UINT_MAX:表示采样所有样本
GPSDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
GPSDesc.NumRenderTargets = 1;
//设置混合
/*
AlphaToCoverageEnable = FALSE;//是否将当前像素作为渲染目标,是否使用当前的Alpha覆盖进行多重采样
IndependentBlendEnable = FALSE;//是否在同步渲染目标中启用独立的审核。FALSE:只使用RenderTarget的0号(一共八个)
*/
GPSDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
//设置深度模板
/* BOOL DepthEnable;//启用深度模板测试
D3D12_DEPTH_WRITE_MASK DepthWriteMask;//对深度模板的属性进行修改
D3D12_COMPARISON_FUNC DepthFunc;//标识的深度数据和现有的深度的数据进行比较顶点函数
BOOL StencilEnable;//启用模板测试
UINT8 StencilReadMask;//模板数据的深度模板缓冲区的识别有关
UINT8 StencilWriteMask;
D3D12_DEPTH_STENCILOP_DESC FrontFace;//表面法线朝向的像素,主要将深度测试和模板测试的结果用在对当前法线朝向相机的像素
D3D12_DEPTH_STENCILOP_DESC BackFace;//背面的像素
*/
GPSDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
//将引擎其他位置的参数调过来,Render提供接口
GPSDesc.SampleDesc.Count = GetEngine()->GetDXGISampleCount();
GPSDesc.SampleDesc.Quality = GetEngine()->GetDXGISampleQuality();
GPSDesc.RTVFormats[0] = GetEngine()->GetBackBufferFormat();
GPSDesc.DSVFormat = GetEngine()->GetDepthStencilFormat();
HRESULT PR = GetD3D12Device()->CreateGraphicsPipelineState(&GPSDesc, IID_PPV_ARGS(&PSO));
ANALYSIS_HRESULT(PR);
Draw
前面准备好了常量缓冲区、根签名(描述符表)、Shader(.hlsl)、拷贝顶点信息到CPU、GPU缓冲区、PSO(渲染管线绑定对象,如Mesh)
提交绘制命令
//获取常量缓冲区
ID3D12DescriptorHeap* DescriptorHeap[] = { CBVHeap.Get() };
GetGraphicsCommandList()->SetDescriptorHeaps(_countof(DescriptorHeap), DescriptorHeap);
GetGraphicsCommandList()->SetGraphicsRootSignature(RootSignature.Get());//描述表在这里输入到常量缓冲区
// 提交数据
绑定渲染流水线上的输入槽,可以输入装配阶段传入的顶点数据
D3D12_VERTEX_BUFFER_VIEW VBV=GetVertexBufferView();
GetGraphicsCommandList()->IASetVertexBuffers(
0,//起始插槽0-15 k
1,//视口号:k+1 k+2 ...k+n-1
&VBV
);
D3D12_INDEX_BUFFER_VIEW IBV=GetIndexBufferView();
GetGraphicsCommandList()->IASetIndexBuffer(
&IBV
);
//要绘制的图元:点、线、面
GetGraphicsCommandList()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
GetGraphicsCommandList()->SetGraphicsRootDescriptorTable(0, CBVHeap->GetGPUDescriptorHandleForHeapStart());
//实际绘制
GetGraphicsCommandList()->DrawIndexedInstanced(
IndexSize,//顶点数量
1,//绘制的实例
0,//顶点缓冲区第一个被绘制的索引
0,//GPU读取索引缓冲区第一个索引的位置
0//从顶点缓冲区读取每个实例之前添加到每个索引的值
);
准备相关矩阵
旋转矩阵
模型算法:
基本概念:
1.DX中3个点顺时针排序表示面面向摄像机(存放Index数组中,顺时针存放Index)
InAxialSubdivision:轴(纵)向分段数。
InHeightSubdvision:横向分段数。
2.绘制环形(圆形,非球)上的点时,点数=横向分段数+1(多一个点方便程序化生成,相对于头尾点完全重叠)。
3.绘制时优先考虑绘制特殊点(南北极),在程序化绘制中间部分。
4.球坐标转笛卡尔坐标:
DX中,Y和Z轴相反,Y轴朝上
Beta:纵向夹角,θ:横向夹角
x=rsin(Beta)cos(θ)
z=rsin(θ)sin(Beta)
y=r*cos(Beta)
Box:
CBoxMesh* CBoxMesh::CreateMesh(FMeshRenderingData& MeshData, float InWidth, float InHeight, float InDepth)
{
float HalfWidth=0.5 * InWidth;
float HalfHeight= 0.5 * InHeight;
float HalfDepth= 0.5 * InDepth;
MeshData.VertexData.push_back(FVertex(XMFLOAT3(-HalfWidth,-HalfHeight,-HalfDepth), XMFLOAT4(Colors::White)));
MeshData.VertexData.push_back(FVertex(XMFLOAT3(-HalfWidth, HalfHeight, -HalfDepth), XMFLOAT4(Colors::AliceBlue)));
MeshData.VertexData.push_back(FVertex(XMFLOAT3(HalfWidth, HalfHeight, -HalfDepth), XMFLOAT4(Colors::Aqua)));
MeshData.VertexData.push_back(FVertex(XMFLOAT3(HalfWidth, -HalfHeight, -HalfDepth), XMFLOAT4(Colors::AntiqueWhite)));
MeshData.VertexData.push_back(FVertex(XMFLOAT3(-HalfWidth, -HalfHeight, HalfDepth), XMFLOAT4(Colors::Azure)));
MeshData.VertexData.push_back(FVertex(XMFLOAT3(-HalfWidth, HalfHeight, HalfDepth), XMFLOAT4(Colors::Brown)));
MeshData.VertexData.push_back(FVertex(XMFLOAT3(HalfWidth, HalfHeight, HalfDepth), XMFLOAT4(Colors::Coral)));
MeshData.VertexData.push_back(FVertex(XMFLOAT3(HalfWidth, -HalfHeight, HalfDepth), XMFLOAT4(Colors::Crimson)));
//构建索引
//前
MeshData.IndexData.push_back(0); MeshData.IndexData.push_back(1); MeshData.IndexData.push_back(2);
MeshData.IndexData.push_back(0); MeshData.IndexData.push_back(2); MeshData.IndexData.push_back(3);
//后
MeshData.IndexData.push_back(4); MeshData.IndexData.push_back(6); MeshData.IndexData.push_back(5);
MeshData.IndexData.push_back(4); MeshData.IndexData.push_back(7); MeshData.IndexData.push_back(6);
//左
MeshData.IndexData.push_back(4); MeshData.IndexData.push_back(5); MeshData.IndexData.push_back(1);
MeshData.IndexData.push_back(4); MeshData.IndexData.push_back(1); MeshData.IndexData.push_back(0);
//右
MeshData.IndexData.push_back(3); MeshData.IndexData.push_back(2); MeshData.IndexData.push_back(6);
MeshData.IndexData.push_back(3); MeshData.IndexData.push_back(6); MeshData.IndexData.push_back(7);
//上
MeshData.IndexData.push_back(1); MeshData.IndexData.push_back(5); MeshData.IndexData.push_back(6);
MeshData.IndexData.push_back(1); MeshData.IndexData.push_back(6); MeshData.IndexData.push_back(2);//2
//下
MeshData.IndexData.push_back(4); MeshData.IndexData.push_back(0); MeshData.IndexData.push_back(3);
MeshData.IndexData.push_back(4); MeshData.IndexData.push_back(3); MeshData.IndexData.push_back(7);
CBoxMesh* OutMesh = new CBoxMesh;
OutMesh->BuildMesh(&MeshData);
OutMesh->Init();
return OutMesh;
}
Sphere:
CSphereMesh* CSphereMesh::CreateMesh(FMeshRenderingData& MeshData, float Radius, float InAxialSubdivision, float InHeightSubdvision)
{
float ThetaValue = XM_2PI / InHeightSubdvision;
float BetaValue = XM_PI / InAxialSubdivision;
//Vertex
//绘制北极
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(
0, Radius, 0),
XMFLOAT4(Colors::Red)));
//绘制中间、
for (uint32_t i = 1; i < InAxialSubdivision; ++i)
{
float Beta = i * BetaValue;
for (uint32_t j = 0; j <= InHeightSubdvision ; ++j)//1
{
float Theta = j * ThetaValue;
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(
Radius * sinf(Beta) * cosf(Theta),
Radius * cosf(Beta),
Radius * sinf(Beta) * sinf(Theta)),
XMFLOAT4(Colors::White)));
int TopIndex = MeshData.VertexData.size() - 1;
FVertex& InVertex = MeshData.VertexData[TopIndex];
//法线
XMVECTOR Pos = XMLoadFloat3(&InVertex.Position);
XMStoreFloat3(&InVertex.Normal, XMVector3Normalize(Pos));
//切线
InVertex.UTangent.x = -Radius * sinf(Beta) * sinf(Theta);
InVertex.UTangent.y = 0;
InVertex.UTangent.z = Radius * sinf(Beta) * cosf(Theta);
}
}
//南极
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(
0, -Radius, 0),
XMFLOAT4(Colors::Red)));
//Index
//绘制北极
for (uint16_t j = 0; j <= InHeightSubdvision; ++j)
{
MeshData.IndexData.push_back(0);
MeshData.IndexData.push_back(j + 1);
MeshData.IndexData.push_back(j);
};
//for (uint16_t j = 1; j < InAxialSubdivision; j++)
//{
// MeshData.IndexData.push_back(0);
// MeshData.IndexData.push_back(j+1);
// MeshData.IndexData.push_back(j);
//};
0 8 1
//MeshData.IndexData.push_back(0);
//MeshData.IndexData.push_back(1);
//MeshData.IndexData.push_back(InAxialSubdivision);
//绘制中间
float BaseIndex = 1;
//float VertexCircleNum = InHeightSubdvision;//南北极也算一圈?
float VertexCircleNum = InHeightSubdvision + 1;//他是InAxialSubdivision?
for (uint32_t i = 0; i < InAxialSubdivision -2; ++i)// InHeightSubdvision
{
for (uint16_t j = 0; j < InHeightSubdvision; ++j)///InAxialSubdivision
{
//三角形1
MeshData.IndexData.push_back(BaseIndex+i*VertexCircleNum+j);
MeshData.IndexData.push_back(BaseIndex + i * VertexCircleNum + j+1);
MeshData.IndexData.push_back(BaseIndex + (i+1)*VertexCircleNum + j);
//三角形2
MeshData.IndexData.push_back(BaseIndex + (i + 1) * VertexCircleNum + j);
MeshData.IndexData.push_back(BaseIndex + i * VertexCircleNum + j + 1);
MeshData.IndexData.push_back(BaseIndex + (i + 1) * VertexCircleNum + j+1);
}
}
//绘制南极
int SouthBaseIndex = MeshData.VertexData.size() - 1;
BaseIndex = SouthBaseIndex - VertexCircleNum;
for (uint16_t j = 0; j <= InHeightSubdvision; ++j)//1
{
MeshData.IndexData.push_back(SouthBaseIndex);
MeshData.IndexData.push_back(BaseIndex +j);
MeshData.IndexData.push_back(BaseIndex + j + 1);
};
/*MeshData.IndexData.push_back(SouthBaseIndex);
MeshData.IndexData.push_back(BaseIndex + InAxialSubdivision);
MeshData.IndexData.push_back(BaseIndex + 1);*/
CSphereMesh* OutMesh = new CSphereMesh;
OutMesh->BuildMesh(&MeshData);
OutMesh->Init();
return OutMesh;
}
Cone:
CConeMesh* CConeMesh::CreateMesh(FMeshRenderingData& MeshData, float InRadius, float InHight, float InAxialSubdivision, float InHeightSubdvision)
{
//考虑上下底面半径不同
float RadiusInterval = -InRadius / InAxialSubdivision;
float HightInterval = InHight / InAxialSubdivision;
float Beta = XM_2PI / InHeightSubdvision;
//自上而下添加点Vertex
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(0, 0.5 * InHight, 0),
XMFLOAT4(Colors::Red)
)
);
for (uint32_t i = 1; i <= InAxialSubdivision; i++)
{
float Radius = -(i * RadiusInterval);
float Y = 0.5 * InHight - i * HightInterval;
for (size_t j = 0; j <= InHeightSubdvision; ++j)
{
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(Radius * cosf(j * Beta), Y, Radius * sinf(j * Beta)),
XMFLOAT4(Colors::White)
)
);
}
}
//Bottom
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(0, -0.5 * InHight, 0),
XMFLOAT4(Colors::Red)
)
);
//Index
//顶
for (uint16_t j = 1; j <= InHeightSubdvision+1; ++j)
{
MeshData.IndexData.push_back(0);
MeshData.IndexData.push_back(j+1);
MeshData.IndexData.push_back(j);
}
float VertexCircleNum = InHeightSubdvision + 1;
for (uint32_t i = 0; i < InAxialSubdivision-1; i++)
{
for (uint16_t j = 1; j <= InHeightSubdvision; ++j)
{
//三角形1
MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j + 1);
MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j);
MeshData.IndexData.push_back(i * VertexCircleNum + j);
//三角形2
MeshData.IndexData.push_back(i * VertexCircleNum + j + 1);
MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j + 1);
MeshData.IndexData.push_back(i * VertexCircleNum + j);
}
}
float Bottom = MeshData.VertexData.size() - 1;
float BaseIndex = Bottom - VertexCircleNum;
for (uint16_t j = 0; j <= InHeightSubdvision; ++j)
{
MeshData.IndexData.push_back(Bottom);
MeshData.IndexData.push_back(BaseIndex+j);
MeshData.IndexData.push_back(BaseIndex+j+1);
}
CConeMesh* OutMesh = new CConeMesh;
OutMesh->BuildMesh(&MeshData);
OutMesh->Init();
return OutMesh;
}
Cylinder:
CCylinderMesh* CCylinderMesh::CreateMesh(FMeshRenderingData& MeshData, float InTopRadius, float InBottomRadius,float InHight, float InAxialSubdivision, float InHeightSubdvision)
{
//考虑上下底面半径不同
float RadiuInterval = (InTopRadius - InBottomRadius) / InAxialSubdivision;
float HightInterval = InHight / InAxialSubdivision;
float Beta = XM_2PI / InHeightSubdvision;
//自上而下添加点Vertex
顶部
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(0, 0.5 * InHight, 0),
XMFLOAT4(Colors::Red)
)
);
/*for (size_t j = 0; j < InAxialSubdivision; ++j)
{
float Radius = InTopRadius;
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(Radius * cosf(j * Beta), 0.5 * InHight, Radius * sinf(j * Beta)),
XMFLOAT4(Colors::White)
)
);
};*/
中部
for (uint32_t i = 0; i <= InAxialSubdivision; i++)//<x-1
{
float Y = 0.5 * InHight - i * HightInterval;
float Radius = InTopRadius - i * RadiuInterval;
for (size_t j = 0; j < InHeightSubdvision+1; ++j)//<X+1
{
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(Radius * cosf(j * Beta), Y, Radius * sinf(j * Beta)),
XMFLOAT4(Colors::White)
)
);
};
}
底部
/*for (size_t j = 0; j < InAxialSubdivision; ++j)
{
float Radius = InBottomRadius;
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(Radius * cosf(j * Beta), -0.5 * InHight, Radius * sinf(j * Beta)),
XMFLOAT4(Colors::White)
)
);
};*/
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(0, -0.5 * InHight, 0),
XMFLOAT4(Colors::Red)
)
);
//绘制Index
//
// 绘制顶部
for (uint16_t j = 0; j < InHeightSubdvision; ++j)///InAxialSubdivision
{
MeshData.IndexData.push_back(0);
MeshData.IndexData.push_back(j+1);
MeshData.IndexData.push_back(j);
}
//绘制中间
float BaseIndex = 1;
//float VertexCircleNum = InHeightSubdvision;//南北极也算一圈?
float VertexCircleNum = InHeightSubdvision + 1;//他是InAxialSubdivision?
for (uint32_t i = 0; i < InAxialSubdivision ; i++)// InHeightSubdvision
{
for (uint16_t j = 1; j <= InHeightSubdvision; ++j)///InAxialSubdivision
{
//反向,法线远离摄像机
三角形1
//MeshData.IndexData.push_back(i * VertexCircleNum + j);
//MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j);
//MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j + 1);
三角形2
//MeshData.IndexData.push_back(i * VertexCircleNum + j);
//MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j+1);
//MeshData.IndexData.push_back(i * VertexCircleNum + j + 1);
//正向,法线朝向摄像机
//三角形1
MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j + 1);
MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j);
MeshData.IndexData.push_back(i * VertexCircleNum + j);
//三角形2
MeshData.IndexData.push_back(i * VertexCircleNum + j + 1);
MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j + 1);
MeshData.IndexData.push_back(i * VertexCircleNum + j);
}
}
// 绘制底部
float Bottom = MeshData.VertexData.size() - 1;
BaseIndex = Bottom - VertexCircleNum;
for (uint16_t j = 0; j < InHeightSubdvision; j++)///InAxialSubdivision
{
MeshData.IndexData.push_back(Bottom);
MeshData.IndexData.push_back(BaseIndex+j);
MeshData.IndexData.push_back(BaseIndex+j+1);
}
CCylinderMesh* OutMesh = new CCylinderMesh;
OutMesh->BuildMesh(&MeshData);
OutMesh->Init();
return OutMesh;
}
PlaneMesh:
CPlaneMesh* CPlaneMesh::CreateMesh(FMeshRenderingData& MeshData, float InWidth, float InHeight, uint32_t InHeightSubdvision, uint32_t InAxialSubdivision )
{
float HalfWidth = 0.5 * InWidth;
float HalfHeight = 0.5 * InHeight;
float WidthInterval = InWidth / InAxialSubdivision;
float HightInterval = InHeight / InHeightSubdvision;
//Vertex
for (uint32_t i = 0; i < InAxialSubdivision+1; i++)
{
float X = HalfWidth - i * WidthInterval;
for (uint32_t j = 0; j < InHeightSubdvision +1; j++)
{
float Z = HalfHeight - j * HightInterval;
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(X, 0, Z),
XMFLOAT4(Colors::AliceBlue)
)
);
}
}
//Index
float VertexCircleNum = InHeightSubdvision + 1;
for (uint32_t i = 0; i < InAxialSubdivision ; i++)
{
for (uint32_t j = 0; j < InHeightSubdvision; j++)
{
//三角形1
MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j + 1);
MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j);
MeshData.IndexData.push_back(i * VertexCircleNum + j);
//三角形2
MeshData.IndexData.push_back(i * VertexCircleNum + j + 1);
MeshData.IndexData.push_back((i + 1) * VertexCircleNum + j + 1);
MeshData.IndexData.push_back(i * VertexCircleNum + j);
}
}
CPlaneMesh* OutMesh = new CPlaneMesh;
OutMesh->BuildMesh(&MeshData);
OutMesh->Init();
return OutMesh;
}
Custom(Object):
CCustomMesh* CCustomMesh::CreateMesh(FMeshRenderingData& MeshData, string& InPath)
{
{
unsigned int FileSize = get_file_size_by_filename(InPath.c_str());
char* Buff = new char[FileSize+1];
memset(Buff, 0, FileSize+1);
get_file_buf(InPath.c_str(), Buff);
if (!LoadObjectFromBuff(Buff, FileSize, MeshData))
{
}
delete Buff;
}
CCustomMesh* OutMesh = new CCustomMesh;
OutMesh->BuildMesh(&MeshData);
OutMesh->Init();
return OutMesh;
}
bool CCustomMesh::LoadObjectFromBuff(char* InBuff, uint32_t InBuffSize, FMeshRenderingData& MeshData)
{
if (InBuffSize>0)
{
stringstream BuffStream(InBuff);
char TmpLine[256] = { 0 };
string MidTmpTag;
for (; !BuffStream.eof();)
{
memset(TmpLine, 0, 256);
//读取一行数据
BuffStream.getline(TmpLine,256);
if (strlen(TmpLine) > 0)
{
//Vertex
if (TmpLine[0] == 'v')
{
stringstream TmpStream(TmpLine);
TmpStream >> MidTmpTag;
if (TmpLine[1] == 'n')
{
}
else if (TmpLine[1] == 't')
{
}
else
{
//先添加一个
MeshData.VertexData.push_back(
FVertex(
XMFLOAT3(),
XMFLOAT4(Colors::White)));
//拿到点的位置
size_t Top = MeshData.VertexData.size() - 1;
XMFLOAT3& Float3InPos= MeshData.VertexData[Top].Position;
//解析位置
TmpStream >> Float3InPos.x;
TmpStream >> Float3InPos.y;
TmpStream >> Float3InPos.z;
}
}
//Index 绘制指令
362/380/361 363/381/363 382/342/382 A/B/C A:顶点索引 B:纹理索引 C:法线索引
else if (TmpLine[0] == 'f')
{
stringstream TmpStream(TmpLine);
TmpStream >> MidTmpTag;
char SaveLineString[256] = {0};
char TmpBuff[256] = { 0 };
for (size_t i = 0; i < 3; i++)
{
memset(SaveLineString, 0, 256);
//输入一行
TmpStream >> SaveLineString;
//找到索引位置,拷贝
int StringPosA = find_string(SaveLineString, "/", 0);
memset(TmpBuff, 0, 256);
char* VPosIndex = string_mid(SaveLineString, TmpBuff, 0, StringPosA);
MeshData.IndexData.push_back(atoi(VPosIndex));
//纹理坐标
int StringPosB = find_string(SaveLineString, "/", StringPosA+1);
memset(TmpBuff, 0, 256);
char* MPosIndex = string_mid(SaveLineString, TmpBuff, StringPosA + 1, StringPosB- StringPosA-1);
//法线索引
memset(TmpBuff, 0, 256);
char* NPosIndex = string_mid(SaveLineString, TmpBuff, StringPosB + 1, strlen(SaveLineString)-StringPosB-1);
}
}
}
}
}
return true;
}
TBN矩阵
tangant轴(T)、bitangent轴(B)、轴(法线)(N),即切线空间(TBN)
基本概念:
1.的意义:一是表示角度二是a投影到b的 长度
2.T B相当于U V
一个三角形的三个点
(U、V )
向量和T B的关系
用矩阵表示
反求T B(也就是我需要的UV)
根据矩阵乘法
展开