Three.js: GLTFLoader: результат модели нормального касательного теста неверен

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

Описание проблемы

Я попытался отобразить модель теста нормального касания .
Однако отображаемый результат, похоже, отличается от образца Хроноса.

Результат модели Three.js + Normal-Tangent Test:
image

Загрузчик образцов Khronos + результат модели Normal-Tangent Test:
image

Я думаю, что этот образец модели должен давать одинаковые левые и правые результаты.

По теме: https://emackey.github.io/testing-pbr/normal-tangent-readme.html

/ cc @emackey

Версия Three.js
  • [x] Dev
  • [] r85
  • [] ...
Браузер
  • [x] Все они
  • [] Chrome
  • [ ] Fire Fox
  • [] Internet Explorer
Операционные системы
  • [x] Все они
  • [] Windows
  • [] macOS
  • [] Linux
  • [] Android
  • [] iOS
Требования к оборудованию (видеокарта, устройство VR, ...)

ThinkPad X260 + Windows 10 + Intel HD Graphics 520

Bug Loaders

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

Я хотел бы выделить одно предложение из спецификации glTF, в частности, для

Нормальные векторы используют соглашения OpenGL, где + X справа, а + Y вверх. + Z указывает на зрителя.

Это предложение позволяет отправлять модели без касательных векторов, экономя место.

Давайте проверим это. Здесь я сделал паршивую карту высот (карту рельефа) из пятна в программе рисования:

TestHeightMap

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

Используя онлайн-конвертер (сомнительного качества, но мы рассмотрим результат чуть позже), я преобразовал его из карты высот в карту нормалей. Имейте в виду, что здесь нет 3D-модели, нет UV-координат, вычислений в микропространстве или какой-либо геометрии. Просто карта высот преобразована в карту нормалей. Мне пришлось вручную настроить онлайн-конвертер в соответствии с инструкциями glTF так, чтобы X был прав, Y вверх, а Z смотрел на зрителя. Вот результат:

TestNormalMap

Давайте вернем это в программу рисования и выделим цветовые каналы, чтобы увидеть, куда эти векторы указывают. Ниже каждый цветовой канал был разделен на собственное изображение в градациях серого. Помните, что они будут интерпретироваться так, что черный означает -1.0 , средний серый означает 0.0 , а белый означает +1.0 .

TestNormalMap-Decomposed

Поэтому я думаю, что онлайн-конвертер сделал то, о чем просил glTF, по крайней мере, после его правильной настройки. На изображении красного цвета (X) мы видим, что наклон справа имеет белые пиксели (+1,0), указывающие вектор X на правом краю изображения. В левой части красного изображения черные пиксели (-1,0) указывают вектор X в левой части изображения. На зеленом (Y) изображении белые пиксели вдоль верхнего склона выступа указывают на вектор Y в верхней части изображения. Значения Z наименее интуитивно понятны, но помните, что вершина выпуклости и сама задняя пластина направлены на зрителя, а наклоны со всех сторон направлены в противоположную сторону, поэтому все они равномерно темнее.

Что, если мы загрузим это в Blender Eevee, который (как и glTF) принимает карты нормалей в стиле OpenGL? Что произойдет, если UV-карту повернуть или даже масштабировать для инвертирования?

NormalSpinTest

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

Но не все программное обеспечение использует соглашение OpenGL. Некоторые используют другое соглашение (иногда называемое соглашением DirectX), где векторы Y указывают на нижнюю часть изображения, а не на верхнюю. Вот разложенный канал Y моего изображения в этой форме. Более светлые пиксели - это те, которые обращены к нижней части изображения.

TestNormalMap_DirectX-Green

Если я загружу одну из этих карт нормалей в стиле DirectX в Blender Eevee, могу ли я ожидать, что она будет работать?

NormalSpinTest_DirectX_v3

Нет. Блендер ожидал + Y вверх. Вычисления неверны, и отраженная линия горизонта вращается вокруг.
То же самое происходит, если вы загружаете карту нормалей в стиле OpenGL в движок, который ожидал падения + Y.

Это то, что пытается проверить модель NormalTangentTest. Каждая строка вращает UV-координаты в разную ориентацию, пытаясь убедиться, что отражения остаются правильными в этих разных ориентациях.

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

Спасибо, что написали это @ cx20.

