render_wallpaper.py drives headless Firefox frame by frame (four at a time, resuming where it stopped), then ffmpeg. Thirty seconds at 30 fps is exactly one plasma cycle, so frame 900 meets frame 0 and the loop has no seam. plasma-plugin/dev.emil.video is a minimal Plasma 6 video wallpaper: one file per screen, filling the screen, looping. H.264 is encoded Baseline because Qt here decodes through openh264, which rejects High profile and leaves a frozen frame; a new source also has to be played explicitly. The #shot hash learned info=0 to hide the on-screen hint for renders.
114 lines
6.6 KiB
Markdown
114 lines
6.6 KiB
Markdown
# Сквозь лёд
|
||
|
||
Плазма, текущая за толстой плитой прозрачного голубого льда. Три самостоятельные
|
||
страницы, каждая — один HTML-файл без внешних зависимостей (WebGL1 + GLSL ES 1.0).
|
||
|
||
- `ice_plasma.html` — просто плазма за льдом.
|
||
- `ice_object.html` — в лёд вморожен огранённый кристалл, преломлённый вместе со льдом.
|
||
- `ice_fish.html` — тёмные силуэты рыб с холодными голубыми глазами проплывают сквозь плиту.
|
||
|
||
Открыть любой файл в браузере. Мышь — параллакс, `−` / `=` — скорость. Цикл плазмы 30 с.
|
||
|
||
## Рендеры
|
||
|
||
*Плазма за льдом*
|
||
|
||

|
||
|
||
*Огранённый кристалл вморожен в плиту: лёд преломляет его так же, как всё за собой*
|
||
|
||

|
||
|
||
*Рыбы: тёмные силуэты с холодными голубыми глазами*
|
||
|
||

|
||
|
||
Кадры сняты с текущих шейдеров в 1280×720; время в них зафиксировано параметром
|
||
`#shot&t=…` (см. «Проверка»). Сами страницы живые: плазма течёт, рыбы проплывают,
|
||
кристалл стоит вмороженный и преломляется.
|
||
|
||
## Как устроено
|
||
|
||
Два прохода на кадр:
|
||
|
||
1. **Сцена** (`6_ice_plasma.frag`, `8_ice_scene.frag`, `10_ice_fish.frag`) — плазма рисуется
|
||
в атлас 4×2 из восьми листов, каждый лист — свой слой на своей глубине. Глубина
|
||
записывается в альфу: `(0.42 + layer * 0.26) / 2.6`. Там, где вместо плазмы твёрдый
|
||
объект (кристалл, рыба), в альфе лежит покрытие, а не глубина.
|
||
2. **Лёд** (`7_ice_over.frag`, `9_ice_over_obj.frag`, `11_ice_over_fish.frag`) — для каждого
|
||
слоя по его глубине считается путь луча во льду, отсюда своё преломление, свой
|
||
параллакс и своё поглощение `exp(-SIGMA * path)`. Поверхность — неподвижный рельеф
|
||
с трещинами; трещины дают ступеньку в склоне и рвут плазму на гранях.
|
||
|
||
Листы с объектами хранят покрытие вместо глубины, поэтому пасс 2 берёт для них глубину
|
||
по номеру листа, а не из альфы.
|
||
|
||
## Сборка
|
||
|
||
```sh
|
||
python3 build_plasma.py # -> ice_plasma.html
|
||
python3 build_plasma.py 8_ice_scene.frag 9_ice_over_obj.frag ice_object.html
|
||
python3 build_plasma.py 10_ice_fish.frag 11_ice_over_fish.frag ice_fish.html
|
||
```
|
||
|
||
`build_plasma.py` вставляет оба шейдера в шаблон страницы. После правки шейдеров страницу
|
||
надо пересобрать — HTML сам по себе не обновляется.
|
||
|
||
## Обои
|
||
|
||
Готовые рендеры с рыбами — по файлу на монитор (в репозиторий не входят, они тяжёлые):
|
||
|
||
| файл | экран | размер |
|
||
| --- | --- | --- |
|
||
| `~/Videos/wallpapers/ice_fish_2560x1080.mp4` | DP-2, ультравайд | 110 МБ |
|
||
| `~/Videos/wallpapers/ice_fish_2560x1440.mp4` | HDMI-A-1 | 112 МБ |
|
||
|
||
30 секунд, 30 fps, петля бесшовная: кадр 900 совпадает с кадром 0, потому что цикл
|
||
плазмы ровно 30 с. Профиль H.264 — **Baseline**: Qt на Fedora декодирует через openh264,
|
||
который отвергает High profile и молча оставляет замерший кадр.
|
||
|
||
Пересобрать:
|
||
|
||
```sh
|
||
python3 render_wallpaper.py ice_fish.html ~/Videos/wallpapers/ice_fish_2560x1440.mp4 2560 1440 30 30
|
||
```
|
||
|
||
Скрипт гонит кадры в headless Firefox по четыре за раз, кладёт их в `*.frames/`
|
||
(можно удалить) и кодирует через `h264_nvenc`. Повторный запуск продолжает с места
|
||
обрыва.
|
||
|
||
Обоями видео ставит плагин `dev.emil.video` (исходники — `plasma-plugin/dev.emil.video/`,
|
||
установленная копия — `~/.local/share/plasma/wallpapers/dev.emil.video/`). Он проигрывает
|
||
файл из своего конфига, заполняя экран, и зацикливает его:
|
||
|
||
```sh
|
||
kpackagetool6 --type Wallpaper -i plasma-plugin/dev.emil.video
|
||
```
|
||
|
||
Дальше — правый клик по рабочему столу → «Настроить рабочий стол…» → тип обоев
|
||
Video Wallpaper → путь к файлу. Настройки у каждого экрана свои.
|
||
|
||
## Проверка
|
||
|
||
```sh
|
||
python3 -m unittest test_ice
|
||
```
|
||
|
||
Рендерит `ice_plasma.html` в headless Firefox и проверяет, что кадр не пустой, плазма
|
||
движется, цикл замыкается и мышь меняет картинку. Нужны Firefox и Pillow; сами страницы —
|
||
нет.
|
||
|
||
Кадр вручную: `firefox --headless --screenshot=/tmp/x.png "file://$PWD/ice_fish.html#shot&t=8"`.
|
||
Параметр `t` фиксирует время, `mx`/`my` — позицию мыши.
|
||
|
||
## Оговорки
|
||
|
||
- `9_ice_over_obj.frag` и `11_ice_over_fish.frag` — копии `7_ice_over.frag`: правки рельефа
|
||
и преломления льда надо переносить во все три файла.
|
||
- `debug_fish.frag` + `debug_fish.html` — плоский рендер силуэтов рыб для отладки формы.
|
||
- `renders/*.jpg` — картинки для этого README, к сборке отношения не имеют.
|
||
- `render_wallpaper.py` — кадры + ffmpeg, длинное видео для обоев.
|
||
- `plasma-plugin/dev.emil.video` — минимальный видео-обои плагин для Plasma 6.
|
||
- `build.py` собирает `playground.html` со всеми `.frag` подряд, `render.py`/`shot.py` —
|
||
старые вспомогательные скрипты.
|