ПрограммированиеФорумГрафика

GODOT->UNITY: помогите разобраться с буффером глубины.

Страницы: 1 2 Следующая »
#0
11:04, 10 сен 2023

Привет всем!
Есть годот-шейдер, который работает с текстурой буффера глубины.
Пытаюсь повторить шейдер в юнити, не получается.
В обоих проектах задал одинаковые Near & Far clip planes, FOV.

Насколько понимаю, _CameraDepthTexture содержит нелинейное значение буффера глубины. Оно находится в диапазоне от [0,1], но оно нелиейно.
То есть 0.5 не соответствует половине расстояния между Far & Near clip plane.

float notLinDepth = tex2D(_CameraDepthTexture, SCREEN_UV).r;

LinearEyeDepth and Linear01Depth - эти методы позволяю линеаризовать значение.
LinearEyeDepth  - это дает линейный WorldScaled Depth
Linear01Depth  - это делает из нелинейного depth линейное.

В шейдере годота глубина вычисляется так:

float depth = textureLod(depth_tex, SCREEN_UV, 0.0).r;
depth = pow(depth, 30.);
ALBEDO.xyz = vec3(depth,depth,depth);

На экране затемненный CUBE_G

Аналогичная операция в Юнити дает другой результат

float depth = tex2D(_CameraDepthTexture, SCREEN_UV).r;
depth = pow(depth, 30.);
return float4(depth, depth, depth, 1.)

Сравнение:
24 | GODOT->UNITY: помогите разобраться с буффером глубины.

Нашел в сети такую операцию: return zNear * zFar / (zFar + depth * (zNear - zFar));
Не понимаю что она делает, но она вроде как в связана с мировым пространством и я выразил из нее depth и переписа так:

float linear_depth_to_notlinear (float srcDepth) {
return (_ProjectionParams.y * _ProjectionParams.z / srcDepth - _ProjectionParams.z)
/ (_ProjectionParams.y - _ProjectionParams.z);
}

Далее сделал так:

float depth = LinearEyeDepth( tex2D(_CameraDepthTexture, SCREEN_UV).r );
depth = linear_depth_to_notlinear(depth);
depth = pow(depth, 30.);
return float4(depth, depth, depth, 1.);

Результат:
gu | GODOT->UNITY: помогите разобраться с буффером глубины.

Теперь результат ближе к тому, что в Годоте, но все равно видно что не тот.

Ребят, кто видит в чем проблема? Все перепробовал, не могу понять почему в годоте глубина выглядит иначе.

#1
11:33, 10 сен 2023

Нормально. В Юнити слегка темнее, чем в годоте, а так одно и тоже.
Можно в юнити подобрать число в место 30
depth = pow(depth, 34.); или 28

Или depth = pow(depth, 30.)*1.25;

#2
12:02, 10 сен 2023

ronniko
> В Юнити слегка темнее, чем в годоте, а так одно и тоже.
А почему оно темнее-то? Колор спейс тот же.
Похоже я где-то не так считаю потому, что далее отклонения становятся значительнее.

Например далее в годоте идет:

vec4 upos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, depth, 1.0);
ALBEDO.xyz = upos.xyz;


Перенес в юнити:
Inverse:

+ Показать
float4x4 INV_PROJECTION_MATRIX = Inverse(UNITY_MATRIX_P);
float4 upos = mul(INV_PROJECTION_MATRIX, float4( SCREEN_UV * 2.0 - 1.0, depth, 1.0) );
return upos;


Видно, что вразнос все пошло:
24 | GODOT->UNITY: помогите разобраться с буффером глубины.

А если вывести:

float3 pixel_position = upos.xyz / upos.w;
return float4(pixel_position, 1);

То вот разница:
24 | GODOT->UNITY: помогите разобраться с буффером глубины.

#3
15:03, 10 сен 2023

Может кто-то знает что здесь вычисляется:

vec4 upos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, depth, 1.0);
vec3 pixel_position = upos.xyz / upos.w;

Насколько понимаю, SCREEN_UV переводится из [0,1] => [-1,1]. То есть это Projection Space, и 1.0 - означает, что вектор рассматривается как позиция.
Далее, насколько понимаю, из пространства проекции происходит отображение в пространство ViewSpace (то есть пространство камеры).