Просто для большего контекста вот некоторая связанная информация и проблемы:

  • Я сообщил о подобной проблеме в программе просмотра ThreeJS glTF от @donmccurdy, donmccurdy / three-gltf-viewer # 10. Но теперь я думаю, что это ошибка в загрузчике glTF от ThreeJS, а не в программе просмотра. Итак, этот новый выпуск лучше моего старого.

  • В предыдущем выпуске модель использовалась лицом к небу, но позже я повернул ее лицом к горизонту. Это позволяет легче увидеть неправильные отражения, потому что горизонт безумно вращается, как показано выше.

  • Правильность использования карты нормалей в модели было подтверждено обсуждением в KhronosGroup / glTF # 952.

  • Работа ThreeJS с картами нормалей была подвергнута сомнению в # 11315.

  • У BabylonJS недавно была аналогичная проблема, о которой здесь сообщалось и которая была исправлена ​​здесь . Вот живая демонстрация загрузчика BabylonJS glTF 2.0 с примененным исправлением .

Хорошая рецензия, спасибо!

Модель выглядит правильно с добавлением этой строки:

materialParams.normalScale = new THREE.Vector2(-1, 1);

Но я не уверен, что хорошо разбираюсь в проблеме. Понимание # 11315 может здесь помочь.

@donmccurdy Спасибо за совет.
Я понял, что улучшение, настроив normalScale.
Однако, если модель glTF верна, я думаю, что лучше обработать ее загрузчику glTF.

@ cx20 согласился, это исправление теперь объединено в THREE.GLTF2Loader.

Я подтвердил, что это исправляется.

Результат модели Three.js + Normal-Tangent Test:
image

Это регрессировало где-то между r101 и r104:
Screenshot from 2019-06-11 16-38-27

См. Https://github.com/mrdoob/three.js/pull/15749 - регрессия является преднамеренной, и ее можно избежать, включив в модель касательные.

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

До сих пор я не знал о # 15749. Меня это застало врасплох, я думал, что мы проделали достаточно хорошую работу по определению касательных в glTF, чтобы их можно было хотя бы приблизить во время выполнения.

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

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

Повторное открытие 😅

Я подозреваю, что это изменение могло нарушить отображение нормалей для большинства моделей glTF в ThreeJS.

Я не верю, что это что-то настолько серьезное - мы всегда генерировали касательные в реальном времени в шейдере с производными, и мы все еще делаем. Ранее мы включили хак ( normalScale.y *= -1 ), который исправлял эту конкретную тестовую модель, но также сломал некоторые другие примеры. У меня нет объяснения, когда это помогло или не помогло, поэтому мы удалили хак, как только поддержали сохраненные касательные - в этом случае это определенно было бы неправильно. Теперь модели, основанные на взломе (и не включающие касательные), сломаны, а модели, которые были сломаны взломом (и не включают касательные), исправлены.

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

См. Выше. В целом, я считаю, что мы адекватно визуализируем модели без касательных. Однако мы не генерируем касательные mikktspace, как того требует спецификация glTF. Насколько мне известно, такой JS-реализации не существует, а наша реализация шейдера на основе производных является просто "в основном достаточно хорошим" приближением. Эта примерная модель представляет собой преднамеренно крайний случай, демонстрирующий пределы этого приближения.

Мы были бы рады получить реализацию генерации тангенса mikktspace в JS; это было бы хорошим дополнением к THREE.BufferGeometryUtils. Но официальный (родной) код mikktspace довольно длинный, и я еще не вникал достаточно, чтобы увидеть, сколько из этого требуется для генерации касательных.

Ранее мы включали хак ( normalScale.y *= -1 ), который исправлял эту конкретную тестовую модель, но также сломал некоторые другие примеры.

Это сломало конкретно другие модели glTF или просто примеры в целом?

В дикой природе существует два различных типа карт нормалей касательного пространства. Substance Painter называет их «Нормали DirectX» и «Нормали OpenGL», что не лучшее название для него. Разница в том, что канал y инвертирован, то есть все значения зеленого канала в текстуре инвертированы. Умножение y *= -1 - правильный способ преобразовать одно в другое. Так называемые "нормали DirectX" используют левую систему координат, а glTF определяет правую систему координат для нормали / касательной / битангенса.

