Сделать тень с помощью stencil-буфера, алгоритм вроде такой: 1. Очистка буферов z-буфера и трафарета;
2. Выводим объекты (объект)
3. Включение теста трафарета и маскирование части экрана с помощью операций с буфером трафарета;
4. Очистка z-буфера;
5. Вывод всей сцены с учетом трафаретной маски.
Вот мой код функции рендеринга до теней// Функция рендеринга Direct3D
void RenderingDirect3D(void)
{
if (pDirect3DDevice == NULL)
return;
// Очистка z-буфера
pDirect3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(172, 221, 101), 1.0f, 0);
pDirect3DDevice->BeginScene();
pDirect3DDevice->SetStreamSource(0, pBufferVertices, 0, sizeof(TRIANGLEVERTEX));
pDirect3DDevice->SetIndices(pBufferIndexes);
pDirect3DDevice->SetFVF(D3DFVF_TRIANGLEVERTEX);
pDirect3DDevice->SetTexture(1, NULL);
// Установка идентификатора первой текстуры
pDirect3DDevice->SetTexture(0, pTexture0);
// Устанавливает состояния и операции первой текстуры
pDirect3DDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
Matrix();
pDirect3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 36, 0, 12);
pDirect3DDevice->SetTexture(0, NULL);
// Установка идентификатора второй текстуры
pDirect3DDevice->SetTexture (1, pTexture1);
// Устанавливает состояния и операции второй текстуры
pDirect3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0);
pDirect3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pDirect3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
Matrix1();
pDirect3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 36, 0, 12);
pDirect3DDevice->EndScene();
pDirect3DDevice->Present(NULL, NULL, NULL, NULL);
}
Вот мой код функции рендеринга и функции создания тени, но почему-то тени не появились, всё как было, так и осталось// Функция рендеринга Direct3D
void RenderingDirect3D(void)
{
if (pDirect3DDevice == NULL)
return;
// Очистка z-буфера
pDirect3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(172, 221, 101), 1.0f, 0);
// Очистка буфера трафарета (stencil)
pDirect3DDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_STENCIL, D3DCOLOR_XRGB(255,255,255), 0.0f, 0);
pDirect3DDevice->BeginScene();
pDirect3DDevice->SetStreamSource(0, pBufferVertices, 0, sizeof(TRIANGLEVERTEX));
pDirect3DDevice->SetIndices(pBufferIndexes);
pDirect3DDevice->SetFVF(D3DFVF_TRIANGLEVERTEX);
pDirect3DDevice->SetTexture(1, NULL);
// Установка идентификатора первой текстуры
pDirect3DDevice->SetTexture(0, pTexture0);
// Устанавливает состояния и операции первой текстуры
pDirect3DDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
Matrix();
pDirect3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 36, 0, 12);
pDirect3DDevice->SetTexture(0, NULL);
// Установка идентификатора второй текстуры
pDirect3DDevice->SetTexture (1, pTexture1);
// Устанавливает состояния и операции второй текстуры
pDirect3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0);
pDirect3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pDirect3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
Matrix1();
pDirect3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 36, 0, 12);
EnterStencilBuffer();
pDirect3DDevice->SetTexture(1, NULL);
// Установка идентификатора первой текстуры
pDirect3DDevice->SetTexture(0, pTexture0);
// Устанавливает состояния и операции первой текстуры
pDirect3DDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
Matrix();
pDirect3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 36, 0, 12);
pDirect3DDevice->SetTexture(0, NULL);
// Установка идентификатора второй текстуры
pDirect3DDevice->SetTexture (1, pTexture1);
// Устанавливает состояния и операции второй текстуры
pDirect3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0);
pDirect3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pDirect3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
Matrix1();
pDirect3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 36, 0, 12);
// Установка нового режима обновления
pDirect3DDevice->SetRenderState(D3DRS_STENCILREF, 1);
pDirect3DDevice->EndScene();
pDirect3DDevice->Present(NULL, NULL, NULL, NULL);
}
// Создание плоской тени (stencil Buffer)
void EnterStencilBuffer(void)
{
// Включаем буфер трафарета (stencil)
pDirect3DDevice->SetRenderState(D3DRS_STENCILENABLE, true);
// Установка для трафарета операцию сравнения
pDirect3DDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
// Установка режима обновления
pDirect3DDevice->SetRenderState(D3DRS_STENCILREF, 0);
// Установка маски сравнения
pDirect3DDevice->SetRenderState(D3DRS_STENCILMASK, 0xffffffff);
// Увеличить значение stencil-буфера на единицу
pDirect3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR);
pDirect3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);
// Очистка z-буфера
pDirect3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(172, 221, 101), 1.0f, 0);
}
Что я сделал не так, почему нет теней?Есть мнение, что я не рассчитываю контурные ребра и не вытягиваю теневой объём.Хотя в книге "Advanced 3D Game Programming Using DirectX 9.0", главу 10, ничего про это не сказано.
Там всего было написано всего два куска кода, не считая текста и вспомогательных таблиц.
Вот код из книгиListing 10.20: Sample code to set up the stencil buffer for an overdraw counter // pDevice is a valid Direct3D Device
// Turn on stenciling
pDevice->SetRenderState( D3DRS_STENCILENABLE, TRUE );
// Set the function to always pass.
pDevice->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
pDevice->SetRenderState( D3DRS_STENCILREF, 0 );
pDevice->SetRenderState( D3DRS_STENCILMASK, -1 );
// Always increment the stencil value
pDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR );
pDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR );
Listing 10.21: Sample code to set up the stencil buffer for a wipe // Stencil is initially cleared to 0.
// pDevice is a valid Direct3D Device pointer
// Set up stencil states for the wipe polygon
pDevice->SetRenderState( D3DRS_STENCILENABLE, TRUE );
pDevice->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
pDevice->SetRenderState( D3DRS_STENCILPASS,D3DSTENCILOP_INCR);
pDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_NEVER );
pDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
// Render the wipe polygon
...
pDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_ALWAYS );
pDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE );
pDevice->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_EQUAL );
pDevice->SetRenderState( D3DRS_STENCILPASS,D3DSTENCILOP_KEEP);
pDevice->SetRenderState( D3DRS_STENCILREF, 0 );
// Render the old scene
...
pDevice->SetRenderState( D3DS_STENCILREF, 1 );
// Render the new scene
...