Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Gry platformy uniwersalnej Windows (UWP) 3-D zwykle używają wielokątów do reprezentowania obiektów i powierzchni w grze. Listy wierzchołków składających się na strukturę tych wielokątnych obiektów i powierzchni są nazywane siatkami. W tym miejscu tworzymy podstawową siatkę dla obiektu sześcianu i przekazujemy ją potokowi cieniowania na potrzeby renderowania i wyświetlania.
Important Przykładowy kod zawarty tutaj używa typów (takich jak DirectX::XMFLOAT3 i DirectX::XMFLOAT4X4) i metod wbudowanych zadeklarowanych w pliku DirectXMath.h. Jeśli kopiujesz i wklejasz ten kod, #include <DirectXMath.h> do projektu.
Co musisz wiedzieć
Technologie
Wymagania wstępne
- Podstawowa wiedza na temat algebry liniowej i układów współrzędnych 3D
- Szablon programu Visual Studio 2015 lub nowszego Direct3D
Instrukcje
W tych krokach pokazano, jak utworzyć podstawowy moduł siatki.
Krok 1. Konstruowanie siatki dla modelu
W większości gier siatka obiektu gry jest ładowana z pliku zawierającego określone dane wierzchołka. Kolejność tych wierzchołków jest zależna od aplikacji, ale są one zwykle serializowane jako paski lub struktury wachlarzowe. Dane wierzchołka mogą pochodzić z dowolnego źródła oprogramowania lub można je utworzyć ręcznie. To od Ciebie zależy, jak zinterpretujesz dane, aby shader wierzchołków mógł je skutecznie przetworzyć.
W naszym przykładzie używamy prostej siatki dla sześcianu. Sześcian, podobnie jak każda siatka obiektów na tym etapie w linii przetwarzania, jest reprezentowany przy użyciu własnego układu współrzędnych. Program cieniujący wierzchołki przyjmuje współrzędne i, stosując podane macierze przekształcenia, zwraca ostateczne projekcje widoku 2-D w jednorodnym układzie współrzędnych.
Zdefiniuj siatkę dla sześcianu. (Lub załaduj go z pliku. Decyzja należy do ciebie!)
SimpleCubeVertex cubeVertices[] =
{
{ DirectX::XMFLOAT3(-0.5f, 0.5f, -0.5f), DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f) }, // +Y (top face)
{ DirectX::XMFLOAT3( 0.5f, 0.5f, -0.5f), DirectX::XMFLOAT3(1.0f, 1.0f, 0.0f) },
{ DirectX::XMFLOAT3( 0.5f, 0.5f, 0.5f), DirectX::XMFLOAT3(1.0f, 1.0f, 1.0f) },
{ DirectX::XMFLOAT3(-0.5f, 0.5f, 0.5f), DirectX::XMFLOAT3(0.0f, 1.0f, 1.0f) },
{ DirectX::XMFLOAT3(-0.5f, -0.5f, 0.5f), DirectX::XMFLOAT3(0.0f, 0.0f, 1.0f) }, // -Y (bottom face)
{ DirectX::XMFLOAT3( 0.5f, -0.5f, 0.5f), DirectX::XMFLOAT3(1.0f, 0.0f, 1.0f) },
{ DirectX::XMFLOAT3( 0.5f, -0.5f, -0.5f), DirectX::XMFLOAT3(1.0f, 0.0f, 0.0f) },
{ DirectX::XMFLOAT3(-0.5f, -0.5f, -0.5f), DirectX::XMFLOAT3(0.0f, 0.0f, 0.0f) },
};
Układ współrzędnych sześcianu umieszcza środek sześcianu w początku układu, z osią y biegnącą od góry do dołu przy użyciu układu współrzędnych leworęcznych. Wartości współrzędnych są wyrażane jako 32-bitowe wartości zmiennoprzecinkowe między -1 a 1.
W każdej parze nawiasów druga grupa wartości DirectX::XMFLOAT3 określa kolor skojarzony z wierzchołkiem jako wartość RGB. Na przykład pierwszy wierzchołek (-0.5, 0.5, -0.5) ma pełny zielony kolor (wartość G jest ustawiona na 1,0, a wartości "R" i "B" są ustawione na 0).
W związku z tym masz 8 wierzchołków, z których każdy ma określony kolor. Każde połączenie wierzchołka/koloru jest pełnymi danymi dla wierzchołka w naszym przykładzie. Po określeniu buforu wierzchołka należy pamiętać o tym konkretnym układzie. Udostępniamy ten układ wejściowy do shadera wierzchołków, aby mógł zrozumieć Twoje dane wierzchołków.
Krok 2. Konfigurowanie układu wejściowego
Teraz masz wierzchołki w pamięci. Jednak urządzenie graficzne ma własną pamięć i używasz funkcji Direct3D, aby uzyskać do niej dostęp. Aby przesłać dane wierzchołków do urządzenia graficznego do przetworzenia, musisz uporządkować kwestie techniczne: musisz zadeklarować sposób, w jaki dane wierzchołków są ułożone, aby urządzenie graficzne mogło je interpretować, gdy otrzyma je z twojej gry. W tym celu należy użyć ID3D11InputLayout.
Zadeklaruj i ustaw układ wejściowy buforu wierzchołka.
const D3D11_INPUT_ELEMENT_DESC basicVertexLayoutDesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
ComPtr<ID3D11InputLayout> inputLayout;
m_d3dDevice->CreateInputLayout(
basicVertexLayoutDesc,
ARRAYSIZE(basicVertexLayoutDesc),
vertexShaderBytecode->Data,
vertexShaderBytecode->Length,
&inputLayout)
);
W tym kodzie określasz układ wierzchołków, w szczególności dane, które każdy element na liście wierzchołków zawiera. W tym miejscu w basicVertexLayoutDescnależy określić dwa składniki danych:
POSITION: jest to semantyka HLSL dla danych pozycji dostarczanych do shader'a. W tym kodzie jest to struktura DirectX::XMFLOAT3, a w szczególności struktura z trzema 32-bitowymi wartościami zmiennoprzecinkowymi odpowiadającymi współrzędnym 3D (x, y, z). Można również użyć float4, jeśli dostarczasz jednorodną współrzędną "w", a w takim przypadku należy określić DXGI_FORMAT_R32G32B32A32_FLOAT. Niezależnie od tego, czy używasz DirectX::XMFLOAT3, czy float4, zależy od konkretnych potrzeb Twojej gry. Upewnij się, że dane wierzchołka siatki odpowiadają poprawnie używanemu formatowi.
Każda wartość współrzędnych jest wyrażona jako wartość zmiennoprzecinkowa z zakresu od -1 do 1 w przestrzeni współrzędnej obiektu. Po zakończeniu działania shadera wierzchołków, przekształcony wierzchołek znajduje się w jednorodnej przestrzeni projekcji widoku ze skorygowaną perspektywą.
"Ale wartość wyliczenia wskazuje RGB, a nie XYZ!" inteligentnie zauważasz. Dobre oko! W obu przypadkach danych kolorowych i danych współrzędnych zazwyczaj używasz wartości składników 3 lub 4, więc dlaczego nie używać tego samego formatu dla obu? Semantyka HLSL, a nie nazwa formatu, wskazuje sposób traktowania danych przez moduł cieniowania.
color: jest to semantyka HLSL dla danych kolorów. Podobnie jak POSITION, składa się z 3 wartości zmiennoprzecinkowych 32-bitowych (DirectX::XMFLOAT3). Każda wartość zawiera składnik koloru: czerwony (r), niebieski (b) lub zielony (g), wyrażony jako liczba zmiennoprzecinkowa z zakresu od 0 do 1.
wartości COLOR są zwykle zwracane jako 4-składnikowa wartość RGBA na końcu potoku cieniowania. W tym przykładzie ustawisz wartość alfa „A” na 1,0 (maksymalną nieprzezroczystość) w strumieniu cieniowania dla każdego piksela.
Aby uzyskać pełną listę formatów, zobacz DXGI_FORMAT. Aby uzyskać pełną listę semantyki HLSL, zobacz Semantics.
Wywołaj ID3D11Device::CreateInputLayout i utwórz układ wejściowy na urządzeniu Direct3D. Teraz musisz utworzyć bufor, który może faktycznie przechowywać dane!
Krok 3: Wypełnić bufory wierzchołków
Bufory wierzchołków zawierają listę wierzchołków dla każdego trójkąta w siatce. Każdy wierzchołek musi być unikatowy na tej liście. W naszym przykładzie masz 8 wierzchołków dla sześcianu. Shader wierzchołków działa na urządzeniu graficznym, odczytuje dane z bufora wierzchołków i interpretuje te dane na podstawie układu wejściowego określonego w poprzednim kroku.
W następnym przykładzie podasz opis i podźródło buforu, które informują Direct3D o wielu rzeczach dotyczących fizycznego mapowania danych wierzchołków i sposobu traktowania ich w pamięci na urządzeniu graficznym. Jest to konieczne, ponieważ używasz ogólnego ID3D11Buffer, który może zawierać wszystko! Struktury D3D11_BUFFER_DESC i D3D11_SUBRESOURCE_DATA są dostępne w celu zapewnienia, że Direct3D zrozumie układ pamięci fizycznej buforu, w tym rozmiar każdego wierzchołka w buforze, a także maksymalny rozmiar listy wierzchołków. Możesz również kontrolować dostęp do pamięci buforu w tym miejscu i sposób jego przeglądania, co jednak wykracza nieco poza zakres omawianego samouczka.
Po skonfigurowaniu buforu wywołasz metodę ID3D11Device::CreateBuffer, aby ją utworzyć. Oczywiście, jeśli masz więcej niż jeden obiekt, utwórz bufor dla każdego unikatowego modelu.
Zadeklaruj i utwórz bufor wierzchołka.
D3D11_BUFFER_DESC vertexBufferDesc = {0};
vertexBufferDesc.ByteWidth = sizeof(SimpleCubeVertex) * ARRAYSIZE(cubeVertices);
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
vertexBufferDesc.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
vertexBufferData.pSysMem = cubeVertices;
vertexBufferData.SysMemPitch = 0;
vertexBufferData.SysMemSlicePitch = 0;
ComPtr<ID3D11Buffer> vertexBuffer;
m_d3dDevice->CreateBuffer(
&vertexBufferDesc,
&vertexBufferData,
&vertexBuffer);
Załadowane wierzchołki. Ale jaka jest kolejność przetwarzania tych wierzchołków? To jest obsługiwane, gdy podasz listę indeksów do wierzchołków — kolejność tych indeksów jest kolejnością, w której shader wierzchołka je przetwarza.
Krok 4. Wypełnianie buforów indeksów
Teraz należy podać listę indeksów dla każdego z wierzchołków. Te indeksy odpowiadają pozycji wierzchołka w buforze wierzchołka, zaczynając od 0. Aby ułatwić wizualizację, należy wziąć pod uwagę, że każdy unikatowy wierzchołek w siatce ma przypisaną unikatową liczbę, taką jak identyfikator. Ten identyfikator to pozycja całkowita wierzchołka w buforze wierzchołka.
W naszym przykładowym sześcianie masz 8 wierzchołków, które tworzą 6 czworokątów dla boków. Dzielisz czworokąty na trójkąty, aby otrzymać w sumie 12 trójkątów, które korzystają z 8 naszych wierzchołków. Przy 3 wierzchołkach na trójkąt istnieją 36 wpisy w naszym buforze indeksowym. W naszym przykładzie ten wzorzec indeksu jest znany jako lista trójkątów i wskazujesz go na Direct3D jako D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST podczas ustawiania topologii pierwotnej.
Jest to prawdopodobnie najbardziej nieefektywny sposób wymieniania indeksów, ponieważ występuje wiele powtórzeń, gdy trójkąty współdzielą punkty i boki. Na przykład gdy trójkąt dzieli bok w kształcie rombu, należy wypisać 6 indeksów dla czterech wierzchołków, w następujący sposób:
rombu
- Trójkąt 1: [0, 1, 2]
- Trójkąt 2: [0, 2, 3]
W topologii paska lub wentylatora porządkuj wierzchołki w sposób eliminujący wiele nadmiarowych krawędzi podczas przechodzenia (na przykład krawędzi od indeksu 0 do indeksu 2 na obrazie). W przypadku dużych siatek znacznie zmniejsza to liczbę operacji cieniowania wierzchołków i znacznie poprawia wydajność. Jednak zachowamy wszystko prosto i trzymamy się listy trójkątów.
Zadeklaruj indeksy buforu wierzchołka jako prostą topologię listy trójkątów.
unsigned short cubeIndices[] =
{ 0, 1, 2,
0, 2, 3,
4, 5, 6,
4, 6, 7,
3, 2, 5,
3, 5, 4,
2, 1, 6,
2, 6, 5,
1, 7, 6,
1, 0, 7,
0, 3, 4,
0, 4, 7 };
Trzydzieści sześć elementów indeksu w buforze jest bardzo nadmiarowe, gdy masz tylko 8 wierzchołków! Jeśli zdecydujesz się wyeliminować niektóre nadmiarowości i użyć innego typu listy wierzchołków, takiego jak pasek lub wachlarz, musisz określić ten typ, kiedy podajesz określoną wartość D3D11_PRIMITIVE_TOPOLOGY do metody ID3D11DeviceContext::IASetPrimitiveTopology.
Aby uzyskać więcej informacji na temat różnych technik listy indeksów, zobacz Topologie pierwotne.
Krok 5. Tworzenie stałego buforu dla macierzy przekształceń
Przed rozpoczęciem przetwarzania wierzchołków należy podać macierze przekształceń, które zostaną zastosowane (pomnożone) do każdego wierzchołka po uruchomieniu. W przypadku większości gier 3-D są trzy główne:
- Macierz 4x4, która przekształca się z układu współrzędnych obiektów (modelu) na ogólny układ współrzędnych świata.
- Macierz 4x4, która przekształca się z układu współrzędnych świata do układu współrzędnych kamery (widok).
- Macierz 4x4, która przekształca układ współrzędnych kamery na układ współrzędnych rzutowania 2D.
Te macierze są przekazywane do cieniowania w buforze stałej . Bufor stały to region pamięci, który pozostaje stały przez cały przebieg potoku cieniowania i który może być bezpośrednio dostępny przez cieniowanie w kodzie HLSL. Każdy bufor stały definiuje się dwa razy: najpierw w kodzie C++ gry i (przynajmniej) raz w składni HLSL przypominającej język C dla kodu cieniowania. Dwie deklaracje muszą odpowiadać bezpośrednio typom i wyrównaniu danych. Łatwo jest wprowadzić trudne do znalezienia błędów, gdy moduł cieniowania używa deklaracji HLSL do interpretowania danych zadeklarowanych w języku C++, a typy nie są zgodne lub wyrównanie danych jest wyłączone!
Bufory stałych nie są zmieniane przez HLSL. Możesz je zmienić, gdy gra aktualizuje określone dane. Często deweloperzy gier tworzą 4 klasy buforów stałych: jeden typ dla aktualizacji na klatkę; jeden typ dla aktualizacji na model/obiekt; jeden typ dla aktualizacji na odświeżenie stanu gry; i jeden typ dla danych, które nigdy się nie zmieniają przez okres trwania gry.
W tym przykładzie mamy tylko jeden element, który nigdy się nie zmienia: dane DirectX::XMFLOAT4X4 dotyczące trzech macierzy.
Uwaga Przykładowy kod przedstawiony tutaj używa macierzy głównych kolumn. Można użyć macierzy o układzie wierszowym, stosując słowo kluczowe row_major w HLSL i upewniając się, że dane macierzy źródłowej są również w układzie wierszowym. DirectXMath używa macierzy w porządku wierszowym i może być używane bezpośrednio z macierzami HLSL zdefiniowanymi za pomocą słowa kluczowego row_major.
Zadeklaruj i utwórz stały bufor dla trzech macierzy używanych do przekształcania każdego wierzchołka.
struct ConstantBuffer
{
DirectX::XMFLOAT4X4 model;
DirectX::XMFLOAT4X4 view;
DirectX::XMFLOAT4X4 projection;
};
ComPtr<ID3D11Buffer> m_constantBuffer;
ConstantBuffer m_constantBufferData;
// ...
// Create a constant buffer for passing model, view, and projection matrices
// to the vertex shader. This allows us to rotate the cube and apply
// a perspective projection to it.
D3D11_BUFFER_DESC constantBufferDesc = {0};
constantBufferDesc.ByteWidth = sizeof(m_constantBufferData);
constantBufferDesc.Usage = D3D11_USAGE_DEFAULT;
constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constantBufferDesc.CPUAccessFlags = 0;
constantBufferDesc.MiscFlags = 0;
constantBufferDesc.StructureByteStride = 0;
m_d3dDevice->CreateBuffer(
&constantBufferDesc,
nullptr,
&m_constantBuffer
);
m_constantBufferData.model = DirectX::XMFLOAT4X4( // Identity matrix, since you are not animating the object
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
);
// Specify the view (camera) transform corresponding to a camera position of
// X = 0, Y = 1, Z = 2.
m_constantBufferData.view = DirectX::XMFLOAT4X4(
-1.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
0.00000000f, 0.89442718f, 0.44721359f, 0.00000000f,
0.00000000f, 0.44721359f, -0.89442718f, -2.23606800f,
0.00000000f, 0.00000000f, 0.00000000f, 1.00000000f);
Uwaga Zwykle deklarujesz macierz projekcji podczas konfigurowania zasobów specyficznych dla danego urządzenia, ponieważ wyniki mnożenia przy użyciu jej muszą być zgodne z aktualnymi parametrami rozmiaru widoku 2-D (które często odpowiadają wysokości i szerokości pikseli wyświetlacza). W przypadku tych zmian należy odpowiednio skalować wartości współrzędnych x i y.
// Finally, update the constant buffer perspective projection parameters
// to account for the size of the application window. In this sample,
// the parameters are fixed to a 70-degree field of view, with a depth
// range of 0.01 to 100.
float xScale = 1.42814801f;
float yScale = 1.42814801f;
if (backBufferDesc.Width > backBufferDesc.Height)
{
xScale = yScale *
static_cast<float>(backBufferDesc.Height) /
static_cast<float>(backBufferDesc.Width);
}
else
{
yScale = xScale *
static_cast<float>(backBufferDesc.Width) /
static_cast<float>(backBufferDesc.Height);
}
m_constantBufferData.projection = DirectX::XMFLOAT4X4(
xScale, 0.0f, 0.0f, 0.0f,
0.0f, yScale, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f, -0.01f,
0.0f, 0.0f, -1.0f, 0.0f
);
Ustaw bufory wierzchołków i indeksów naID3D11DeviceContextoraz topologię, której używasz.
// Set the vertex and index buffers, and specify the way they define geometry.
UINT stride = sizeof(SimpleCubeVertex);
UINT offset = 0;
m_d3dDeviceContext->IASetVertexBuffers(
0,
1,
vertexBuffer.GetAddressOf(),
&stride,
&offset);
m_d3dDeviceContext->IASetIndexBuffer(
indexBuffer.Get(),
DXGI_FORMAT_R16_UINT,
0);
m_d3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
W porządku! Montaż wejściowy skończony. Wszystko jest gotowe do renderowania. Przejdźmy do uruchomienia shadera wierzchołków.
Krok 6. Przetwarzanie siatki za pomocą cieniowania wierzchołków
Teraz, gdy masz bufor wierzchołków z wierzchołkami definiującymi siatkę oraz bufor indeksów definiujących kolejność przetwarzania wierzchołków, wysyłasz je do shadera wierzchołków. Kod cieniowania wierzchołków, wyrażony jako skompilowany język cieniowania wysokiego poziomu, jest uruchamiany jeden raz dla każdego wierzchołka w buforze, co pozwala na wykonywanie przekształceń na każdym wierzchołku. Końcowy wynik jest zazwyczaj projekcją 2-D.
(Czy moduł cieniowania wierzchołków został załadowany? Jeśli nie, zapoznaj się z Jak załadować zasoby w grze DirectX.)
W tym miejscu utworzysz shader wierzchołków...
// Set the vertex and pixel shader stage state.
m_d3dDeviceContext->VSSetShader(
vertexShader.Get(),
nullptr,
0);
...i ustaw bufor stałych.
m_d3dDeviceContext->VSSetConstantBuffers(
0,
1,
m_constantBuffer.GetAddressOf());
Oto kod cieniowania wierzchołków, który obsługuje transformację ze współrzędnych obiektów do współrzędnych świata, a następnie do układu współrzędnych projekcji widoku 2-W. Stosujesz również proste oświetlenie dla wierzchołków, aby wszystko wyglądało ładnie. To umieszczasz w pliku HLSL dla cieniowania wierzchołków (SimplerVertexShader.hlsl w tym przykładzie).
cbuffer simpleConstantBuffer : register( b0 )
{
matrix model;
matrix view;
matrix projection;
};
struct VertexShaderInput
{
DirectX::XMFLOAT3 pos : POSITION;
DirectX::XMFLOAT3 color : COLOR;
};
struct PixelShaderInput
{
float4 pos : SV_POSITION;
float4 color : COLOR;
};
PixelShaderInput SimpleVertexShader(VertexShaderInput input)
{
PixelShaderInput vertexShaderOutput;
float4 pos = float4(input.pos, 1.0f);
// Transform the vertex position into projection space.
pos = mul(pos, model);
pos = mul(pos, view);
pos = mul(pos, projection);
vertexShaderOutput.pos = pos;
// Pass the vertex color through to the pixel shader.
vertexShaderOutput.color = float4(input.color, 1.0f);
return vertexShaderOutput;
}
Widzisz ten cbuffer na górze? Jest to analogia HLSL do tego samego buforu stałego, który zadeklarowaliśmy wcześniej w kodzie C++. A VertexShaderInputstruct? Czyżby to wyglądało tak jak Twój układ wejściowy i deklaracja danych wierzchołków! Ważne jest, aby deklaracje bufora stałego i danych wierzchołków w kodzie C++ odpowiadały deklaracjom w kodzie HLSL i zawierały znaki, typy oraz wyrównanie danych.
PixelShaderInput określa układ danych zwracanych przez główną funkcję shaderu wierzchołkowego. Po zakończeniu przetwarzania wierzchołka zostanie zwrócona pozycja wierzchołka w przestrzeni projekcji 2-D i kolor używany do oświetlenia na wierzchołku. Karta graficzna używa danych wyjściowych z shadera do obliczania "fragmentów" (możliwych pikseli), które muszą być pokolorowane, gdy shader pikseli jest uruchamiany w następnym etapie przetwarzania.
Krok 7. Przekazywanie siatki przez shader pikseli
Zazwyczaj na tym etapie potoku grafiki wykonujesz operacje na pikselach na widocznych rzutowanych powierzchniach obiektów. (Ludzie lubią tekstury). Jednak na potrzeby próbki wystarczy przejść przez ten etap.
Najpierw utwórzmy wystąpienie cieniowania pikseli. Shader pikseli działa dla każdego piksela w projekcji 2D sceny, przypisując kolor do tego piksela. W tym przypadku przekazujemy kolor piksela zwróconego przez cieniowanie wierzchołków prosto przez.
Ustaw cieniowanie pikseli.
m_d3dDeviceContext->PSSetShader( pixelShader.Get(), nullptr, 0 );
Zdefiniuj cieniowanie pikseli przekazywania w programie HLSL.
struct PixelShaderInput
{
float4 pos : SV_POSITION;
};
float4 SimplePixelShader(PixelShaderInput input) : SV_TARGET
{
// Draw the entire triangle yellow.
return float4(1.0f, 1.0f, 0.0f, 1.0f);
}
Umieść ten kod w osobnym pliku HLSL, oddzielnie od cieniownika wierzchołków HLSL (na przykład SimplePixelShader.hlsl). Ten kod jest uruchamiany za każdym razem dla każdego widocznego piksela w obszarze widoku (reprezentacja w pamięci części ekranu, na której rysujesz), co w tym przypadku mapuje się na cały ekran. Teraz twój potok przetwarzania grafiki jest całkowicie zdefiniowany!
Krok 8. Rasteryzacja i wyświetlanie siatki
Uruchommy rurę. Jest to łatwe: wywołaj ID3D11DeviceContext::DrawIndexed.
Rysuj ten sześcian!
// Draw the cube.
m_d3dDeviceContext->DrawIndexed( ARRAYSIZE(cubeIndices), 0, 0 );
Wewnątrz karty graficznej każdy wierzchołek jest przetwarzany w kolejności określonej w buforze indeksowym. Po wykonaniu cieniowania wierzchołków i zdefiniowaniu fragmentów 2-W cieniowanie pikseli jest wywoływane, a trójkąty są kolorowe.
Teraz umieść kostkę na ekranie.
Prześlij ten bufor ramki na wyświetlacz.
// Present the rendered image to the window. Because the maximum frame latency is set to 1,
// the render loop is generally throttled to the screen refresh rate, typically around
// 60 Hz, by sleeping the app on Present until the screen is refreshed.
m_swapChain->Present(1, 0);
Gotowe! W przypadku sceny pełnej modeli należy użyć wielu buforów wierzchołków i indeksów, a także różnych shaderów dla różnych typów modeli. Należy pamiętać, że każdy model ma własny układ współrzędnych i musisz przekształcić je do współużytkowanego systemu współrzędnych świata, używając macierzy zdefiniowanych w buforze stałym.
Uwagi
W tym temacie opisano tworzenie i wyświetlanie prostej geometrii utworzonej samodzielnie. Aby uzyskać więcej informacji na temat ładowania bardziej złożonej geometrii z pliku i jej konwertowania na format obiektu bufora wierzchołkowego specyficzny dla próbki (.vbo), zobacz Jak załadować zasoby w grze DirectX.
Tematy pokrewne