Перенос функциональности трафарета OpenGL в DirectX 11

У меня есть код рендеринга, написанный на OpenGL. Я использую трафаретный буфер для реализации отсечения:


    //Let's assume this is done in render loop.

    if(!already_created())
    {
      create_stencil_attachment_and_bind_to_FB_as_depth_stencil_attachment();
    }

    glEnable(GL_STENCIL_TEST);
    glColorMask(0,0,0,0);
    glDepthMask(0);
    glClearStencil(0);
    glClear(GL_STENCIL_BUFFER_BIT);
    glStencilFunc(GL_ALWAYS,1,1);
    glStencilOp(GL_REPLACE,GL_REPLACE,GL_REPLACE);

    render_to_stencil();

    glColorMask(1,1,1,1);
    glDepthMask(1);
    glStencilFunc(GL_EQUAL,1,1);
    glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);

    render_with_clipping();

    glDisable(GL_STENCIL_TEST);

Теперь проблема в том, что мне нужно перенести этот код на DX11. Я видел примеры в MSDN и несколько хороших руководств. Я заканчиваю с этой логикой:

1. Create ID3D11Texture2D with format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT.
2. Create ID3D11DepthStencilState for rendering to stencil: //Let's call it DS_RENDER
   - For both front and back faces:
     - op = D3D11_STENCIL_OP_REPLACE for all 3 cases
     - func = D3D11_COMPARISON_ALWAYS
   - DepthEnable = FALSE
   - StencilEnable = TRUE
   - StencilReadMask = 0xFF
   - StencilWriteMask = 0xFF
3. Create ID3D11DepthStencilView for state and texture created before. //Let's call it DSV
4. Create ID3D11DepthStencilState for using stencil as 'input': //Let's call it DS_CLIP
   - For both front and back faces:
     - op = D3D11_STENCIL_OP_KEEP for all 3 cases
     - func = D3D11_COMPARISON_EQUAL
   - DepthEnable = FALSE
   - StencilEnable = TRUE
   - StencilReadMask = 0xFF
   - StencilWriteMask = 0xFF

Теперь я не уверен, как установить трафарет в качестве цели или ввода.

MSDN говорит:

`pDevice->OMSetDepthStencilState(pDSState, 1);`

а также

`pd3dDeviceContext->OMSetRenderTargets(1, &pRTV, pDSV);`

Если я правильно понимаю эти вызовы, первый устанавливает состояние трафарета, а второй привязывает pDSV как дополнительное «вложение» к цели рендеринга. Это правильно?

Если да, то будет ли это работать так, как я ожидаю?



    pDevice->OMSetDepthStencilState(DS_RENDER, 1);
    pd3dDeviceContext->OMSetRenderTargets(1, &pRTV, DSV);

    render_geometry_to_stencil_buffer();

    pDevice->OMSetDepthStencilState(DS_CLIP, 1);

    render_geometry_with_clipping();

    pd3dDeviceContext->OMSetRenderTargets(1, &pRTV, NULL); //Does this disable stencil testing?

Заранее спасибо за любую помощь или полезную подсказку.


person Mateusz Grzejek    schedule 11.10.2013    source источник


Ответы (1)


Если вы хотите отображать только трафарет, используйте (настройка состояния для записи):

pd3dDeviceContext->OMSetRenderTargets(0, NULL, DSV);

Вам не нужно выполнять рендеринг в цветовой буфер, поэтому не нужно его привязывать.

Затем для рендеринга вашей цели и включения теста трафарета используйте:

pd3dDeviceContext->OMSetRenderTargets(1, &pRTV, DSV);

Когда вы используете трафарет в качестве входных данных, очень просто установить StencilWriteMask = 0; Поэтому он никогда не будет писать в него (это то, что вы хотите отобразить усеченной геометрии).

Если вы используете:

pd3dDeviceContext->OMSetRenderTargets(1, &pRTV, NULL); 

Вы действительно отключите любую форму теста глубины/трафарета (глубина больше не ограничена, поэтому DepthStencilState вообще не будет иметь никакого эффекта).

Также я бы использовал DXGI_FORMAT_D24_UNORM_S8_UINT для вашего формата глубины (хотя личное предпочтение), он идеально подойдет для вашего варианта использования и потребляет меньше памяти.

Надеюсь, это поможет.

person mrvux    schedule 11.10.2013
comment
У меня не было возможности протестировать это решение, однако оно кажется последовательным и соответствует этим фрагментам. Я помню о трафарете в DX :) Я предоставлю отзыв как можно скорее. - person Mateusz Grzejek; 15.10.2013