• Добро пожаловать на Quest3D - Русскоязычное сообщество.
 

"Крутизна и реализьм" - тема про шейдеры

Автор KBECT0MAH, 25 декабря 2007, 04:18:22

« назад - далее »

Sqwer

ЦитироватьКроме того компилятор может просечь что к чему и на выходе сделать вообще так:


а подумай:  зачем я поставил перед "="   плюс?  ;)



Цитироватьэти данные кэшируются и после первой выборки чтение идет из кеша.
это  уже на совести  разработчиков драйверов и архитектуры железки.


РС
да и насколько я помню кэшируется только  вертексные данные (не уверен на 100%)

dfx

Цитироватьа подумай:  зачем я поставил перед "="   плюс?

Сложение с текущим значением переменной, т.е. сделать выборку и сто раз прибавить результат.) Компиляторы не такие глупые, да и в железках кучу железных оптимизаций.

Цитироватьэто  уже на совести  разработчиков драйверов и архитектуры железки.
РС
да и насколько я помню кэшируется только  вертексные данные (не уверен на 100%)

И это тоже кешируется) Иначе бы небыло 50 фпс)
А что за железка?

Sqwer

ЦитироватьКомпиляторы не такие глупые
плохо подумал, давай ещё  :D

(не думай  что я стебусь, в своей правоте я уверен...  ибо сам ставил всевозможные опыты )


Цитироватьжелезках кучу железных оптимизаций.
где ты такое  узрел? пруф линк на инфу в студию


GPU видяхи устроен по принципу  RISC процессора, так что никокого инлайн оптимазинга нет.
Видяха берёт вычисления количиством, а не качеством.


ЦитироватьИ это тоже кешируется) Иначе бы небыло 50 фпс)
и опять всего лишь слова...
нужны не предположения  а факты.


железка старая  Гфорса 8800 серии.

для чистоты эксперемента могу провести на  болеее новой


ЦитироватьРС
да и насколько я помню кэшируется только  вертексные данные (не уверен на 100%)
http://www.gamedev.ru/terms/VertexCache

dfx

#153
Цитироватьгде ты такое  узрел? пруф линк на инфу в студию


GPU видяхи устроен по принципу  RISC процессора, так что никокого инлайн оптимазинга нет.
Видяха берёт вычисления количиством, а не качеством.

Я думаю, что кэши и прочее, как раз для оптимизации производительности и используется.


Цитироватьи опять всего лишь слова...
нужны не предположения  а факты.

Какие факты? То, что существует не только вершинный кэш, но и текстурный и еще горстка кешей? :D Были ветки на форумах, где народ эксперементировал с тем же SSAO и было замечено, что производительность сильно зависит от радиуса выборки соседних пикселей и т.д.

Либо ты прикалываешся, либо мы совсем о разном говорим.


ЦитироватьДвойной кэш текстур
Уже существовал на GeForce3. Новые алгоритмы лучше работали при использовании мультитекстурирования или высококачественной фильтрации. Благодаря этому в GeForce4 Ti была значительно улучшена производительность при наложении 3-4 текстур.
http://gamegpu.ru/geforce-4-series/geforce-4-ti-4200-osobennosti-arhitektury.html

Цитировать– Текстурный блок – логика
адресации текстурных массивов в 1D,
2D, 3D  + L1 Кэш Текстур
http://www.nvidia.ru/docs/IO/60385/Lecture_44.pdf

ЦитироватьПотоковые процессоры сгруппированы в восемь блоков по 16 штук, каждый из которых оснащен четырьмя текстурными модулями и общим L1-кэшем.
http://www.compress.ru/Archive/CP/2006/12/5/

ЦитироватьКэш первого уровня имеет объем 64 KB, по 32 KB для вершин и текстур (похоже на L1-кэш для данных и инструкций у CPU), общий же кэш второго уровня равен 256 KB. Текстурных блока у R600 всего четыре.
http://article.techlabs.by/30_940_2.html

ЦитироватьС помощью утилиты NVPerfHUD можно включать или выключать ту или иную функциональность драйвера или GPU. Например с помощью mipmap LOD bias можно сделать все текстуры размером 2х2. Если производительность при этом возрастет, значит узкое место � кэш-промахи при доступе к текстурам
http://amax.h16.ru/docs/nv.html


