Я не уверен, обновляли ли вы недавно код сглаживания, так как я использую более старую версию, но после того, как я нашел хороший способ сглаживания кругов, нарисованных шейдером, я захотел попробовать его и на вашем тексте. , потому что текст основан на SDF, а сглаживание круга также основано на расстоянии.
В моей текущей версии Тройки вы делаете return length(fwidth(vTroikaGlyphUV * vTroikaGlyphDimensions)) * 0.5;
для расстояния aa. У этого есть артефакт, заключающийся в том, что при просмотре под углом крайний левый и крайний правый края получают несколько видимое размытие:
Я изменил его на скаляр; расстояние, как в моем коде круга: return fwidth(distance) * 0.5;
С расстоянием, переданным из troikaGetFragDistValue
следующим образом: float distance = troikaGetFragDistValue();
float aaDist = troikaGetAADist(distance);
Делая это таким образом, я не получаю артефакт размытия:
Коэффициент 0.5
можно увеличить для более плавного сглаживания. Например, 0.8
:
Я подумал, может быть, вы, как и я, не знали об этом методе, поэтому решил поделиться им. Однако в моей «реализации» есть некоторые странные артефакты (см. ниже), и, возможно, именно поэтому вы выбрали другой метод. Кроме того, я не совсем уверен, как вы используете переменную aaDist в коде шейдера, так что вы можете быть лучше подготовлены к реализации этого. Может быть, есть какой-то код, который следует изменить или удалить, например, из-за этого изменения, который мог бы еще больше улучшить мою «реализацию».
Я нашел этот метод в сообщении bgolus здесь: https://forum.unity.com/threads/antialiasing-circle-shader.432119/ , где есть дополнительная информация. Он также говорит, что вы можете сделать, например, length(vec2(dFdx(distance), dFdy(distance)))
вместо fwidth(distance)
для еще большей точности, хотя я не уверен, что это незначительно или нет.
Спасибо за предложение! Я обязательно посмотрю на это, так как я заметил эти размытые края и под наклонными углами и хотел бы их устранить.
Теоретически я думаю, что и изменение в distance
, и изменение в vTroikaGlyphUV * vTroikaGlyphDimensions
должны быть эквивалентны, поскольку они оба представляют расстояние в единицах пространства шрифта, но должна быть какая-то тонкая разница, которую я упущен из виду. Если я смогу избежать артефактов, которые вы показали, я буду рад интегрировать ваше изменение. :)
Здорово! Изменение так же просто, как эта одна строка (и передача этого аргумента расстояния для его размещения). Если вам все еще нужен необработанный код, я могу отправить его завтра, когда буду работать.
Теоретически я думаю, что и изменение расстояния, и изменение vTroikaGlyphUV * vTroikaGlyphDimensions должны быть эквивалентны, поскольку они оба представляют расстояние в единицах пространства шрифта.
Я не совсем понимаю, как производные будут одинаковыми. distance
— это расстояние SDF, которое я предполагаю, но другое — масштабированное положение uv. Я не смотрел код и то, как они сравниваются, но мне кажется, что их производные должны отличаться. Насколько я знаю, fwidth
просто принимает разницу определенного входного значения, переданного в качестве аргумента, с теми же конкретными входными значениями в соседних фрагментах, что возможно, потому что соседние фрагменты выполняются одновременно и параллельно. Ранее сегодня я провел тест с gl_FragColor.rgb = vec3(fwidth(gl_FragColor.x + gl_FragColor.g + gl_FragColor.b));
, чтобы увидеть, отображаются ли края, как при обнаружении краев/фильтре Собеля, чтобы попытаться немного подтвердить этот факт, и это произошло.
Спасибо за дискуссию, иногда эта штука ломает мне мозг. ;)
Когда я сказал, что они «эквивалентны», я имел в виду, что они оба представляют расстояние в одних и тех же единицах, но вы правы, они не совсем одинаковы.
Поддерживая, здесь нам нужна _потенциальная_ скорость изменения между фрагментами. Использование изменения в переменной distance
, которое вы предлагаете, часто будет точным для этого, но в некоторых случаях оно будет очень неточным. Это связано с тем, что SDF, из которого выбирается это значение, является _неоднородным_; он изгибается и меняет направление изменения глифа. Поэтому производная distance
между соседними фрагментами может оказаться слишком маленькой, даже нулевой, например, когда поле расстояния переключается с увеличения на уменьшение на полпути между путями глифов, или слишком большой, например, при отображении текста. при малых размерах, а сетка фрагментов перекрывает SDF в непредсказуемых местах. Я подозреваю, что это объясняет, по крайней мере, некоторые артефакты, которые вы видите.
Итак, как мы можем определить _потенциальную_ скорость изменения, не используя distance
? Что ж, эта «масштабированная ультрафиолетовая позиция», как вы ее называете, по сути является координатой x/y внутри прямоугольника глифа с использованием тех же единиц измерения, что и distance
. Производная от этого x/y дает нам скорость потенциального перемещения между фрагментами. В целом это дает лучший результат, чем использование distance
, потому что он основан на _равномерной_ скорости изменения по всему глифу, и поэтому мы не получаем артефактов, и он более точен при небольших размерах.
Но, как вы видели, она ломается под косыми углами; в этих случаях скорость потенциального изменения x/y по вертикали сильно отличается от скорости по горизонтали. И поэтому мы в конечном итоге используем одно значение для потенциальной скорости изменения, которое слишком велико в одном направлении и слишком мало в другом, что дает размытые и/или прерывистые линии в зависимости от фактического направления изменения SDF в этом фрагменте.
Так что да, в наклонном случае определенно есть место для улучшения, но простое использование производной от distance
само по себе недостаточно. Я открыт для идей, чтобы улучшить это, конечно. Одной из возможностей может быть попытка определить сценарий (большой размер текста под косым углом, близко к пути) и использовать производную distance
только в этом одном случае.
Да, об этом сложно думать, ха-ха. Я вижу, что поле расстояний менее гладкое, да.
Эти глючные пиксели могут быть просто потому, что у фрагментов есть какие-то странные значения расстояния.
Издалека это не невероятно изменчиво, но вы определенно можете видеть, что ультрафиолетовые лучи стали лучше. Возможно, будет хорошо работать интерполяция между переменной расстояния и UV, зависящими от расстояния до камеры; например, выбрать больше fwidth (расстояние), когда близко, и больше fwidth (uv), когда далеко.
Для сравнения (не снимал оба с точно такой же позиции и ориентации камеры, но я думаю, что разница хорошо видна):
Расстояние (коэффициент 0,8):
УФ:
Я заметил, что эта модификация значительно улучшает результат для пользовательских преобразований текста. Вот некоторый текст, измененный, чтобы следовать кривой, используя createDerivedMaterial
( см. эту технику ). Здесь используются текущие шейдеры troika-three-text:
Вот тот же снимок экрана, но с модификацией @asbjornlystrup на troikaGetAADist
:
На втором кадре видно чрезвычайно растянутое «ВЕЛИКОЛЕПНО!» немного четче.
Как ни странно: я также обнаружил, что настройка константы до 0,25 (с 0,5) также дает хороший четкий край:
return length(fwidth(vTroikaGlyphUV * vTroikaGlyphDimensions)) * 0.25;
Спасибо @canadaduane , я определенно вижу улучшение растянутых частей. Я также вижу уродливые артефакты, появляющиеся между буквами L в HELLO, которые нам обязательно нужно выяснить, прежде чем принимать это изменение.