Перейти к содержанию

Вопросы по sfall и пиксельным шейдерам.


Рекомендуемые сообщения

Есть тут гении кто разбирается в написании пиксельных шейдеров?

т.е. вот в такой вот лабуде :)

string texname1 = "weather\\mask-inv.png";
texture tex1;
string texname2 = "";
texture tex2;

static const float tscale=3;
int tickcount;
float multi;
float speed;

sampler s0;
sampler s1 = sampler_state {
	texture = <tex1>;
};
sampler s2 = sampler_state {
	texture = <tex2>;
	addressu=wrap;
	addressv=wrap;
};

float4 ps_p0(float2 tex : TEXCOORD0) : COLOR0
{
	float3 r1=tex2D(s0, tex);

	float offset=(float)tickcount/speed;
	float2 y={0.342, 0.940};
	y*=offset;
	float3 r2=tex2D(s2, tex*tscale-y)*tex2D(s1, tex)*multi;
	float alpha=r2.g;
	r1=r1*(1-alpha) + r2*alpha;
	return float4(saturate(r1), 1);
}


technique T0
{
	pass P0 { PixelShader = compile ps_2_0 ps_p0(); }
}
Ссылка на комментарий

В общем в чем суть, есть идея реализовать аля HUD в Fallout2   :D

и нужно написать анимированный шейдер появление/затухание текстуры(картинки) - и вообще мне неизвестно возможно ли реализовать анимацию посредством шейдера. Вот в чем вопрос?

 

Я написал анимацию скриптово, работает но не так как хотелось.

вот че получилось, правда анимация зафрапсилась не так плавно как в игре.

https://yadi.sk/i/ykqJIpBpmC3UD

Ссылка на комментарий

аналогично, Foxx

и поджать free videojoiner'om 

Fallout 2Путеводитель по модам | FAQ | Перевод модов | Путеводитель по RP

Nevada Band: Путеводитель по играм серииFAQ

Fallout Tactics: Путеводитель по модам | FAQ

База Данных: YD\YD\MF

Помогая другим, не забывай о себе =) 

Ссылка на комментарий

выкладываю сделанные наработки аля HUD исходники F2_HUD

реализовано две пиктограммы, радиация и биологическая опасность.

скрип вполне рабочий, но его еще нужно отшлифовать.

включается пиктограммы из любого скрипта в игре такими строчками:

set_sfall_global("RAD_SHEN", 6); - вкл. значка радиации. 

set_sfall_global("BIO_SHEN", 6);  - вкл. значка биолог. заражения. цифра 6 это то сколько раз раз будет мигать значек.

 

если кто дружит со скриптами то может с легкостью реализовать к примеру в неваде отображение значка радиации вместо(или вместе с) "пикаюшего" звука.

а я пойду дальше пилить свое чудо)

 

демонстрация (на видео анимация выглядит тормознутой, но в игре выглядит отлично)

Ссылка на комментарий

Написать шейдер можно, если знать, что мы можем получить из движка. Я с sfall не знаком просто. Вот этот вот шейдер в #1 например, он вообще о чём?

Ссылка на комментарий

Написать шейдер можно, если знать, что мы можем получить из движка. Я с sfall не знаком просто. Вот этот вот шейдер в #1 например, он вообще о чём?

с движка игры ничего не получишь там же нет никаких 3d объектов.

можно только параметры передавать из скипта игры в шейдер.

 

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

float offset=(float)tickcount/speed;

float2 y={0.342, 0.940};

y*=offset; 

 

я пару дней пытался вникнуть и разобраться в систему шейдеров, но для без хорошего учебника для новичков и практики многое не понятно.

Ссылка на комментарий

с движка игры ничего не получишь там же нет никаких 3d объектов.

можно только параметры передавать из скипта игры в шейдер.

 

Ну, я про параметры и говорил. То есть например, нам нужен будет некий параметр контролирующий уровень прозрачности твоего HUD.

 

Для более сложной анимации, сопряжённой например с переключениями кадров анимации - шейдер не годится. Наверное такое лучше делать из скрипта.

 

Разобраться в системе шейдеров конечно мне как уже знающему человеку, кажется довольно просто. Задавай вопросы, попробую на них тебе ответить.

 