??? ::) ???
Сори за такой длинный пост(


Вот один из фактов оптимизации кода компилятором, с которым я столкнулся. Это такой же цикл как и у тебя, Sqwer.
Берем такой код :

half2 passessUV = half(6,3);
float3 refColor=0;
for (int x = 0; x < passessUV.x; ++x)
{
float pX = x-p_.x;
if (pX<=0) {rTn = -rTn;}
for (int y = 0; y < passessUV.y; ++y)
{
float pY = y-p_.y;
if (pY<=0) {rBTn = -rBTn;}
float3 tNn = normalize(lerp(normals,rTn,(abs(pX)+noise_.x)*glossinessUV.x));
float3 btNn = normalize(lerp(tNn,rBTn,(abs(pY)+noise_.y)*glossinessUV.y));
refColor += texCUBE(iSamplerCube, -reflect(iEyeVec,btNn) ).r;
}
}
refColor /=passesQ;

Результат - 7фпс (
Отключаем выборку, но используем значение предыдущей переменной, что бы компилятор не отбросил предыдущие вычисления-
refColor += btNn//texCUBE(iSamplerCube, -reflect(iEyeVec,btNn) ).r;
Результат - 30фпс
далее убираем из вычислений значение переменной интерации  -
float pX = p_.x;//x-p_.x;
if (pX<=0) {rTn = -rTn;}
for (int y = 0; y < passessUV.y; ++y)
{
float pY = p_.y;//y-p_.y;

Результат - 52фпс
возвращаем выборку, но оставляем убранные значения счетчика - 46фпс


Смотрим результаты и делаем выводы.
В первый раз имеем большую зону выборки - 7фпс
В последний - читаем один и тот же пиксель - 46фпс
Во второй - не читаем текстуру вообще, но с каждой интерацией прибавляемое значение меняется - 30фпс
в третий не меняется, т.к. вычисления остаются идентичными для каждой интерации - 52 фпс

видео: GF8600GT
Объект занимает 100% вьюпорта. разрешение - 1272х849
В шейдере есть другие инструкции, помимо этого цикла.

Sqwer

#154
Цитироватьда и в железках кучу железных оптимизаций.
ну и где эта куча?   
кроме кэша ничего не нашлось  ::)

ЦитироватьБыли ветки на форумах, где народ эксперементировал с тем же SSAO и было замечено, что производительность сильно зависит от радиуса выборки соседних пикселей и т.д.
наверное ты не так понял.
суть ССАО  в том, что  для затенения мы проверяем  соседние пиксели на разницу глубины.
выборка происходит из соседних пикселей.
чем дальше стреляем - тем разреженней   зона выборки
(представь зерно в кучке  и  зерно этой же кучки разбросанное по складу)
поскольку   происходит разряжение (снижение плотности) тестов надо её компенсировать, вопрос  КАК??
ответ: увеличив плотность    увеличением кол-ва выборок.

Итого   -  увеличивая размер выборки    мы  увеличиваем кол-во выборок, дабы сохранить прежнюю плотность (качество ссао)

ЗЫ.
"не доверяй каждому слову" так  говорил Виктор Куропятник.
и блин.. он был прав
на  геймдеве топчатся много новичков, у которых что-то не так с...   и они начинают  выдумывать   непонятно, что, внушая свои  догатки остальным. Хорошо, что там есть старожилы (обычно  со стороны участников), которые пресекают подобные идеи.

В любом случае, доверять можно им  или пэперам, к постам новечков яб относился с опаской.  :-\



ЦитироватьЭто такой же цикл как и у тебя, Sqwer.
вовсе нет, твой жирнее!


   
ЦитироватьЛибо ты прикалываешся, либо мы совсем о разном говорим.
не, я серьёзный как индюк
меня заинтересовал твои суждения и решил убедиться сам

Тест №1 Задача:  ИЗМЕРИТЬ  ФПС при включ/выключенном цикле
узнать, работает ли бранчинг

вкл/выкл  контролируется   условием IF 
переменная yes    - внешняя,  тип float
if (yes>1)
{
for( int i = 0;i < 100; i++ )
{
aldedo += tex2D (gAlbedoMap, (pIn.texC ));
normal += tex2D (gNORMALMap, (pIn.texC) );
position += tex2D (gPOSITIONMap, (pIn.texC) );
self += tex2D (gSELFILLUMMap, (pIn.texC) );

}

}


Результаты:
включ цикл  - 56 ФПС   (18 мс)
выключ цикл - 170 ФПС  (6 мс)
бранчинг работает



Тест №2 Задача:  проверить гипотезу  о нарушении попадания в кэш текстур в случае сдвига текстурных координат.

добавим в код  смещение текстурных
(оптимизатор не схлопнет цикл, поскольку стоят + / также изменения текстурных координат зависит от цикла , поскольку подключаем переменную i /  i  принимает целые значения , а адресация текстур приводится в диапозоны [0..1], т.е.  мы по сути стреляем в одни и теже координаты, для исключения этого  добавим произвольное смещения *0,ххх)

Цитировать
if (yes>1)
{
for( int i = 0;i < 100; i++ )
{

aldedo       += tex2D (gAlbedoMap,       (pIn.texC+i*0.01) );
normal       += tex2D (gNORMALMap,       (pIn.texC+i*0.011) );
position    += tex2D (gPOSITIONMap,    (pIn.texC+i*0.0111) );
self      += tex2D (gSELFILLUMMap,    (pIn.texC+i*0.01111) );
   
   }

}   

Результат:

10 ФПС (100,0 мс)


в цикле выполняется доп операция +i*0.ххх, которая  не бесплатна
посмотрим на  штрафы включения этой  +i*0.ххх
для этого поменяем код

Цитироватьif (yes>1)
{
for( int i = 0;i < 100; i++ )
{
aldedo    +=i*0.01;
normal     +=i*0.011;
position  +=i*0.0111;
self     +=i*0.01111;


   aldedo       += tex2D (gAlbedoMap, (pIn.texC));
   normal       += tex2D (gNORMALMap, (pIn.texC) );
   position    += tex2D (gPOSITIONMap, (pIn.texC) );
   self      += tex2D (gSELFILLUMMap, (pIn.texC) );
   
   }

}   

Результат:
34 ФПС  (29,4  мс)


Узнаем штраф не попадания по кэшу:

100,0 мс - 29,4 мс = 70,6 мс

Узнаем штраф  на  вызов операций   +i*0.ххх

29,4 мс -18 мс = 11,4 мс

Пусть  цикл без смещения текстурок  и без   функции +i*0.хххх   является номиналом, тогда посчитаем  относительный штраф:

(70,6/18)*100%= 392%
(11,4/18)*100%= 63%

Это значит , что ввод  блока  +i*0.хххх замедлил работу шейдера на 63%

Промах по кэшу замедлил  ещё на 392% 


Теперь  проверим между собой

(70,6/11,4)*100%=619%
т.е.  штраф на не попадания в кэш состовляет  619% от штрафа на  блок +i*0.хххх


ТЕПЕРЬ подумаем,   а вбруг  эксперемент не читстый??!   вдруг  у нас   все текстуры находятся в кэше??!!   
ответ- ИСКЛЮЧЕНО  (ибо текстуры  разрешения 1280*1024 на 64бит/пиксель     это примерно для 4 текстур  40мб!!    естественно, что  такого  кэша  видяха  8800GTX не имеет)

мэй би кэшируется этими самими  регионами.  ::)  ???
нужны пэперы для конкретных архитектур и дров.



ОБЩИЙ ВЫВОД:

миф о штрафе промаха текстурного кэша   ПОДТВЕРЖДЁН




!!!люди  будьте аккуратнее с циклами!!!



dfx

#155
Цитироватьнаверное ты не так понял.
Я правильно понял. Имелось ввиду увеличение радиуса без увеличения интераций, но там использовалась жесткая тектура шума (256х256), когда стали использовать шум 4х4. Скорость выросла, но артифакты стали заметнее.

тест подтверждает суждения


ЦитироватьРезультаты:
включ цикл  - 56 ФПС   (18 мс)
выключ цикл - 170 ФПС  (6 мс)
бранчинг работает
Это не может не работать :) Проблема была немного в другом - значение для условий читалось из тектуры. А это уже совсем другое. Если внешнее значение - константа на момент исполнения шейдера, то значение создаваемое самим шейдером в процессе заранее не известно, что содает свои штрафы при ветвлениях(

Интересный экперимент. Но тут странно, что производительность так рухнула.
if (yes>1)
{
for( int i = 0;i < 100; i++ )
{
   aldedo       += tex2D (gAlbedoMap, (pIn.texC+i+0.3 ));
    normal       += tex2D (gNORMALMap, (pIn.texC+i+0.3) );
   position    += tex2D (gPOSITIONMap, (pIn.texC+i+0.3) );
   self      += tex2D (gSELFILLUMMap, (pIn.texC+i+0.3) );
   
   }

} 
 

ага очень странно,  поправил  -  разница ощутима стала.  :-X

Кстати, насчет схлопывания цикла и дороговизны сложения, попробуй код
   aldedo+=i+0.3;
   normal+=i+0.3;
   position+=i+0.3;
   self+=i+0.3;

заменить на
   aldedo+=0.2+0.3;
   normal+=0.4+0.3;
   position+=0.8+0.3;
   self+=0.1+0.3;

исключив, тем самым, значение интератора из вычислений. У меня, как я писал, производительность сильно отличается при таких раскладах. Т.е. если в выражениях учавствует значение интератора, то производительность падает прилично, при идентичных операциях. Вполне возможно, что при одних и тех же результатах во всех интерациях, сложение не производятся честно каждую интерацию. надо попробовать посмотреть асм на выходе - там виднее будет.

ага в таких случаях он выносит выражение 0.2+0.3 за цикл

Вообще же, если копать глубоко по устройству гпу, оптимизации кода и т.д., то более полезными оказываются статьи по CUDA, там более подробно описывают все нюансы, чем в статьях по графическим эффектам. Сам сейчас курю эти доки из сети. :)


