add block material shaders

- 'shader' property of block materials: shaders/materials/<name>.glslv, .glslf with material_vertex / material_fragment hooks and #param uniforms
- material shaders code is included into main, translucent and shadows programs through generated headers, no extra draw calls
- chunk vertex normal.w byte replaced with 'flags': bit 7 - emission flag, bits 0-6 - material shader index (vertex format size is not changed)
- doc/*/block-materials.md
This commit is contained in:
lookibed 2026-10-02 06:33:01 +03:00
parent f90750c066
commit 81489a13cf
33 changed files with 761 additions and 53 deletions

97
doc/en/block-materials.md Normal file
View file

@ -0,0 +1,97 @@
# Block materials
A material is a common kit of properties applied to groups of blocks.
Material definitions are located in the `block_materials/` folder of a content pack.
A block refers to a material with the `material` property in the `pack:material_name` format
(see [block properties](block-properties.md)).
Example (`block_materials/glass.json`):
```json
{
"steps-sound": "steps/glass",
"place-sound": "blocks/glass_place",
"break-sound": "blocks/glass_break",
"sound-absorption": 0.3
}
```
## Properties
| Name | Type | Description |
|------------------|--------|----------------------------------------------------------|
| steps-sound | string | steps sound |
| place-sound | string | block placing sound |
| break-sound | string | block breaking sound |
| hit-sound | string | block hitting sound (`steps-sound` by default) |
| sound-absorption | number | ambient sounds absorption when the camera is in the block|
| shader | string | material shader name (see below) |
## Material shaders
A material shader allows to customize blocks and entities rendering without replacing the engine shaders.
Material shader code is included in the world shaders (opaque, translucent and shadows passes of blocks
and the entities program), so blocks with different materials are still rendered within a single draw call per chunk.
An entity uses the shader of its `material` property (see [entity properties](entity-properties.md)).
The material may be overridden at runtime with `rig:set_material` (see [skeleton](scripting/ecs.md)).
The `shader` property specifies the name of a shader located in the `shaders/materials/` folder of a pack.
Each of two files is optional, but an existing file must define its function:
- `shaders/materials/name.glslv` - vertex stage, must define the function:
```glsl
// position - vertex world position
vec3 material_vertex(vec3 position)
```
The function may also modify the vertex normal `a_realnormal` (world space),
for example when displacing a surface.
- `shaders/materials/name.glslf` - fragment stage, must define the function:
```glsl
// color - block texture color before lighting applied
vec4 material_fragment(vec4 color)
```
All the world shader uniforms (`u_timer`, `u_cameraPos`, `u_dayTime`, etc.),
vertex attributes (`v_position`, `v_texCoord`, `v_light`, `v_normal`) in the vertex stage and
varyings (`a_texCoord`, `a_modelpos`, `a_realnormal`, `a_skyLight`, etc.) in the fragment stage are available.
The same material shader code is compiled into all the programs (blocks, shadows and entities), so only
the common interface declared in `shaders/lib/world_vertex_header.glsl`, `world_fragment_header.glsl`
and `world_uniforms.glsl` may be used.
Shader parameters are declared with the `#param` directive, the same way as in [post-effects](scripting/builtins/libgfx-posteffects.md),
and controlled from scripts with the [gfx.materials](scripting/builtins/libgfx-materials.md) library.
Example (`shaders/materials/leaves.glslv`):
```glsl
#param float p_amplitude = 0.03
#param float p_speed = 1.2
vec3 material_vertex(vec3 position) {
float phase = position.x * 0.7 + position.z * 1.1 + position.y * 0.4;
position.x += sin(u_timer * p_speed + phase) * p_amplitude;
return position;
}
```
Materials with the same `shader` share the shader code and its params.
Hook functions and params names are made unique for every shader automatically,
so different shaders may declare the same params.
Other functions and global variables of all the material shaders are compiled
into one program, so their names must be unique (use a prefix).
> [!NOTE]
> Compilation errors refer to a material shader by its index: `3:12` means line 12
> of the shader number 3. The indices are printed to the log on content loading,
> `128` is the generated dispatch code, `0` is the engine shader.
Limitations:
- up to 127 material shaders may be loaded at the same time
- array params are not supported, params names must not start with `_`
- the same param declared in both stages must have the same type
- vertex displacement must be continuous (depend on the vertex position only),
otherwise gaps between faces appear; it must not depend on `u_cameraPos`,
because the shadows pass is rendered from the light's point of view
- `texture()` calls inside `material_fragment` have undefined derivatives
at borders between materials, use `textureLod` there

View file

@ -81,7 +81,7 @@ until the block is destroyed or the camera moves away a certain distance.
### Material - *material*
Defines the name of the block's material in the format `pack:material_name`, which affects the selection of block interaction sounds.
Material definitions are located in /block_materials.
Material definitions are located in /block_materials (see [block materials](block-materials.md)).
## Variants

View file

@ -89,6 +89,7 @@ Don't be intimidated by the following text, as a minimal pack only requires `pac
- `textures/` - Textures
- `shaders/` - Shaders
- `effects/` - Post-processing effects
- `materials/` - Block material shaders
- `sounds/` - Sounds and Music
- `texts/` - Localization files
- GUI:

View file

@ -7,6 +7,7 @@
- [Assets preloading](assets-preload.md)
- [Audio](audio.md)
- [Block materials](block-materials.md)
- [Block models](block-models.md)
- [Block properties](block-properties.md)
- [Console](console.md)

97
doc/ru/block-materials.md Normal file
View file

@ -0,0 +1,97 @@
# Материалы блоков
Материал - общий набор свойств, применяемых к группам блоков.
Определения материалов расположены в папке `block_materials/` контент-пака.
Блок ссылается на материал свойством `material` в формате `пак:имя_материала`
(см. [свойства блоков](block-properties.md)).
Пример (`block_materials/glass.json`):
```json
{
"steps-sound": "steps/glass",
"place-sound": "blocks/glass_place",
"break-sound": "blocks/glass_break",
"sound-absorption": 0.3
}
```
## Свойства
| Имя | Тип | Описание |
|------------------|--------|------------------------------------------------------------|
| steps-sound | string | звук шагов |
| place-sound | string | звук установки блока |
| break-sound | string | звук разрушения блока |
| hit-sound | string | звук удара по блоку (по умолчанию - `steps-sound`) |
| sound-absorption | number | поглощение окружающих звуков, когда камера внутри блока |
| shader | string | имя шейдера материала (см. ниже) |
## Шейдеры материалов
Шейдер материала позволяет настроить отрисовку блоков и сущностей без замены шейдеров движка.
Код шейдера материала включается в мировые шейдеры (проходы непрозрачных, полупрозрачных блоков, теней
и программу сущностей), поэтому блоки с разными материалами по-прежнему отрисовываются одним вызовом на чанк.
Сущность использует шейдер материала из своего свойства `material` (см. [свойства сущностей](entity-properties.md)).
Материал можно переопределить в рантайме через `rig:set_material` (см. [скелет](scripting/ecs.md)).
Свойство `shader` указывает имя шейдера, расположенного в папке `shaders/materials/` пака.
Каждый из двух файлов опционален, но существующий файл обязан определять свою функцию:
- `shaders/materials/имя.glslv` - вершинная стадия, должен определять функцию:
```glsl
// position - мировая позиция вершины
vec3 material_vertex(vec3 position)
```
Функция также может изменять нормаль вершины `a_realnormal` (мировые координаты),
например, при смещении поверхности.
- `shaders/materials/имя.glslf` - фрагментная стадия, должен определять функцию:
```glsl
// color - цвет текстуры блока до применения освещения
vec4 material_fragment(vec4 color)
```
Доступны все uniform-переменные мировых шейдеров (`u_timer`, `u_cameraPos`, `u_dayTime` и т.д.),
атрибуты вершин (`v_position`, `v_texCoord`, `v_light`, `v_normal`) в вершинной стадии и
varying-переменные (`a_texCoord`, `a_modelpos`, `a_realnormal`, `a_skyLight` и т.д.) во фрагментной.
Один и тот же код материала компилируется во все программы (блоки, тени и сущности), поэтому можно
использовать только общий интерфейс, объявленный в `shaders/lib/world_vertex_header.glsl`,
`world_fragment_header.glsl` и `world_uniforms.glsl`.
Параметры шейдера объявляются директивой `#param`, так же, как в [пост-эффектах](scripting/builtins/libgfx-posteffects.md),
и управляются из скриптов библиотекой [gfx.materials](scripting/builtins/libgfx-materials.md).
Пример (`shaders/materials/leaves.glslv`):
```glsl
#param float p_amplitude = 0.03
#param float p_speed = 1.2
vec3 material_vertex(vec3 position) {
float phase = position.x * 0.7 + position.z * 1.1 + position.y * 0.4;
position.x += sin(u_timer * p_speed + phase) * p_amplitude;
return position;
}
```
Материалы с одинаковым `shader` используют общий код шейдера и его параметры.
Имена функций-хуков и параметров автоматически делаются уникальными для каждого шейдера,
поэтому разные шейдеры могут объявлять одинаковые параметры.
Остальные функции и глобальные переменные всех шейдеров материалов компилируются
в одну программу, поэтому их имена должны быть уникальными (используйте префикс).
> [!NOTE]
> Ошибки компиляции ссылаются на шейдер материала по его номеру: `3:12` означает строку 12
> шейдера номер 3. Номера печатаются в лог при загрузке контента,
> `128` это сгенерированный код диспетчера, `0` шейдер движка.
Ограничения:
- одновременно может быть загружено до 127 шейдеров материалов
- параметры-массивы не поддерживаются, имена параметров не могут начинаться с `_`
- один и тот же параметр в обеих стадиях должен иметь одинаковый тип
- смещение вершин должно быть непрерывным (зависеть только от позиции вершины),
иначе между гранями появляются щели; оно не должно зависеть от `u_cameraPos`,
так как проход теней рисуется с точки зрения источника света
- у вызовов `texture()` внутри `material_fragment` не определены производные
на границах материалов, используйте там `textureLod`

View file

@ -82,7 +82,7 @@
### Материал - *material*
Определяет имя материала блока в формате `пак:имя_материала`, что влияет на выбор звуков взаимодействия с блоком.
Определения материалов расположены в /block_materials.
Определения материалов расположены в /block_materials (см. [материалы блоков](block-materials.md)).
## Варианты

View file

@ -91,6 +91,7 @@ print(file.read("пак:package.json")) -- выведет содержимое p
- `textures/` - текстуры
- `shaders/` - шейдеры
- `effects/` - эффекты пост-обработки
- `materials/` - шейдеры материалов блоков
- `sounds/` - звуки и музыка
- `texts/` - файлы локализации
- GUI:

View file

@ -11,6 +11,7 @@
- [Движок генерации мира](world-generator.md)
- [Консоль](console.md)
- [Контент‐паки](content-packs.md)
- [Материалы блоков](block-materials.md)
- [Модели блоков](block-models.md)
- [Предзагрузка ассетов](assets-preload.md)
- [Рекомендации по использованию движка](engine-use-recommendations.md)