学习如何使用 d3d11,使用 ComPtrs,没有错误检查是故意的,因为我只是使用断点来查看所有内容是否都被初始化,但没有任何内容被绘制到窗口,调试标志标记没有错误或警告,不要'不知道如何发现问题原因,据我所知一切都很好,只是想在屏幕上看到一个三角形,代码少于 200-250 行,请帮我解决这个问题。
#include <Windows.h>
#include <d3d11_1.h>
#include <wrl/client.h>
#include <d3dcompiler.h>
#pragma comment(lib, "d3dcompiler")
#pragma comment(lib, "d3d11")
#pragma comment(lib, "dxgi")
#define VSFile L"shader.sh"
#define FSFile L"shader.sh"
#include <iostream>
struct position {
float x, y;
};
struct color {
float r, g, b;
};
struct vertex {
position pos;
color col;
};
const vertex vertices[] = {
{-1.0f, 1.0f, 0.0f, 1.0f, 0.0f},
{ 1.0f, -1.0f, 0.0f, 0.0f, 1.0f},
{-1.0f, -1.0f, 1.0f, 0.0f, 0.0f},
};
int other(HINSTANCE hInstance);
LRESULT CALLBACK proc(HWND wnd, UINT msg, WPARAM wpr, LPARAM lpr) {
switch (msg) {
case WM_DESTROY: PostQuitMessage(0); break;
default: return DefWindowProc(wnd, msg, wpr, lpr);
}
return 0;
}
int main()
{
WNDCLASS wc = {};
wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB((255/2), (255 / 2), (255 / 2)));
wc.lpfnWndProc = proc;
wc.lpszClassName = L"class name";
RegisterClass(&wc);
HWND hwnd = CreateWindow(wc.lpszClassName, L"window name", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 500, nullptr, nullptr, nullptr, nullptr);
UnregisterClass(wc.lpszClassName, nullptr);
Microsoft::WRL::ComPtr<IDXGIFactory1> factory = nullptr;
Microsoft::WRL::ComPtr<ID3D11Device> device = nullptr;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> context = nullptr; {
CreateDXGIFactory1(IID_PPV_ARGS(&factory));
Microsoft::WRL::ComPtr<IDXGIAdapter> adapter = nullptr;
factory->EnumAdapters(0, adapter.GetAddressOf());
D3D11CreateDevice(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, 0, D3D11_CREATE_DEVICE_DEBUG, 0, 0, D3D11_SDK_VERSION, device.GetAddressOf(), 0, context.GetAddressOf());
}
Microsoft::WRL::ComPtr<ID3D11Buffer> vertex_buffer = nullptr; {
D3D11_BUFFER_DESC desc = {}; {
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.ByteWidth = sizeof(vertices);
desc.MiscFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.StructureByteStride = sizeof(vertex);
desc.Usage = D3D11_USAGE_DYNAMIC;
}
D3D11_SUBRESOURCE_DATA data = {}; {
data.pSysMem = &vertices;
}
device->CreateBuffer(&desc, &data, &vertex_buffer);
}
Microsoft::WRL::ComPtr<ID3D11VertexShader> vertex_shader = nullptr;
Microsoft::WRL::ComPtr<ID3DBlob> vs = nullptr; {
D3DCompileFromFile(VSFile, NULL, NULL, "vs_main", "vs_5_0", 0, 0, vs.GetAddressOf(), NULL);
device->CreateVertexShader(vs->GetBufferPointer(), vs->GetBufferSize(), NULL, vertex_shader.GetAddressOf());
}
Microsoft::WRL::ComPtr<ID3D11PixelShader> pixel_shader = nullptr; {
Microsoft::WRL::ComPtr<ID3DBlob> ps = nullptr;
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob = nullptr;
HRESULT hr = D3DCompileFromFile(FSFile, NULL, NULL, "fs_main", "ps_5_0", 0, 0, ps.GetAddressOf(), errorBlob.GetAddressOf());
hr = device->CreatePixelShader(ps->GetBufferPointer(), ps->GetBufferSize(), NULL, pixel_shader.GetAddressOf());
}
Microsoft::WRL::ComPtr<IDXGISwapChain> swapchain = nullptr; {
DXGI_SWAP_CHAIN_DESC desc = {}; {
desc.Windowed = 1;
desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
desc.OutputWindow = hwnd;
desc.SampleDesc.Count = 1;
desc.BufferCount = 3;
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.BufferDesc.RefreshRate = {120, 1};
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
}
factory->CreateSwapChain(device.Get(), &desc, swapchain.GetAddressOf());
}
Microsoft::WRL::ComPtr <ID3D11RenderTargetView> RTV = nullptr; {
D3D11_RENDER_TARGET_VIEW_DESC desc = {}; {
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
}
Microsoft::WRL::ComPtr<ID3D11Texture2D> back_buffer = nullptr;
swapchain->GetBuffer(0, IID_PPV_ARGS(back_buffer.GetAddressOf()));
device->CreateRenderTargetView(back_buffer.Get(),0, &RTV);
}
Microsoft::WRL::ComPtr<ID3D11InputLayout> layout = nullptr; {
const D3D11_INPUT_ELEMENT_DESC desc[] = {
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT , D3D11_INPUT_PER_VERTEX_DATA, 0}
};
HRESULT hr = device->CreateInputLayout(desc, ARRAYSIZE(desc), vs->GetBufferPointer(), vs->GetBufferSize(), layout.GetAddressOf());
if(true){}
}
{ UINT32 stride = sizeof(vertex); UINT offset = 0;
context->IAGetVertexBuffers(0, 1, vertex_buffer.GetAddressOf(), &stride, &offset);
context->IASetInputLayout(layout.Get());
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
context->VSSetShader(vertex_shader.Get(), NULL, 0);
context->PSSetShader(pixel_shader.Get(), NULL, 0);
context->OMSetRenderTargets(1, &RTV, nullptr);
}
ShowWindow(hwnd, SW_SHOW);
MSG msg = {};
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg); DispatchMessageW(&msg);
}
RECT winRect;
GetClientRect(hwnd, &winRect);
D3D11_VIEWPORT port[] = {
{.TopLeftX = 0, .TopLeftY = 0,
.Width = (FLOAT)(winRect.right - winRect.left),
.Height = (FLOAT)(winRect.bottom - winRect.top),
.MinDepth = 0, .MaxDepth = 1 }
}; context->RSSetViewports(1, port);
float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
context->ClearRenderTargetView(RTV.Get(), clearColor);
context->Draw(3, 0);
swapchain->Present(1, 0);
}
return 0;
}
// the shader (shaders.sh)
// Input structure representing a single vertex
struct VertexInput {
float2 Position : POSITION;
float3 Color : COLOR;
};
// Output structure to be passed to the pixel shader
struct VertexOutput {
float4 Position : SV_POSITION;
float3 Color : COLOR;
};
// The main vertex shader function
VertexOutput vs_main(VertexInput input) {
VertexOutput output;
// Transform the vertex position to clip space
output.Position = float4(input.Position, 0.0f, 1.0f);
// Pass the vertex color to the pixel shader
output.Color = input.Color;
return output;
}
float4 fs_main(VertexOutput input) : SV_TARGET
{
return float4(input.Color, 1.0f);
}
编辑:更新,发生错误,OMSetRenderTargets函数将RTV设置为null,但不知道为什么,msdn说如果我“尝试将相同的子资源设置为多个渲染目标插槽”,它将设置为null,我不太知道那是什么。
context->OMSetRenderTargets(1, &RTV, nullptr);
处的Addressof 运算符不会执行您认为的操作。它释放存储的接口并返回一个指向(现在为空)内部指针的指针。当您想要从方法获取接口并覆盖该接口的指针时,应该使用此方法,例如
device->CreateRenderTargetView(back_buffer.Get(),0, &RTV);
。
这里你应该使用
GetAddressOf
方法返回一个指向内部指针的指针而不释放所持有的接口:
context->OMSetRenderTargets(1, RTV.GetAddressOf(), nullptr);
或在临时数组中存储指针:
::std::array views{RTV.Get()};
context->OMSetRenderTargets(views.size(), views.data(), nullptr);
另外“故意不进行错误检查”是搬起石头砸自己的脚。