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

Урок как создать прозрачный шейдер для ХУДа

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

 

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

XR-3-DA-2022-04-18-17-53-02-24.png XR-3-DA-2022-04-18-18-49-52-03.png

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

XR-3-DA-2022-04-18-17-52-23-85.png

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

Чтобы это пофиксить нужно создать специальный костыльный шейдер прозрачности для худа, который рисует всё с уменьшенным углом обзора. В модели аномального бизона для прозрачности используется шейдер models\pautina, на его основе и будем делать. Поэтому лезем в gamedata\shaders\r1 и находим там файл models_pautina.s. Если его открыть можно увидеть такой код:

function normal		(shader, t_base, t_second, t_detail)
  shader:begin		("model_distort4ghost","particle")    -- particle_alphaonly
      : sorting		(3, true)
      : blend		(true,blend.srccolor,blend.invsrcalpha)
      : aref		(true,0)
      : zb		(true,false)
      : fog		(false)
      : distort		(false)
  shader:sampler	("s_base")      :texture  (t_base)
end

function l_special	(shader, t_base, t_second, t_detail)
  shader:begin		("model_distort4ghost","particle_distort")
      : sorting		(3, true)
      : blend		(true,blend.srcalpha,blend.invsrcalpha)
      : zb		(true,false)
      : fog		(false)
      : distort		(true)
  shader:sampler	("s_base")      :texture  (t_base)
  shader:sampler	("s_distort")   :texture  ("pfx\\pfx_dist_glass") //:texture  (t_base) -- ("pfx\\pfx_dist_glass2"
end

function normal		(shader, t_base, t_second, t_detail)
  shader:begin		("model_def_lplanes","base_lplanes")
      : fog		(false)
      : zb		(true,false)
      : blend		(true,blend.srccolor,blend.one)
      : aref		(true,0)
      : sorting		(2, true)
  shader:sampler	("s_base")      :texture  (t_base)
end

Во первых, тут у нас две функции normal, что конечно является ошибкой разработчиков в самом деле используется только одна, вторая, поэтому первую лучше удалить чтобы не путаться. НО это нам с прозрачностью на худе не поможет. Дальше нужно поменять имя вершинного шейдера, которое идёт первым параметром функции shader:begin, ведь именно там применяются все транформации, в том числе и угол обзора. Я заменил model_distort4ghost и model_def_lplanes на model_distort4ghost_hud, в итоге получился такой файл:

function l_special	(shader, t_base, t_second, t_detail)
  shader:begin		("model_distort4ghost_hud","particle_distort")
      : sorting		(3, true)
      : blend		(true,blend.srcalpha,blend.invsrcalpha)
      : zb		(true,false)
      : fog		(false)
      : distort		(true)
  shader:sampler	("s_base")      :texture  (t_base)
  shader:sampler	("s_distort")   :texture  ("pfx\\pfx_dist_glass") //:texture  (t_base) -- ("pfx\\pfx_dist_glass2"
end

function normal		(shader, t_base, t_second, t_detail)
  shader:begin		("model_distort4ghost_hud","base_lplanes")
      : fog		(false)
      : zb		(true,false)
      : blend		(true,blend.srccolor,blend.one)
      : aref		(true,0)
      : sorting		(2, true)
  shader:sampler	("s_base")      :texture  (t_base)
end

Сохраняю его под именем gamedata\shaders\r1\models_pauhuda.s, имя нового шейдера прозрачности для худа будет models\pauhuda. Обратите внимание что в оригинале использовалось два разных вершинных шейдера (model_def_lplanes и model_distort4ghost), но я буду использовать только один, т.к. они всё-ровно не сильно отличаются.

Дальше самое интересное, нужно создать вершинный шейдер. Делать его будем на основе model_distort4ghost, поэтому копируем model_distort4ghost.vs и переименовываем его как model_distort4ghost_hud.vs, и смотрим что у него внутри:

#include "common.h"
#include "skin.h"

struct vf
{
  float4 hpos  : POSITION;
  float2 tc0  : TEXCOORD0;    // base
  float4 c0  : COLOR0;    // color
};

vf   _main (v_model v)
{
  vf     o;

  o.hpos       = mul      (m_WVP, v.pos);    // xform, input in world coords
  o.tc0      = v.tc.xy;          // copy tc

  // calculate fade
  float3  dir_v     = normalize    (mul(m_WV,v.pos));
  float3  norm_v     = normalize     (mul(m_WV,v.norm));
  float   fade    = 0.9*abs      (dot(dir_v,norm_v));
  o.c0    = fade;

  return o;
}

/////////////////////////////////////////////////////////////////////////
#ifdef   SKIN_NONE
vf  main(v_model v)     { return _main(v);     }
#endif

#ifdef   SKIN_0
vf  main(v_model_skinned_0 v)   { return _main(skinning_0(v)); }
#endif

#ifdef  SKIN_1
vf  main(v_model_skinned_1 v)   { return _main(skinning_1(v)); }
#endif

#ifdef  SKIN_2
vf  main(v_model_skinned_2 v)   { return _main(skinning_2(v)); }
#endif

И где же здесь применяется угол обзора? А вот в этой строчке:

  o.hpos       = mul      (m_WVP, v.pos);    // xform, input in world coords

Тут нужно немного пояснить что к чему. Угол обзора заключен в матрице m_WVP, которая на самом деле является комбинацией трёх основных матриц m_W, m_V, и m_P. Так же в шейдерах доступны и другие комбинации этих матриц, m_WV к примеру. Буквы W, V, P это первые буквы от слов World, View, Projection. Не буду сильно вдаваться в подробности того как это работает и для чего нужно, скажу только что угол обзора находится в m_P. Если взглянуть на функцию создания такой матрицы, то можно узнать что:

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

б) угол обзора и соотношение сторон можно получить обратно из готовой матрицы путём нехитрым математических вычислений ( отношение сторон как m_P[1][1] / m_P[0][0], а угол как atan( 1.0 / m_P[1][1] ) )

С этими знаниями уже можно выцарапать угол и соотношение сторон из готовой матрицы m_P, поделить угол на два и сконструировать новую матрицу m_P_fix с исправленным углом обзора, а плоскости отсечения можно не трогать. Чтож, меньше слов, больше дела. Модифицируем наш вершинный шейдер model_distort4ghost_hud таким образом:

#include "common.h"
#include "skin.h"

struct vf
{
  float4 hpos  : POSITION;
  float2 tc0  : TEXCOORD0;    // base
  float4 c0  : COLOR0;    // color
};

vf   _main (v_model v)
{
  vf     o;

  float hud_fov = 0.45;
  float aspect_ratio = m_P[1][1] / m_P[0][0];
  float half_fovy = atan( 1.0 / m_P[1][1] );
  float4x4 m_P_fix = m_P;
  
  m_P_fix[1][1] = 1.0 / tan(half_fovy * hud_fov);
  m_P_fix[0][0] = m_P_fix[1][1] / aspect_ratio;

  float3 view_pos = mul(m_WV, v.pos);

  o.hpos       = mul      (m_P_fix, float4(view_pos, 1));    // xform, input in world coords
  o.tc0      = v.tc.xy;          // copy tc

  // calculate fade
  float3  dir_v     = normalize    (mul(m_WV,v.pos));
  float3  norm_v     = normalize     (mul(m_WV,v.norm));
  float   fade    = 0.9*abs      (dot(dir_v,norm_v));
  o.c0    = fade;

  return o;
}

/////////////////////////////////////////////////////////////////////////
#ifdef   SKIN_NONE
vf  main(v_model v)     { return _main(v);     }
#endif

#ifdef   SKIN_0
vf  main(v_model_skinned_0 v)   { return _main(skinning_0(v)); }
#endif