если вкусное найдёшь -  заливай.. посмотрим  :)

За тесты +1 ;D

Cludz

Цитироватьfloat4 blend(float4 texture0, float4 texture1, float layerOpacity)
{
    const float blendRange = 0.1;

    if (texture1.a < layerOpacity - blendRange)     
    {
         return texture1;
    }
    else if (texture1.a > layerOpacity + blendRange)
    {
        return texture0;
    }
    else
    {
        float f = (texture1.a - layerOpacity + blendRange) / (2 * blendRange);
        return lerp(texture1, texture0, f);
    }
}
смешивание текстур через альфа канал, как это адаптировать под квест?
Skype "Cludz159"

Alteste

Цитироватьсмешивание текстур через альфа канал, как это адаптировать под квест?

// BLEND DIFFUSE ALPHA
/////////////////////////////////////////////////////////////////////////
///// Объявление Переменных /////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
// Объявление матриц
float4x4 WorldVP : WorldViewProjection; // Произведение мировой, видовой и проекционной матриц
float4x4 World   : World; // Матрица мирового преобразования
float4x4 WorldIT : WorldInverseTranspose; // Инвертированная - транспонированная мир матрица

// Переменные (Value)
float LayerOpac : CHANNELVALUE0 <
    string UIWidget = "slider";
    float UIMin = 0.0;
    float UIMax = 1.0;
    string UIName =  "Layer Opacity";
