D3D11 创建个顶点布局需要依赖编译的 vsBlob 二进制代码,这点太影响封装了,问了问 AI,引用的 GameDev 网站的一个帖子,大概原理就是:创建一个虚拟的 blob,然后通过这个 blob 创建顶点布局。
/*** 根据输入布局描述生成匹配的虚拟顶点着色器 Blob* @param layoutDesc 输入布局描述数组* @param numElements 元素个数* @param ppBlob 返回生成的Blob对象* @return HRESULT 成功返回S_OK*/ CGL_API HRESULT CreateDummyVertexShaderBlob(const D3D11_INPUT_ELEMENT_DESC* layoutDesc,UINT size,ID3DBlob** ppBlob ) {if (!layoutDesc || !ppBlob)return E_INVALIDARG;// 构建着色器代码字符串 std::stringstream shaderCode;shaderCode << "struct VS_INPUT {\n";// 遍历每个输入元素,生成对应的成员变量for (UINT i = 0; i < size; ++i) {const auto& desc = layoutDesc[i];// 根据 DXGI 格式推导 HLSL 类型std::string hlslType = "float4"; // 默认switch (desc.Format) {case DXGI_FORMAT_R32_FLOAT: hlslType = "float"; break;case DXGI_FORMAT_R32G32_FLOAT: hlslType = "float2"; break;case DXGI_FORMAT_R32G32B32_FLOAT: hlslType = "float3"; break;case DXGI_FORMAT_R32G32B32A32_FLOAT: hlslType = "float4"; break;case DXGI_FORMAT_R32_UINT: hlslType = "uint"; break;case DXGI_FORMAT_R32_SINT: hlslType = "int"; break;// todo... 添加更多类型default:break;}// 语义名称 + 索引(例如:POSITION0, TEXCOORD1)std::string semantic = desc.SemanticName;if (desc.SemanticIndex > 0) {semantic += std::to_string(desc.SemanticIndex);}// 添加到结构体shaderCode << " " << hlslType << " " << semantic<< " : " << desc.SemanticName << desc.SemanticIndex << ";\n";}// 添加占位的输出结构体(像素着色器需要)shaderCode << "};\n\n";shaderCode << "struct VS_OUTPUT {\n";shaderCode << " float4 position : SV_POSITION;\n";shaderCode << "};\n\n";// 顶点着色器主函数 - 什么都不做,只返回一个固定的位置// 注意:SV_POSITION必须有值,否则D3D会报错shaderCode << "VS_OUTPUT main(VS_INPUT input) {\n";shaderCode << " VS_OUTPUT output;\n";shaderCode << " output.position = float4(0.0f, 0.0f, 0.0f, 1.0f);\n";shaderCode << " return output;\n";shaderCode << "}\n";// 2. 编译这个动态生成的着色器ID3DBlob* pErrorBlob = nullptr;HRESULT hr = D3DCompile(shaderCode.str().c_str(),shaderCode.str().length(),nullptr, // 文件名nullptr, // 宏定义nullptr, // 包含文件处理"main", // 入口函数名"vs_4_0", // 着色器模型D3DCOMPILE_OPTIMIZATION_LEVEL0, // 不优化,编译更快0,ppBlob,&pErrorBlob);// 如果编译失败,输出错误信息(用于调试)if (FAILED(hr) && pErrorBlob) {OutputDebugStringA((char*) pErrorBlob->GetBufferPointer());pErrorBlob->Release();}return hr; }// // 使用 //// 顶点格式 const D3D11_INPUT_ELEMENT_DESC VERTEX_LAYOUT[4] = {{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(vertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 },{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(vertex, normal), D3D11_INPUT_PER_VERTEX_DATA, 0 },{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(vertex, color), D3D11_INPUT_PER_VERTEX_DATA, 0 },{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(vertex, texcoord), D3D11_INPUT_PER_VERTEX_DATA, 0 }, };// Compile the vertex shader ID3DBlob* pVSBlob = nullptr; HRESULT hr = CreateDummyVertexShaderBlob(VERTEX_LAYOUT, 4, &pVSBlob);if (FAILED(hr)) {// 检查错误... } else {// Create the input layouthr = d3dDevice->CreateInputLayout(inputLayout, inputLayoutSize,pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(),m_inputLayout.ReleaseAndGetAddressOf());pVSBlob->Release(); }
附录:dxgi 格式转 hlsl 格式
#include <dxgiformat.h>/* 将DXGI格式转换为HLSL类型字符串* 基于完整的DXGI_FORMAT枚举(十六进制值已标注)*/ CGL_API std::string DXGIFormatToHLSLType(DXGI_FORMAT format) {switch (format) {// === 128-bit (4分量) 格式 ===case DXGI_FORMAT_R32G32B32A32_TYPELESS: // 0x1case DXGI_FORMAT_R32G32B32A32_FLOAT: // 0x2return "float4";case DXGI_FORMAT_R32G32B32A32_UINT: // 0x3return "uint4";case DXGI_FORMAT_R32G32B32A32_SINT: // 0x4return "int4";// === 96-bit (3分量) 格式 ===case DXGI_FORMAT_R32G32B32_TYPELESS: // 0x5case DXGI_FORMAT_R32G32B32_FLOAT: // 0x6return "float3";case DXGI_FORMAT_R32G32B32_UINT: // 0x7return "uint3";case DXGI_FORMAT_R32G32B32_SINT: // 0x8return "int3";// === 64-bit (4分量) 格式 ===case DXGI_FORMAT_R16G16B16A16_TYPELESS: // 0x9case DXGI_FORMAT_R16G16B16A16_FLOAT: // 0xareturn "float4";case DXGI_FORMAT_R16G16B16A16_UNORM: // 0xbcase DXGI_FORMAT_R16G16B16A16_SNORM: // 0xdreturn "float4";case DXGI_FORMAT_R16G16B16A16_UINT: // 0xcreturn "uint4";case DXGI_FORMAT_R16G16B16A16_SINT: // 0xereturn "int4";// === 64-bit (2分量) 格式 ===case DXGI_FORMAT_R32G32_TYPELESS: // 0xfcase DXGI_FORMAT_R32G32_FLOAT: // 0x10return "float2";case DXGI_FORMAT_R32G32_UINT: // 0x11return "uint2";case DXGI_FORMAT_R32G32_SINT: // 0x12return "int2";// === 特殊深度/模板格式 ===case DXGI_FORMAT_R32G8X24_TYPELESS: // 0x13case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: // 0x14case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: // 0x15case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: // 0x16return "float2";// === 32-bit (4分量) 打包格式 ===case DXGI_FORMAT_R10G10B10A2_TYPELESS: // 0x17case DXGI_FORMAT_R10G10B10A2_UNORM: // 0x18case DXGI_FORMAT_R10G10B10A2_UINT: // 0x19case DXGI_FORMAT_R11G11B10_FLOAT: // 0x1areturn "float4";// === 32-bit (4分量) 格式 ===case DXGI_FORMAT_R8G8B8A8_TYPELESS: // 0x1bcase DXGI_FORMAT_R8G8B8A8_UNORM: // 0x1ccase DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: // 0x1dcase DXGI_FORMAT_R8G8B8A8_SNORM: // 0x1freturn "float4";case DXGI_FORMAT_R8G8B8A8_UINT: // 0x1ereturn "uint4";case DXGI_FORMAT_R8G8B8A8_SINT: // 0x20return "int4";// === 32-bit (2分量) 格式 ===case DXGI_FORMAT_R16G16_TYPELESS: // 0x21case DXGI_FORMAT_R16G16_FLOAT: // 0x22case DXGI_FORMAT_R16G16_UNORM: // 0x23case DXGI_FORMAT_R16G16_SNORM: // 0x25return "float2";case DXGI_FORMAT_R16G16_UINT: // 0x24return "uint2";case DXGI_FORMAT_R16G16_SINT: // 0x26return "int2";// === 32-bit (1分量) 格式 ===case DXGI_FORMAT_R32_TYPELESS: // 0x27case DXGI_FORMAT_D32_FLOAT: // 0x28case DXGI_FORMAT_R32_FLOAT: // 0x29return "float";case DXGI_FORMAT_R32_UINT: // 0x2areturn "uint";case DXGI_FORMAT_R32_SINT: // 0x2breturn "int";// === 24-bit 深度/模板格式 ===case DXGI_FORMAT_R24G8_TYPELESS: // 0x2ccase DXGI_FORMAT_D24_UNORM_S8_UINT: // 0x2dcase DXGI_FORMAT_R24_UNORM_X8_TYPELESS: // 0x2ecase DXGI_FORMAT_X24_TYPELESS_G8_UINT: // 0x2freturn "float";// === 16-bit (2分量) 格式 ===case DXGI_FORMAT_R8G8_TYPELESS: // 0x30case DXGI_FORMAT_R8G8_UNORM: // 0x31case DXGI_FORMAT_R8G8_SNORM: // 0x33return "float2";case DXGI_FORMAT_R8G8_UINT: // 0x32return "uint2";case DXGI_FORMAT_R8G8_SINT: // 0x34return "int2";// === 16-bit (1分量) 格式 ===case DXGI_FORMAT_R16_TYPELESS: // 0x35case DXGI_FORMAT_R16_FLOAT: // 0x36case DXGI_FORMAT_D16_UNORM: // 0x37case DXGI_FORMAT_R16_UNORM: // 0x38case DXGI_FORMAT_R16_SNORM: // 0x3areturn "float";case DXGI_FORMAT_R16_UINT: // 0x39return "uint";case DXGI_FORMAT_R16_SINT: // 0x3breturn "int";// === 8-bit (1分量) 格式 ===case DXGI_FORMAT_R8_TYPELESS: // 0x3ccase DXGI_FORMAT_R8_UNORM: // 0x3dcase DXGI_FORMAT_R8_SNORM: // 0x3freturn "float";case DXGI_FORMAT_R8_UINT: // 0x3ereturn "uint";case DXGI_FORMAT_R8_SINT: // 0x40return "int";// === 特殊格式 ===case DXGI_FORMAT_A8_UNORM: // 0x41 (单一 alpha 通道)return "float";case DXGI_FORMAT_R1_UNORM: // 0x42 (1-bit格式)return "float";case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: // 0x43 (共享指数格式)return "float3";case DXGI_FORMAT_R8G8_B8G8_UNORM: // 0x44case DXGI_FORMAT_G8R8_G8B8_UNORM: // 0x45return "float4"; // 打包格式// === BC压缩格式 (纹理压缩) ===case DXGI_FORMAT_BC1_TYPELESS: // 0x46case DXGI_FORMAT_BC1_UNORM: // 0x47case DXGI_FORMAT_BC1_UNORM_SRGB: // 0x48case DXGI_FORMAT_BC2_TYPELESS: // 0x49case DXGI_FORMAT_BC2_UNORM: // 0x4acase DXGI_FORMAT_BC2_UNORM_SRGB: // 0x4bcase DXGI_FORMAT_BC3_TYPELESS: // 0x4ccase DXGI_FORMAT_BC3_UNORM: // 0x4dcase DXGI_FORMAT_BC3_UNORM_SRGB: // 0x4ecase DXGI_FORMAT_BC4_TYPELESS: // 0x4fcase DXGI_FORMAT_BC4_UNORM: // 0x50case DXGI_FORMAT_BC4_SNORM: // 0x51case DXGI_FORMAT_BC5_TYPELESS: // 0x52case DXGI_FORMAT_BC5_UNORM: // 0x53case DXGI_FORMAT_BC5_SNORM: // 0x54case DXGI_FORMAT_BC6H_TYPELESS: // 0x5ecase DXGI_FORMAT_BC6H_UF16: // 0x5fcase DXGI_FORMAT_BC6H_SF16: // 0x60case DXGI_FORMAT_BC7_TYPELESS: // 0x61case DXGI_FORMAT_BC7_UNORM: // 0x62case DXGI_FORMAT_BC7_UNORM_SRGB: // 0x63return "float4";// === BGR格式 ===case DXGI_FORMAT_B5G6R5_UNORM: // 0x55case DXGI_FORMAT_B5G5R5A1_UNORM: // 0x56case DXGI_FORMAT_B8G8R8A8_UNORM: // 0x57case DXGI_FORMAT_B8G8R8X8_UNORM: // 0x58case DXGI_FORMAT_B8G8R8A8_TYPELESS: // 0x5acase DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: // 0x5bcase DXGI_FORMAT_B8G8R8X8_TYPELESS: // 0x5ccase DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: // 0x5dcase DXGI_FORMAT_B4G4R4A4_UNORM: // 0x73return "float4";case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: // 0x59return "float4";// === 视频格式 ===case DXGI_FORMAT_AYUV: // 0x64case DXGI_FORMAT_Y410: // 0x65case DXGI_FORMAT_Y416: // 0x66case DXGI_FORMAT_NV12: // 0x67case DXGI_FORMAT_P010: // 0x68case DXGI_FORMAT_P016: // 0x69case DXGI_FORMAT_420_OPAQUE: // 0x6acase DXGI_FORMAT_YUY2: // 0x6bcase DXGI_FORMAT_Y210: // 0x6ccase DXGI_FORMAT_Y216: // 0x6dcase DXGI_FORMAT_NV11: // 0x6ecase DXGI_FORMAT_P208: // 0x82case DXGI_FORMAT_V208: // 0x83case DXGI_FORMAT_V408: // 0x84return "float4";// === 调色板格式 ===case DXGI_FORMAT_AI44: // 0x6fcase DXGI_FORMAT_IA44: // 0x70case DXGI_FORMAT_P8: // 0x71case DXGI_FORMAT_A8P8: // 0x72return "float4";default:return "unknown";} }
sdragonx https://github.com/sdragonx
