Привет всем!
Работаю на шейдером, который использует буффер глубины, Unity 5.6.0f.
Вот часть кода:
float depth; #if UNITY_REVERSED_Z// DirectX float a = depthMain;// 1- float b = depthBall; if(a > b){ b1 = true; depth = b; }else{ b1 = false; //depth = 1-depthBall; } #else// OpebGL //bool b1 = depthMain > depthBall;// My mac if( depthMain > depthBall){ b1 = true; depth = depthBall; }else{ b1 = false; //depth = depthMain; } #endif
По идее UNITY_REVERSED_Z (на сколько я понял) true, когда буффер глубины инвертирован.
Так вот, код представленный выше был запущен на компах с directx и OpenGL.
Причем #if UNITY_REVERSED_Z вызывается для directx, a #else для OpenGL.
Я пришел к тому, что UNITY_REVERSED_Z вызывается при неинвертированном буффере для directx. Почему?
И еще что:
float u = i.uv.x; float v = i.uv.y; #if defined(UNITY_UV_STARTS_AT_TOP) //&& !defined(SHADER_API_MOBILE) v = 1.0 - v; #endif
Alerr
> #if UNITY_REVERSED_Z// DirectX
Я не уверен что в шейдере эта строчка будет выполняться правильно, тут проверка true/false, а не define, а должно быть:
#if defined(UNITY_REVERSED_Z)
А откуда ты значение глубины берешь?
Если из _CameraDepthTexture то там достаточно:
float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, screen));
Alerr
> #if defined(UNITY_UV_STARTS_AT_TOP) //&& !defined(SHADER_API_MOBILE)
А вот тут как раз наоборот надо использовать так:
#if !UNITY_UV_STARTS_AT_TOP
Alerr
> Причем #if UNITY_REVERSED_Z вызывается для directx, a #else для OpenGL.
На OpenGL инвертировать буфер глубины не так тривиально. Из-за клип спейса [-1;1] в OpenGL инвертирование буфера не дает никакого профита. Для этого есть всякие костыли, которые от версии к версии меняются. Так по честному проблему можно решить только в OpenGL 4.1 версии через glDepthRangef. На более ранних версиях приходится юзать glDepthRangedNV, но только для NVidia, либо заводить клипплейны, и тягать их аж через все шейдеры.
Поэтому подозреваю, что в Юнити эту проблему просто не стали решать, а забили, и считают, что если у тебя OpenGL, то буфер глубины не инвертирован.
Alerr
> Вот этот код запускался на directx и инвертирует картинку неверно. Почему???
Потому что на DirectX не надо картинку инвертировать. Он изначально рисует в текстуру адекватно в левый верхний угол и не перевернуто, в отличие от OpenGL
MrShoor
> Поэтому подозреваю, что в Юнити эту проблему просто не стали решать, а забили,
> и считают, что если у тебя OpenGL, то буфер глубины не инвертирован.
В юнити для этого есть специально _ZBufferParams в шейдере и функция:
// Z buffer to linear 0..1 depth inline float Linear01Depth( float z ) { return 1.0 / (_ZBufferParams.x * z + _ZBufferParams.y); } // Z buffer to linear depth inline float LinearEyeDepth( float z ) { return 1.0 / (_ZBufferParams.z * z + _ZBufferParams.w); }
Alerr
Я делал эффект тумана, без глубины это просто вот такая плоскость
foxes
> В юнити для этого есть специально _ZBufferParams в шейдере и функция:
Только это ломает early depth test. И линейная глубина не то же самое что обратная, хотя в пиксельном можно и обратную глубину сделать.
foxes
Красивый туман. Вершинную функцию я описал так(vert_img):
SubShader { Pass { ZTest Always Cull Off ZWrite Off Fog { Mode off } CGPROGRAM #pragma vertex vert_img//<<<<<<< #pragma fragment frag //#pragma target 3.0 ENDCG } }
Написал в шейдере так:
#if !UNITY_UV_STARTS_AT_TOP v = 1.0 - v; #endif
И вот это работает без инферсий буффера глубины:
float depthMain = Linear01Depth(UNITY_SAMPLE_DEPTH( tex2D( _MainDepth, i.uv))); //tex2D(_MainDepth, i.uv); float depthBall = Linear01Depth( UNITY_SAMPLE_DEPTH( tex2D( _CameraDepthTexture, i.uv)));
Посмотрел вершинную функцию:
v2f_img vert_img(appdata_img v ) { v2f_img o; o.pos = UnityObjectToClipPos ( v.vertex); o.uv = v.texcoord; return o; }
Alerr
> #if !UNITY_UV_STARTS_AT_TOP
> v = 1.0 - v;
> #endif
> и на OpenGl фрагментный шейдер стал выдавать невернеые результаты.
Мне так кажется что тебе в принципе можно спокойно эти строчки убрать.
- Make UNITY_SAMPLE_DEPTH deal automatically with reversed z-buffer.
Alerr
> o.uv = v.texcoord;
Вот эта часть, если используется для координат буфера глубины то считается так:
float4 screen = ComputeScreenPos(o.pos); o.uv = screen.xy / screen.w;
o.screen = ComputeScreenPos(o.pos); ... float depthBall = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, UNITY_PROJ_COORD(i.screen))));
Спасибо
Тема в архиве.