Я сейчас прокапитаню базовые вещи, наверное они тебе известны.

 

В базе - пиксельный (иногда называемый - фрагментный) шейдер - некая программа, отвечающая за цвет пикселя при отрисовке. В простейшем виде - за цвет пикселя на экране. Если у нас экран с разрешением 1920х1080, получаем 2073600 пикселей, соответственно столько раз будет вызван шейдер - по разу на пиксель.

 

На вход пиксельного шейдера подаются данные с конвейера (в твоём примере - float2 tex : TEXCOORD0) - они вообще говоря могут иметь самый разный смысл, но в твоём случае - это текстурные координаты - т.е. указание - из какой части текстуры взять данные о цвете. Плюс, из шейдера есть доступ к глобальным данным - т.н. uniforms. У тебя это tickcount, multi, speed. Я так понимаю, их в sfall можно подать из скрипта?

 

Дальше, чего ты там хочешь со всей этой ботвой, то и делаешь. Любая математика. Главное что на выходе шейдера ты получаешь некоторый вектор float4, обозначающий интенсивность цветовых компонентов пикселя. (r, g, b, a). Цифры должны находиться в диапазоне [0.0; 1.0], 0.0 - нулевая интенсивность, 1.0 - полная интенсивность. Цифры за пределами этих диапазонов имеют смысл только при промежуточных расчётах, либо при наличии HDR (чего в sfall врядли есть).

Ссылка на комментарий

 

Для более сложной анимации, сопряжённой например с переключениями кадров анимации - шейдер не годится. Наверное такое лучше делать из скрипта.

Плюс, из шейдера есть доступ к глобальным данным - т.н. uniforms. У тебя это tickcount, multi, speed. Я так понимаю, их в sfall можно подать из скрипта?

то есть простое мигание значка шейдером не сделать да?

 

tickcount - это какая-то внутренняя фигня.

multi, speed - это параметры которые можно передать из скрипта, multi - уровень прозрачности.

 

а как действует техники technique T0 - я сюда подставлял blur, и чето никакого эффекта.

 

float2 y={0.342, 0.940} - а как вот это понимать?

 

float alpha=r2.g и вот это, я так понимаю берется цвет зеленых пикселей?

 

семплеры 

s0 - сюда я так понимаю заносится изображение с экрана да?

s1 - здесь у нас маска, чтобы выводить картинку в определенный участок экрана, а можно как-нибудь это выводить без маски? а то текстура покрывает все изображение на экране

 

 

OvcWHi0i-2Q.jpg

 

 

s2 - здесь сама текстура нашей картинки. 

addressu=wrap;

addressv=wrap;

тут тоже вопрос? убирал эти строчки никакого эффекта не заметил. 

 

и еще вот с другого шейдера пример

Color = tex2D( s0, float2(Tex.x, Tex.y));

Tex.x, Tex.y - c этого что мы получаем?

Ссылка на комментарий

то есть простое мигание значка шейдером не сделать да?

Ну как, управляя прозрачностью - можно. Это я так понимаю, можно сделать управляя из скрипта, параметром multi.

 

а как действует техники technique T0 - я сюда подставлял blur, и чето никакого эффекта.

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

 

float2 y={0.342, 0.940} - а как вот это понимать?

В первом случае просто создаётся двумерный вектор с заданными значениями. В дальнейшем он используется для сдвига текстурных координат. Тут надо расплыться текстом про текстурные координаты и вообще выборку. Выборка цвета из текстурки берётся по координатам вот таким макаром

 

 

IC282223.jpg

 

 

по координатам (0.0, 0.0) берётся верхний левый угол текстуры, по координатам (1.0, 1.0) - нижний правый. Промежуточные значения - соответственно где-то в середине текстуры. Если значения координат поданные в tex2D выходят за эти рамки - выборка регулируется вот этими параметрами в семплере:

 

addressu=wrap;

addressv=wrap;

 

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

 

В конечном итоге, физический смысл при расчётах далее

float2 y={0.342, 0.940} - сдвиг координат на треть по горизонтали и почти на целую текстуру по вертикали.

 

