3D shader: материал и параметры
PBR-окраска склонов, обычные и instance uniform, независимый материал и сохранение .rdata.
Использовать ту же сцену
Начните с первого урока или скачайте готовый проект. Оба рельефных меша используют один ShaderMaterial. Правый получает surface_tint через instance uniform.
Рассчитать свойства поверхности
fragment() из Terrain.reckfellshader смешивает low_color и rock_color по крутизне, добавляет светлый цвет вершинам и полосы по высоте. Результат записывается в ALBEDO. ROUGHNESS берётся из surface_roughness, METALLIC=0.02 оставляет поверхность почти неметаллической.
NORMAL уже рассчитана в vertex(). slope передаётся оттуда через varying: в fragment() встроенная нормаль пространственного shader находится в другом пространстве, поэтому нельзя бездумно использовать NORMAL.y как мировую крутизну склона.
source_color нужен цветовым uniform, чтобы движок корректно обрабатывал цветовое пространство. Heightmap содержит числовые данные, поэтому её sampler не помечен как source_color. Не добавляйте gamma-коррекцию ко всем входам подряд.
Разделить три вида изменения
| Что изменить | Путь | Что ещё изменится |
|---|---|---|
| Общую высоту обоих образцов | TerrainMaterial.SetShaderParameter("height_scale", value) | все меши с этим материалом |
| Только оттенок правого меша | Right.SetInstanceShaderParameter("surface_tint", Color) | другие меши не получают этот override |
| Любой обычный uniform только справа | MakeRightIndependent(), затем правка возвращённого материала | левый сохраняет исходный материал |
Обычный uniform объявлен как uniform, индивидуальный — как instance uniform. SetInstanceShaderParameter не заменяет SetShaderParameter для произвольного имени. В примере Shader.GetShaderUniformList перечисляет обычные material uniform; instance/global параметры в этот список не входят.
Справа независимый материал с height_scale=0; слева сохранён исходный рельеф:
MakeRightIndependent() вызывает Duplicate() у материала и назначает копию правому мешу. Shader остаётся общим ресурсом. Это означает независимые значения параметров, а не независимую копию shader-кода. Изменение самой программы — отдельное действие.
Понять default, Nil и опечатку
| Действие | Getter и результат |
|---|---|
| height_scale не задан на материале | GetShaderParameter возвращает Nil; shader использует default 0.9 |
| SetShaderParameter("height_scale", 0f) | сохранён float 0, рельеф плоский |
| SetShaderParameter("height_scale", default(Variant)) | override удалён, визуально вернулся shader-default |
| Записать Height_scale вместо height_scale | значение может читаться из кеша, но объявленный uniform не изменился |
| Снять surface_tint через Nil у правого меша | GetInstanceShaderParameter возвращает shader-default White |
Это проверенные разные контракты двух getter. Для диагностики сначала проверьте регистр имени, объявление и назначенный ресурс, затем чтение значения и кадр. Одно успешное чтение кеша не подтверждает работающий shader.
Сохранить настройки материала
ResourceSaver.Save(material, "user://TerrainMaterial.rdata") сохраняет ресурс; затем загрузите его через ResourceLoader.Load<ShaderMaterial>. Проверяйте Error от Save и существование результата Load. user:// подходит для данных работающего приложения; asset:// в экспортированной игре не следует считать доступным для записи.
В нативной проверке сохранены height_scale=1.2, ссылка на shader и встроенная ImageTexture карты высот. После загрузки параметр, размер текстуры 256×256 и реальное смещение сохранились. Материал продолжает зависеть от доступного Terrain.reckfellshader: сохранение .rdata не является упаковкой всей игры в один файл.
Проверить результат
| Симптом | Причина, которую нужно проверить |
|---|---|
| Правка одного материала изменила оба меша | Они используют один ShaderMaterial |
| Копия материала не изменила цвет | Изменена ли назначенная копия; не перекрывает ли цвет instance tint |
| Shader-параметр читается, эффекта нет | Опечатанное имя, неверный тип, не тот материал или uniform не участвует в формуле |
| Getter вернул Nil | У material uniform может не быть явного override; это не обязательно ошибка |
| После загрузки отсутствует рельеф | Доступны ли shader, height_map и сохранённый height_scale |
Проверены текущий Forward+/Vulkan и статические кадры. Анимация, все типы uniform, динамическая смена shader-программы и другие renderer этим примером не подтверждены.