Оффсет+рейкаст

Шейдеры и все-все-все.

Оффсет+рейкаст

Сообщение Norman 28 авг 2017, 18:48

Товарищи, такая ситуация. Находимся внутри сферы (сфера, соответственно, текстурирована изнутри). Камера стоит в центре и свободно крутится на 360 градусов по любой оси, испуская рэйкасты. Т.е. может бросить луч в любую точку сферы.
Что нужно - деформировать поверхность (промять) в точке рейкаста. Проминается шейдером, чёрная текстура с белым пятном посередине - где белое пятно там и проминается, соответственно.
Что хочу понять - как реализовать такое, чтобы маска смещалась оффсетом так, чтобы белое пятно в её центре всегда оказывалось в точке рэйкаста и, соответственно, проминала в этой точке сферу.

Вот кусок шэйдера ответственный за проминание:

void vertexDataFunc( inout appdata_full v, out Input o )
{
UNITY_INITIALIZE_OUTPUT( Input, o );
float4 uv_Spot = float4(v.texcoord * _Spot_ST.xy + _Spot_ST.zw, 0 ,0);
v.vertex.xyz += ( tex2Dlod( _Spot, uv_Spot ) * _Bulge ).xyz;
}

_Spot - это текстура с белым пятном
_Bulge - переменная, определяющая силу и направление проминания

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

Есть у кого идеи?
Norman
UNIт
 
Сообщения: 90
Зарегистрирован: 31 мар 2017, 18:38

Re: Оффсет+рейкаст

Сообщение jetyb 30 авг 2017, 08:16

Ничего сложного, аналитическая 3D геометрия и немного программирования.

Пусть есть вектор луча рэйкаста OR1 , дополним его до ортонормированного репера (OR1; OR2; OR3).
В фрагментном шейдере мы можем получить мировые координаты точки в базовом репере (Ox; Oy; Oz).
Зная их, получаем координаты точки (Xr; Yr; Zr) в репере (OR1; OR2; OR3).
По этим координатам идем в текстуру продавливания _ProdTex:
можно перевести координаты (Xr; Yr; Zr) в полярные (Phi_r; Psi_r) и по этой паре обращаться к текстуре :
float prod = tex2D(_ProdTex, float2(Phi_r, Psi_r)).r,
можно сделать текстуру продавливания кубмэпой и ничего не переводить
float prod = texCUBE(_ProdTex, float3(Xr, Yr, Zr)).r
используя кубмэпу, у вас не будет полярных искажений.

На этом в общем геометрия закончилась. Вы можете либо определять продавливание в вершинном шейдере и затем в зависимости от степени смещения сдвигать вершины.
(в вершинном шейдере придется пользоваться функциями tex2Dlod , texCUBElod , ниже я написал пример доступа к текстуре из вершинного шейдера для обычной и CubeMap текстуры)
Синтаксис:
Используется csharp
float prod1, prod2;
#if !defined(SHADER_API_OPENGL)                            
        prod1  = tex2Dlod (_ProdText, float4(Phi_r; Psi_r,0,0)).r;
        prod2  = texCUBElod(_ProdText, float4(Xr, Yr, Zr,0)).r;
 #endif
 


Либо в фрагментном шейдере, но тогда можно только вырезать "продавливаемые пиксели" через команду clip или discard.
jetyb
Адепт
 
Сообщения: 1376
Зарегистрирован: 31 окт 2011, 17:21

Re: Оффсет+рейкаст

Сообщение Norman 31 авг 2017, 15:51

Спасибо!
Norman
UNIт
 
Сообщения: 90
Зарегистрирован: 31 мар 2017, 18:38


Вернуться в Shader Lab

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3