float alpha=r2.g и вот это, я так понимаю берется цвет зеленых пикселей?

Тут у нас берётся зелёная компонента цвета, рассчитанного здесь

 

float3 r2=tex2D(s2, tex*tscale-y)*tex2D(s1, tex)*multi;

 

Чо это всё значит.

 

tex2D(s2, tex*tscale-y) в этой части, берётся цвет из семплера s2, который соответствует текстуре

 

string texname2 = ""; <- кстати - где путь?

texture tex2;

 

Цвет берётся по координатам tex*tscale-y - вектор tex покомпонентно умножен на число tscale, и из него вычтен вектор y. Физически это значит что картинку увеличили в 3 раза и сдвинули (см выше - как)

 

семплеры 

s0 - сюда я так понимаю заносится изображение с экрана да?

s1 - здесь у нас маска, чтобы выводить картинку в определенный участок экрана, а можно как-нибудь это выводить без маски? а то текстура покрывает все изображение на экране

 

 

OvcWHi0i-2Q.jpg

 

 

s2 - здесь сама текстура нашей картинки. 

addressu=wrap;

addressv=wrap;

тут тоже вопрос? убирал эти строчки никакого эффекта не заметил.

Смотри, про семплер вообще говоря. Семплер - это не текстура сама по себе, это некоторая фигня, которая делает выборку цвета из текстуры (семплит, ага). У неё есть настройки - вот эти addressu, addressv, ещё есть другие вещи, типа фильтрации, мипмэпинга, но это потом, если понадобится, в 2D вообще говоря плохо применимо. Про значения этих addressu я написал выше. И есть настройка texture - вот это собственно текстура. Семплер s0 вероятно захардкожен и в нём всегда текстура, содержащая уже отрисованную основную сцену.

 

Когда ты потом в коде шейдера пишешь tex2D(s1, tex) - это значит - "семплер s1, дай мне цвет из своей texture по координатам tex"

 

Скорей всего, тебе чтобы рисовать без маски, т.е. чтобы текстура не повторялась - достаточно будет применить в семплере s1 параметры

addressu = clamp;

addressv = clamp;

 

а s2 и соответственно выборку из неё вообще убрать нафиг.

 

и еще вот с другого шейдера пример

Color = tex2D( s0, float2(Tex.x, Tex.y));

Tex.x, Tex.y - c этого что мы получаем?

Здесь взяли значения x и y компонент вектора Tex, создали из этого 2-мерный вектор, который используется как координаты при выборке из текстуры.

 

И тут кстати надо рассказать про то насколько тут шейдерный язык удобен в некоторых моментах. Например, у тебя есть вектор

float4 myVector = {1.0, 2.0, 3.0, 4.0};

т.е. тут создан вектор где x = 1.0, y = 2.0, z = 3.0, w = 4.0

 

и ты можешь где-нибудь потом написать

float2 my2DVector = myVector.xy;

 

и будет создан 2-мерный вектор, у которого x = myVector.x, y = myVector.y

 

более того, можно написать следующую несусветицу

 

float2 my2DVector = myVector.yx;

 

и будет вектор с x = myVector.y, y = myVector.x

 

такие дела.

Нифигасе портянка получилась...

Ссылка на комментарий

Ну как, управляя прозрачностью - можно. Это я так понимаю, можно сделать управляя из скрипта, параметром multi.

ну вот так у меня и есть, но может есть какой способ анимировать из шейдера, 

ведь строчка float offset=(float)tickcount сдвигает текстуру без управления из скрипта, может и на прозрачность можно что-то повесить.

 

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

В другом шейдере было использовано blur, но может действительно оно формально.

 

 

 







sampler s0;

static const float2 rcpres =
{
	0.0015625,
	0.0020833333333333333333333333333333
};

float4 Blur(float2 Tex : TEXCOORD0) : COLOR0
{
	float4 Color = 0;

	Color += tex2D( s0, float2(Tex.x, Tex.y));
	Color += tex2D(s0, float2(Tex.x + rcpres.x, Tex.y));
	Color += tex2D(s0, float2(Tex.x - rcpres.x, Tex.y));
	Color += tex2D(s0, float2(Tex.x, Tex.y + rcpres.y));
	Color += tex2D(s0, float2(Tex.x, Tex.y - rcpres.y));

	return Color * 0.2;
}