И судя по тому что в годоте и в юнити в pixel_position содержатся разные значения, это говорит о том, что проблема в depth.
Есть какие-то идеи? Я уже все высосал из пальца, не понимаю почему значения в юнити и в годоте получаются разные.

#4
17:10, 10 сен 2023

А не линейную глубину пробовал сравнить от Godot c Unity? Возьми пиксель например где нибудь в середине текстуры который отображает глубину для куба и посмотри значение, мб изначально глубина не линейная в годоте записывается как-то иначе от Unity?

#5
17:14, 10 сен 2023

Ещё попробуй все-таки принудительно сам полученный результат в твоем втором скрине глубины от юнити перевести в гамму:

+ Показать
#6
18:03, 10 сен 2023

А ты уверен, что матрица проектирования одна и та же в обоих случаях? Может разные плоскости отсечения задаются, отсюда и разный оттенок карты глубины..

#7
18:15, 10 сен 2023

Target
> Ещё попробуй все-таки принудительно сам полученный результат в твоем втором скрине глубины от юнити перевести в гамму:
Спасибо!
Попробовал и, кажется, помогло!

AMM1AK
> А ты уверен, что матрица проектирования одна и та же в обоих случаях?
не уверен, сейчас пробуюс дальше, смотрю...

Update 1:
Да... В общем годот завешивает мне весь комп так, что его от кнопки приходится отключать.
Сейчас заметил, что у меня проект в юнити сбился(камера настроена как попало, еще гамма спейс...) Дурдом...

Update 2:
AMM1AK
> А ты уверен, что матрица проектирования одна и та же в обоих случаях?
Похоже, что эта матрица нужна: unity_CameraInvProjection

#8
18:40, 10 сен 2023

Target
Не пойму, после вызова FloatLinearToGamma(depth); значение глубины становится как в годоте, но это же только для виуализации?
Глупый вопрос, но почему в юнити нужно просчитывать гамму?

До этого момента код вроде удалось перенести (есть небольшие различия вроде как, но вроде одинаковые картинки):

fixed4 frag(v2f i) : SV_Target{
                i.VIEW = normalize(i.VIEW);
                // return float4(i.VIEW, 1);

                float2 SCREEN_UV = i.screenPos.xy / i.screenPos.w;//+
                // 0 - close
                // 1 - far
                float depth = LinearEyeDepth( tex2D(_CameraDepthTexture, SCREEN_UV).r );//Linear01Depth LinearEyeDepth
                depth = linear_depth_to_notlinear(depth);
                // FloatLinearToGamma(depth);
                // depth = pow(depth, 30.); return float4(depth, depth, depth, 1.);//<<<<<<<<<

                //<< INV_PROJECTION_MATRIX  <=>   unity_CameraInvProjection --- ?
                // Clip space => Obj space
                float4x4 INV_PROJECTION_MATRIX = unity_CameraInvProjection;// Inverse(UNITY_MATRIX_P);
                float4 upos = mul(INV_PROJECTION_MATRIX, float4( SCREEN_UV * 2.0 - 1.0, depth, 1.0) );
                //FloatLinearToGamma(upos.x);
                return float4(upos.xyz / upos.w, 1);

    ...
}

Код годота:

+ Показать

На выходе так:
gg | GODOT->UNITY: помогите разобраться с буффером глубины.

Но теперь в годоте:

vec4 wpos = INV_VIEW_MATRIX * (upos / upos.w);

В юнити прописал так:

float4 wpos = mul(UNITY_MATRIX_I_V, (upos / upos.w));

Сравнение:
gg | GODOT->UNITY: помогите разобраться с буффером глубины.

Выхдит, что UNITY_MATRIX_I_V не та матрица?

#9
18:44, 10 сен 2023

UNITY_MATRIX_I_V

Типа матрица номер 4
Пробуй остальные 9 матриц :)

Я знал, что Юнити ненормальные писали, но не думал что прям такие психи.

#10
19:23, 10 сен 2023

ronniko
Ну емое, говорящей название на деле не совсем то. Почитал про матрицу, она на что-то там ещё домножена...

