HLFX.Ru Forum
профиль •  правила •  регистрация •  календарь •  народ •  FAQ •  поиск •  новое •  сутки •  главная •  выход  
HLFX.Ru Forum HLFX.Ru Forum > Теория и практика > OpenGL > Эффект преломления как в Half-Life2
Рассматриваем реализацию шейдеров на Cg
Страницы (2): [1] 2 »   Предыдущая тема   Следующая тема
Автор
Тема Новая тема    Ответить
 XaeroX
Crystice Softworks

Дата регистрации: Oct 2005
Проживает: Торонто
Сообщений: 34528
Нанёс повреждений: 514 ед.
Возраст: 37

Рейтинг



Награды
 
[1 награда]


Эффект преломления как в Half-Life2

Эффект преломления

Преломление во многих разработках реализуется в вершинной программе на основе вектора нормали к данной вершине. Однако для этого требуется высокополигональная модель, иначе вершин (а значит, и нормалей) будет недостаточно для правильного преломления.
Сейчас повсеместно используются карты нормалей для детализации поверхностей. Недавно я приводил пример, как сделать высокодетализированный эффект хромированной поверхности с их помощью. Теперь рассмотрим эффект преломления.
Вспомните ребристые дверные стекла в Half-Life 2. Искажение мира за ними выглядит очень правдоподобно. Мы сделаем что-то очень похожее.
Для начала нам нужно захватить изображение мира в текстуру. Для этого я сделал один проход, выводящий изображение в квадрат 256 х 256. В принципе, можно было этого не делать и использовать расширение GL_NV_texture_rectangle, при этом нужно было бы изменить матрицу текстуры и заменить функции обращения к текстуре в шейдере.
Итак, мы отрендерили объекты мира в текстуру. Теперь нужно настроить матрицу текстуры для проецирования обычным способом и подключить вершинную и фрагментную программу.
Сама идея преломления заключается в следующем. Мы передаем нормаль к поверхности во фрагментную программу. Далее в ней мы получаем попиксельно нормали из карты нормалей и вычисляем их скалярное произведение. После этого мы просто умножаем координаты проекции на полученное значение. В случае, если обе нормали совпали (dot=1), сцена не искажается, иначе – искажается тем сильнее, чем больше отличие нормалей.
Вершинная программа делает вот что:
1. Вычисляет проекцию вершины.
2. Вычисляет координаты проекции для вершины.
3. Передает нормаль как координаты текстуры юнита 2.
4. Передает координаты текстуры юнита 0 и текущий цвет.

Cg Vertex Shader:
1
struct VertIn
2
{
3
  float4 pos : POSITION;
4
  float3 normal : NORMAL;
5
  float2 tex0 : TEXCOORD0;
6
  float4 color : COLOR;
7
};
8
 
9
struct VertOut
10
{
11
  float4 pos : POSITION;
12
  float2 tex0 : TEXCOORD0;
13
  float4 tex1 : TEXCOORD1;
14
  float3 norm : TEXCOORD2;
15
  float4 color : COLOR;
16
};
17
 
18
VertOut main(VertIn vin)
19
{
20
  VertOut vout;
21
  vout.pos = mul(glstate.matrix.mvp, vin.pos);
22
  vout.tex0 = vin.tex0;
23
  vout.tex1 = mul(glstate.matrix.texture[1], vin.pos);
24
  vout.norm = vin.normal;
25
  vout.color = vin.color;
26
  return vout;
27
}

Переходим к фрагментной программе. Для начала получаем нормаль и приводим ее к диапазону [-1,1], после чего вычисляем координаты преломления, как описано выше. W-компонент не трогаем, он используется для проецирования. Получаем цвета текстуры и проекции и усредняем их, домножив на текущий цвет.
Cg Pixel Shader:
1
struct VertOut
2
{
3
  float4 pos : POSITION;
4
  float2 tex0 : TEXCOORD0;
5
  float4 tex1 : TEXCOORD1;
6
  float3 norm : TEXCOORD2;
7
  float4 color : COLOR;
8
};
9
 
10
struct FragOut
11
{
12
  float4 col : COLOR;
13
};
14
 
15
FragOut main(VertOut fin,
16
uniform sampler2D diffuseMap :TEXUNIT0,
17
uniform sampler2D screenMap :TEXUNIT1,
18
uniform sampler2D normalMap :TEXUNIT2)
19
{
20
  FragOut fout;
21
 
22
  //get diffuse texture color
23
  float4 diffuse = tex2D(diffuseMap, fin.tex0);
24
 
25
  //get normal and expand it from [0,1] to [-1,1]
26
  float3 normal = tex2D(normalMap, fin.tex0).xyz;
27
  normal = normal*2 - 1;
28
 
29
  //compute refraction texcoords using difference btw normals, and lookup screen texture
30
  float4 refraction;
31
  refraction.xyz = fin.tex1.xyz * dot(normal, fin.norm);
32
  refraction.w = fin.tex1.w;
33
  float4 screen = tex2Dproj(screenMap, refraction);
34
 
35
  fout.col = fin.color * (diffuse + screen) * 0.5;
36
  return fout;
37
}

В примере слева вы увидите проекцию без преломления (это именно проекция, а не полупрозрачная поверхность!). Справа – шейдерное преломление. Кликайте мышью для смены карты нормалей. Жду ваших отзывов
P.S.: заранее отвечаю на вопрос, почему нет полных исходников. Я выложил код шейдеров, а это и есть само ноу-хау. Остается только их присоединить к проекту – это дело техники. Кроме того, этот эффект используется в Half-Life FX, а потому полные исходники не могут быть открыты до его релиза.

Для работы примера требуется поддержка вершинных и пиксельных шейдеров 2.0

Вложение: refract.zip (330.4 кб)
Этот файл был скачан 1160 раз.
XaeroX проверил это вложение на вирусы 03-11-2005 в 18:29

__________________

Сообщить модератору | | IP: Записан
Сообщение: 118

Старое сообщение 22-10-2005 08:37
-
 XaeroX
Crystice Softworks

Дата регистрации: Oct 2005
Проживает: Торонто
Сообщений: 34528
Нанёс повреждений: 514 ед.
Возраст: 37

Рейтинг



Награды
 
[1 награда]


Что-то народ неактивно комментирует
Для тех, у кого вторые шейдеры не поддерживаются, вот пара скринов. Конечно, видеть это надо в динамике, но все же...


__________________

Сообщить модератору | | IP: Записан
Сообщение: 138

Старое сообщение 23-10-2005 09:12
-
 Дядя Миша
racing for fish

Дата регистрации: Oct 2005
Проживает: Кубань
Сообщений: 32213
Нанёс повреждений: 392 ед.

Рейтинг



XaeroX
Насколько я понимаю - рассчет преломления делается на основе самой текстурки и напрямую от нее зависит.
В хл2 рифленые стекла были вертикальными
Хорошая штука

Сообщить модератору | | IP: Записан
Сообщение: 154

Старое сообщение 24-10-2005 06:43
-
 XaeroX
Crystice Softworks

Дата регистрации: Oct 2005
Проживает: Торонто
Сообщений: 34528
Нанёс повреждений: 514 ед.
Возраст: 37

Рейтинг



Награды
 
[1 награда]


g-cont нарисуй "вертикальную" нормалмапу, в смысле полосы на ней вертикальные, и будет тебе щастье ;Р

__________________

Сообщить модератору | | IP: Записан
Сообщение: 158

Старое сообщение 24-10-2005 07:04
-
Security
Flamberg user

Дата регистрации: Oct 2005
Проживает: spb
Сообщений: 467
Возраст: 34

Рейтинг



Xaerox

Это для первой халвы???!!!

Сообщить модератору | | IP: Записан
Сообщение: 191

Старое сообщение 24-10-2005 14:39
- За что?
 Дядя Миша
racing for fish

Дата регистрации: Oct 2005
Проживает: Кубань
Сообщений: 32213
Нанёс повреждений: 392 ед.

Рейтинг



XaeroX да я понимаю
Security да для первой.

Сообщить модератору | | IP: Записан
Сообщение: 198

Старое сообщение 24-10-2005 16:10
-
BUzer
Pills here!

Группа: Опытный
Дата регистрации: Oct 2005
Проживает: Владивосток
Сообщений: 349
Возраст: 40

Рейтинг



Классно, только текстурку-бы получше подобрать..

Тутор, наверное, писался для таких дубов в этом деле, как я? Можно уж было тогда по-понятнее.. Вот, например, фраза
"1. Вычисляет проекцию вершины.
2. Вычисляет координаты проекции для вершины."
очень жуткая Я так понял, под первым подразумевается умножение на видовую матрицу, а под вторым - нахождение спроецированных текстурных координат для "экранной" текстуры?

