![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Вопрос по теням (из Example DirectX8/StencilBuffer/ShadowVolume) [Delphi, DirectX 9]
ElectriC © (2007-05-11 17:35:00)Как сделать, чтобы тени не рисовались на камере?
ElectriC (2007-06-23 15:18:00) [1].
ElectriC (2007-06-15 18:50:00) [2]Так что посоветуете делать?
Sapersky (2007-06-15 15:36:00) [3]В некоторых ракурсах есть.
Эффект от WeldVertices виден на самолёте и без тени, освещение становится более гладким.
ElectriC (2007-06-15 15:18:00) [4]Так почему в SDK нет "белых точек"?
Sapersky (2007-06-15 14:47:00) [5]Я для проверки воткнул в CD3DMesh.Create_ после D3DXLoadMeshFromX:
FillChar(eps, SizeOf(eps), 0);
eps.Flags := D3DXWELDEPSILONS_WELDALL;
Result := D3DXWeldVertices(m_pSysMemMesh, @eps,
pAdjacencyBuffer.GetBufferPointer,
pAdjacencyBuffer.GetBufferPointer, nil, nil);
Самолёт - тоже кривой, да.
ElectriC (2007-06-14 16:09:00) [6]
> Похоже, из-за кривых мешей, в которых имеются избыточные
> вершины.
Тогда получатся, что самолёт (из SDK) тоже кривая мешь, т.к. на тени тоже
появляются точки,а в SDK их нет?((((
Что делать?
ElectriC (2007-06-13 21:19:00) [7]Так белые точки как были, так и остались.
Может я что-то не так делаю или ещё что:
...
var
AdjBuffer : ID3DXBuffer;
Epsilons : TD3DXWeldEpsilons;
...
ZeroMemory(@Epsilons, SizeOf(TD3DXWeldEpsilons));
D3DXWeldVertices(SLMeshObj, D3DXWELDEPSILONS_WELDPARTIALMATCHES, @Epsilons,
AdjBuffer.GetBufferPointer,
AdjBuffer.GetBufferPointer, nil, nil);
D3DXValidMesh(SLMeshObj, AdjBuffer.GetBufferPointer, nil);
...
Sapersky (2007-06-13 18:38:00) [8]В ProgressiveMesh (SDK) есть пример.
ElectriC (2007-06-13 18:06:00) [9]Может объяснить, как работать с D3DXWeldVertices?
P.S. Если можно, то на примере.
ElectriC (2007-06-13 17:14:00) [10]
> Подозреваю, что теневые объёмы пересчитываются на каждом
> кадре для всех объектов.
Кстати пересчитываются только один раз - при первом запуске программы!!!
Sapersky (2007-06-13 17:10:00) [11]почему на тенях пояляются артефакты ввиде белых точек?
Похоже, из-за кривых мешей, в которых имеются избыточные вершины.
Удалить такие вершины - D3DXWeldVertices.
Творение посмотрел... ну что сказать... неплохо для начала.
С тенями на встроенной видео страшно тормозит - 2-3 fps, без - около 30.
Подозреваю, что теневые объёмы пересчитываются на каждом кадре для всех объектов. Так вот, для статичных объектов (школы) можно сделать это один раз в начале, ещё хорошо бы загнать их в VB вместо рисования через DrawPrimitiveUP.
"Отражения" в окнах можно сделать динамическими, см. пример SphereMap из SDK. В SDK8.1 его зачем-то переделали на шейдер, но только Delphi-вариант, С++ остался (видимо, Cooltie забыл обновить) на автоматической генерации текстурных координат, что ИМХО проще:
// Generate spheremap texture coords, and shift them over
D3DXMATRIX mat;
mat._11 = 0.5f; mat._12 = 0.0f; mat._13 = 0.0f; mat._14 = 0.0f;
mat._21 = 0.0f; mat._22 =-0.5f; mat._23 = 0.0f; mat._24 = 0.0f;
mat._31 = 0.0f; mat._32 = 0.0f; mat._33 = 1.0f; mat._34 = 0.0f;
mat._41 = 0.5f; mat._42 = 0.5f; mat._43 = 0.0f; mat._44 = 1.0f;
m_pd3dDevice->SetTransform( D3DTS_TEXTURE0, &mat );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL );
Само собой, окна тогда нужно рендерить отдельно от всего.
Некоторые пояснения есть в readme к примеру.
ElectriC (2007-06-13 15:04:00) [12].
ElectriC (2007-06-12 18:56:00) [13]Кстати, если не лень, можешь посмотреть, почему на тенях пояляются
артефакты ввиде белых точек?
P.S. Если не лень скачай моё первое творение ;))) -> http://slil.ru/24404040/874845188/School_54.rar
ElectriC (2007-06-12 18:19:00) [14]За перевод спасибо (хотя и не надо было - перевёл давно уже сам).
Мне бы разобраться, как не рисовать тень на камере.
Sapersky (2007-06-12 17:40:00) [15]А я вот, в свою очередь, не понимаю, что мешает попытаться понять самостоятельно.
Ну, кроме лени, конечно. А мне, что ли, не лень писать за тебя?
Векторную алгебру, насколько помню, в школе изучают. Даже если ещё не - тем лучше, сейчас выучишь, потом не надо будет.
Фактически здесь нужно использовать:
1) для определения, какой стороной полигон повёрнут к ист. света - скалярное произведение (dot product) даёт косинус угла между векторами. Синусы/косинусы в школе изучают однозначно...
2) угол нужно искать между нормалью полигона и вектором от ист. света. Нормаль (перпендикуляр) получается векторным произведением (cross product) двух граней полигона.
3) для получения заднего среза теневого объёма - масштабирование (scale), сложение/вычитание (add/subtract) векторов.
Причём с нуля писать ничего не надо, всё это уже есть в TShadowVolume.BuildFromMesh (построение стандартного теневого объёма), но используется несколько по-другому. Т.е. нужно понять, что именно там происходит, и дописать на основе это кода "затычки" к теневому объёму.
Что касается переделки CMyD3DApplication.RenderShadow на z-fail - там чуть ли не каждая строчка откомментирована, даже не зная английского можно уловить знакомые словосочетания "z-pass" и "z-fail" и сделать выводы. Щёлкнув с Ctrl на любую константу вроде D3DRS_STENCILPASS можно найти в Direct3D.pas список других подходящих для этой функции констант, часто с поясняющими комментариями.
Могу даже сделать перевод (пока это всё ещё z-pass, я только выкинул кое-что лишнее):
function CMyD3DApplication.RenderShadow: HResult;
begin
m_pd3dDevice.SetTransform(D3DTS_WORLD, m_matObjectMatrix);
// Выключаем запись в z-буфер (но z-тест работает)
m_pd3dDevice.SetRenderState(D3DRS_ZWRITEENABLE, iFALSE);
// включаем stencil-буфер
m_pd3dDevice.SetRenderState(D3DRS_STENCILENABLE, iTRUE);
// Выключить цветовую интерполяцию (для оптимизации, не обязательно)
m_pd3dDevice.SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
// Выключаем вывод на экран теневых объёмов.
// Чтобы они рисовались - закомментировать
m_pd3dDevice.SetRenderState(D3DRS_ALPHABLENDENABLE, iTRUE);
m_pd3dDevice.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
m_pd3dDevice.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
// для большей наглядности при рисовании теневых объёмов можно ещё включить wireframe-режим
// m_pd3dDevice.SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
// Устанавливаем stencil-функцию сравнения, в данном случае stencil-тест
// всегда проходит (D3DCMP_ALWAYS). Другие константы в Direct3D8.pas.
m_pd3dDevice.SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
// Если stencil и Z-тесты проходят, увеличиваем значения в буфере.
// поскольку stencil-тест проходит всегда, фактически получается "если Z-тест проходит"
m_pd3dDevice.SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);
// Рисуем только передние грани
m_pd3dDevice.SetRenderState(D3DRS_CULLMODE, D3DCULL_CСW);
// выводим объём
m_pShadowVolume.Render(m_pd3dDevice);
// Если stencil и Z-тесты проходят, уменьшаем значения в буфере
m_pd3dDevice.SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_DECR);
// Рисуем только задние грани
m_pd3dDevice.SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
// выводим объём
m_pShadowVolume.Render(m_pd3dDevice);
// Восстанавливаем стейты
m_pd3dDevice.SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
m_pd3dDevice.SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
m_pd3dDevice.SetRenderState(D3DRS_ZWRITEENABLE, iTRUE);
m_pd3dDevice.SetRenderState(D3DRS_STENCILENABLE, iFALSE);
m_pd3dDevice.SetRenderState(D3DRS_ALPHABLENDENABLE, iFALSE);
m_pd3dDevice.SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
Result := S_OK;
end;
Будут КОНКРЕТНЫЕ вопросы по деталям - задавай.
ElectriC (2007-06-12 15:27:00) [16]Так как же??? ;)))
ElectriC (2007-06-12 15:25:00) [17]Конечно ;))))))))))
Sapersky (2007-06-12 13:14:00) [18]Это тот же z-fail.
Как выяснилось отсюда:
http://developer.nvidia.com/attach/6831
отличие его в том, что нужно "заткнуть" теневой объём с двух сторон полигонами модели. Спереди (или сверху, в общем, с той стороны, которая ближе к источнику света) - лицевыми по отношению к источнику света, сзади - соответственно, задними, перемещёнными к заднему срезу теневого объёма и отмасштабированными под этот срез. Ну вот эти самые "задние грани модели, вытянутые в бесконечность".
Догадываюсь, какой будет следующий пост...
"Так я не понимаю, как реализовать это на дельфи?"
ElectriC (2007-06-11 19:14:00) [19]Кста:
>Исправляем ситуацию, когда камера находится внутри объёма.
>1. Отключим запись в буфер глубины и цвета
>2. Включим отсечение передних граней. Установим операция в >инкрементирование на единицу при провале теста глубины. Нарисуем >объём.
>3. Включим отсечение задних граней. Установим операцию трафарета в >уменьшение на единицу при провале теста глубины. Нарисуем объём.
>Все освещённые точки будут иметь значение 0 в буфере трафарета.
>Для нормальной работы метода может потребоваться отрисовка всех >задних граней модели, вытянутых в бесконечность, но в большинстве >случаев этого не требуется, так как эти грани в любом случае были бы >закрыты геометрией.
Как реализовать этот метод - может поможет???
ElectriC (2007-06-11 18:42:00) [20]Да, видимо, всё сложнее, чем думалось))