Настройка функций Depth-Stencil
В этом разделе рассматриваются действия по настройке буфера элементов глубины и состояния элементов глубины для этапа слияния выходных данных.
- Создать ресурс Depth-Stencil
- создание Depth-Stencil состояния
- Привязка данных Depth-Stencil к этапу OM
После того как вы узнаете, как использовать буфер глубины-шаблона и соответствующее состояние глубины-шаблона, ознакомьтесь с расширенными методами работы с шаблонами.
Создание ресурса Depth-Stencil
Создайте глубинно-трафаретный буфер с помощью ресурса текстуры.
ID3D11Texture2D* pDepthStencil = NULL;
D3D11_TEXTURE2D_DESC descDepth;
descDepth.Width = backBufferSurfaceDesc.Width;
descDepth.Height = backBufferSurfaceDesc.Height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = pDeviceSettings->d3d11.AutoDepthStencilFormat;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
hr = pd3dDevice->CreateTexture2D( &descDepth, NULL, &pDepthStencil );
Создание состояния Depth-Stencil
Состояние набора глубины сообщает этапу слияния выходных данных, как выполнить тест глубины элементов. Тест глубины и трафарета определяет, следует ли рисовать данный пиксель.
D3D11_DEPTH_STENCIL_DESC dsDesc;
// Depth test parameters
dsDesc.DepthEnable = true;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
// Stencil test parameters
dsDesc.StencilEnable = true;
dsDesc.StencilReadMask = 0xFF;
dsDesc.StencilWriteMask = 0xFF;
// Stencil operations if pixel is front-facing
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Stencil operations if pixel is back-facing
dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Create depth stencil state
ID3D11DepthStencilState * pDSState;
pd3dDevice->CreateDepthStencilState(&dsDesc, &pDSState);
DepthEnable и StencilEnable включают (и отключают) тестирование глубины и трафаретное тестирование. Задайте значение DepthEnable для FALSE, чтобы отключить тестирование глубины и запретить запись в буфер глубины. Задайте параметру StencilEnable значение FALSE, чтобы отключить тестирование трафарета и запретить запись в буфер трафарета (если DepthEnable FALSE и StencilEnable TRUE, то тест глубины всегда проходит в операции трафарета).
DepthEnable влияет только на этап объединения выходных данных — он не затрагивает отсечение, смещение глубины или ограничение значений перед подачей данных в пиксельный шейдер.
Привязать данные Depth-Stencil к стадии OM
Привязка состояния набора элементов глубины.
// Bind depth stencil state
pDevice->OMSetDepthStencilState(pDSState, 1);
Привяжите ресурс глубины и шаблона с помощью представления.
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
descDSV.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
// Create the depth stencil view
ID3D11DepthStencilView* pDSV;
hr = pd3dDevice->CreateDepthStencilView( pDepthStencil, // Depth stencil texture
&descDSV, // Depth stencil desc
&pDSV ); // [out] Depth stencil view
// Bind the depth stencil view
pd3dDeviceContext->OMSetRenderTargets( 1, // One rendertarget view
&pRTV, // Render target view, created earlier
pDSV ); // Depth stencil view for the render target
Массив представлений, предназначенных для отрисовки, может передаваться в ID3D11DeviceContext::OMSetRenderTargets, однако все эти представления отрисовки будут соответствовать одному представлению элементов глубины. Целевой массив отрисовки в Direct3D 11 — это функция, которая позволяет приложению обрабатывать несколько целевых объектов отрисовки одновременно на примитивном уровне. Массивы целевых объектов отрисовки обеспечивают повышенную производительность по сравнению с индивидуально устанавливаемыми целевыми объектами при множественных вызовах ID3D11DeviceContext::OMSetRenderTargets (по сути, метод, используемый в Direct3D 9).
Все целевые объекты отрисовки должны быть одинакового типа ресурсов. Если используется мультисэмплинговое сглаживание, все привязанные целевые объекты отрисовки и буферы глубины должны иметь одинаковые счетчики выборок.
Если буфер используется в качестве целевого объекта отрисовки, тестирование глубины и множественные целевые объекты отрисовки не поддерживаются.
- Одновременно можно связать 8 целевых объектов отрисовки.
- Все целевые объекты отрисовки должны иметь одинаковый размер во всех измерениях (ширина и высота и глубина для 3D или размера массива для *Типов массивов).
- Каждый целевой объект отрисовки может иметь другой формат данных.
- Маски записи определяют, какие данные записываются в целевой объект отрисовки. Маски записи выходных данных управляют для каждого целевого объекта отрисовки и на уровне каждого компонента тем, какие данные записываются в целевые объекты отрисовки.
Продвинутые техники работы с трафаретом
Часть буфера глубины-шаблона можно использовать для создания эффектов отрисовки, таких как композитинг, декалирование и выделение контура.
- Композитинг
- нанесение декали
- Контуры и силуэты
- Two-Sided трафарет
- чтение буфера Depth-Stencil в виде текстуры
Композитинг
Ваше приложение может использовать трафаретный буфер для наложения 2D или трехмерных изображений на 3D сцену. Маска в буфере трафарета используется для закрытия области на целевой поверхности отрисовки. Сохраненные 2D-данные, такие как текст или растровые изображения, затем можно записать в затемненную область. В качестве альтернативы, ваше приложение может отображать дополнительные трехмерные примитивы на заштрихованной области поверхности целевого объекта отрисовки. Он может даже отобразить всю сцену.
Игры часто комбинируют несколько трехмерных сцен вместе. Например, в играх для вождения обычно отображается зеркало заднего вида. Зеркало содержит изображение трехмерной сцены за водителем. По сути, это вторая трехмерная сцена, составная с представлением вперед водителя.
Нанесение декалей
Приложения Direct3D используют декалинг для управления тем, какие пиксели из определенного примитивного изображения рисуются на целевую поверхность отрисовки. Приложения применяют декали к изображениям примитивов, чтобы обеспечить правильную отрисовку копланарных многоугольников.
Например, при нанесении следов от шин и желтых линий на дорожное покрытие, разметка должна отображаться непосредственно на нем. Однако значения z маркировки и дороги одинаковы. Таким образом, буфер глубины может не производить чистое разделение между двумя. Некоторые пиксели в заднем примитиве могут отображаться поверх переднего примитива и наоборот. Полученный образ, как представляется, сияет от кадра к кадру. Этот эффект называется z-файтинг или фликеринг.
Чтобы решить эту проблему, используйте трафарет для маскировки участка заднего примитива, где будет отображаться декаль. Отключите Z-буферизацию и отрисуйте изображение переднего примитива в область, исключенную маской, на поверхности целевого объекта рендеринга.
Для решения этой проблемы можно использовать смешивание нескольких текстур.
Контуры и силуэты
Трафаретный буфер можно использовать для более абстрактных эффектов, таких как обводка и создание силуэтов.
Если ваше приложение выполняет два прохода отрисовки — один для создания трафаретной маски и второй для применения трафаретной маски к изображению, но с примитивами немного уменьшены на втором проходе, итоговое изображение будет содержать только контур примитива. Затем приложение может заполнить маскированную область изображения сплошным цветом, что придает примитиву рельефный вид.
Если трафаретная маска совпадает с размером и формой примитива, который вы отрисовываете, в результате получается изображение с отверстием на месте примитива. Затем приложение может заполнить отверстие черным, чтобы создать силуэт примитива.
Two-Sided трафарет
Теневые объемы используются для рисования теней с трафаретным буфером. Приложение вычисляет теневые объемы, создаваемые геометрией, вычисляя края силуэта и протягивая их от источника света, формируя набор трехмерных объемов. Затем эти тома отрисовываются дважды в трафаретный буфер.
Первая отрисовка рисует полигоны, обращенные вперед, и увеличивает значения трафаретного буфера. Вторая отрисовка рисует обратные многоугольники теневого тома и уменьшает значения трафаретного буфера. Как правило, все инкрементированные и декрементированные значения отменяют друг друга. Однако сцена уже была отрисована с нормальной геометрией, что приводит к сбою теста z-буфера при отрисовке объема теней. Значения, оставшиеся в трафаретном буфере, соответствуют пикселям, которые находятся в тени. Это оставшееся содержимое буфера трафаретов используется в качестве маски, чтобы альфа-смешиванием добавить в сцену большой черный квадрат, покрывающий её всю. При использовании трафаретного буфера, выступающего в качестве маски, результатом является затемнение пикселей, находящихся в тени.
Это означает, что теневая геометрия создается дважды для каждого источника света, тем самым увеличивая нагрузку на пропускную способность вершин GPU. Двухсторонняя функция трафарета разработана для решения этой проблемы. В этом подходе существуют два набора состояния трафарета (именуемых ниже): один набор для передних треугольников и другой для задних треугольников. Таким образом, только один проход выполняется на каждый теневой объем, на источник света.
Пример двухсторонней реализации трафаретов можно найти в примере ShadowVolume10.
Чтение буфера Depth-Stencil в виде текстуры
Неактивный буфер глубины и трафарета можно прочитать шейдером в виде текстуры. Приложение, которое считывает буфер глубины и трафарета как текстуру, визуализируется в два прохода: первый проход записывает в буфер глубины и трафарета, а второй считывает из буфера. Это позволяет шейдеру сравнивать значения глубины или трафаретные значения, ранее записанные в буфер, с со значением для пикселя, который в данный момент обрабатывается. Результат сравнения можно использовать для создания эффектов, таких как сопоставление тени или мягкие частицы в системе частиц.
Чтобы создать глубинно-трафаретный буфер, который можно использовать как глубинный и трафаретный ресурс, а также как ресурс шейдера, необходимо внести некоторые изменения в пример кода в разделе Создание Depth-Stencil ресурса.
Ресурс набора элементов глубины должен иметь нетипизированный формат, например, DXGI_FORMAT_R32_TYPELESS.
descDepth.Format = DXGI_FORMAT_R32_TYPELESS;
Ресурс глубины-трафарета должен использовать оба флага привязки D3D10_BIND_DEPTH_STENCIL и D3D10_BIND_SHADER_RESOURCE.
descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL | D3D10_BIND_SHADER_RESOURCE;
Кроме того, необходимо создать представление ресурсов шейдера для буфера глубины с помощью структуры D3D11_SHADER_RESOURCE_VIEW_DESC и ID3D11Device::CreateShaderResourceView. Представление ресурсов шейдера будет использовать типизированный формат, например DXGI_FORMAT_R32_FLOAT, который эквивалентен формату без типа, указанному при создании ресурса набора элементов глубины.
В первом проходе рендеринга буфер глубины привязывается, как указано в разделе Bind Depth-Stencil Data to the OM Stage. Обратите внимание, что формат, переданный в D3D11_DEPTH_STENCIL_VIEW_DESC, будет использовать типизированный формат, например DXGI_FORMAT_D32_FLOAT. После первого прохода отрисовки буфер глубины будет содержать значения глубины сцены.
Во втором проходе рендеринга функция ID3D11DeviceContext::OMSetRenderTargets используется для установки представления глубины-трафарета на NULL или другой ресурс глубины-трафарета, а представление ресурса шейдера передается в шейдер с использованием ID3D11EffectShaderResourceVariable::SetResource. Это позволяет шейдеру обращаться к значениям глубины, вычисленным в первом проходе отрисовки. Обратите внимание, что для получения значений глубины необходимо применить преобразование, если точка зрения первого прохода отрисовки отличается от второго прохода отрисовки. Например, если используется метод теневого картирования, первый проход отрисовки будет с точки зрения источника света, а второй — с точки зрения наблюдателя.
Связанные разделы
-
Output-Merger этап
-
Этапы конвейера (Direct3D 10)