> = 1;

/////////////////////////////////////////////////////////////////////////
///// Текстуры //////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

texture texmap : TEXTURE0;
sampler Texture1 = sampler_state
{
Texture = <texmap>;
    MinFilter = Linear;
    MipFilter = Linear;
    MagFilter = Linear;
    AddressU = Wrap;
    AddressV = Wrap;
    AddressW = Wrap;
};

texture texmap2 : TEXTURE1;
sampler Texture2 = sampler_state
{
Texture = <texmap2>;
    MinFilter = Linear;
    MipFilter = Linear;
    MagFilter = Linear;
    AddressU = Wrap;
    AddressV = Wrap;
    AddressW = Wrap;
};
/////////////////////////////////////////////////////////////////////////
///// Структуры /////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

//Входящие данные
struct appdata
{
    float4 position : POSITION; // Позиция объекта
float3 Normal    : NORMAL; // Нормаль к поверхности
float2 texcoord0 : TEXCOORD0; // Текстурные координаты
};

//Исходящие данные
struct vertexOutput
{
    float4 HPosition    : POSITION; // Позиция объекта
float3 wNormal    : TEXCOORD0; // Направление нормали в мировом пространстве
float2 texcoord0 : TEXCOORD3; // Текстурные координаты
};

/////////////////////////////////////////////////////////////////////////
///// Шейдеры ///////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//Вершинный шейдер
vertexOutput VS(appdata IN)
{
    vertexOutput OUT;
OUT.wNormal = normalize(mul(IN.Normal,WorldIT));
float4 worldSpacePos = mul(IN.position,World);
    OUT.HPosition = mul(IN.position,WorldVP);
OUT.texcoord0 = IN.texcoord0;
    return OUT;
}

