Three.js: Новый MeshStandardMaterial в r112 имеет артефакты полос на некоторых графических процессорах

Созданный на 30 дек. 2019  ·  18Комментарии  ·  Источник: mrdoob/three.js

Начиная с версии r112, MeshStandardMaterial по умолчанию (в данном случае, в частности, поскольку он используется при загрузке файлов glTF, но, вероятно, и в других сценариях) демонстрирует артефакты полос на некоторых графических процессорах. В частности, я видел эту проблему в Pixelbook и в каждом поколении телефонов Pixel. Проблема не возникает на графических процессорах Nvidia для настольных ПК, которые я пробовал, а также на Oculus Go или Oculus Quest.

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

Артефакты выглядят так (отрисованы с помощью Three.js r112 в Pixelbook)

Screenshot 2019-12-29 at 9 15 19 PM

Ожидаемый результат выглядит следующим образом (визуализировано с помощью Three.js r111 в том же Pixelbook)

Screenshot 2019-12-29 at 9 24 31 PM

Живая ссылка, в настоящее время используется r112: https://xrdinosaurs.com

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

Материал на снимке экрана (полностью вставлен ниже) использует расширение glTF «KHR_materials_pbrSpecularGlossiness» и имеет текстуры диффузного, нормального и зеркального / глянцевого.

    {
      "doubleSided": true,
      "emissiveFactor": [
        0,
        0,
        0
      ],
      "extensions": {
        "KHR_materials_pbrSpecularGlossiness": {
          "diffuseFactor": [
            0.46512957319999998,
            0.46512957319999998,
            0.46512957319999998,
            1
          ],
          "diffuseTexture": {
            "index": 4,
            "texCoord": 0
          },
          "glossinessFactor": 0.27610518290000002,
          "specularFactor": [
            0.92244664629999995,
            0.92244664629999995,
            0.92244664629999995
          ],
          "specularGlossinessTexture": {
            "index": 6,
            "texCoord": 0
          }
        }
      },
      "name": "TRex",
      "normalTexture": {
        "index": 5,
        "scale": 1,
        "texCoord": 0
      }
    }
Bug Device Issue

Самый полезный комментарий

@elalish, выполнив несколько тестов на нескольких примерах, я смог точно определить PMREMGenerator обрабатывает devicePixelRatio .

На устройствах с номинальной плавающей запятой pixelRatio мы получаем "плохие" координаты mipmap на сгенерированной текстуре. Так что есть небольшие пробелы и пересекающиеся области. Я также обнаружил, что моя машина имеет разные devicePixelRatios зависимости от того, просматриваю ли я пример локально (0.899 ..) или онлайн (1), и поэтому я обнаружил эти артефакты только локально.

Я установил простой тест, отключив setPixelRatio и, похоже, он решил проблему, если это так для других, тогда было бы лучше провести рефакторинг так, как PMREMGenerator обрабатывает его.

@toji @ plut0nist Не могли бы вы проверить следующие примеры на устройствах, на которых представлены эти артефакты?

Пример DEV
ТЕСТ Пример

Все 18 Комментарий

Я могу подтвердить сбой на моем Pixel (1). Однако артефакты, кажется, возникают только при использовании KHR_materials_pbrSpecularGlossiness .

В 18042 году появилось геометрическое сглаживание. Однако GLTFLoader заменяет код блока шейдера lights_physical_fragment следующим:

https://github.com/mrdoob/three.js/blob/3ba0553208cfc9113152f5f39b4036a448cf3f25/examples/js/loaders/GLTFLoader.js#L683 -L688

@toji Не могли бы вы изменить копию своего приложения GLTFLoader , заменив приведенный выше код на:

var lightPhysicalFragmentChunk = [
    'PhysicalMaterial material;',
    'material.diffuseColor = diffuseColor.rgb;',
    'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );',
    'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );',

    'material.specularRoughness = max( 1.0 - glossinessFactor, 0.0525 );// 0.0525 corresponds to the base mip of a 256 cubemap.',
    'material.specularRoughness += geometryRoughness;',
    'material.specularRoughness = min( material.specularRoughness, 1.0 );',
    'material.specularColor = specularFactor.rgb;',
].join( '\n' );

@elalish Даже если этот патч не решает проблему, мы должны в любом случае добавить его в GLTFLoader , верно?

@ Mugen87 Да, конечно. Я посмотрю, смогу ли я воспроизвести свой Pixel 3.

@toji Я не воспроизводю свой Pixel 3 с Android 10, так что, по крайней мере, это не все пиксели ...

Ошибка драйвера? Я не уверен, какая линия его вызывает. Я почти уверен, что присутствие / отсутствие геометрического сглаживания в любом случае не приведет к появлению такого артефакта.

@toji Я также только что попробовал свой специальный дерьмовый телефон-тестер (Alcatel, который стоит около 30 долларов от Target). Я не вижу артефактов полос, хотя заметил, что небо черное. Насчет перфоманса: не совсем маслянистый, но и неплохой. Честно говоря, этот 3D-вид реагирует лучше, чем 2D-интерфейс клавиатуры на этом телефоне. Иди разбери.

Ух, черное небо на самом деле означает, что генерация PMREM полностью завершилась неудачей, и это из-за этой странной ошибки и обходного пути, которые мы нашли: https://github.com/GoogleWebComponents/model-viewer/pull/920. Я хотел вставить это в r112, но это ускользнуло от меня. Скорее всего, это не связано с ошибкой OP.

Я воспроизвел ошибку OP на своем OnePlus 5T как в Chrome, так и в Firefox.

