Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Unity: альтернатива OnRenderImage и Graphics.Blit - проблема с DrawMeshNow - fullscreen quad и render texture

Unity: альтернатива OnRenderImage и Graphics.Blit - проблема с DrawMeshNow - fullscreen quad и render texture

Поделиться

Страницы: 1 2 Следующая

KumoKairoПостоялецwww17 окт. 201717:20#0
Экспериментирую с постпроцессингом на мобилках по примеру вот этого видео: https://www.youtube.com/watch?v=IJ_oP2aMS2Q
Пытаюсь использовать вариант "Рендер-В-Текстуру и Рисуем Полноэкранный Квад с этой текстурой"

Пытался разными вариантами и пока остановился на Camera.Render(). По документации требуется выключить камеру и вручную вызывать Render на ней. Код примерно такой:

    
// Setting up things - render texture, screen quad and disabling a camera
private void Start()
{
  _quadMesh = CreateQuadMesh();
  _renderTexture = CreateRenderTexture();
 
  material.SetTexture("_MainTex", _renderTexture);
 
  _camera = GetComponent<Camera>();
  _camera.targetTexture = _renderTexture;
  _camera.enabled = false;
}
 
public void LateUpdate()
{
  _camera.Render();
}
 
//After all rendering is done, display our fullscreen quad
public void OnRenderObject()
{
  material.SetTexture("_MainTex", _renderTexture);
  material.SetPass(0);
  Graphics.DrawMeshNow(_quadMesh, Matrix4x4.identity);
}

Но экран чёрный и ощущение что в текстуру ничего не рендерится:
Изображение
Поверх чёрного экрана ещё гуишная кнопка просто чтобы проверить что квад не рендерится поверх Canvas.RenderOverlays (к этому ещё вернёмся).

Но интересный момент - если включить Frame Debugger, всё рендерится нормально, и применяется постпроцессинговый эффект (в данном случае просто серое изображение для проверки работоспособности)

Изображение

Если вырубить Frame Debugger или не кликать каждый draw pass мышкой, то всё снова становится чёрным (хотя список пассов остаётся таким же).
Но иногда список пассов выглядит вот так (как будто рендерится только канвас):

Изображение

Я пробовал заюзать совершенно другой способ, описанный вот тут: https://forum.unity.com/threads/pos...phics-blit-onrenderimage.41… #post-2759255
Но по какой-то причине выглядит это как рендеринг чёрной текстуры в правом верхнем квадранте (как будто вершины квада Graphics.Blit находятся не в Screen Space координатах). Более того, иногда юнька выдаёт ошибку "Assertion failed (!m_CurrentCamera.IsNull())". Ну и сам эффект не применяется:

Изображение

    
public void OnPreRender()
{
  _renderTexture = RenderTexture.GetTemporary(Screen.width, Screen.height, 16);
  _camera.targetTexture = _renderTexture;
}
 
private void OnPostRender()
{
  _camera.targetTexture = null;
  Graphics.Blit(_renderTexture, null, material, 0);
  RenderTexture.ReleaseTemporary(_renderTexture);
}

Что ещё более интересно - если рендерить этот полноэкранный квад в корутине с WaitForEndOfFrame, то всё рендерится как надо, но поверх Canvas.RenderOverlays

public void LateUpdate()
{
  _camera.Render();
}
 
// Moved OnRenderObject to this coroutine
private IEnumerator WaitAndRender()
{
  while (true)
  {
    yield return new WaitForEndOfFrame();
 
    material.SetTexture("_MainTex", _renderTexture);
    material.SetPass(0);
    Graphics.DrawMeshNow(_quadMesh, Matrix4x4.identity);
  }
}

По списку дроколов видно что квад рисуется сразу после канваса
Изображение

Также я пробовал юзать другие сообщения Unity для вызова camera.Render и Graphics.DrawMeshNow(), но результат везде отрицательный. Пробовал и в Unity 5.5 и в Unity 2017.2 - абсолютно идентичное поведение.