float4 Blind(float2 Tex : TEXCOORD0) : COLOR0
{
	float4 Color = tex2D(s0, Tex);
	return Color * saturate(1.5 - (length(Tex - 0.5)*2));
}

Technique blur
{
	Pass P0 { PixelShader = compile ps_2_0 Blur(); }
	Pass P1 { PixelShader = compile ps_2_0 Blur(); }
	Pass P2 { PixelShader = compile ps_2_0 Blur(); }
	Pass P3 { PixelShader = compile ps_2_0 Blur(); }
	Pass P4 { PixelShader = compile ps_2_0 Blur(); }
	Pass P5 { PixelShader = compile ps_2_0 Blind(); }
}

 

 

 

string texname2 = ""; <- кстати - где путь?

 

Цвет берётся по координатам tex*tscale-y - вектор tex покомпонентно умножен на число tscale, и из него вычтен вектор y. Физически это значит что картинку увеличили в 3 раза и сдвинули (см выше - как)

путь в скрипте задается, но это не важно.

данном случае уменьшили в 3 раза.

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

 

 









string texname1 = "scrmask1.png";
texture tex1;
string texname2 = "biowarn.png";
texture tex2;

static const float tscale=13;
float multi;

sampler s0;
sampler s1 = sampler_state {
	texture = <tex1>;
};
sampler s2 = sampler_state {
	texture = <tex2>;
};

float4 ps_p0(float2 tex : TEXCOORD0) : COLOR0
{
	float3 r1=tex2D(s0, tex);
	
	float2 y={0.342, 0.940};
	y*=0.25; //offset;
	float3 r2=tex2D(s2, tex*tscale-y)*tex2D(s1, tex)*multi;
	float alpha=r2.g;
	r1=r1*(1-alpha) + r2*alpha;
	return float4(saturate(r1), 1);
}

technique T0
{
	pass P0 { PixelShader = compile ps_2_0 ps_p0(); }
}

 

 

 

Скорей всего, тебе чтобы рисовать без маски, т.е. чтобы текстура не повторялась - достаточно будет применить в семплере s1 параметры

addressu = clamp;

addressv = clamp;

 

а s2 и соответственно выборку из неё вообще убрать нафиг.

ты наверное имел ввиду применить к s2 ?

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

а как вывести картинку в определенные координаты, так-то я маской определял положение и подстраивал картинку смешением через y*=0.25; //offset

 

upd: clamp помог, но теперь появляется какая-то малозаметная(полупрозрачная) вертикальная полоса от картинки на весь экран.

видимо от того что в png нет альфа канала?

 

и еще как работать с альфа каналом в png?

Ссылка на комментарий

ну вот так у меня и есть, но может есть какой способ анимировать из шейдера, 

ведь строчка float offset=(float)tickcount сдвигает текстуру без управления из скрипта, может и на прозрачность можно что-то повесить.

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

 

В другом шейдере было использовано blur, но может действительно оно формально.

Здесь Blur() - это название функции - точки входа шейдера. Своеобразный main(). называться такая функция может как угодно. Главное чтобы она была в файле и была прописана в пассе. В этом шейдере кстати обрати внимание, несколько пассов, каждый делает blur, кроме последнего. Каждый пасс - проход рендера картинки, в первом пассе s0 - просто отрисованная сцена, в каждом последующем - в s0 лежит результат предыдущего пасса.

 

То есть работает это так. В пассе делаются вызовы для всех пикселей экрана, получается некоторый результат. Он складывается в текстуру, и отрисованный результат предыдущего пасса можно получить из s0. И так далее.

 

путь в скрипте задается, но это не важно.

данном случае уменьшили в 3 раза.

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

Да, точно, уменьшили в 3 раза. Ошибся.

 

ты наверное имел ввиду применить к s2 ?

Да, к s2. Короче к тому семплеру, который берёт из текстуры со значком.

 

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

Когда ничего не задаётся целенаправленно - используется настройка по умолчанию. Тут по умолчанию видимо стоит wrap.

 

