Всем привет!
При реализации размытия столкнулся с эффектом, который я локализовал, но понять природу его возникновения не получается.
Суть такова:
Размываем круг, совпадающий с бОльшим кругом на данном скриншоте
// Весовой массив const float weights[25] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; float4 PS_VertBlur2(VS_OUT In): COLOR { float4 col = 0.0f; float texStepY = BlurScale * InvTexSize.y; for (int i = 0; i < 25; i++) col.rgb += tex2D(SceneTex, float2(In.Tex.x, In.Tex.y + texStepY * (i - 12))).rgb * weights[i]; col.rgb /= 25; col.a = 1.0f; return col; }
Весовой массив weights здесь заполнен единицами, чтобы лучше показать абсурдность ситуации.
BlurScale и InvTexSize задается из приложения и в ходе эксперимента не меняется. Точнее даже так - вообще ничего в окружении не меняется.
Компилирую его, как ps_3_0.
С данным шейдером получаем следующую картинку:
Как видим, круг почему-то съехал вверх.
Если закомментировать
* weights[i]
, то мы видим правильную картинку, на которой круг находится там, где ему полагается быть:
Напомню, что веса в массиве все единичные, то есть само по себе умножение на
weights[i]
никак не должно влиять на результат.
В дальнейших экспериментах я выяснил, что глюк проявляется вообще при любом обращении к массиву весов в цикле.
У кого-нибудь есть идеи, что это за Voodoo Magic, и как с ней бороться?
Cannibal
Ты грузишь шейдера напрямую? Или успользуешь какой-нибудь FXShader. Посмотри на асм после компиляции (можно быстро посмотреть в PIX'e).
Или сделай быстрый тест - перенеси объявление весов внутрь функции и убери слово const.
VirT
> Ты грузишь шейдера напрямую?
D3DXCreateEffectFromFile.
> Или сделай быстрый тест - перенеси объявление весов внутрь функции и убери слово const.
Не помогло.
PIX посмотрю.
Посмотрел рендер черех PIX.
Получившиеся после компиляции asm тут: [file=72619] и [file=72620]
Я в них понял только:
1) если совсем не использовать массив, то он и не создается
2) в версии с массивом (которая Wrong) он почему-то развернул цикл.
Возникли вопросы по прешейдеру с массивом:
preshader mul r0.x, c0.y, c1.x mul c0.x, r0.x, (12) mul c1.x, r0.x, (11) mul c2.x, r0.x, (10) mul c3.x, r0.x, (9) mul c4.x, r0.x, (8) mul c5.x, r0.x, (7) mul c6.x, r0.x, (6) mul c7.x, r0.x, (5) mul c8.x, r0.x, (4) mul c9.x, r0.x, (3) mul c10.x, r0.x, (2) add c12.x, r0.x, r0.x mul c13.x, r0.x, (-3) mul c14.x, r0.x, (4) mul c15.x, r0.x, (5) mul c16.x, r0.x, (6) mul c17.x, r0.x, (7) mul c18.x, r0.x, (8) mul c19.x, r0.x, (9) mul c20.x, r0.x, (10) mul c21.x, r0.x, (11) mul c22.x, r0.x, (12) mov c11.x, r0.x
Что это за числа в скобочках?
Если это индексы заполняемых элементов массива, то почему у них такой странный порядок? А (-3) совсем выбивается из колеи...
Какая версия SDK, последняя?
Попробуй отключить прешейдеры.
Попробуй для начала static const float weights.
Проблема решена заменой строки
col.rgb += tex2D(SceneTex, float2(In.Tex.x, In.Tex.y + texStepY * (i - 12))).rgb * weights[i];
на код вида
col.rgb += tex2D(SceneTex, In.Tex + texStepY * offsets[i]).rgb * weights[i];
где offsets это:
const float2 offsets[25] = { {0, -12}, {0, -11}, {0, -10}, ...и так далее .... {0, 11}, {0, 12} };
Теперь все, вроде, работает правильно. Но я не понимаю, почему был глюк и почему он исчез после такой замены :(
Магия - не иначе.
arabesc
> Какая версия SDK, последняя?
Да.
>Попробуй отключить прешейдеры.
Как? Хоть проблема и решена, интересно узнать побольше.
Wraith
> Попробуй для начала static const float weights.
Пробовал. Не помогло.
> Как? Хоть проблема и решена, интересно узнать побольше.
HRESULT D3DXCreateEffectFromFile( __in LPDIRECT3DDEVICE9 pDevice, __in LPCTSTR pSrcFile, __in const D3DXMACRO *pDefines, __in LPD3DXINCLUDE pInclude, __in DWORD Flags, // <-- D3DXSHADER_NO_PRESHADER __in LPD3DXEFFECTPOOL pPool, __out LPD3DXEFFECT *ppEffect, __out LPD3DXBUFFER *ppCompilationErrors );
Ну тут действительно есть подлянка.
Вот тестовый шойдыр, очень похожий: http://www.everfall.com/paste/id.php?th2z5zremsbb
А вот результат: http://www.everfall.com/paste/id.php?uofcfr7g3jfx
А разгадка, я чую, вот в чем: компилятор облажался по вине программиста.
Дело все в том, что в ps_3_0 нету адресного регистра: http://msdn.microsoft.com/en-us/library/windows/desktop/bb172920%… VS.85%29.aspx
Поэтому ему просто нечем индексировать массив весов. Для коротких фильтров компилятор иногда умеет использовать dot product trick.
Если скомпилить с /Gfp (prefer flow control), он выдает прекрасное полотно из 50 25 cmp и 1 texld внутри цикла: http://www.everfall.com/paste/id.php?1bt059cp35lr
Вот и.
Upd: поставил [unroll] перед циклом, все равно неправильно.
Wraith
> А разгадка, я чую, вот в чем: компилятор облажался по вине программиста.
> Дело все в том, что в ps_3_0 нету адресного регистра:
> http://msdn.microsoft.com/en-us/library/windows/desktop/bb172920%…
> VS.85%29.aspx
> Поэтому ему просто нечем индексировать массив весов. Для коротких фильтров
> компилятор иногда умеет использовать dot product trick.
> Если скомпилить с /Gfp (prefer flow control), он выдает прекрасное полотно из
> 50 cmp и 1 texld внутри цикла
странно, обычно делается unroll с жесткой привязкой к индексу констант
ой, там ещё и rep ... жесть просто
пардон, конечно, нужно массив float2, а не массив float :)
Так, это я пофейлился.
Там надо c += tex2D(..., а у меня c = tex2D( ...
Поправив ошибку, получаются интересные вещи: http://www.everfall.com/paste/id.php?wnsed0bzvrcs - шейдер.
Результат с /Gfp: http://www.everfall.com/paste/id.php?2plgi5oyau1h
Результат с /Gfp, если сделать static const float: http://www.everfall.com/paste/id.php?r1d3cqzuzj50 - намного приятнее.
Add:
Результат с /Gfa, если сделать static const float: http://www.everfall.com/paste/id.php?1nbjnl95tyq3
Попробовал скомпилировать глючный вариант шейдера в офлайне. Использовал и /Gfp и /Gfa. В первом случае был получен варнинг:
В обоих случаях скомпилированный шейдер работает неверно.
Получается, что нужно обойти проблему введением массива сдвигов (offsets) и забыть о
float2(In.Tex.x, In.Tex.y + texStepY * (i - 12))
как о страшном сне.
Блин, но так ведь в другой ситуации всплывет что-нибудь подобное :(
UPD. Варнинг оказался про другое.
Тема в архиве.