Pull to refresh

Comments 24

Когда у меня пару лет назад возникла похожая задача — изменить шейдер ландшафта, жутко мешала необходимость заменять стандартные шейдеры в Hidden/TerrainEngine/..., т.е. то, что шейдер нельзя заменить динамически (на одной сцене мой, на другой — стандартный). По сути, это какой-то недокументированный хак. Это по прежнему так и работает или в последних версиях Unity что-то изменили?
Шейдер можно заменить только полностью для всего проекта, динамически менять его для каждой сцены по прежнему нельзя.
А как насчёт пройтись в скрипте по нужным объектам и поправить материалы?
Ландшафту в юнити нельзя менять материал
А почему не сделать так?
1) Сливаем смешанные диффузы в рендер таргет
2) Сливаем смешанные нормалы в другой рендер таргет
3) Рисуем ландшафт с экранным фетчем диффуз и нормал рендер таргета
Не совсем понимаю о чем вы
1) делаем 2 рендер таргета покрывающих экран
2) 1 проход — мешаем только диффуз текстуры и записываем в рендер таргет 1
3) 2 проход — мешаем только нормал текстуры и записываем в рендер таргет 2
4) 3 проход — делаем финальный проход где диффуз и нормал цвета фетчим из этих текстур.

Вы не забывайте, где всё это происходит. В своём рендере такое сделать не проблема, а вот от Unity я бы такой свободы не ожидал.
Работает для SM 2.0 и с Flash тоже не будет проблем
Если будет время попробую сделать так.
Несколько вопросов/замечаний:
o.Normal += lerp(fixed3(0.5,0.5,1), n2, clamp(splat_control.b + 0.3,0,1));

А нормализовывать её мы не будем? Если UnpackNormal — функция Unity, то она почти наверняка возвращает единичную нормаль, а значит и «o.Normal» от нас ждут единичной.

// A general tangent estimation
fixed3 T1 = float3(1, 0, 1);
fixed3 Bi = cross(T1, v.normal);
fixed3 newTangent = normalize(cross(v.normal, Bi));

В каком пространстве всё это считается: объектном или мировом?
Почему в качестве опорного тангенса выбран (1,0,1)? По идее, раз Unity этой информации не предоставляет, то Вам нужна какая-то договорённость с дизайнером. Скажем, U направлена по мировой/локальной оси X, или что-то в этом духе. Эта договорённость и определяет опорный тангенс. Не верю, что вы договорились до (1,0,1) ну никак:)

Альтернативно, Вы можете вывести тангенс и битангенс из pixel derivatives, если Unity позволит Вам:
1. Подставить тангенс уже в пиксельном шейдере (чего уж там, можно и UnpackNormal самому переписать).
2. Использовать инструкции dFdx, dFdy (в терминологии GL). Уверен, что не все устройста, на которых работает Unity, эти инструкции поддерживают.

В общем, получается, что нормали произвольной длины и в неконтролируемо-повёрнутом пространстве. Разве что для шума годятся, не более…
Насколько я знаю далее оно в недрах ShaderLab нормализуется.
На всякий случай сейчас добавлю нормализацию в коде.
Функция расчета тангенса взята из другого шейдера ландшафта и прекрасно работает
Договориться с дизайнером о чем? Мех в данном случае строит юнити.
В общем, получается, что нормали произвольной длины и в неконтролируемо-повёрнутом пространстве. Разве что для шума годятся, не более…

Зачем писать про шум если вы не знакомы с юнити и тем более не видели шейдер в работе?
Вот это тоже повеселило:
o.Normal = lerp(fixed3(0.5,0.5,1), n1, clamp(splat_control.r + 0.3,0,1));
Нормаль — это единичный вектор перпендикулярный к поверхности. И так как нам нужно ее плавно уменьшать, мы не можем просто умножать ее на какой-то коэффициент. Для решения этой задачи я интерполирую текущую нормаль в т.н. «нулевую нормаль», при которой на текстуре не будет никакого рельефа.

Ваша «нулевая нормаль» мало того что не «нулевая», так даже и не единичная :) Должно быть (0,0,1). И впредь, если копируете чужой код — ссылайтесь на него в комментариях к коду, а то все будут думать, что это вы свой код не понимаете.

Насколько я знаю далее оно в недрах ShaderLab нормализуется.

Это возможно, но не имело бы смысла, ибо вредит производительности. UnpackNormal точно возвращает единичную нормаль (в пространстве TBN), так что тратить целую инструкцию нормализации «на всякий случай» никто не будет.

Функция расчета тангенса взята из другого шейдера ландшафта и прекрасно работает

Ага, и следующий, кто скопирует Ваш код, тоже будет так писать. Тяп-ляп, copy-paste, и вуаля — работает! Это не подход в 3D-графике, и уж тем более не для тех, кто выставляет свой код на суд общественности.
Я вижу, что тангенс неверный, и даже могу объяснить выбор (1,0,1) вместо, скажем (1,0,0). Просто при (1,0,0) высока вероятность совпасть с нормалью, на чём код успешно рухнет (или произведёт на свет NaN и Inf значения). Естественно, (1,0,1) от этого тоже ничего не защитит, просто вероятность меньше :) Это то же самое, что объяснять, почему самоубийцы прыгают с крыши высоких домов, а не низких: логика есть, но в целом подход неверный (лучше совсем не самоубиваться).

Договориться с дизайнером о чем? Мех в данном случае строит юнити.

Значит нужно понять, куда у меха Unity направлена U координата.

Зачем писать про шум если вы не знакомы с юнити и тем более не видели шейдер в работе?

То есть по Вашему, раз песочек сверкает при повороте камеры, то шейдер работает? Я делаю суждения из кода и скринов, которые Вы предоставили. Ваша карта нормалей — классический шум нормалей (песок), так что, конечно, на её ориентацию можно забить. Вот если бы показали что-либо вменяемое — там и посмотрели бы.
Я бы не стал выкладывать шейдер не протестировав его. Тестил на нормалях скал, досок и все было замечательно. К сожалению сейчас под рукой нет юнити, чтобы сделать скрины.
Расчет тангенсов взят из другого проверенного шейдера с офф. форума, которым я долго пользовался до этого (ссылка на него в начале поста).
Значит нужно понять, куда у меха Unity направлена U координата.

По идее U всегда направлена по X.
Расчет тангенсов взят из другого проверенного шейдера с офф. форума, которым я долго пользовался до этого (ссылка на него в начале поста).

Не вижу я там официального форума, а виже блог некого «sixtimesnothing».

По идее U всегда направлена по X.

А значит и тангенс будет ...? (1,0,1)?
Садитесь, незачёт.

Пожалуй, слишком я Вас сильно критикую… В интернете практически нет абсолютно верных реализации normal/parallax mapping с указанием ограничений и подробным описанием логики. А у Вас всё-таки первый пост… И главное — чтобы смотрелось красиво, так ведь? Понимаю, но Вы всё же задумайтесь над моими замечаниями, если хотите понять, как Ваш код (не-) работает.
Не вижу я там официального форума, а виже блог некого «sixtimesnothing».

Вот его пост на офф. форуме

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

Да, форум Unity, но это не подтверждает правильность кода. Автор же не разработчик Unity, а такой же как мы с вами.

Примеров реализации расчета тангенсов в коде очень много, но в шейдере ни одного.

Обратите внимание на этот вопрос (и мой ответ к нему).

Собственно, вычислить tangent из вершинного шейдера нельзя. Так что Ваша задача не вычислить, а воспроизвести его из той самой «договорённости», минуя вершинные атрибуты. Из пиксельного — можно, но с потерей некоторой доли гладкости вдоль рёбер (смотрите алгоритм по ссылке выше). Правильно, конечно, генерировать тангенсы во время экспорта.

Что посоветовать? Давайте хотя бы использовать правильный тангенс:
fixed3 T1 = float3(1, 0, 0);
if (dot(T1,v.normal) > 0.99) {
T1 = float3(0,1,0); //workaround
}
fixed3 Bi = cross(T1, v.normal);
...

В ближайшее время разберусь с этим вопросом и поправлю процедуру. Спасибо за пример.
Давно я уже не копался в Unity3D, еще со второй версии, а все еще в ней сложно сделать вменяемые вещи. Ну вот кто в наше время делает ландшафт текстурным сплаттингом в несколько проходов? Бъем сетку чаще, коэффициенты смешивания в вершинных атрибутах — можем мешать за проход гораздо больше 4 текстур, да еще и в реальном времени можно этот сплаттинг перестраивать.

И небольшое замечание по поводу названия темы: у вас написано Terrain Bump Specular Shader, но в статье вы используете normalmap, это все же несколько разные техники, хоть и похожие.
В Юнити все шейдера с нормал мапой называются с приставкой Bumped, поэтому чтобы он не выделялся среди остальных, я назвал его по той же схеме.
Да и честно говоря, terrain в юнити — еще та тормозячка, недавно под андроид пытались его оптимизировать — никак. Низкий фпс и все. Пришлось через модели делать.
Уменьшение разрешения тоже не помогло?
Sign up to leave a comment.

Articles