Благодаря! Применил патч к GLTFLoader и заметил, что артефакт полосатости уменьшился, но не исчез.

Перед патчем:

Screenshot 2019-12-30 at 12 11 36 PM

После патча:

Screenshot 2019-12-30 at 12 10 35 PM

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

С радостью внесем исправления в любые другие изменения, которые вы хотите протестировать, или вы можете проверить https://github.com/toji/xr-dinosaurs, если хотите протестировать его локально. (Не требует никаких серверных компонентов.)

Насчет перфоманса: не совсем маслянистый, но и неплохой.

Спасибо. 😁 Усердно работал над исполнением. В этом случае во время обновления до r112 я заметил регресс производительности и спросил об этом @mrdoob . Он предположил, что это может быть новый, более точный стандартный шейдер, и предложил заменить некоторые материалы на MeshLambertMaterial для проверки. Поскольку в модели среды все равно не были должным образом настроены материалы PBR, я принудительно передал ее Ламберту и оставил там, что позволило восстановить все регрессии производительности, а затем и некоторые (так как они занимают большую часть окна просмотра). Оставил динозавров с стандартный материал, так как они являются активом «героя».

Замечание: Scene.environment настоящее время не работает, когда GLTFLoader загружает сетки с использованием материалов specular / glossiness, поскольку средство визуализации проверяет MeshStandardMaterial например.

https://github.com/mrdoob/three.js/blob/dd81aad5513d66e35e51f3a3b42555bc8aef5cbc/src/renderers/WebGLRenderer.js#L1633

Однако GLTFLoader создает ShaderMaterial для каждого материала specular / glossiness. Осознал это сегодня при тестировании с моделью T-Rex ^^. Что ж, еще одна причина наконец-то доделать # 14099.

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

Гм, похоже, есть больше проблем с физическими материалами, использующими карту окружающей среды. Посмотрите, как следующие примеры выглядят на Pixel 1, Android 10.

https://threejs.org/examples/webgl_materials_envmaps_exr

Screenshot_20200106-111923

https://threejs.org/examples/webgl_materials_physical_clearcoat

Screenshot_20200106-111856

https://threejs.org/examples/webgl_materials_envmaps_hdr

Screenshot_20200106-111809

Я не могу воспроизвести эти артефакты на моем iMac.

Что-то довольно странное происходит на моей машине, я могу воспроизвести эти артефакты во всех примерах, использующих новый PMREMGenerator . Но только при локальном запуске; при просмотре их в Интернете (со страницы threejs.org) все они кажутся правильными.

Я никогда не сталкивался с такой проблемой, и я совершенно не понимаю, что ее вызывает.

Я использую Windows 10 с GeForce GTX 750 TI, поэтому не думаю, что это проблема конкретного устройства.

Но только при локальном запуске; при просмотре их в Интернете (со страницы threejs.org) все они кажутся правильными.

Имейте в виду, что в версии dev есть изменения, которых пока нет в prod . Не могли бы вы проверить текущую ветку master а затем выполнить локальный тест?

Не могли бы вы проверить текущую главную ветку, а затем выполнить локальный тест?

Первое, что я попробовал, заметив такое поведение, - те же результаты. Действительно любопытно.

Не могли бы вы протестировать с окнами в режиме инкогнито? Иногда что-то может быть кешировано, или расширения браузера мешают, что может сбивать с толку.

Пробовал с инкогнито, те же результаты :(

Думаю, я знаю, почему возникает эта полосатость.
Во время генерации mip моя локальная (неправильная) версия создает черную полосу, которой нет в живой версии.

local
online

Это также распространяется на более низкие уровни MIP.

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

@elalish, выполнив несколько тестов на нескольких примерах, я смог точно определить PMREMGenerator обрабатывает devicePixelRatio .

На устройствах с номинальной плавающей запятой pixelRatio мы получаем "плохие" координаты mipmap на сгенерированной текстуре. Так что есть небольшие пробелы и пересекающиеся области. Я также обнаружил, что моя машина имеет разные devicePixelRatios зависимости от того, просматриваю ли я пример локально (0.899 ..) или онлайн (1), и поэтому я обнаружил эти артефакты только локально.

Я установил простой тест, отключив setPixelRatio и, похоже, он решил проблему, если это так для других, тогда было бы лучше провести рефакторинг так, как PMREMGenerator обрабатывает его.

@toji @ plut0nist Не могли бы вы проверить следующие примеры на устройствах, на которых представлены эти артефакты?

Пример DEV
ТЕСТ Пример

@sciecode Большое спасибо за выяснение первопричины! Я посмотрю, смогу ли я найти решение.

@sciecode : Проверено на моих устройствах. Тест DEV Example показывает очень очевидную черную линию на карте среды, а тест TEST - нет. Отличная отладка, спасибо!

Мне было очень любопытно, почему PMREMGenerator вообще нужно учитывать для devicePixelRatio , поэтому я пошел копать. Оказывается, это потому, что renderer.setViewport() автоматически преобразовывает DPR в любые значения, которые вы ему отправляете, что кажется явно неправильным поведением для целей рендеринга, кроме стандартного фреймбуфера, которые выделяются с точными значениями пикселей, которые не учитывать соотношение пикселей вообще. Я бы посоветовал «правильное» поведение здесь: внутренне rendere.setViewport() должен использовать getTargetPixelRatio() , который возвращает 1 когда активная цель рендеринга отличается от значения по умолчанию. Однако я определенно вижу, как это может вызвать проблемы с обратной совместимостью.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги