Depth и graphics.Blit

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

Depth и graphics.Blit

Сообщение kripto289 04 май 2016, 12:15

День добрый.
Делаю шейдер с буфером через graphics.Blit.
У стандартного шейдера (допустим particles/blended) буфер глубины считается как матрица MVP * vertex.
Попробовал просчитать матрицу в c# и передавать в шейдер. Всё корректно отрисовывается. То есть UNITY_MATRIX_MVP я передаю из скрипта.
Теперь проблема. Блит работает с квадом 0-1 растянутым на весь экран. (а не с мешем который может быть где-то в пространстве). Поэтому встроенный UNITY_MATRIX_MVP и буфер глубины работают только если меш с проецируемой текстурой находятся ровно на весь экран. Сместив меш, буфер глубины всё равно считается для экрана, а не для меша.
Подумал что можно вручную передать UNITY_MATRIX_MVP из скрипта, но считать матрицу не для экранного квада, а для меша, на котором я рисую текстуру. И это тоже не работает.
Юзаю такой расчёт MVP матрицы. Скрипт приаттачен на меш
Синтаксис:
Используется csharp
bool d3d = SystemInfo.graphicsDeviceVersion.IndexOf("Direct3D") > -1;
Matrix4x4 M = transform.localToWorldMatrix;
Matrix4x4 V = camera.worldToCameraMatrix;
Matrix4x4 P = camera.projectionMatrix;
if (d3d) {
    // Invert Y for rendering to a render texture
    for (int i = 0; i < 4; i++) {
        p[1,i] = -p[1,i];
    }
    // Scale and bias from OpenGL -> D3D depth range
    for (int i = 0; i < 4; i++) {
        p[2,i] = p[2,i]*0.5f + p[3,i]*0.5f;
    }
}
Matrix4x4 MVP = P*V*M;

В чём может быть проблема? Как в блит расчитать буфер глубины не в экранных позициях?
Аватара пользователя
kripto289
UNIверсал
 
Сообщения: 476
Зарегистрирован: 30 сен 2013, 03:30
Откуда: Екатеринбург
  • Сайт

Re: Depth и graphics.Blit

Сообщение jetyb 05 май 2016, 08:11

ничё не понял
косяков с проекционной матрицей не замечал, на всякий случай:
http://www.songho.ca/opengl/gl_projectionmatrix.html
jetyb
Адепт
 
Сообщения: 1486
Зарегистрирован: 31 окт 2011, 17:21

Re: Depth и graphics.Blit

Сообщение kripto289 05 май 2016, 10:39

jetyb писал(а):ничё не понял
косяков с проекционной матрицей не замечал, на всякий случай:
http://www.songho.ca/opengl/gl_projectionmatrix.html

Попробуйте заюзать depth buffer и шейдере который передаётся в graphics.Blit (source, dist, shader)
Буфер будет рассчитываться для всего экрана, а не для плоскости.
Полагаю в саму текстуру буфера глубины "DepthTexture" приходят расчёты для всего экрана и на этой стадии уже ничего не изменить. Но не уверен.
Аватара пользователя
kripto289
UNIверсал
 
Сообщения: 476
Зарегистрирован: 30 сен 2013, 03:30
Откуда: Екатеринбург
  • Сайт

Re: Depth и graphics.Blit

Сообщение jetyb 05 май 2016, 11:01

Опять не понял.
Depth Buffer задается один для всей рендер текстуры. Если рисуется фигура, то вычисления/запись в Depth Buffer будут вестись в пределах проекции этой фигуры на экран.

Graphics.Blit просто рисует квадрат с материалом, квадрат такой чтобы в проекции он растянулся на экран. Таким образом создается иллюзия, что обрабатывается каждый пиксель экрана, а не каждый пиксель натянутой на экран фигуры.
Можно рисовать свои фигуры размерами не на экран:
Или через Graphics.DrawMeshNow
Или через класс GL (см пример в PostEffectBase.cs)
Синтаксис:
Используется csharp
protected void DrawBorder (RenderTexture dest, Material material)
                {
            float x1;
            float x2;
            float y1;
            float y2;

            RenderTexture.active = dest;
            bool  invertY = true; // source.texelSize.y < 0.0ff;
            // Set up the simple Matrix
            GL.PushMatrix();
            GL.LoadOrtho();

            for (int i = 0; i < material.passCount; i++)
            {
                material.SetPass(i);

                float y1_; float y2_;
                if (invertY)
                {
                    y1_ = 1.0f; y2_ = 0.0f;
                }
                else
                {
                    y1_ = 0.0f; y2_ = 1.0f;
                }

                // left
                x1 = 0.0f;
                x2 = 0.0f + 1.0f/(dest.width*1.0f);
                y1 = 0.0f;
                y2 = 1.0f;
                GL.Begin(GL.QUADS);

                GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
                GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
                GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
                GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);

                // right
                x1 = 1.0f - 1.0f/(dest.width*1.0f);
                x2 = 1.0f;
                y1 = 0.0f;
                y2 = 1.0f;

                GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
                GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
                GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
                GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);

                // top
                x1 = 0.0f;
                x2 = 1.0f;
                y1 = 0.0f;
                y2 = 0.0f + 1.0f/(dest.height*1.0f);

                GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
                GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
                GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
                GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);

                // bottom
                x1 = 0.0f;
                x2 = 1.0f;
                y1 = 1.0f - 1.0f/(dest.height*1.0f);
                y2 = 1.0f;

                GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
                GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
                GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
                GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);

                GL.End();
            }

            GL.PopMatrix();
        }
 
