studio/src/editor/engine/GdPostFx.js
МИН 31adbf151b Initial public release: Студия Рублокса v1.0
Open-source веб-студия для создания игр Рублокса, двойная лицензия
AGPL-3.0 + Коммерческая.

Главное:
- Vite 5 + React 18 + Babylon 7.54.3 + Monaco Editor + Colyseus 0.16
- Самодостаточный движок ~28к строк (66 файлов): BlockManager,
  TerrainVoxelBuilder, ModelManager, DecoManager, PlayerController,
  ScriptSandboxWorker, MultiplayerSync, 30+ GD-гейммодов
- Главный редактор KubikonEditor (~37к строк) + панели, ScriptEditor (Monaco)
- Витрина игр (KubikonFeed, KubikonStudio, KubikonDocs, KubikonLearn)
- Geometry Dash sub-app (GdMenu, GdShop, GdRules, GdCoverArt)
- 10 admin-preview каталогов для дизайнеров (скины, музыка, порталы и т.д.)
- Конфигурируемый бэкенд через VITE_API_BASE — работает со staging
  (dev-api.rublox.pro) без настройки
- Standalone-режим (VITE_STANDALONE=true) — открыть пустой редактор без бэка
- Полная документация (на русском): README, ARCHITECTURE, CONTRIBUTING,
  SECURITY, CHANGELOG
- ESLint + Prettier + EditorConfig
- Legal: LICENSE (AGPL-3.0), LICENSE-COMMERCIAL.md, CLA.md, COPYRIGHT.md
- Issue templates: bug_report, feature_request, security_disclosure

Перед публикацией:
- Все импорты из minecraftia заменены на локальные
- Все хардкоды URL (minecraftia-school.ru) и внутренних IP убраны → env
- Admin-эндпоинты Kubikon3DService вырезаны (остаются в приватном репо)
- AdminKubikonModeration не публикуется (модерация — в team.rublox.pro)
- 93 МБ ассетов public/kubikon-assets вынесены в .gitignore
  (раздаются через release artifact)
2026-05-27 23:41:10 +03:00

117 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* GdPostFx — пост-обработка для GD-уровней (этап G9).
*
* Подключает Babylon DefaultRenderingPipeline с:
* - Bloom — свечение ярких объектов (куб с glow, неон-края, конфетти)
* - Vignette — мягкое затемнение углов
* - ImageProcessing tone-mapping + лёгкий тёплый сдвиг
*
* Также подкручивает hemi/sun свет: тёплый свет сверху, прохладный снизу.
*
* Использование:
* const fx = new GdPostFx();
* fx.attach(scene, camera, scene3d);
* fx.dispose();
*/
import {
DefaultRenderingPipeline, Color3, Color4, ImageProcessingConfiguration,
} from '@babylonjs/core';
export class GdPostFx {
constructor() {
this.scene = null;
this._scene3d = null;
this._pipeline = null;
// Backup света (восстанавливаем при dispose)
this._lightBackup = null;
}
attach(scene, camera, scene3d) {
if (!scene || !camera) return;
this.scene = scene;
this._scene3d = scene3d;
// Качество: 'high' (default) | 'low' — из localStorage
const quality = (typeof localStorage !== 'undefined'
&& localStorage.getItem('gd_graphics_quality')) || 'high';
// === DefaultRenderingPipeline ===
const pipeline = new DefaultRenderingPipeline(
'gd_post_pipeline',
quality === 'high', // HDR только в high
scene,
[camera],
);
// Bloom — только в high quality (самый дорогой эффект)
pipeline.bloomEnabled = quality === 'high';
if (pipeline.bloomEnabled) {
pipeline.bloomThreshold = 0.85;
pipeline.bloomWeight = 0.35;
pipeline.bloomKernel = 64;
pipeline.bloomScale = 0.5;
}
// Image processing — лёгкая коррекция (без затемнения)
pipeline.imageProcessingEnabled = true;
if (pipeline.imageProcessing) {
// Tone mapping отключаем — он сжимает яркие участки и общая
// картинка темнеет. Без него bloom+vignette не «съедают» свет.
pipeline.imageProcessing.toneMappingEnabled = false;
pipeline.imageProcessing.exposure = 1.0;
pipeline.imageProcessing.contrast = 1.0;
// Лёгкий vignette — только по краям, не глобальное затемнение
pipeline.imageProcessing.vignetteEnabled = true;
pipeline.imageProcessing.vignetteWeight = 0.6;
pipeline.imageProcessing.vignetteColor = new Color4(0, 0, 0, 0);
pipeline.imageProcessing.vignetteStretch = 0.3;
pipeline.imageProcessing.vignetteCameraFov = 0.5;
pipeline.imageProcessing.vignetteBlendMode = ImageProcessingConfiguration.VIGNETTEMODE_MULTIPLY;
// Чуть-чуть насыщенности (без сдвига hue)
pipeline.imageProcessing.colorCurvesEnabled = true;
try {
const curves = pipeline.imageProcessing.colorCurves;
if (curves) {
curves.globalSaturation = 8;
}
} catch (e) {}
}
// FXAA — антиалиасинг (бесплатно с pipeline)
pipeline.fxaaEnabled = true;
pipeline.samples = 4;
this._pipeline = pipeline;
// Свет дефолтный движка не трогаем — наш предыдущий «тёплый» сдвиг
// делал картинку темнее (intensity 1.1 + diffuse 0.82B не компенсирует).
console.log('[GdPostFx] подключен (bloom + лёгкий vignette)');
}
dispose() {
if (this._pipeline) {
try { this._pipeline.dispose(); } catch (e) {}
this._pipeline = null;
}
if (this._lightBackup && this._scene3d) {
try {
const sun = this._scene3d._sunLight;
const hemi = this._scene3d._hemiLight;
if (sun && this._lightBackup.sunDiffuse) {
sun.diffuse = this._lightBackup.sunDiffuse;
sun.specular = this._lightBackup.sunSpecular;
sun.intensity = this._lightBackup.sunIntensity;
}
if (hemi && this._lightBackup.hemiDiffuse) {
hemi.diffuse = this._lightBackup.hemiDiffuse;
hemi.groundColor = this._lightBackup.hemiGroundColor;
hemi.intensity = this._lightBackup.hemiIntensity;
}
} catch (e) {}
this._lightBackup = null;
}
this._scene3d = null;
this.scene = null;
}
}