#11
20:28, 10 сен 2023

ronniko
> Пробуй остальные 9 матриц :)
Где они есть? Яздесь нашел только эти:
юнидок
и тут:
юнигит

Попробовал так получить матрицу I_V:

float4x4 INV_VIEW_MATRIX = mul(UNITY_MATRIX_I_V, Inverse(unity_ObjectToWorld))

Как-то криво работает, информацию нашел в сети (не факт что она верная):
> built-in matrix provided by Unity's shader system, and it specifically represents the inverse of the view matrix
> multiplied by the inverse of the unity_ObjectToWorld matrix. In other words, it combines both the view and
> world space transformations.

#12
20:49, 10 сен 2023

Unity использует соглашения о матрицах представлений OpenGL и они переверорачивают выходное z-значение m.SetRow(2, -m.GetRow(2)); Как там в годоте - я хз. Возможно в этом дело и тебе нужно просто учесть в шейдере этот момент. Не уверен но попробуй, а так можешь сам составить IV матрицу. Более того, важно учесть различие матриц в годоте и Unity, row ordered или column ordered может быть и потому умножение нужно делать не матрицы не вектор а вектора на матрицу (либо в коде перед передачей матрицы в шейдер делай транспонирование матрицы) Т.е. вместо

float4 wpos = mul(UNITY_MATRIX_I_V, (upos / upos.w));

делаешь так

float4 wpos = mul((upos / upos.w), UNITY_MATRIX_I_V);

Если бред выходит - сам попробуй построить матрицу:

Matrix4x4 p = GL.GetGPUProjectionMatrix(camera.projectionMatrix, true);
Matrix4x4 v = camera.worldToCameraMatrix;
Matrix4x4 vp = p * v;
Matrix4x4 vpi = vp.inverse;
... тут уже передаешь в свой шейдер полученную матрицу, только в шейдере уже умножай матрицу на вектор

В целом менять местами умножение матриц не нужно, т.к. ты все равно пробуешь юзать стандартные матрицы от юнити и порядок там верный

#13
21:13, 10 сен 2023

Alerr
> Не пойму, после вызова FloatLinearToGamma(depth); значение глубины становится
> как в годоте, но это же только для виуализации?
Хз почему, но от значения глубины, что ты перевел в гамму, будут зависеть другие полученные результаты вычислений. Я делал перенос не одного шейдера и юзаю этот метод, без него результаты совсем не те что ожидаешь выходят. Почему так происходит я так и не разобрался (не хотел разбираться)

P.S. инвертирование матрицы тяжелая операция если что, я бы не стал её юзать в шейдере пофрагментно

#14
21:57, 10 сен 2023

Target
Пробовал и строки и столбцы UNITY_MATRIX_I_V на -1 умножать - это не помогло.

Это тоже не помогло:

float4x4 INV_VIEW_MATRIX = Inverse (UNITY_MATRIX_V);
float4 wpos = mul(INV_VIEW_MATRIX, (upos / upos.w));

Вроде как это ViewSpace матрица:

var invViewMatrix = cam.transform.worldToLocalMatrix;
        
        if (SystemInfo.usesReversedZBuffer)
        {
            invViewMatrix.m20 = -invViewMatrix.m20;
            invViewMatrix.m21 = -invViewMatrix.m21;
            invViewMatrix.m22 = -invViewMatrix.m22;
            invViewMatrix.m23 = -invViewMatrix.m23;
        }// */

        Shader.SetGlobalMatrix("_IV", invViewMatrix.inverse);

Target, вы наверно точно знаете когда правильно инвертировать ряд (до или после инвертации). Я верно инвертировал до?

Этот код создает верную матрицу, но...  Знатоки Unity, встроенная инверсная вью матрица существует или нужно самому кидать ее в шейдер?

> P.S. инвертирование матрицы тяжелая операция если что, я бы не стал её юзать в шейдере пофрагментно
Да, спасибо, знаю. Просто сам все хочу руками просчитать чтобы перед глазами было. потом буду оптимизирвать.

Страницы: 1 2 Следующая »
ПрограммированиеФорумГрафика

Тема в архиве.