Я подозреваю, что происходит то, что когда ThreeJS автоматически вычисляет касательные, он ожидает, что карта нормалей была создана с перевернутым стилем Y (DirectX), и получает этот канал в обратном направлении для glTF, поэтому требуется переворот. Однако при наличии касательных такой переворот не требуется.

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

(Это также обсуждается в прошлом году в KhronosGroup / glTF-Sample-Models # 174)

Я хотел бы выделить одно предложение из спецификации glTF, в частности, для

Нормальные векторы используют соглашения OpenGL, где + X справа, а + Y вверх. + Z указывает на зрителя.

Это предложение позволяет отправлять модели без касательных векторов, экономя место.

Давайте проверим это. Здесь я сделал паршивую карту высот (карту рельефа) из пятна в программе рисования:

TestHeightMap

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

Используя онлайн-конвертер (сомнительного качества, но мы рассмотрим результат чуть позже), я преобразовал его из карты высот в карту нормалей. Имейте в виду, что здесь нет 3D-модели, нет UV-координат, вычислений в микропространстве или какой-либо геометрии. Просто карта высот преобразована в карту нормалей. Мне пришлось вручную настроить онлайн-конвертер в соответствии с инструкциями glTF так, чтобы X был прав, Y вверх, а Z смотрел на зрителя. Вот результат:

TestNormalMap

Давайте вернем это в программу рисования и выделим цветовые каналы, чтобы увидеть, куда эти векторы указывают. Ниже каждый цветовой канал был разделен на собственное изображение в градациях серого. Помните, что они будут интерпретироваться так, что черный означает -1.0 , средний серый означает 0.0 , а белый означает +1.0 .

TestNormalMap-Decomposed

Поэтому я думаю, что онлайн-конвертер сделал то, о чем просил glTF, по крайней мере, после его правильной настройки. На изображении красного цвета (X) мы видим, что наклон справа имеет белые пиксели (+1,0), указывающие вектор X на правом краю изображения. В левой части красного изображения черные пиксели (-1,0) указывают вектор X в левой части изображения. На зеленом (Y) изображении белые пиксели вдоль верхнего склона выступа указывают на вектор Y в верхней части изображения. Значения Z наименее интуитивно понятны, но помните, что вершина выпуклости и сама задняя пластина направлены на зрителя, а наклоны со всех сторон направлены в противоположную сторону, поэтому все они равномерно темнее.

Что, если мы загрузим это в Blender Eevee, который (как и glTF) принимает карты нормалей в стиле OpenGL? Что произойдет, если UV-карту повернуть или даже масштабировать для инвертирования?

NormalSpinTest

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

Но не все программное обеспечение использует соглашение OpenGL. Некоторые используют другое соглашение (иногда называемое соглашением DirectX), где векторы Y указывают на нижнюю часть изображения, а не на верхнюю. Вот разложенный канал Y моего изображения в этой форме. Более светлые пиксели - это те, которые обращены к нижней части изображения.

TestNormalMap_DirectX-Green

Если я загружу одну из этих карт нормалей в стиле DirectX в Blender Eevee, могу ли я ожидать, что она будет работать?

NormalSpinTest_DirectX_v3

Нет. Блендер ожидал + Y вверх. Вычисления неверны, и отраженная линия горизонта вращается вокруг.
То же самое происходит, если вы загружаете карту нормалей в стиле OpenGL в движок, который ожидал падения + Y.

Это то, что пытается проверить модель NormalTangentTest. Каждая строка вращает UV-координаты в разную ориентацию, пытаясь убедиться, что отражения остаются правильными в этих разных ориентациях.

В спецификации по-прежнему должна быть конкретная формула для вычисления касательной для одиночного примитива, учитывая примитив и его UV-координаты, и какой знак W использовать для битангенса. "Нормали OpenGL" и "нормали DX" недостаточно точны, чтобы вывести формулу. Они могут относиться к соглашениям, но я как разработчик понятия не имею, что с этим делать.

В настоящее время я использую перевернутый TangentW из MikkTSpace, чтобы он соответствовал этому конкретному образцу, но именно это сработало.

Это сломало конкретно другие модели glTF или просто примеры в целом?

Сообщенные ошибки были связаны, в частности, с моделями glTF. Тем не менее, я сомневаюсь, что есть достаточно уверенности в экспорте материалов через FBX или COLLADA, чтобы сказать, что эти соглашения о картах нормалей когда-либо были полностью поняты и протестированы.

Разница в том, что инвертирован канал y, то есть инвертированы все значения зеленого канала в текстуре. Умножение y * = -1 - правильный способ конвертировать одно в другое.

Спасибо, это гораздо лучшее оправдание нашего «взлома», чем у нас, когда мы его реализовали. 😇

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

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

В спецификации по-прежнему должна быть конкретная формула для вычисления касательной для одиночного примитива, учитывая примитив и его UV-координаты, и какой знак W использовать для битангенса.

Я не уверен, что алгоритм MikkTSpace так легко представить в виде дискретной формулы ... вы просите альтернативу каноническому коду MikkTSpace? Или какая-то дополнительная информация помимо инструкции по использованию MikkTSpace? @Themaister


Для исходной проблемы, похоже, нам нужно где-то восстановить множитель normal.y *= -1 . Для этого есть три возможных места:

  • (а) в GLTFLoader, для сеток без касательных
  • (б) в GLTFLoader для всех сеток
  • (c) в WebGLRenderer для всех сеток

Если threejs действительно использует соглашение DirectX, а, например, Blender - нет, я мог бы рассмотреть вариант (c). Однако в интересах быстрого и безопасного решения я склоняюсь к (а).

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

Нет, three.js не предполагает, что ...

three.js предполагает, что + Y "вверх" для касательного пространства, а увеличение-V "вверх" для uv-пространства.

То есть three.js предполагает, что uv (0, 0) находится в нижнем левом углу текстуры, а спецификация glTF предполагает верхний левый угол. Вот почему GLTFLoader устанавливает texture.flipY в false . (three.js по умолчанию устанавливает texture.flipY равным true .)

Когда касательных нет, three.js использует производные экранного пространства для оценки касательных. Это делается с помощью цепного правила. При этом вычислении предполагается, что касательное пространство и УФ-пространство имеют одинаковую ориентацию.

Для правильно написанных моделей glTF это предположение неверно. Однако вы должны иметь возможность компенсировать это, установив normalScale.y = - 1 для любой модели, которая _ должным образом соответствует спецификации glTF_.

Мне также кажется, что мы можем исправить это автоматически, соблюдая флаг flipY в шейдере.

Если установка normalScale.y не работает, значит, происходит что-то еще.

Спасибо за это разъяснение. Думаю, здесь у нас есть путь вперед.

Мне также кажется, что мы можем исправить это автоматически, соблюдая флаг flipY в шейдере.

Да, за исключением случаев, когда glTF предоставляет свои собственные касательные векторы, верно? Я ожидал, что только автоматически вычисляемые касательные потребуют теста flipY и соответствующего отрицания y .

Если это не так ... это будет означать, что в моей модели NormalTangentMirrorTest закодированы неправильные касательные, то есть сам экспортер glTF Blender помещает неправильные касательные в модели glTF.

Изменить: я считаю, что подтвердил правильность экспортированных касательных векторов, и им не нужно переворачивать Y. Если нужно, я могу опубликовать более подробную информацию.

Но похоже, что правильное действие - перевернуть normalScale.y только тогда, когда автоматически сгенерированные касательные (не поставляемые касательные) используются с флагом flipY . Мысли?

В моем предыдущем посте я объяснил, как вручную компенсировать инвертированные нормали, когда касательные атрибутов отсутствуют. При наличии касательных нечего компенсировать, потому что производные экранного пространства не используются.

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

В любом случае, прежде чем мы пойдем по этому пути, я считаю совершенно необходимым проверить эту гипотезу:

[Y] Вы должны иметь возможность компенсировать, установив normalScale.y = - 1 для любой модели, которая должным образом соответствует спецификации glTF.

У нас должно быть объяснение для каждой модели, которая не отображается правильно.

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

Да, извините, я не собирался навязывать такие детали реализации. Я просто пытаюсь убедиться, что нет неправильного понимания того, что _honoring the flipY flag_ означает математически для целей генерации касательной к экранному пространству.

У нас должно быть объяснение для каждой модели, которая не отображается правильно.

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

Я полагаю, это тесно связано с этой проблемой? https://github.com/KhronosGroup/glTF-Sample-Models/issues/174

@WestLangley Вот что я нашел. По умолчанию khronos-NormalTangentTest (без касательных) выглядит неправильно:
NormalTangentTest
Если я установил normalScale.y = -1, это все равно неправильно:
NormalTangentTestNegY
Если я вместо этого установлю normalScale.x = -1, это будет выглядеть правильно:
NormalTangentTestNegX
За возможным исключением, что рендеринг выглядит немного пиксельным, особенно на золотом отражателе. Ожидается ли это с приближением экранного пространства или это индикатор другой ошибки?

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

@elalish Этот

ИМХО, этот пример слишком запутан. Нам нужен последовательный тестовый пример, который предоставляет достаточно визуальных элементов, чтобы понять, что происходит.

Кстати, раньше у нас был VertexTangentHelper (# 3511), который можно было оживить для поддержки геометрии буфера.

@WestLangley Мне жаль, что я не знал, как сделать NormalTangentTest более понятным. Он не делает ничего необычного, он просто меняет ориентацию (в УФ-пространстве) каждого образца. Три колонки предназначены только для тестирования различных материалов, золотой колонки может хватить и самой. Помимо этого, я не думаю, что тестовая модель может стать намного проще и все же протестировать эти разные УФ-ориентации.

Несмотря на повороты UV, изображение карты нормалей довольно согласовано в том, в какую сторону указывают векторы, когда карта нормалей рассматривается как 2D-изображение. В двухмерном представлении изображения правые стороны всех полушарий имеют высокие значения красного канала, а верхние края всех полушарий имеют высокие значения зеленого канала, независимо от UV-координат. Это соответствует спецификации glTF, согласно которой красный (+ X) указывает на правую сторону текстуры в УФ-пространстве, а зеленый (+ Y) указывает на верхний край текстуры в УФ-пространстве. Для выполнения этой работы не требуются поставляемые касательные векторы: простая оценка в экранном пространстве того, в каком направлении обычно находится ось + U для данного треугольника, достаточна для определения касательных и двухкасательных векторов, как это делают BabylonJS и CesiumJS, и, конечно, ThreeJS тоже, но с некоторым пока необъяснимым переворотом оси normalScale.

Существует известная путаница с использованием glTF флага flipY , инвертирующего координаты V в UV-пространстве, о чем, я думаю, вы уже хорошо знаете. Я давно подозревал, что это играет роль в необъяснимом флипе normalScale.

Также есть небольшая ошибка запекания изображения (моя вина, я был новым пользователем Substance Painter в то время, много лет назад). Небольшой диагональный шов особенно заметен на плоской части золотых полусфер. Но это не должно умалять общего эффекта. Основная круглая часть запекания получилась прекрасной и хорошо демонстрирует, что эффект «вверх» и «вправо» остается постоянным по всему 2D-изображению нормальной текстуры, независимо от трехмерных или UV-координат, повернутых во всех направлениях и касательных. опущено.

Это важный эффект для художников, создающих повторяющиеся текстуры карты нормалей до создания трехмерной геометрии, поскольку художнику не требуется доступ к координатам UV или касательной перед созданием изображения текстуры.

@WestLangley Мне нравится этот тест только потому, что это лучшее, что я видел, то есть единственное. Я буду счастлив использовать любую другую тестовую модель, на которую мне укажут.

Также сюжет утолщается: исходный тест - это двусторонний материал. Из-за # 17804 решил попробовать как одностороннюю. По умолчанию это все еще неправильно, но теперь я получаю правильный ответ, когда устанавливаю normalScale.y = -1:
NormalTangentTestFrontNegY
По крайней мере, я надеюсь, что мы можем согласиться с тем, что изменение двухстороннего не должно влиять на рендеринг лицевой стороны?

@emackey Другая тестовая модель, которая могла бы быть полезной, я думаю, будет блестящим кубом со сваренными нормалями и соответствующей картой нормалей, предназначенной для придания ему формы куба, а не закругления. Вероятно, две версии, одна с поставляемыми касательными, а другая без. К сожалению, мне не хватает авторских навыков, чтобы сделать это самому. Все, что я могу предложить, - это большое спасибо, если вы сделаете это за нас: молитесь:

@emackey Спасибо за всю вашу работу над этим. Я очень это ценю. Я понимаю все различные проблемы, которые могут возникнуть с художниками, и проблемы, которые необходимо преодолеть.

Возможно, вы захотите поработать с @elalish и предоставить любые модели glb, которые он запрашивает. Я надеюсь, это поможет нам понять.

@elalish Мы уже обращались к этим проблемам ранее. В какой-то момент у меня создалось впечатление, что все работает. Если есть простой тестовый пример, я могу использовать bisect чтобы определить, где что-то сломалось.

блестящий куб со сваренными нормалями и соответствующей картой нормалей, призванной придать ему форму куба, а не закругления.

Готово: normal_map_flat.zip . Я взял пример касательных, написанный командой Draco, и создал дополнительную версию без атрибута касательной.

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

Я думаю, мы достигли состояния, когда все работает, _если_ модель включает касательные. Если нет, то обычно все в порядке, но возможны некоторые крайние случаи, особенно вокруг УФ-швов. В этом случае мы советуем пользователям добавлять касательные. Или, как упомянул @emackey в https://github.com/mrdoob/three.js/issues/11438#issuecomment -507027586, возможно, нам следует восстановить флип normalScale.y *= -1 в GLTFLoader, только в тех случаях, когда сетка опускает касательные к вершинам.

@donmccurdy Спасибо. Сегодня у меня нет времени для этого вопроса, но я все еще борюсь с плоскими гранями куба. Если вы отредактируете свою модель, чтобы получить блестящую поверхность ( metallicFactor: 1, roughnessFactor: 0.1 ), вы увидите, что отражения на сторонах куба немного плавают вокруг.

Я наблюдаю тот же эффект на своей тестовой модели. Хуже того, это другой эффект, если я выполняю обычное запекание в Substance Painter и запекаю его в Blender Cycles. Каждая программа запекает его так, чтобы он соответствовал своему собственному окну просмотра, но он не идеально плоский при загрузке в другую программу, даже без использования glTF в миксе. Это очень близко, но на такой ровной поверхности малейшие отличия превращают его в забавное зеркало, причем не в лучшую сторону.

Я думаю, что вижу тонкую разницу в способе интерполяции векторов нормалей (или пространства TBN) между вершинами на поверхности треугольника в SP, Blender и различных движках WebGL. Я использовал GIMP, чтобы выполнить "различие" запекания SP и запекания Blender, и оно получилось черным (идентичные значения RGB) в каждой вершине, но пространство между вершинами показывает закрученные различия очень слабой интенсивности.

Я ожидал бы тонких забавных эффектов, но не того, что я получаю сейчас (версия без касательных):
image
Версия с касательными на самом деле ничем не лучше, что заставляет меня задуматься, действительно ли это действительный glTF:
image
@emackey Считаете ли вы себя квалифицированным, чтобы сказать нам, действительно ли одна или обе из этих моделей, предоставленных @donmccurdy , действительны для glTF? Если да, то я думаю, что у нас большая проблема.

Этот конкретный куб является настолько ярким примером, что я действительно не знаю, что сказать, и можно ли ожидать от физически реалистичных отражений. Карты нормалей предназначены для добавления деталей, таких как неровности и вмятины, а не для деформации всей поверхности меша. Просто так получилось, что это очень эффективный способ проверить правильность считывания или создания касательных. Я знаю, что изменения normalScale.y *= -1 никогда не было достаточно, чтобы исправить это; это был один из примеров, который побудил нас в первую очередь поддерживать сохраненные касательные.

Отражения тоже выглядят дико в BabylonJS:
Screen Shot 2019-10-23 at 4 00 02 PM

Если единственная выявленная проблема связана с NormalTangentTest, и ни один пользователь не представил модели, которые на практике отображаются некорректно, возможно, нам следует отложить внесение изменений здесь?

Я все еще в порядке с восстановлением множителя normalScale.y *= -1 , но отсутствие примеров проблемы кажется признаком того, что проблема незначительна, а не указанием на то, что нам нужно создать такие крайние примеры.

Если единственная выявленная проблема связана с NormalTangentTest, и ни один пользователь не представил модели, которые на практике отображаются некорректно, возможно, нам следует отложить внесение изменений здесь?

Исправление: https://github.com/mrdoob/three.js/issues/17804 предполагает, что что-то действительно могло регрессировать с двусторонними материалами. Кажется, это заслуживает дальнейшего изучения, хотя для простоты и здравого смысла, возможно, мы должны пока оставить Проклятый куб в покое. 😇

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