// Функция смешивания
float4 blend(float4 texture0, float4 texture1, float layerOpacity)
{
    const float blendRange = 0.1;

    if (texture1.a < layerOpacity - blendRange)     
    {
         return texture1;
    }
    else if (texture1.a > layerOpacity + blendRange)
    {
        return texture0;
    }
    else
    {
        float f = (texture1.a - layerOpacity + blendRange) / (2 * blendRange);
        return lerp(texture1, texture0, f);
    }
}

//Пиксельный шейдер
float4 PS(vertexOutput IN) : COLOR
{
float4 tex1 = tex2D(Texture1,IN.texcoord0.xy);
float4 tex2 = tex2D(Texture2,IN.texcoord0.xy);
float4 result = blend(tex1,tex2,LayerOpac);
return result;
}

/////////////////////////////////////////////////////////////////////////
///// Техника ///////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
technique Main
{
    pass p0
{
        VertexShader = compile vs_2_0 VS();
        PixelShader = compile ps_2_0 PS();
ZWriteEnable = true;
}
}


Cludz

blendRange что это? и зачем оно нужно?)
выходит это была уже готовая функция
а как альфа каналу задать отдельные текстурные координаты?
Skype "Cludz159"

Alteste

Цитата: Cludz от 10 апреля 2011, 21:37:20
blendRange что это? и зачем оно нужно?)
выходит это была уже готовая функция
а как альфа каналу задать отдельные текстурные координаты?
Ты лучше скажи что тебе нужно получить

Cludz

ЦитироватьТы лучше скажи что тебе нужно получить
смешивание множества текстур(8шт лимит квеста если не ошибаюсь) на терейне(terrain),текстура в альфа канале растянута на всю модель, величина в альфа канале показывает процент заполнения текстуры.
Skype "Cludz159"

Alteste

Цитата: Cludz от 11 апреля 2011, 11:46:50
ЦитироватьТы лучше скажи что тебе нужно получить
смешивание множества текстур(8шт лимит квеста если не ошибаюсь) на терейне(terrain),текстура в альфа канале растянута на всю модель, величина в альфа канале показывает процент заполнения текстуры.
Напиши подробно (какие текстуры и как смешиваются, какие текстурные коодринаты и у какой текстуры альфа-канал) или приведи пример на материалах 3dsmax.

Cludz

1я текстура смешивается с 2й относительно альфа маски 1й,
если в альфа канале 1 (белый) рисовать 1ю текстуру если 0 (черный) рисовать 2ю а если 0.5 (серый) рисовать 50/50
также 2я и 3я текстуры через альфа маску 2й, 3я и 4я и так далее до 8й, альфа 8й текстуры хочу сделать теневой маской.
Текстурные координаты для альфа маски 1, 1
Для цветовой не знаю это зависит от размеров модели, я хотел делать модель размеров 1км на 1км но думаю не в ложусь в лимит пикселей, для всех текстур координаты одинаковы (кроми альфа каналов)
Skype "Cludz159"

dfx

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

Смешиваем песок,зеленую траву, желтую траву, камни, снег -
песок, трава, камни - тайлящаяся текстура 512х512 RGB
снег - можно просто материалом или бамп...
маски храним в отдельной текстуре, например 2048х2048 RGB
в канале RED - одна маска, скажем для песка и травы, в канале BLUE - другая и т.д.
Тайловые текстуры у нас получаются одинаковые для всех уровней, а маски привязаны к ландшафту.

Тем не менее можно найти применение и для альфа-канала текстур - там тоже хранить маски, но локальные, учитывающие особенности диффузной текстуры. Они будут просто визуально увеличивать детализацию перехода от одного слоя к другому, т.к. какой бы не была большой текстура, переходы все равно будут слишком мягкие, что смотрится не очень красиво.