Сказка

Я обнаружил, что MaterialBillboardComponent неправильно вычисляет векторы TBN при построении своего VertexBuffer. И это приводит к неправильному освещению для MaterialBillboardComponent. Так же, как показано выше.

Как воспроизвести это? Вы можете разместить MaterialBillboard далеко от источника (0,0,0), например (6000, 0,0), тогда вы обнаружите, что освещение выглядит довольно странно. Поэтому я поставил рядом еще один статический меш (плоскость) и сравнил разницу.

Наблюдение

Затем я переключился в режим просмотра World Normal и увидел, что два вектора нормалей сильно различаются, как показано ниже. И одна интересная вещь заключается в том, что нормаль MaterialBillboard будет приближаться к нормали меша по мере увеличения масштаба. (Вид в сторону Положительного-Y)

Затем я повернулся и посмотрел в сторону Negative-Y. Когда я крутил, WorldNormal MaterialBillboard почти не изменился (как будто это локальная нормаль). И то же самое здесь, нормаль MaterialBillboard будет приближаться к нормали меша по мере увеличения масштаба.

И неправильность становится более очевидной, если я использую карту нормалей (и выбираю использовать нормали касательного пространства). MaterialBillboard просто выглядит очень неправильно. Он будет появляться даже тогда, когда рекламный щит находится рядом с границей окна просмотра.

Расследование

После того, как я изучил код в MaterialBillboardComponent.cpp, GetDynamicMeshElements():

Исходный LocalCameraForward выдает странное значение и больше не перпендикулярен Up & Right. На самом деле вы можете найти, что все три вектора даже не нормализованы.

Исправить

Поэтому я изменяю это, заставляя его быть перекрестным произведением Вверх и Вправо (как 4-я строка). Теперь все выглядит правильно, но тангенс и бинормаль перевернуты.

Поэтому я также изменяю SetVertexTangents(), устанавливая для TangentX/Y значение -Вверх/Вправо вместо Вправо/Вверх, как показано ниже. Теперь это выглядит правильно.

Окончательное элегантное исправление

Я подтвердил это на UDN, и на самом деле это ошибка. А еще мне предложили более элегантную модификацию. И обратите внимание, что в SetVertexTangents() вам нужно использовать ”-TangentX” .

Размер рекламного щита

Последнее, что нужно изменить, касается размера. Первоначально LocalCamraRight/Up не нормализованы, и из-за того, что VertexPosition() является производным от WorldSizeX/Y и LocalCameraRight/Up. Таким образом, WorldSizeX/Y масштабируются заранее, чтобы «отменить» размер вектора при построении вершин.

Но теперь TangentX, Y, Z нормализованы, поэтому нам не нужно делать этот «/CameraRight.Size()» при вычислении WorldSize.

Пулл-реквест

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