а как вывести картинку в определенные координаты, так-то я маской определял положение и подстраивал картинку смешением через y*=0.25; //offset

Придётся заморочиться. У тебя на входе шейдера есть float2 tex : TEXCOORD0. Изначально - это координаты для выборки из s0. В диапазоне (0.0, 0.0) - (1.0, 1.0). Зная разрешение экрана и эти координаты, мы можем вычислить - для какого пикселя на экране сделан вызов шейдера и относительно этих данных, прикинуть, какие текстурные координаты нам надо выдернуть из s2. Далее распишу на примерных числах, дальше сам подгонишь.

 

// позиция иконки в экранных координатах
const float2 icon_position = {32, 32};

// размер иконки в экранных координатах
const float2 icon_size = {64, 64};

// разрешение экрана - подаём из скрипта
float2 screen_resolution;

float4 ps_main(float2 tex : TEXCOORD0) : COLOR0
{
    // коэффециент преобразования из экранных координат в текстурные
    float2 ratio = 1.0f / screen_resolution;

    // сдвиг текстурных координат иконки
    float2 shift = icon_position * ratio;

    // масштабирование текстурных координат иконки
    float2 scale_factor = icon_size * ratio; 

    // берём цвет из уже отрисованной сцены
    float4 base_color = tex2D(s0, tex);

    // берём цвет из текстуры иконки
    float4 icon_color = tex2D(s2, (tex - shift) / scale_factor); 

    // считаем итоговый цвет по формуле аддитивного блендинга
    float4 result_color = icon_color * (1.0f - icon_color.a) + base_color * icon_color.a;

    return float4(saturate(result_color.rgb), 1.0f);
}

Чёто так вроде. Вообще говоря, оптимизируя - ratio, shift и scale_factor лучше посчитать предварительно, ещё в скрипте и в шейдер уже подать готовые значения. icon_position и icon_size соответственно тоже можешь подать из скрипта, а не забивать их константами.

 

Вот эта хреновина

(tex - shift) / scale_factor

в выборке из s2 - и есть вот этот пересчёт - как из текстурных координат tex получить координаты в s2.

Ссылка на комментарий

Ну, да, скорей всего tickcount даёт какую-то цифру времени прошедшего со старта игры.

этот tickcount вообще никак не связан с игрой, это что-то шейдерное.

да плохо что нельзя. ну да ладно.

 

Придётся заморочиться. 

Я уже немного разобрался просто пишу в строке float2 y={0.342, 0.940} значения и картинка сдвигается куда надо, правда это никак не привязано к разрешению экрана.

 

С полоской тоже разобрался и убрал - оказывается clamp крайние пиксели в текстуре дублировал(растягивал) на весь экран.

а есть еще что-нибудь кроме clamp и wrap?

 

ладно буду мозговать) спасибо за разъяснения.

 

// считаем итоговый цвет по формуле аддитивного блендинга

float4 result_color = icon_color * (1.0f - icon_color.a) + base_color * icon_color.a;

эту строку ты сам написал или взял с какого-то примера. не работает она правильно.

Ссылка на комментарий

а есть еще что-нибудь кроме clamp и wrap?

Есть mirror - текстура повторяется но зеркально

есть bordercolor, там тупо цвет идёт, за пределами текстуры, надо сам цвет ещё в семплер задавать.

 

эту строку ты сам написал или взял с какого-то примера. не работает она правильно.

На память писал. И естественно накосячил. Должно быть так:

 

float4 result_color = base_color * (1.0f - icon_color.a) + icon_color * icon_color.a;

Ссылка на комментарий

есть bordercolor, там тупо цвет идёт, за пределами текстуры, надо сам цвет ещё в семплер задавать.

 

float4 result_color = base_color * (1.0f - icon_color.a) + icon_color * icon_color.a;

хм, а это нормально что clamp заливает экран за пределами текстуры цветом с краев текстуры

может мне bordercolor надо было писать а цвет указать черный.

 

это я уже понял что ты перепутал местами base_color), но тут косяк в том, что не хочет оно работать с альфой icon_color.a

не видит оно альфу в png в белый цвет отрисовывается. 

Ссылка на комментарий

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйте новый аккаунт в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...