При обновлении со 107 до 108 я заметил, что части моей модели теперь выглядят так, как будто они перевернули нормали. Это происходит только с двусторонними материалами.
Смотрите здесь: https://vaaled-jonquil.glitch.me/
Вот как это должно выглядеть с отступом на обоих колесах. Так было в 107
В 108, хотя одно из колес имеет узор, похожий на выскакивающий:
@pushmatrix Можете ли вы подтвердить, есть ли у этой модели собственные касательные? Мне любопытно, может ли это быть связано с # 11438.
Я не верю, что он указывает свои собственные касательные
Используя другой тестовый пример, git bisect указывает на # 17586 как PR, который инициировал проблему, если сетка двусторонняя и имеет отрицательный масштаб X. Однако это было в версии 109, а не в версии 108.
Это не было проверено на модели из этого PR, потому что эта модель недоступна.
Вот тестовый glb
wheels.glb.zip
3 года назад: https://github.com/mrdoob/three.js/issues/10331#issue -194807426
В основном кажется, что ... gl_FrontFace некорректно работает с двусторонними материалами на графических процессорах Adreno.
Это все еще проблема, которую мы должны решить?
//
Эта модель отображается правильно на моем компьютере, если мы удалим обходной путь Adreno в normalmap_pars_fragment
:
#ifdef DOUBLE_SIDED
// Workaround for Adreno GPUs gl_FrontFacing bug. See #15850 and #10331
bool frontFacing = dot( cross( S, T ), N ) > 0.0;
mapN.xy *= ( float( frontFacing ) * 2.0 - 1.0 );
#else
mapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );
#endif
Хм, я тоже помню, что читал этот комментарий; Думаю, я столкнулся с этим, глядя на эту ошибку, которая, по-видимому, была исправлена в r108 (по крайней мере, обновление исправило ее для нас): https://github.com/GoogleWebComponents/model-viewer/issues/740
Может это связано? FWIW, я получил некоторые отзывы о старых графических процессорах Adreno, так что, по-видимому, они все еще довольно распространены.
Просто чтобы подтвердить, это все еще происходит в dev
:
Просто чтобы подтвердить, это все еще происходит в dev:
Правильно. Но только не, если вы удалите обходной путь Adreno.
Но только не, если вы удалите обходной путь Adreno.
Как насчет того, чтобы временно удалить обходной путь, а затем искать другое решение? Текущая реализация приводит к неправильной визуализации независимо от того, какую платформу вы используете.
@ Mugen87 В этом конкретном случае я считаю, что геометрии являются зеркалами друг друга, но имеют одну и ту же карту нормалей.
Я согласен. Я потратил много часов, пытаясь найти обходной путь, совместимый с Adreno, который подходит для каждого случая использования.
При осмотре модели колеса каждое колесо имеет свою собственную УФ оболочку. Он не разделяет ни одного.
И порядок вершин противоположный.
Однако ориентация лица такая же, по крайней мере, в Blender.
Так что я не уверен, ошибка ли это в r108 или r108 теперь работает правильно. ¯_ (ツ) _ / ¯
@pushmatrix можно сравнить с Unity или Blender?
@mrdoob
@pushmatrix
Unity трудно увидеть, потому что свет идет в том же направлении, что и камера, но похоже, что Unity тоже ошибается? 🤔
@mrdoob
Да, это немного зависит от освещения, это в конечном итоге оказывается иллюзией и выглядит так, будто кое-где выскакивает. Но когда вы вращаетесь, он исчезает.
Вот это в другом свете, где это кажется правильным
@mrdoob Лицевые стороны имеют порядок намотки против часовой стрелки в three.js. Обычно UV-координаты трех вершин каждой грани также имеют порядок поворота против часовой стрелки на UV-карте.
В этом примере моя _conjecture_ - модель слева имеет UV-развертки против часовой стрелки, а модель справа имеет UV-развертки _clockwise_. Модель справа отображается неправильно в three.js, когда doubleSide
равно true
.
AFAIK, удаление Adreno-обходного пути решает проблему для графических процессоров, отличных от Adreno.
@pushmatrix В вашем примере Unity есть направленные источники света с двух сторон. Это затрудняет понимание того, что происходит. Может быть предпочтительнее одиночный свет.
@WestLangley Я использую ту же карту среды, которую использует просмотрщик моделей , но, вероятно, у нее нет такого же поворота. Я попробую с одним светом.
@WestLangley Однонаправленный свет, вращающийся вокруг. Я чувствую, что смотрю на оптическую иллюзию
Похоже, Unity заставляет канавки появляться и выходить в зависимости от того, как на них попадает свет, но, по крайней мере, это одинаково для обоих.
Threejs также согласован, но один определенно выглядит всегда выскакивающим:
Я чувствую, что с Unity что-то не так ...
Вроде нужно что-то вроде. material.normalMapScale.x = -1
.
@WestLangley
@mrdoob Лицевые стороны имеют порядок намотки против часовой стрелки в three.js. Обычно UV-координаты трех вершин каждой грани также имеют порядок поворота против часовой стрелки на UV-карте.
В этом примере моя _conjecture_ - модель слева имеет UV-развертки против часовой стрелки, а модель справа имеет UV-развертки _clockwise_. Модель справа отображается неправильно в three.js, когда
doubleSide
равноtrue
.AFAIK, удаление Adreno-обходного пути решает проблему для графических процессоров, отличных от Adreno.
Спасибо, в этом есть смысл. Я думаю, что это все еще заслуживает дальнейшего изучения. Если Sketchfab выглядит правильно на всех устройствах, нам, возможно, придется взглянуть на их шейдеры.
Сегодня я взглянул на соответствующий код шейдера, и мне кажется, что они не используют «Попиксельное отображение нормалей касательного пространства».
Согласно этому сообщению , Sketchfab ожидает определения касательных в активах или эти данные
генерировать на основе ультрафиолетовых координат. Это соответствует тому, что я видел в коде GLSL.
Если я добавлю касательные к модели с помощью BufferGeometryUtils.computeTangents()
и установлю Material.vertexTangents
равным true
, результат будет выглядеть нормально:
Кстати: можно ли поделиться фрагментами кода из Sketchfab в этом посте ^^? В конце концов, это не открытый исходный код.
Для единообразия, вот Sketchfab с 1 направленным светом, движущимся вперед и назад:
Да, нужно иметь в виду, что Sketchfab выполняет обработку на своей стороне, когда вы загружаете модель, поэтому очень вероятно, что они могут создавать / изменять вещи. Вы просматриваете не файл glTF, а файл glTF, преобразованный в собственный формат.
@pushmatrix Не могли бы вы _подтвердить_, что # 17958 подходит для вашей модели?
three.js вычисляет касательные во фрагментном шейдере. Я считаю, что это работает правильно, если убрать хакерство для исправления некоторых глючных графических процессоров Adreno. См. № 17958.
//
Sketchfab вычисляет касательные на ЦП, когда касательные требуются и не предусмотрены моделью. ( @donmccurdy Это то, что требует спецификация glTF.)
three.js тоже может это сделать, но это будет означать добавление правильных касательных ко всем встроенным геометриям. three.js также должен будет реализовать алгоритм MIKKTSpace для замены ComputeTangents()
. Поскольку three.js поддерживает как индексированные, так и неиндексированные геометрии, я ожидаю, что это потребует значительных усилий.
Исправляет это!
Хорошо, похоже, что решение здесь состоит в том, чтобы отменить обходной путь Adreno (# 17958) и рекомендовать людям использовать BufferGeometryUtils.computeTangents()
когда у модели нет касательных и они стремятся поддерживать графические процессоры Adreno (# 15850) .
Звучит неплохо?
Другое решение - автоматически вызвать BufferGeometryUtils.computeTangents()
в движке, если он не указан, и удалить весь код, вычисляющий касательные во фрагментном шейдере ... 🤔
BufferGeometryUtils.computeTangents()
настоящее время требует индекса, поэтому его нельзя использовать в ядре. Однако я думаю, что было бы предпочтительнее, если бы three.js
в какой-то момент мог генерировать касательные согласно MIKKTSpace, а затем удалять perturbNormal2Arb()
.
@WestLangley написал:
это будет означать добавление правильных касательных ко всем встроенным геометриям.
Передумал ... Касательные не обязательно. Вместо этого я бы восстановил метод BufferGeometry.computeTangents()
и "переопределил" этот метод для всех встроенных геометрий, для которых мы можем задавать точные касательные аналитически.
//
Другое решение - автоматически вызвать BufferGeometryUtils.computeTangents () в движке, если он не указан, и удалить весь код, который вычисляет касательные во фрагментном шейдере ...
Мне это кажется правильным.
BufferGeometryUtils.computeTangents () в настоящее время требует индекса, поэтому его нельзя использовать в ядре.
Я думаю, это легко исправить. И его нужно будет исправить для поддержки https://github.com/mrdoob/three.js/issues/17804#issuecomment -557135610.
было бы предпочтительнее, если бы three.js мог генерировать касательные в соответствии с MIKKTSpace в какой-то момент, а затем удалять perturbNormal2Arb () ...
Я не знаю, должен ли MikkTSpace обязательно заменить вычисление фрагментного шейдера. Шейдер практически не требует затрат на производительность и отлично работает с большинством моделей. Предварительное вычисление касательных требует предоплаты за вершину каждый раз и не дает никаких преимуществ, за исключением этих особых случаев. 😕 Несмотря на то, что сказано в спецификации glTF, мне трудно оправдать это по умолчанию.
Было бы неплохо, если бы BufferGeometryUtils.computeTangents
мог реализовать подход MikkTSpace - это лучший алгоритм, если вы должны предварительно вычислить их. Но, вероятно, было бы проще поместить MikkTSpace в такие инструменты, как glTF-Pipeline или gltfpack, которые могут использовать существующую собственную реализацию и выполнять расчет заранее, в автономном режиме.
@donmccurdy
Но, скажем ... в случае использования <model-viewer>
, я не думаю, что существует надежный способ узнать, есть ли у пользователя графический процессор Adreno, но мы бы хотели выглядеть правильно (https: // github. ru / GoogleWebComponents / model-viewer / issues / 740).
Должен ли <model-viewer>
(и другие проекты, которым нужна поддержка x-gpu) вызывать BufferGeometryUtils.computeTangents
когда касательные не указаны, или следует использовать Three?
@pushmatrix
Ха-ха, я только что понял, откуда эти колеса 😁
@mrdoob 🕵
Хорошо, давайте пока вернемся к обходному пути.
Самый полезный комментарий
Исправляет это!