Плюшки и куча ошибок

Добавлен , опубликован
Добрый вечер.
Сегодня решил продолжить цикл записей о работе с графикой. За это время накопилось много всего интересного, и на этот раз я собирал материал для поста заранее. Так что начнем по порядку.
Как вы могли заметить, у меня присутствует логотип Direct X 10, и это не просто так. Я смог прикрутить поддержку версии 10.1 при этом используя и программируя исключительно под 11 версию. Кроме того, что мне удалось прикрутить поддержку 10 версии, я сделал загрузку моделей из формата obj, как оказалось это не так сложно. Но все это было очень давно, сразу где-то после предыдущего поста о графике.

Строгая работа

В общем навалилась на меня работа, может бы как-нибудь напишу вам, чем я там занимаюсь. Поэтому времени было не очень много. Но смысл в том, что я решил составить план, хороший, строгий план, по которому я буду двигаться по мере написания, этого приложения. В принципе это было очень верное решение, по тому, что как показало время получилось все хорошо и быстро и на данный момент текущий план уже закончен процентов на 80% и временами дополняется новыми пунктами.

Начало работ

Первым делом надо было избавиться от вшитой в DirectX системы эффектов. Да она хорошая и все такое, но не очень гибкая, к тому же, после 10 версии, она перестала поставляться как оф. библиотека, лишь только с SDK и открытым исходным кодом, что говорит, о том, что дальнейшее её развитие будет остановлено (скорее всего).
Ну вот очередные выходные, родители тащат на дачу, но мне удается отказаться и остаться дома, получив в свое распоряжение монитор и кучу рабочего пространства, а так же ночное время. Ну в общем удалив код поставляемой библиотеки, сел разрабатывать свою систему материалов. В принципе в ней ничего особенного нет, разве, что код шейдеров теперь генерируется и компилируется автоматически по мере нужности определенных частей кода. Это избавит нас от рутинной работы написания кучи кода похожих шейдеров, например стеклянный объект с освещением и обычный объект с освещением. В принципе тут оказалось не все так сложно и быстро поддалось исправлению.

Работа с разными проектами

Рано или поздно понимаешь, что писать код в одной библиотеке жутко не удобно, по этому решил вынести непосредственную работу с DirectX в отдельный проект. Вынес, дописал нужные функции, что бы можно было про инициализировать все это дело и... А результат можно увидеть на скриншоте слева.
Да, да 1600 ошибок компиляции. А что поделать, сел исправляться. Промучался 24 часа и у меня осталось всего 4 ошибки. А ошибки то были связанные с линковкой проектов. Тут пришлось изрядно потрудиться, удалить часть кода, который в принципе оказался не нужным (подсчет ссылок объекта), а впервой идея казалась очень хорошей, но увы не прижилась она, потому что не работала как надо. В общем к концу нового дня, у меня все заработало. Вот в этот момент я и прикрутил поддержку 10 версии DirectX

Шаг 3. Система пост эффектов

По скольку старая система пост эффектов основывалась на основе старой системы эффектов, то надо было переписывать и систему пост эффектов. Да и к тому же старая была не очень гибкая, нельзя было перенаправить вывод, прикрепить другие текстуры, да и размер текстуры был всегда фиксированным, как размер основного буфера. А сейчас можно еще и разного размера текстуры подставлять, настраивать порядок применения обработки текстур, использовать не только текстуру полученную при рисовании сцены, но еще и использовать свои текстуры, полученные из дополнительных проходов. Решил я попробовать нарисовать сцену в маленькую текстуру, так ради теста и получил плохой результат. Сцена на рисовалась туда криво. Помните проблему, когда я делал тени? Когда у меня криво получался буфер глубины? Так вот проблема оказалась в том, что я не менял область рисования. Текстура была 512х512, а я рисовал по прежнему на весь экран 1366х768. Ну в общем исправил я это и теперь все нормально работает в новой системе пост-эффектов. Первым делом я просто повторил старые эффекты, дабы убедиться, что все работает. А дальше решил попробовать что-то серьёзное.

Blur

Первое, что под руку мне попалось, это размытие. Нашел простой по реализации алгоритм размытия, это метод "пинг-понга", как его называют. А принцип в том, чтобы нарисовать сцену в текстуру меньшего размера, затем в еще одну текстуру меньшего размера (раза в 2), а потом в обратном порядке. То есть получается примерно так 1366x768 -> 512x512 -> 256x256 -> 512x512 -> 1366x768. В принципе эффект есть, но он сильно квадратный, к сожалению скриншота не осталось.

Bloom

Дальше под руку мне попался bloom, когда яркие объекты светятся. Для этого надо было отрендерить сцену в отдельную текстуру, так чтобы яркие участки были на этой текстуре белыми, а остальными черными. Затем эта текстура размывалась. И уже потом накладывалась с нужным коэффициентом на основную текстуру. Скриншот можно увидеть ниже.

DoF

Дальше решил сделать DoF эффект (Distance of Field). Эффект, где используется не только текстура цвета, но еще и текстура глубины сцены. Вот тут то мне пришлось немного повозиться. Если раньше (когда делал тени) я получал эту текстуру, с помощью еще одного прохода, рисуя сцену еще раз. Тут же я решил сделать это сразу и по ходу заполнения текстуры цвета, заполнять сразу и текстуру глубины. Как оказалось, у меня не работал рендер в несколько текстур. Промучался весь вечер, сдался, пошел уже на форум просить помощи, пока ждал ответа, уже сам нашел косяк, исправил и все заработало.
DoF изнутри программы
IPostEffectPass* pPass;
IRenderTargetView* pTemp0;
IRenderTargetView* pTemp1;
uINT pepXBlur, pepYBlur, pepFinal;
IPostEffect* pPostEffect = scene->GetPostEffect();

pRenderAPIManager->GetDevice()->CreateRenderTarget(512, 512, &pTemp0);
pRenderAPIManager->GetDevice()->CreateRenderTarget(512, 512, &pTemp1);
	
pPostEffect->CreatePass("xBlur", &pPass, &pepXBlur);
pPass->BindTextureSlot(0);
pPass->SetOutRenderTarget(pTemp0);
pPass->GetShader()->CompileFromFile("simple_post.shader", "PS_xBlur", "ps_4_0");

pPostEffect->CreatePass("yBlur", &pPass, &pepYBlur);
pPass->SetInputTexture(0, pTemp0->GetTexture());
pPass->SetOutRenderTarget(pTemp1);
pPass->GetShader()->CompileFromFile("simple_post.shader", "PS_yBlur", "ps_4_0");

pPostEffect->CreatePass("final", &pPass, &pepFinal);
pPass->BindTextureSlot(0);
pPass->BindDepthTextureSlot(2);
pPass->SetInputTexture(1, pTemp1->GetTexture());
pPass->SetOutRenderTarget(pRenderAPIManager->GetStdRenderTarget());
pPass->GetShader()->CompileFromFile("simple_post.shader", "PS_dof", "ps_4_0");

IPostEffectSequence* pSeq;
pPostEffect->CreateSequence("seq1", &pSeq);
pSeq->AddPass(pPostEffect->GetPassLink(pepXBlur));
pSeq->AddPass(pPostEffect->GetPassLink(pepYBlur));
pSeq->AddPass(pPostEffect->GetPassLink(pepFinal));
Ну и скриншоты этих эффектов

Шаг 4. Вынесение создание окна и плюшки

Да, создание окна я тоже решил вынести из общей библиотеки. Ну тут в принципе так же пришлось исправлять кучу ошибок, конечно меньше, чем было но тоже много. Благо ошибок линковки не было, поэтому быстро справился. Дальше решил заняться ресайзом окна. В принципе оно работало, но картинка растягивалась и получалось просто растянутое изображение, а не увеличение видимой зоны. В общем почитал как это делается, сделал. Делаем ресайз и .... о нет. Выбивает ошибку.
Посмотрев, что выводит выяснил забавную вещь
//Про ресайз окна
//Захавать 2ГБ видео памяти ничего не делая, надо тоже уметь
D3D11: ERROR: ID3D11Device::CreateTexture2D: Returning E_OUTOFMEMORY, meaning memory was exhausted. [ STATE_CREATION ERROR #105: CREATETEXTURE2D_OUTOFMEMORY_RETURN ]
Все 2.2 Гб видео памяти съелись. Начал думать, что за фигня. Думал, что я просто криво очищал данные в деструкторах нужных классов. Перелопатил весь код, переписал все деструкторы и даже большинство функций. А все равно. Но тут меня выручил ScorpioT1000, аве ему! Хотя он тоже был удивлен, но именно с ним разобрался с этой проблемой.
Собственно о проблеме
#include <iostream>
using namespace std;

#define interface struct

interface IObject
{
};
class CObject : public IObject
{
public:
   CObject() {sout << "CObject::ctor"};
   ~CObject() {sout << "CObject::dtor"};
};

int main()
{
   IObject* pObj = new CObject();
   delete pObj;
   return 0;
}
//Output:
//CObject::ctor
Да кто же знал, что деструкторы по умолчанию не виртуальные. Из-за это фигни и жралось 2Гб видео памяти. Ну в общем пришлось очередной раз пробегаться по коду и везде расставлять виртуальные деструкторы. Зато, теперь все заработало
Как надо было делать интерфейс
interface IObject
{
   virtual ~IObject() {};
};
Заработало и теперь я смог менять размер окна, как мне угодно. И кроме того, пока искал информацию про изменение размера области вывода на DirectX нашел замечательную вшитую вещь, начиная с 10 версии. По нажатии на Alt+Enter идет переключение режима (оконный \ полно-экранный). А я уж думал, что мне придется реализовывать это самому.

Шаг 5. Стекло и лед, или о рефракции

Теперь я решил сделать замечательную вещь. Это рефракция (преломление проходящего света сквозь материал). Как все это дело происходит. Рисуем сцену, при этом копируя перед нужным эффектом результат вывода в отдельную текстуру, а затем с помощью текстуры рефрации, получаем искаженное изображение за этим объектом. Тут в принципе ни каких изъянов не было, только не внимательность в коде шейдера. Скриншоты ниже

Шаг 6. Зеркало и улучшенный лед, или история о текстуре рефлекции

Вот это хорошая тема для разговора. Сперва я промучался с матрицей отражения, так как библиотека с матаном оказалась какая то ущербная и такого понятия как матрица отражения, она не знала <_< ну ладно, вывели сами. Затем у меня не чего не рисовалось в текстуру отражения. Если рисовать в какую другую текстуру все нормально, если рисовать в текстуру отражения отражение, то получаю фигню, местами что то выводилось, когда я проходил сквозь геометрию объектов сцены. В общем тыкал все подряд так и не нашел в чем причина. Один раз получилось так, что комп просто намертво повис, пришлось его ребутить. А время то уже много, спать надо ложиться, а я все сижу и ищю гребанный баг. Забил. Лег спать. Всю ночь делал трассировку программы во сне, в результате нашел проблемное место. И потом весь день руки чесались это исправить (был на даче, весь в делах, дорвался только к вечеру до ноута). Проверяю это место, и о да. Я был прав. То, что я и думал. А все оказалось, что у меня не чистился нужный буфер глубины сцены, сцена самый первый кадр рисовалась как надо, а потом буфер глубины просто не позволял этого сделать. Ну в общем исправил. Запустил, заработало. Немного покрутил настройки, поправил код, сделал скрины, сохранил их и со спокойной душой пошел пить пиво.
На сегодня все. Не забывайте подписываться, дабы не пропустить ничего нового. И удачи в ваших начинаниях и разработках!
`
ОЖИДАНИЕ РЕКЛАМЫ...
34
норм, только причем тут dx10? Все это делается на 9 еще с 2004.
29
Hellcore, при том что обратная совместимость.
Годный пост.
29
Hellcore:
норм, только причем тут dx10?
Делается, но с большими проблемами. И дело в том, что я не писал на API для работы с 10 директом, а писал конкретно на 11. Так же можно сделать поддержку и 9. Но тогда придется перейти на шейдерную модель 3 версии, а там нету забавных вещей в виде константных буферов, конечно их можно эмулировать, но это потребуется дополнительных энерго затрат
25
Малаца!
реквестрирую баловство с тесселяцией.
29
XimikS, как раз вот собираюсь уже начать баловаться с тесселяцией, потому что в туторах из SDK это выглядит просто эпично, по сравнению с каким-то бампом и прочими извращений в 2D пространстве
2 комментария удалено
29
XimikS, да не это не он, хотя хз. Но реально, странно, кто такой противный, хотя пост не минусанул
ScorpioT1000, похоже на АА?
вот окончательный вариант АнтиАлайсинга
Этот комментарий удален
6 комментариев удалено
Чтобы оставить комментарий, пожалуйста, войдите на сайт.