/
pobr
/
dx11-app
Обзор
Документация
Войти
/
pobr
/
dx11-app
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
main.cpp
557 строк
18 KB
evpobr
Quick fix
02 авг 2026, 04:50
02 авг 2026, 04:50
2733c01
Код
Авторство
О чём код?
#define UNICODE #define _UNICODE #include <windows.h> #include <windowsx.h> #include <DirectXMath.h> #include <d3d11.h> #include <d3dcompiler.h> #include <memory> #include <CommonStates.h> #include <Effects.h> #include <SimpleMath.h> #include <VertexTypes.h> #include <WICTextureLoader.h> #include <wrl/client.h> using namespace DirectX; using namespace DirectX::SimpleMath; using namespace Microsoft::WRL; const int SCREEN_WIDTH = 1024; const int SCREEN_HEIGHT = 768; ComPtr<ID3D11Device> g_spDevice; ComPtr<ID3D11DeviceContext> g_spContext; ComPtr<IDXGISwapChain> g_spSwapChain; ComPtr<ID3D11RenderTargetView> g_spRenderTargetView; ComPtr<ID3D11DepthStencilView> g_spDepthStencilView; // Глобальные указатели для куба ComPtr<ID3D11Buffer> g_spVertexBuffer; ComPtr<ID3D11Buffer> g_spIndexBuffer; ComPtr<ID3D11InputLayout> g_spInputLayout; ComPtr<ID3D11ShaderResourceView> g_spTextureView; Matrix g_World; Matrix g_View; Matrix g_Projection; UINT g_indexCount = 0; std::unique_ptr<BasicEffect> g_spEffect; void UpdateProjection ( int width, int height ) { if( !g_spContext || !g_spEffect ) return; // 1. Сбрасываем старые привязки рендер-таргетов g_spContext->OMSetRenderTargets( 0, nullptr, nullptr ); g_spRenderTargetView.Reset(); g_spDepthStencilView.Reset(); // 2. Изменяем размер Swap Chain под новое окно g_spSwapChain->ResizeBuffers( 0, width, height, DXGI_FORMAT_UNKNOWN, 0 ); // 3. Пересоздаем Render Target View ComPtr<ID3D11Texture2D> pBackBuffer; g_spSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast<void**>( pBackBuffer.GetAddressOf() ) ); g_spDevice->CreateRenderTargetView( pBackBuffer.Get(), nullptr, &g_spRenderTargetView ); g_spContext->OMSetRenderTargets( 1, g_spRenderTargetView.GetAddressOf(), g_spDepthStencilView.Get() ); // 5. Обновляем Viewport D3D11_VIEWPORT vp; vp.Width = (FLOAT)width; vp.Height = (FLOAT)height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; g_spContext->RSSetViewports( 1, &vp ); // 6. РАСЧЕТ И ПЕРЕДАЧА ПРОЕКЦИИ В ЭФФЕКТ float aspectRatio = static_cast<float>( width ) / static_cast<float>( height ); g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV4, aspectRatio, 0.01f, 100.0f ); // Передаем в BasicEffect один раз здесь! g_spEffect->SetProjection( g_Projection ); } BOOL OnSize ( HWND hwnd, UINT state, int cx, int cy ) { // Исключаем обработку при минимизации окна (когда размеры равны 0) if( state != SIZE_MINIMIZED && cx > 0 && cy > 0 ) { UpdateProjection( cx, cy ); } return TRUE; } BOOL OnPaint ( HWND hwnd ) { PAINTSTRUCT ps; HDC hdc = BeginPaint( hwnd, &ps ); EndPaint( hwnd, &ps ); return TRUE; } VOID OnDestroy ( HWND hwnd ) { PostQuitMessage( 0 ); } LRESULT CALLBACK WndProc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { HANDLE_MSG( hwnd, WM_SIZE, OnSize ); HANDLE_MSG( hwnd, WM_PAINT, OnPaint ); HANDLE_MSG( hwnd, WM_DESTROY, OnDestroy ); } return DefWindowProc( hwnd, msg, wParam, lParam ); } int WINAPI wWinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ) { UNREFERENCED_PARAMETER( hPrevInstance ); UNREFERENCED_PARAMETER( lpCmdLine ); WNDCLASSW wc = {}; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.hCursor = LoadCursorW( nullptr, IDC_ARROW ); wc.hbrBackground = reinterpret_cast<HBRUSH>( COLOR_WINDOW + 1 ); wc.lpszClassName = L"MainWindowClass"; RegisterClass( &wc ); RECT rcWnd; rcWnd.left = 0; rcWnd.right = SCREEN_WIDTH; rcWnd.top = 0; rcWnd.bottom = SCREEN_HEIGHT; const DWORD dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; AdjustWindowRect( &rcWnd, dwStyle, FALSE ); const int nWidth = rcWnd.right - rcWnd.left; const int nHeight = rcWnd.bottom - rcWnd.top; HWND hwnd = CreateWindowW( L"MainWindowClass", L"dx11-app", dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, nWidth, nHeight, nullptr, nullptr, hInstance, nullptr ); if( !hwnd ) { return 1; } ShowWindow( hwnd, nCmdShow ); UpdateWindow( hwnd ); DXGI_SWAP_CHAIN_DESC scd{}; scd.BufferCount = 1; scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scd.BufferDesc.Width = SCREEN_WIDTH; scd.BufferDesc.Height = SCREEN_HEIGHT; scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scd.OutputWindow = hwnd; scd.SampleDesc.Count = 1; scd.SampleDesc.Quality = 0; scd.Windowed = TRUE; D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 }; D3D_FEATURE_LEVEL supportedFeatureLevel; HRESULT hr = D3D11CreateDeviceAndSwapChain( nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, featureLevels, ARRAYSIZE( featureLevels ), D3D11_SDK_VERSION, &scd, &g_spSwapChain, &g_spDevice, &supportedFeatureLevel, &g_spContext ); if( FAILED( hr ) ) { return 1; } ComPtr<ID3D11Texture2D> spBackBuffer; hr = g_spSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast<void**>( spBackBuffer.GetAddressOf() ) ); if( FAILED( hr ) ) { return 1; } hr = g_spDevice->CreateRenderTargetView( spBackBuffer.Get(), nullptr, &g_spRenderTargetView ); if( FAILED( hr ) ) { return 1; } // 1. Описание текстуры для Z-буфера D3D11_TEXTURE2D_DESC descDepth = {}; descDepth.Width = SCREEN_WIDTH; descDepth.Height = SCREEN_HEIGHT; descDepth.MipLevels = 1; descDepth.ArraySize = 1; descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; // 24 бита на глубину, 8 бит на трафарет (stencil) descDepth.SampleDesc.Count = 1; // Должно совпадать со Swap Chain (у нас MSAA выключен) descDepth.SampleDesc.Quality = 0; descDepth.Usage = D3D11_USAGE_DEFAULT; descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; // Указываем, что это Z-буфер descDepth.CPUAccessFlags = 0; descDepth.MiscFlags = 0; ComPtr<ID3D11Texture2D> spDepthStencilTexture; // Создаем саму текстуру в памяти видеокарты hr = g_spDevice->CreateTexture2D( &descDepth, nullptr, &spDepthStencilTexture ); if( FAILED( hr ) ) { return 1; } // 2. Создание Depth Stencil View (объекта отображения глубины) D3D11_DEPTH_STENCIL_VIEW_DESC descDSV = {}; descDSV.Format = descDepth.Format; descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; descDSV.Texture2D.MipSlice = 0; hr = g_spDevice->CreateDepthStencilView( spDepthStencilTexture.Get(), &descDSV, &g_spDepthStencilView ); if( FAILED( hr ) ) { return 1; } g_spContext->OMSetRenderTargets( 1, g_spRenderTargetView.GetAddressOf(), nullptr ); D3D11_VIEWPORT viewport = {}; viewport.TopLeftX = 0; viewport.TopLeftY = 0; viewport.Width = static_cast<float>( SCREEN_WIDTH ); viewport.Height = static_cast<float>( SCREEN_HEIGHT ); viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; g_spContext->RSSetViewports( 1, &viewport ); g_spEffect = std::make_unique<BasicEffect>( g_spDevice.Get() ); g_spEffect->SetVertexColorEnabled( true ); g_spEffect->SetLightingEnabled( true ); g_spEffect->SetPerPixelLighting( false ); g_spEffect->SetDiffuseColor( Color( 1.0f, 1.0f, 1.0f, 1.0f ) ); // Объект полностью отражает текстуру g_spEffect->SetSpecularColor( Color( 0.4f, 0.4f, 0.4f, 1.0f ) ); // Цвет бликов на металле ящика g_spEffect->SetSpecularPower( 32.0f ); g_spEffect->SetTextureEnabled( true ); g_spEffect->SetLightEnabled( 0, true ); Vector4 LightDirection( 1.0f, -1.0f, 1.0f, 0.0f ); LightDirection.Normalize(); g_spEffect->SetLightDirection( 0, LightDirection ); // Свет падает сверху-справа-сзади g_spEffect->SetLightDiffuseColor( 0, Color( 1.0f, 1.0f, 1.0f, 1.0f ) ); // Белый свет g_spEffect->SetLightSpecularColor( 0, Color( 0.5f, 0.5f, 0.5f, 1.0f ) ); // Блики // Настраиваем окружающий (Ambient) свет, чтобы затененные грани не были абсолютно черными g_spEffect->SetAmbientLightColor( Color( 0.15f, 0.15f, 0.15f, 1.0f ) ); // 2. Загрузка текстуры из файла cube_texture.png // (Файл должен лежать в папке с проектом/исполняемым файлом) hr = CreateWICTextureFromFile( g_spDevice.Get(), g_spContext.Get(), L"crate.png", nullptr, &g_spTextureView ); if( FAILED( hr ) ) { // Если текстура не нашлась, выведем ошибку, чтобы программа не падала без предупреждения MessageBoxW( hwnd, L"Не удалось загрузить файл cube_texture.png!", L"Ошибка", MB_ICONERROR ); return 1; } g_spEffect->SetTexture( g_spTextureView.Get() ); void const* shaderByteCode; size_t byteCodeLength; g_spEffect->GetVertexShaderBytecode( &shaderByteCode, &byteCodeLength ); hr = g_spDevice->CreateInputLayout( VertexPositionNormalColorTexture::InputElements, VertexPositionNormalColorTexture::InputElementCount, shaderByteCode, byteCodeLength, &g_spInputLayout ); if( FAILED( hr ) ) { return 1; } // ВАЖНО: Используем тип VertexPositionNormalColorTexture на 24 вершины (по 48 байт каждая) VertexPositionNormalColorTexture vertices[] = { // --- Передняя грань (Z = -1.0f, Нормаль: вперед) --- { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) }, { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.0f ) }, { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.5f ) }, { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.5f ) }, // --- Задняя грань (Z = +1.0f, Нормаль: назад) --- { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) }, { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.0f ) }, { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.5f ) }, { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.5f ) }, // --- Левая грань (X = -1.0f, Нормаль: влево) --- { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) }, { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.0f ) }, { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.5f ) }, { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.5f ) }, // --- Правая грань (X = +1.0f, Нормаль: вправо) --- { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) }, { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.0f ) }, { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.5f ) }, { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.5f ) }, // --- Верхняя грань (Y = +1.0f, Нормаль: вверх) --- { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) }, { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.0f ) }, { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.5f ) }, { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.5f ) }, // --- Нижняя грань (Y = -1.0f, Нормаль: вниз) --- { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) }, { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.0f ) }, { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.5f, 0.5f ) }, { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.5f ) } }; D3D11_BUFFER_DESC vbd = {}; vbd.Usage = D3D11_USAGE_DEFAULT; vbd.ByteWidth = sizeof( vertices ); vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER; D3D11_SUBRESOURCE_DATA vsd = {}; vsd.pSysMem = vertices; hr = g_spDevice->CreateBuffer( &vbd, &vsd, &g_spVertexBuffer ); if( FAILED( hr ) ) return 1; // Математически выверенный порядок обхода для 24 вершин WORD indices[] = { // Передняя грань (вершины 0, 1, 2, 3) 0, 1, 2, 0, 2, 3, // Задняя грань (вершины 4, 5, 6, 7) 4, 5, 6, 4, 6, 7, // Левая грань (вершины 8, 9, 10, 11) 8, 9, 10, 8, 10, 11, // Правая грань (вершины 12, 13, 14, 15) 12, 13, 14, 12, 14, 15, // Верхняя грань (вершины 16, 17, 18, 19) 16, 17, 18, 16, 18, 19, // Нижняя грань (вершины 20, 21, 22, 23) 20, 21, 22, 20, 22, 23 }; g_indexCount = ARRAYSIZE( indices ); D3D11_BUFFER_DESC ibd = {}; ibd.Usage = D3D11_USAGE_DEFAULT; ibd.ByteWidth = sizeof( indices ); ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; D3D11_SUBRESOURCE_DATA isd = {}; isd.pSysMem = indices; hr = g_spDevice->CreateBuffer( &ibd, &isd, &g_spIndexBuffer ); if( FAILED( hr ) ) return 1; Vector4 Eye( 0.0f, 2.0f, -5.0f, 0.0f ); Vector4 At( 0.0f, 0.0f, 0.0f, 0.0f ); Vector4 Up( 0.0f, 1.0f, 0.0f, 0.0f ); g_View = XMMatrixLookAtLH( Eye, At, Up ); RECT rc; GetClientRect( GetActiveWindow(), &rc ); g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV4, ( rc.right - rc.left ) / (FLOAT)( rc.bottom - rc.top ), 0.01f, 100.0f ); UpdateProjection( SCREEN_WIDTH, SCREEN_HEIGHT ); MSG msg = {}; bool bIsRunning = true; while( bIsRunning ) { if( PeekMessageW( &msg, nullptr, 0, 0, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessageW( &msg ); if( msg.message == WM_QUIT ) { bIsRunning = false; } } else { const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; g_spContext->ClearRenderTargetView( g_spRenderTargetView.Get(), clearColor ); g_spContext->ClearDepthStencilView( g_spDepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 ); static float t = 0.0f; t += 0.001f; // Скорость вращения g_World = Matrix::CreateFromYawPitchRoll( t, t, 0.0f ); // 3. Передача матриц в BasicEffect // В отличие от стандартного HLSL, BasicEffect принимает матрицы напрямую без транспонирования g_spEffect->SetWorld( g_World ); g_spEffect->SetView( g_View ); // 4. Применение настроек эффекта к пайплайну g_spEffect->Apply( g_spContext.Get() ); CommonStates states( g_spDevice.Get() ); g_spContext->OMSetDepthStencilState( states.DepthDefault(), 0 ); auto sampler = states.LinearWrap(); g_spContext->PSSetSamplers( 0, 1, &sampler ); // 5. Отрисовка геометрии g_spContext->IASetInputLayout( g_spInputLayout.Get() ); UINT stride = sizeof( VertexPositionNormalColorTexture ); UINT offset = 0; g_spContext->IASetVertexBuffers( 0, 1, g_spVertexBuffer.GetAddressOf(), &stride, &offset ); g_spContext->IASetIndexBuffer( g_spIndexBuffer.Get(), DXGI_FORMAT_R16_UINT, 0 ); g_spContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); g_spContext->DrawIndexed( g_indexCount, 0, 0 ); g_spSwapChain->Present( 1, 0 ); } } return static_cast<int>( msg.wParam ); }