Также не помешали-бы комментарии к переменным при описании структур - типа что в них будет храниться... По-русски

И наконец, вечно мучивший меня вопрос - а что, из пиксельного шейдера нельзя узнать цвет пикселя в цветовом буфере экрана? Если да, то это просто кидалово какое-то. А как тогда делать прозрачный полигон? (я так понимаю, в твоем примере он не прозрачен)

Сообщить модератору | | IP: Записан
Сообщение: 214

Старое сообщение 25-10-2005 02:09
- За что?
 XaeroX
Crystice Softworks

Дата регистрации: Oct 2005
Проживает: Торонто
Сообщений: 34528
Нанёс повреждений: 514 ед.
Возраст: 37

Рейтинг



Награды
 
[1 награда]


BUzer
1. да, ты понял совершенно верно
2. гм... не люблю русские комментарии.
3. нельзя. зато прозначность можно задать умножением на fin.color.w - это и есть альфа фрагмента.

__________________

Сообщить модератору | | IP: Записан
Сообщение: 218

Старое сообщение 25-10-2005 07:10
-
BUzer
Pills here!

Группа: Опытный
Дата регистрации: Oct 2005
Проживает: Владивосток
Сообщений: 349
Возраст: 40

Рейтинг



XaeroX
3. Не понял, умножением чего?.. Вот я хочу вывести полупрозрачный полигон с пикс шейдером. Мне надо будет испольховать glEnable(GL_BLEND), glBlendFunc..? И куда шейдер будет выдавать альфу?

Сообщить модератору | | IP: Записан
Сообщение: 233

Старое сообщение 25-10-2005 10:16
- За что?
 XaeroX
Crystice Softworks

Дата регистрации: Oct 2005
Проживает: Торонто
Сообщений: 34528
Нанёс повреждений: 514 ед.
Возраст: 37

Рейтинг



Награды
 
[1 награда]


Цитата:
Автор XaeroX
fin.color.w - это и есть альфа фрагмента

Это в терминологии Cg. То есть это альфа входная (задаваемая через glColor4f). Альфу текстуры нужно учитывать самому. А обычная прозрачность будет выводиться так:
Cg Pixel Shader:
fout.col.w = fin.col.w;

С учетом альфа-канала текстуры:
Cg Pixel Shader:
float4 diffuse = tex2D(diffuseMap, fin.tex0);
// any code here...
fout.col.w = fin.col.w * diffuse.w;

__________________

Сообщить модератору | | IP: Записан
Сообщение: 234

Старое сообщение 25-10-2005 10:20
-
BUzer
Pills here!

Группа: Опытный
Дата регистрации: Oct 2005
Проживает: Владивосток
Сообщений: 349
Возраст: 40

Рейтинг



А контролировать процесс смешивания расчитанного в шейдере цвета с цветом на экране можно только через glBlendFunc, получается?..

Сообщить модератору | | IP: Записан
Сообщение: 235

Старое сообщение 25-10-2005 11:17
- За что?
 XaeroX
Crystice Softworks

Дата регистрации: Oct 2005
Проживает: Торонто
Сообщений: 34528
Нанёс повреждений: 514 ед.
Возраст: 37

Рейтинг



Награды
 
[1 награда]


glBlendFunc, как я понимаю, учитывается частично - для цвета имеющегося фрагмента. А цвет фрагмента наложения рассчитывается целиком в шейдере.

__________________

Сообщить модератору | | IP: Записан
Сообщение: 247

Старое сообщение 25-10-2005 17:02
-
FiEctro
Кот Арсис

Дата регистрации: Aug 2006
Проживает: код
Сообщений: 12901
Возраст: 32

Рейтинг



Знаю что тема устарела ... Но у меня ламерский вопрос : Реализовывать в хл это все точно также как и func_mirror ? И как сделать что бы вместо нормалей читалась обычная WAD текстура с началом к примеру ( * ) ?

