#include #include #include #include #include #include #include #include #include #include #include #include #include #include using Microsoft::WRL::ComPtr; #define DXCHK(condition) \ if (FAILED(condition)) { \ throw std::runtime_error("bad DirectX calling"); \ } #pragma region Win32 Window Creation // Window procedure for the render window static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CLOSE: PostQuitMessage(0); return 0; default: break; } return DefWindowProcW(hwnd, msg, wParam, lParam); } // Create a render window for DirectX static HWND CreateRenderWindow(std::uint32_t width, std::uint32_t height) { static bool g_CLSREG = false; constexpr wchar_t class_name[] = L"DirectXRenderWindowClass"; if (!g_CLSREG) { WNDCLASSEXW wc = {0}; wc.cbSize = sizeof(WNDCLASSEXW); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.hInstance = GetModuleHandleW(nullptr); wc.hCursor = LoadCursorW(nullptr, IDC_ARROW); wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wc.lpszClassName = class_name; if (!RegisterClassExW(&wc)) { throw std::runtime_error("Failed to register window class"); } g_CLSREG = true; } // Calculate window size including borders RECT rect = {0, 0, static_cast(width), static_cast(height)}; AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); HWND hwnd = CreateWindowExW(0, class_name, L"DirectXRenderWindow", WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, nullptr, nullptr, GetModuleHandleW(nullptr), nullptr); if (!hwnd) { throw std::runtime_error("Failed to create render window"); } return hwnd; } static void DestroyRenderWindow(HWND hwnd) { DestroyWindow(hwnd); } /** * @brief Non-block event loop. * @return True for indicate active exit. */ static bool EventLoop() { MSG msg; if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE) == 0) { // No msg return false; } else { if (msg.message == WM_QUIT) { return true; } else { TranslateMessage(&msg); DispatchMessageW(&msg); return false; } } } #pragma endregion // 立方体顶点(位置) struct Vertex { float x, y, z; }; // 简单顶点着色器(只传位置) const char* g_VS = R"( float4 main(float3 pos : POSITION) : SV_POSITION { return float4(pos, 1.0f); } )"; // 简单像素着色器(返回固定颜色) const char* g_PS = R"( float4 main() : SV_TARGET { return float4(0.2f, 0.4f, 0.8f, 1.0f); } )"; namespace guid = ::basalt::shared::guid; namespace engine = ::basalt::shared::engine; using ::basalt::shared::math::Vector3; using engine::EngineConfig; using engine::IEngine; class DirectX11Engine : public IEngine { public: DirectX11Engine() : IEngine() {} virtual ~DirectX11Engine() {} private: HWND window; ///< Win32窗口 ComPtr factory; ///< 适配器工厂 ComPtr adapter; ///< 适配器 ComPtr device; ///< 设备 ComPtr context; ///< 上下文 ComPtr swap_chain; ///< 交换链 ComPtr rtv; ///< 渲染目标视图 ComPtr back_buffer; ///< 后缓冲 ComPtr depth_buffer; ///< 深度缓冲 ComPtr dsv; ///< 深度模板视图 ComPtr depth_staging; ///< 用于CPU读取的深度暂存纹理 ComPtr vs; ///< 顶点着色器 ComPtr ps; ///< 像素着色器 ComPtr vs_blob; ///< 顶点着色器字节码 ComPtr ps_blob; ///< 像素着色器字节码 ComPtr input_layout; ///< 输入布局 ComPtr vertex_buffer; ///< 顶点缓冲 ComPtr depth_state; ///< 深度状态 ComPtr rasterizer_state; ///< 光栅化状态 std::vector depth_data; ///< 深度数据 UINT vertex_count; ///< 顶点数量 public: virtual guid::Guid get_guid() const { return guid::DIRECTX11_ENGINE; } virtual void startup(EngineConfig&& config) override { IEngine::startup(std::move(config)); // 创建Win32窗口并显示 if (this->config.headless) { window = NULL; } else { window = CreateRenderWindow(this->config.width, this->config.height); ShowWindow(window, SW_SHOW); UpdateWindow(window); } // 初始化 COM DXCHK(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)); // 创建Factory和Adapter,枚举并选择设备 DXCHK(CreateDXGIFactory(IID_PPV_ARGS(&factory))); spdlog::info(BSTEXT("Available DirectX Devices:")); { UINT i = 0; while (factory->EnumAdapters(i, &adapter) != DXGI_ERROR_NOT_FOUND) { DXGI_ADAPTER_DESC desc; DXCHK(adapter->GetDesc(&desc)); spdlog::info(BSTEXT("\t{}\t{}"), i, desc.Description); ++i; } } DXCHK(factory->EnumAdapters(static_cast(this->config.device), &adapter)); // 创建设备和上下文 DXCHK(D3D11CreateDevice(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0,//D3D11_CREATE_DEVICE_DEBUG, nullptr, 0, D3D11_SDK_VERSION, &device, nullptr, &context)); // 创建交换链(窗口可选,这里仅用于渲染上下文) DXGI_SWAP_CHAIN_DESC sd = {}; sd.BufferDesc.Width = this->config.width; sd.BufferDesc.Height = this->config.height; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.SampleDesc.Count = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.BufferCount = 1; sd.OutputWindow = window; sd.Windowed = TRUE; DXCHK(factory->CreateSwapChain(device.Get(), &sd, &swap_chain)); // 创建渲染目标 DXCHK(swap_chain->GetBuffer(0, IID_PPV_ARGS(&back_buffer))); DXCHK(device->CreateRenderTargetView(back_buffer.Get(), nullptr, &rtv)); // 创建深度缓冲(D32_FLOAT) D3D11_TEXTURE2D_DESC depth_desc = {}; depth_desc.Width = this->config.width; depth_desc.Height = this->config.height; depth_desc.MipLevels = 1; depth_desc.ArraySize = 1; depth_desc.Format = DXGI_FORMAT_D32_FLOAT; depth_desc.SampleDesc.Count = 1; depth_desc.Usage = D3D11_USAGE_DEFAULT; depth_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; DXCHK(device->CreateTexture2D(&depth_desc, nullptr, &depth_buffer)); DXCHK(device->CreateDepthStencilView(depth_buffer.Get(), nullptr, &dsv)); // 创建 staging texture 用于 CPU 读取深度(R32_FLOAT) D3D11_TEXTURE2D_DESC staging_desc = depth_desc; staging_desc.Format = DXGI_FORMAT_R32_FLOAT; // 注意:DSV 用 D32_FLOAT,staging 用 R32_FLOAT staging_desc.BindFlags = 0; staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; staging_desc.Usage = D3D11_USAGE_STAGING; DXCHK(device->CreateTexture2D(&staging_desc, nullptr, &depth_staging)); // 编译并创建着色器 DXCHK(D3DCompile(g_VS, static_cast(strlen(g_VS)), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vs_blob, nullptr)); DXCHK(D3DCompile(g_PS, static_cast(strlen(g_PS)), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &ps_blob, nullptr)); DXCHK(device->CreateVertexShader(vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), nullptr, &vs)); DXCHK(device->CreatePixelShader(ps_blob->GetBufferPointer(), ps_blob->GetBufferSize(), nullptr, &ps)); // 输入布局 D3D11_INPUT_ELEMENT_DESC layout[] = {{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}}; DXCHK(device->CreateInputLayout(layout, 1, vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), &input_layout)); // Create vertex buffer from object loader data std::vector vertices; size_t total_vertices = 0; // Count total vertices from all objects for (size_t i = 0; i < this->config.object_loader->get_object_count(); ++i) { const auto& obj = this->config.object_loader->get_object(i); total_vertices += obj.get_vertices_count(); } // Collect all vertices from all objects for (size_t i = 0; i < this->config.object_loader->get_object_count(); ++i) { const auto& obj = this->config.object_loader->get_object(i); const auto* obj_vertices = obj.get_vertices(); size_t obj_vertex_count = obj.get_vertices_count(); for (size_t j = 0; j < obj_vertex_count; ++j) { Vertex v; v.x = obj_vertices[j].x; v.y = obj_vertices[j].y; v.z = obj_vertices[j].z; vertices.push_back(v); } } // Create vertex buffer with dynamic size D3D11_BUFFER_DESC vb_desc = {}; vb_desc.ByteWidth = static_cast(vertices.size() * sizeof(Vertex)); vb_desc.Usage = D3D11_USAGE_DEFAULT; vb_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; D3D11_SUBRESOURCE_DATA vb_data = {vertices.data()}; DXCHK(device->CreateBuffer(&vb_desc, &vb_data, &vertex_buffer)); // Update draw call to use actual vertex count vertex_count = vertices.size(); // 深度测试启用 D3D11_DEPTH_STENCIL_DESC ds_desc = {}; ds_desc.DepthEnable = TRUE; ds_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; ds_desc.DepthFunc = D3D11_COMPARISON_LESS; DXCHK(device->CreateDepthStencilState(&ds_desc, &depth_state)); // 设置光栅化模式 D3D11_RASTERIZER_DESC rasterizer_desc; ZeroMemory(&rasterizer_desc, sizeof(D3D11_RASTERIZER_DESC)); rasterizer_desc.FillMode = D3D11_FILL_SOLID; rasterizer_desc.CullMode = D3D11_CULL_NONE; DXCHK(device->CreateRasterizerState(&rasterizer_desc, &rasterizer_state)); // 视口 D3D11_VIEWPORT vp; ZeroMemory(&vp, sizeof(D3D11_VIEWPORT)); vp.TopLeftX = 0; vp.TopLeftY = 0; vp.Width = (float) this->config.width; vp.Height = (float) this->config.height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; context->RSSetViewports(1, &vp); // RSSetViewports doesn't return HRESULT, so no need to wrap //// 打开命名管道(需另一进程已创建) //constexpr const wchar_t* PipeName = L"\\\\.\\pipe\\54da494c-301a-47a9-9d67-4fbebaeda8cf"; //hPipe = CreateFileW(PipeName, GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); //if (hPipe == INVALID_HANDLE_VALUE) { // std::cerr << "Failed to open named pipe. Ensure another process created it.\n"; // return; //} // 设置管线 context->OMSetRenderTargets(1, rtv.GetAddressOf(), dsv.Get()); context->OMSetDepthStencilState(depth_state.Get(), 1); context->RSSetState(rasterizer_state.Get()); context->VSSetShader(vs.Get(), nullptr, 0); context->PSSetShader(ps.Get(), nullptr, 0); context->IASetInputLayout(input_layout.Get()); UINT stride = sizeof(Vertex), offset = 0; context->IASetVertexBuffers(0, 1, vertex_buffer.GetAddressOf(), &stride, &offset); context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // 缩放深度数据数组到指定大小 depth_data.resize(this->config.width * this->config.height * sizeof(float)); //frameCount = 0; } virtual bool tick() override { if (IEngine::tick()) return true; // Event loop if (EventLoop()) return true; // 获取动画关键帧数据 basalt::shared::anime_loader::KeyFrameSpan keyframe_span; if (this->config.anime_loader) { keyframe_span = this->config.anime_loader->tick(); // Blender坐标系到DirectX坐标系的转换 // Blender (右手坐标系): 右+x, 上+y, 前-z // DirectX (左手坐标系): 右+x, 上+y, 前+z // 位置变换: X不变, Y不变, Z取反 float pos_x = keyframe_span.prev_position.x * keyframe_span.prev_time + keyframe_span.next_position.x * keyframe_span.next_time; float pos_y = keyframe_span.prev_position.y * keyframe_span.prev_time + keyframe_span.next_position.y * keyframe_span.next_time; float pos_z = -(keyframe_span.prev_position.z * keyframe_span.prev_time + keyframe_span.next_position.z * keyframe_span.next_time); // 旋转四元数变换: X和Z取反, Y和W保持不变 float rot_x = -(keyframe_span.prev_rotation.x * keyframe_span.prev_time + keyframe_span.next_rotation.x * keyframe_span.next_time); float rot_y = keyframe_span.prev_rotation.y * keyframe_span.prev_time + keyframe_span.next_rotation.y * keyframe_span.next_time; float rot_z = -(keyframe_span.prev_rotation.z * keyframe_span.prev_time + keyframe_span.next_rotation.z * keyframe_span.next_time); float rot_w = keyframe_span.prev_rotation.w * keyframe_span.prev_time + keyframe_span.next_rotation.w * keyframe_span.next_time; // 归一化四元数 float length = std::sqrt(rot_x * rot_x + rot_y * rot_y + rot_z * rot_z + rot_w * rot_w); if (length > 0.0f) { rot_x /= length; rot_y /= length; rot_z /= length; rot_w /= length; } // 这里可以应用相机变换,但目前我们只是获取了动画数据 // 在实际渲染中,这些值将用于构建视图矩阵 } // 清屏 float clear_color[] = {0.8f, 0.1f, 0.1f, 1.0f}; context->ClearRenderTargetView(rtv.Get(), clear_color); context->ClearDepthStencilView(dsv.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0); // Draw vertices from object loader or fallback cube context->Draw(vertex_count, 0); //// 复制深度缓冲到 staging texture //context->CopyResource(depth_staging.Get(), depth_buffer.Get()); //// Map 获取数据 //D3D11_MAPPED_SUBRESOURCE mapped; //DXCHK(context->Map(depth_staging.Get(), 0, D3D11_MAP_READ, 0, &mapped)); //memcpy(depth_data.data(), mapped.pData, this->config.width * this->config.height * sizeof(float)); //context->Unmap(depth_staging.Get(), 0); //// 写入命名管道 //DWORD written; //if (!WriteFile(hPipe, depth_data.data(), static_cast(this->config.width * this->config.height * sizeof(float)), &written, nullptr) || written != this->config.width * this->config.height * sizeof(float)) { // std::cerr << "WriteFile failed or incomplete.\n"; //} // 呈现(可选) DXCHK(swap_chain->Present(0, 0)); //frameCount++; return false; } virtual void shutdown() override { IEngine::shutdown(); //if (hPipe != INVALID_HANDLE_VALUE) { // CloseHandle(hPipe); //} CoUninitialize(); if (!this->config.headless) { CloseWindow(window); DestroyRenderWindow(window); } } }; BS_EXPORT void* BSCreateInstance() { return static_cast(new DirectX11Engine()); } BS_EXPORT void BSDestroyInstance(void* instance) { delete dynamic_cast(static_cast(instance)); }