#ifdef  SKIN_1
vf  main(v_model_skinned_1 v)   { return _main(skinning_1(v)); }
#endif

#ifdef  SKIN_2
vf  main(v_model_skinned_2 v)   { return _main(skinning_2(v)); }
#endif

Тут конструируется матрица m_P_fix с уменьшенным до 45% углом обзора, потом точка из модели (v.pos) трансформируется сначала стандартной матрицей m_WV (комбинацией m_W и m_V), а уже потом исправленной матрицей m_P_fix. Строго говоря значение переменной hud_fov (0.45) должно быть равным значению одноимённой консольной команды hud_fov. В финальной версии игры эта команда заблокирована, а значение константно и никогда не меняется. Впрочем, всякие движковые моды типа FOV switcher могут его менять.

Ну всё, шейдер готов, осталось только указать его в модели. Лезем в геймдату, открываем gamedata\meshes\weapons\bizo1\wpn_bizon_hud1.ogf через СДК, или по старинке через хекс-редактор, меняем все шейдеры models\pautina на models\pauhuda, а потом смотрим на результат:

XR-3-DA-2022-04-18-18-38-42-27.png

А вот так эта модель выглядит с родными текстурами оружия, вместо текстуры воды:

XR-3-DA-2022-04-18-18-45-31-89.png

 

Короче вот готовый пример прозрачного шейдера для худа + модель аномального бизона которая его использует (для Народной Солянки 2010): https://drive.google.com/file/d/1W4R28ON2x8z1u_xlw2ACOdfi-9YEYGra/view?usp=sharing

А задачу создания такого шейдера для R2 рендера я оставляю вам в качестве домашнего задания, гегеге.

  • Лайк 1
  • Мастер! 2
  • Аплодисменты 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
 

Когда-нибудь кому то пригодится 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
 

Обычный шейдер прозрачности это какая то шутка?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
 
31 минуту назад, I am dead сказал:

Обычный шейдер прозрачности это какая то шутка?

С обычным шейдером будет вот такой вытянутый результат.

XR-3-DA-2022-04-18-17-52-23-85.png

Хотя с тем что я предложил тоже есть баг, модель может исчезать в стене если вплотную встать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
 

Осталось понять зачем в Сталкере прозрачное оружие..)))

  • Смех 1

Группа мода в VK
Мод делался и тестировался на железе
i5-11400, 32Гб ОЗУ, Radeon RX580  Разрешение 2560 х 1440.  ВСЕ на максималке

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
 

Policai Дело не в прозрачном оружии (хотя помню как неказисто выглядело "невидимое" оружие призраков в руках ГГ). Когда мы делали ХУД-использование предметов ГГ крайне не хватало нормального шейдера с прозрачностью для бутылки с водкой например.

  • Мастер! 1

Путь во мгле. Связь времен.
"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..." (Чугунный всадник)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
 

 

10 часов назад, Modera сказал:

С обычным шейдером будет вот такой вытянутый результат.

Хмм, как жаль что у меня такого бага нету...


Дополнено 0 минут спустя

d8e667aff8af.png


Дополнено 5 минуты спустя

Наверное я что то делаю не так...
spacer.png

Изменено пользователем I am dead

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
 
14 часов назад, I am dead сказал:

 

Хмм, как жаль что у меня такого бага нету...


Дополнено 0 минут спустя

d8e667aff8af.png


Дополнено 5 минуты спустя

Наверное я что то делаю не так...
spacer.png

Значит в некоторых движках эту бяку исправили. Но в ванильном ТЧ и ЧН точно есть.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
 
7 часов назад, Modera сказал:

Но в ванильном ТЧ и ЧН точно есть.

И в оригинальном ЗП тоже. А уж как и где это исправляли другой вопрос.


Путь во мгле. Связь времен.
"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..." (Чугунный всадник)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Создать учетную запись

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

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

Войти

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

Войти

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

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