jetyb
Адепт
 
Сообщения: 1486
Зарегистрирован: 31 окт 2011, 17:21

Re: Depth и graphics.Blit

Сообщение kripto289 05 май 2016, 11:47

jetyb писал(а):Опять не понял.
Depth Buffer задается один для всей рендер текстуры. Если рисуется фигура, то вычисления/запись в Depth Buffer будут вестись в пределах проекции этой фигуры на экран.

Graphics.Blit просто рисует квадрат с материалом, квадрат такой чтобы в проекции он растянулся на экран. Таким образом создается иллюзия, что обрабатывается каждый пиксель экрана, а не каждый пиксель натянутой на экран фигуры.
Можно рисовать свои фигуры размерами не на экран:
Или через Graphics.DrawMeshNow
Или через класс GL (см пример в PostEffectBase.cs)
Синтаксис:
Используется csharp
protected void DrawBorder (RenderTexture dest, Material material)
                {
            float x1;
            float x2;
            float y1;
            float y2;

            RenderTexture.active = dest;
            bool  invertY = true; // source.texelSize.y < 0.0ff;
            // Set up the simple Matrix
            GL.PushMatrix();
            GL.LoadOrtho();

            for (int i = 0; i < material.passCount; i++)
            {
                material.SetPass(i);

                float y1_; float y2_;
                if (invertY)
                {
                    y1_ = 1.0f; y2_ = 0.0f;
                }
                else
                {
                    y1_ = 0.0f; y2_ = 1.0f;
                }

                // left
                x1 = 0.0f;
                x2 = 0.0f + 1.0f/(dest.width*1.0f);
                y1 = 0.0f;
                y2 = 1.0f;
                GL.Begin(GL.QUADS);

                GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
                GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
                GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
                GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);

                // right
                x1 = 1.0f - 1.0f/(dest.width*1.0f);
                x2 = 1.0f;
                y1 = 0.0f;
                y2 = 1.0f;

                GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
                GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
                GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
                GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);

                // top
                x1 = 0.0f;
                x2 = 1.0f;
                y1 = 0.0f;
                y2 = 0.0f + 1.0f/(dest.height*1.0f);

                GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
                GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
                GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
                GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);

                // bottom
                x1 = 0.0f;
                x2 = 1.0f;
                y1 = 1.0f - 1.0f/(dest.height*1.0f);
                y2 = 1.0f;

                GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
                GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
                GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
                GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);

                GL.End();
            }

            GL.PopMatrix();
        }
 

Суть.
У меня есть шейдер, который рисует рябь на воде от коллизий. Для этого ему необходим буфер. То есть я записываю что-то в текстуру, вывожу её, и через graphics.Blit снова подаю на вход шейдеру. Всё работает прекрасно, сдвиги, смещения, повороты и всё такое. Сама же текстура волны накладывается на меш. Допустим плейн воды. По сути, текстуру ряби я рассчитываю отдельно от самой воды. (я не могу это делать прямо в шейдере воды, даже MRT мне тут не поможет)
Решил я добавить динамические волны от буфера глубины. Буфер глубины естественно получаю в шейдере. Но, буфер глубины отображается корректно, только если плейн воды будет перпендикулярно камере, и бдует заполнять всю видимую область (разрешение квадратное, плейн квадратный). Иначе буфер глубины отображается с искажениями.

Мне не надо рисовать меш. Мне надо корректно расчитывать текстуру. Так что drawmesh не поможет.
Аватара пользователя
kripto289
UNIверсал
 
Сообщения: 476
Зарегистрирован: 30 сен 2013, 03:30
Откуда: Екатеринбург
  • Сайт

Re: Depth и graphics.Blit

Сообщение kripto289 06 май 2016, 02:19

Подытожим. Нужно было сделать смещение вертексов.
o.projPos = ComputeScreenPos (mul(_Matrix , v.vertex - float4(0.5, 0.5, 0, 0)));
Скорее всего координаты вертексов какие-то другие.
Аватара пользователя
kripto289
UNIверсал
 
Сообщения: 476
Зарегистрирован: 30 сен 2013, 03:30
Откуда: Екатеринбург
  • Сайт


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

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

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