__________________
У котёнка мокрый нос и гладенькая шерсть, у него забавный хвост и быстрых лапок шесть. Две задних, две средних и две передних лапы, такая многоножка получилася у папы.
Он ученый — папа мой — зверушек изучает, гуляет по помойкам, ловит крыс и чаек. Две крысы белокрылые и чайки две унылые покрытые пупырчатою кожей лягушат без пёрышек тоскуют и ускакать спешат.
А ещё есть муравей большой размером с гуся он пугает всех зверей, и я его боюся, когда он ковыляет на лапках на своих.
И в двери ударяет, и начинает стих: Я — муравей, воды налей! Не меньше ведра, напиться мне пора!

Сообщить модератору | | IP: Записан
Сообщение: 18038

Старое сообщение 25-08-2007 13:51
- За что?
 XaeroX
Crystice Softworks

Дата регистрации: Oct 2005
Проживает: Торонто
Сообщений: 34528
Нанёс повреждений: 514 ед.
Возраст: 37

Рейтинг



Награды
 
[1 награда]


-CJ- как найти текстуру в ваднике по имени - есть в коде ксаша (там просматривается texinfo). Ну и потом биндишь ее, что-то типа glBindTexture(GL_TEXTURE_2D, msurface->texinfo->texture->gl_index);

__________________

Сообщить модератору | | IP: Записан
Сообщение: 18046

Старое сообщение 25-08-2007 17:05
-
FiEctro
Кот Арсис

Дата регистрации: Aug 2006
Проживает: код
Сообщений: 12901
Возраст: 32

Рейтинг



XaeroX спасибо ! Но в ксаше ( water.cpp ) я неособо разобрался какой код отвечает за наложение эфекта преломления и отражения на текстуру ( % )
И еще я не особо понял смысл закоментированого в ( water.cpp ) кода и коментов

code:
/* // This code should do the same on Gf4Ti (nv_texture_shader, nv_texture_shader2, nv_texture_shader3) // BUT IT DOESN'T!!!! // // NB: if you wanna test it, do the following in gl_mirrors.cpp // - operate the texture matrix for texture1 // - swap texcoords for units 0 and 1 void CreateWaterShader_ARB(void) { logPrint("Generating noise texture\n"); CreateNoiseTextureDsDt(1); logPrint("Completed\n"); } ....

__________________
У котёнка мокрый нос и гладенькая шерсть, у него забавный хвост и быстрых лапок шесть. Две задних, две средних и две передних лапы, такая многоножка получилася у папы.
Он ученый — папа мой — зверушек изучает, гуляет по помойкам, ловит крыс и чаек. Две крысы белокрылые и чайки две унылые покрытые пупырчатою кожей лягушат без пёрышек тоскуют и ускакать спешат.
А ещё есть муравей большой размером с гуся он пугает всех зверей, и я его боюся, когда он ковыляет на лапках на своих.
И в двери ударяет, и начинает стих: Я — муравей, воды налей! Не меньше ведра, напиться мне пора!

Сообщить модератору | | IP: Записан
Сообщение: 18059

Старое сообщение 26-08-2007 11:49
- За что?
Тема: (Опционально)
Ваш ответ:



Переводчик транслита


[проверить длину сообщения]
Опции: Автоматическое формирование ссылок: автоматически добавлять [url] и [/url] вокруг интернет адресов.
Уведомление по E-Mail: отправить вам уведомление, если кто-то ответил в тему (только для зарегистрированных пользователей).
Отключить смайлики в сообщении: не преобразовывать текстовые смайлики в картинки.
Показать подпись: добавить вашу подпись в конец сообщения (только зарегистрированные пользователи могут иметь подписи).

Временная зона GMT. Текущее время 23:58. Новая тема    Ответить
Страницы (2): [1] 2 »   Предыдущая тема   Следующая тема
HLFX.Ru Forum HLFX.Ru Forum > Теория и практика > OpenGL > Эффект преломления как в Half-Life2
Рассматриваем реализацию шейдеров на Cg
Версия для печати | Отправить тему по E-Mail | Подписаться на эту тему

Быстрый переход:
Оцените эту тему:

Правила Форума:
Вы not можете создавать новые темы
Вы not можете отвечать в темы
Вы not можете прикреплять вложения
Вы not можете редактировать ваши сообщения
HTML Код ВЫКЛ
vB Код ВКЛ
Смайлики ВКЛ
[IMG] Код ВКЛ
 

< Обратная связь - HLFX.ru >

На основе vBulletin
Авторское право © 2000 - 2002, Jelsoft Enterprises Limited.
Дизайн и программирование: Crystice Softworks © 2005 - 2024