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";}
}
View Code