Собственно вопрос - как рисовать полноэкранный квад с текстурой через Graphics.DrawMeshNow?

LeopotamПостоялецwww18 окт. 20170:16#1
KumoKairo, повесь на основную камеру скрипт и в OnPostRender (https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnPostRender.html) методе зови рендер своей скрытой камеры. Рендеринг чего-либо можно вызывать только в колбеках рендеринга, в Update / LateUpdate оно не должно работать.
KumoKairoПостоялецwww18 окт. 20170:22#2
OnPostRender не работает для выключенной камеры, то есть вариант с ручным выключением камеры и вызовом Camera.Render не будет работать вместе с OnPostRender (https://docs.unity3d.com/ScriptReference/Camera.Render.html - события OnPreCull, OnPreRender и OnPostRender будут вызваны после вызова Camera.Render)
Более того, как я написал в посте, я уже пробовал варианты с OnPreRender + OnPostRender для включённой камеры (см. абзац со ссылкой на юньковский форум)
LateUpdate оно не должно работать.
в игре Nitro Nation Stories, о которой речь в докладе на видео, используется именно такие варианты - Camera.Render в LateUpdate, Graphics.DrawMeshNow в OnRenderObject. Более того, в моём случае этот вариант работает с включённым Frame Debugger но не работает без него

Правка: 18 окт. 2017 0:25

LeopotamПостоялецwww18 окт. 20170:24#3
KumoKairo, еще раз прочитай что я написал:
повесь на основную камеру скрипт и в OnPostRender

Т.е на ту, которая активная и рендерится.
Как вариант - цеплять вторую камеру дочерней к основной, ставить порядок рендера после основной, назначать рендер в текстуру. Ну и использовать эту текстуру дальше (в следующем фрейме по сути).

Правка: 18 окт. 2017 0:27

KumoKairoПостоялецwww18 окт. 20170:41#4
Т.е на ту, которая активная и рендерится.

У меня одна единственная основная камера, которая рендерит всё в текстуру. И которая либо выключена в самом начале сцены, и рендерится по ручному вызову Camera.Render, либо включена, но рендерит всё сразу в текстуру сама по себе
Как вариант - цеплять вторую камеру дочерней к основной, ставить порядок рендера после основной, назначать рендер в текстуру. Ну и использовать эту текстуру дальше (в следующем фрейме по сути).

Пока не очень понятна суть двух камер. Если они одинаковы, то вся сцена же будет рендериться два раза подряд?

Правка: 18 окт. 2017 0:42

LeopotamПостоялецwww18 окт. 20170:45#5
Я вообще не сильно понял сути проблемы. Почему не OnRenderImage? Graphics.DrawMeshNow работает с ним, только что проверил (вешаем на камеру и не выключаем ее):
sealed class PostEffect : MonoBehaviour {
    [SerializeField]
    Material _postEffect;

    [SerializeField]
    Mesh _dynamicMesh;

    void OnRenderObject () {
        if (_dynamicMesh != null) {
            Graphics.DrawMeshNow (_dynamicMesh, Vector3.zero, Quaternion.identity);
        }
    }

    void OnRenderImage (RenderTexture src, RenderTexture dest) {
        if (_postEffect != null) {
            Graphics.Blit (src, dest, _postEffect);
        }
    }
}
Пока не очень понятна суть двух камер. Если они одинаковы, то вся сцена же будет рендериться два раза подряд?
рендерит всё сразу в текстуру сама по себе

Если рендеришь в текстуру (указав в свойствах камеры), то такую текстуру можешь использовать только в рендере другой камеры (я ее называл основной). Ну и вторая камера должна быть выключена (которая рендерит в текстуру)

Правка: 18 окт. 2017 0:48

KumoKairoПостоялецwww18 окт. 20170:51#6
Почему не OnRenderImage?

Нет прямого контроля над размером, фильтрингом и глубиной таргет рендера, нет возможности сделать даунсемплинг всей сцены (даунсемпл 3Д геометрии отдельно от ГУИ)
Например для большинства девайсов подойдёт RBG565, но для Tegra нужен 32х битный буффер, на девайсах типа Nvidia Shield Tablet на рендер таргетах меньше чем 8 бит на канал явный banding

Правка: 18 окт. 2017 0:53

LeopotamПостоялецwww18 окт. 20170:52#7
KumoKairo, почему нет? Рендерь во временный рендер таргет через blit, поставив у него нужный размер / формат, а потом делай еще один блит в конечный таргет (это будет экран).
Про 32битный таргет - оне не нужен. Про тегру3 - она мертва, апдейтов не предвидится, количество таких девайсов ничтожно мало (можно пробить по базе юнитеков: https://hwstats.unity3d.com/mobile/gpu.html )

Правка: 18 окт. 2017 0:55

KumoKairoПостоялецwww18 окт. 20170:53#8
KumoKairo, почему нет? Рендерь во временный рендер таргет через blit, поставив у него нужный размер / формат, а потом делай еще один блит в конечный таргет (это будет экран).

Первый рендер, который source, будет полноразмерным рендером в разрешение экрана. Мне нужен даунсемпл ДО этого самого первого рендера. Потом для постэффектов, конечно, можно даунсемплить дальше через встроенный Blit или через GPUшный самодельный Blit с тем же DrawMeshNow

Правка: 18 окт. 2017 0:55

LeopotamПостоялецwww18 окт. 20170:56#9
Первый рендер, который source, будет полноразмерным рендером в разрешение экрана.

Можно понизить целевое разрешение через https://docs.unity3d.com/ScriptReference/Screen.SetResolution.html - мобилки поддерживают такое.
KumoKairoПостоялецwww18 окт. 20170:56#10
Про 32битный таргет - оне не нужен. Про тегру3 - она мертва, апдейтов не предвидится, количество таких девайсов ничтожно мало

Вы уходите от сути вопроса. При чём тут тегра 3. На Nintendo Switch стоит Tegra X1 - там те же самые проблемы с banding как и на Tegra K1
KumoKairoПостоялецwww18 окт. 20170:57#11
Можно понизить целевое разрешение через https://docs.unity3d.com/ScriptReference/Screen.SetResolution.html - мобилки поддерживают такое.

Этот вариант понижает рендер всего, включая гуи, в т.ч. оверлейный. В своём сообщении про даунсемплинг я написал про то что требуется отдельно на 3Д сцену
KumoKairoПостоялецwww18 окт. 20170:59#12
Я наверное лучше напрямую Александру Долбилову по этому поводу напишу, отпишусь потом о результатах
LeopotamПостоялецwww18 окт. 20171:00#13
KumoKairo, тогда без двойной камеры не обойтись:
  • ) делаем специальный слой, который не будет рендериться основной камерой. сам слой пустой, нужен только для кулинга камерами.
  • ) основная камера рендерит в даунсемпленный рендертаргет все, что нужно, за исключением вышеуказанного слоя.
  • ) на вторую камеру (ставим куда-угодно, порядок рендера - после основной, рендерить - только выделенный слой) вешаем скрипт с OnRenderImage и подсовываем рендертаргет из первой.

    Если нужен gui, то тогда тут проще - для него есть готовый слой. Хотя при таком раскладе виджеты тоже будут постпроцесситься. Тогда все как написано выше, + еще одна камера для UI если он в world space, для оверлея не нужно, оно вроде как рендерится автоматически после всего.

  • Правка: 18 окт. 2017 1:04

    KumoKairoПостоялецwww18 окт. 20176:53#14
    Leopotam
    Будем экспериментировать, спасибо :)

    Страницы: 1 2 Следующая

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

    2001—2017 © GameDev.ru — Разработка игр