Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Создание Stencil-тени в DirectX 9  (Прочитано 11170 раз)
0 Пользователей и 4 Гостей смотрят эту тему.
zuze
Опытный

ru
Offline Offline
Пол: Мужской
Россия, Москва


« : 21-06-2009 15:22 » 

Сделать тень с помощью 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
   ...
« Последнее редактирование: 29-06-2009 09:16 от Sel » Записан
zuze
Опытный

ru
Offline Offline
Пол: Мужской
Россия, Москва


« Ответ #1 : 21-06-2009 20:42 » 

Я пытался сделать тени по книге
Франк Луна "Введение в программирование трехмерных игр с DirectX 9"

А там Stencil-тени, только на ровную поверхность

Нашёл краткое описание процесса построения stencil-теней или теневы объёмов (Shadow Volume):
  
1. Рисуем всю сцену без теней.    
2. Запрещаем запись в z-буфер и в буфер кадра.    
3. Рисуем обратные, т.е. невидимые грани конуса тени, при этом увеличивая на единицу значения в stencil-буфере для тех точек, которые лежат ближе выводимых граней.    
4. Рисуем передние, т.е. видимые грани конуса тени и уменьшаем на единицу значения stencil-буфера для точек, которые лежат ближе выводимых граней. Теперь в stencil-буфере мы имеем маску для тех точек, которые попали в область конуса тени.    
5. Рисуем серый полупрозрачный прямоугольник на весь экран, разрешая закраску только тех пикселей, для которых значения stencil-буфера остались увеличенными на единицу.

Хотел спросить это правильное описание или это правильное, но только для ровной поверхности?
« Последнее редактирование: 21-06-2009 20:47 от zuze » Записан
zuze
Опытный

ru
Offline Offline
Пол: Мужской
Россия, Москва


« Ответ #2 : 23-06-2009 01:52 » 

С тенями пока подожду, это достаточно сложный вопрос, а начну я тогда с загрузки X-файла, но к теням я обязательно вернусь, только пока не знаю когда.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines