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

Добавлен , опубликован
Программирование
Язык:
C++
Добрый вечер.
Сегодня решил продолжить цикл записей о работе с графикой. За это время накопилось много всего интересного, и на этот раз я собирал материал для поста заранее. Так что начнем по порядку.
Как вы могли заметить, у меня присутствует логотип 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. Зеркало и улучшенный лед, или история о текстуре рефлекции

Вот это хорошая тема для разговора. Сперва я промучался с матрицей отражения, так как библиотека с матаном оказалась какая то ущербная и такого понятия как матрица отражения, она не знала <_< ну ладно, вывели сами. Затем у меня не чего не рисовалось в текстуру отражения. Если рисовать в какую другую текстуру все нормально, если рисовать в текстуру отражения отражение, то получаю фигню, местами что то выводилось, когда я проходил сквозь геометрию объектов сцены. В общем тыкал все подряд так и не нашел в чем причина. Один раз получилось так, что комп просто намертво повис, пришлось его ребутить. А время то уже много, спать надо ложиться, а я все сижу и ищю гребанный баг. Забил. Лег спать. Всю ночь делал трассировку программы во сне, в результате нашел проблемное место. И потом весь день руки чесались это исправить (был на даче, весь в делах, дорвался только к вечеру до ноута). Проверяю это место, и о да. Я был прав. То, что я и думал. А все оказалось, что у меня не чистился нужный буфер глубины сцены, сцена самый первый кадр рисовалась как надо, а потом буфер глубины просто не позволял этого сделать. Ну в общем исправил. Запустил, заработало. Немного покрутил настройки, поправил код, сделал скрины, сохранил их и со спокойной душой пошел пить пиво.
На сегодня все. Не забывайте подписываться, дабы не пропустить ничего нового. И удачи в ваших начинаниях и разработках!
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.