From 19f47b2d75e6f7e30994e8fe564d752886f4ef60 Mon Sep 17 00:00:00 2001 From: min Date: Mon, 8 Jun 2026 18:54:00 +0300 Subject: [PATCH] =?UTF-8?q?feat(inspector):=20=D0=BD=D0=BE=D0=B2=D1=8B?= =?UTF-8?q?=D0=B5=20=D1=81=D0=BB=D0=B0=D0=B9=D0=B4=D0=B5=D1=80=D1=8B=20?= =?UTF-8?q?=D1=81=D0=B2=D0=B5=D1=82=D0=B0=20=E2=80=94=20=D0=B7=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D0=B2=D0=BA=D0=B0=20=D1=82=D0=B5=D0=BD=D0=B5=D0=B9,=20?= =?UTF-8?q?=D1=8D=D0=BA=D1=81=D0=BF=D0=BE=D0=B7=D0=B8=D1=86=D0=B8=D1=8F,?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=B0=D1=81=D1=82,=20=D0=BD?= =?UTF-8?q?=D0=B0=D1=81=D1=8B=D1=89=D0=B5=D0=BD=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit В Свет и атмосфера добавлено: - Заливка теней (scene.ambientColor) — позволяет окрасить тени в сером тоне без пересвета diffuse материалов. - Экспозиция (ipc.exposure 0.3-2) — общая яркость через imageProcessingConfiguration. - Контраст (ipc.contrast 0.5-2) - Насыщенность (colorCurves.globalSaturation -100..+100) Юзер крутит слайдеры до момента когда импортированная Roblox-карта выглядит как оригинал. Дефолты: ambient 0.3, exposure 1.0, contrast 1.0, saturation 1.0. Также убрал mat.ambientColor=цвет — теперь default (0,0,0). Освещение управляется глобально через панель. Состояние пока не сохраняется в проект (только сессия). Persistence добавим в следующем шаге. --- src/editor/InspectorPanel.jsx | 62 +++++++++++++++++++++++++++ src/editor/engine/BabylonScene.js | 33 ++++++++++++++ src/editor/engine/PrimitiveManager.js | 8 ++-- src/editor/engine/SelectionManager.js | 5 +++ 4 files changed, 103 insertions(+), 5 deletions(-) diff --git a/src/editor/InspectorPanel.jsx b/src/editor/InspectorPanel.jsx index 35d68b1..f450038 100644 --- a/src/editor/InspectorPanel.jsx +++ b/src/editor/InspectorPanel.jsx @@ -526,11 +526,73 @@ const InspectorPanel = ({ style={{ width: '100%' }} /> +
+
+ Заливка теней + {(selection.sceneAmbient ?? 0.3).toFixed(2)} +
+ props.onSetLightingProps?.({ sceneAmbient: parseFloat(e.target.value) })} + style={{ width: '100%' }} + /> +
+ Подсветка теней — цвет в затенённых гранях. 0 = чёрные тени, 1 = плоско. +
+
Цвет окружающего света подбирается автоматически по времени суток.
+ {/* Цветокоррекция */} +
+
Цветокоррекция
+
+
+ Экспозиция + {(selection.exposure ?? 1.0).toFixed(2)} +
+ props.onSetLightingProps?.({ exposure: parseFloat(e.target.value) })} + style={{ width: '100%' }} + /> +
+ Общая яркость. <1 = темнее, >1 = светлее. +
+
+
+
+ Контраст + {(selection.contrast ?? 1.0).toFixed(2)} +
+ props.onSetLightingProps?.({ contrast: parseFloat(e.target.value) })} + style={{ width: '100%' }} + /> +
+
+
+ Насыщенность + {(selection.saturation ?? 1.0).toFixed(2)} +
+ props.onSetLightingProps?.({ saturation: parseFloat(e.target.value) })} + style={{ width: '100%' }} + /> +
+ 0 = чёрно-белое, 1 = норма, 2 = очень сочно. +
+
+
+ {/* Туман */}
Туман
diff --git a/src/editor/engine/BabylonScene.js b/src/editor/engine/BabylonScene.js index 175c430..dc89f9a 100644 --- a/src/editor/engine/BabylonScene.js +++ b/src/editor/engine/BabylonScene.js @@ -37,6 +37,7 @@ import { Ray, PointerEventTypes, Tools as BabylonTools, + ColorCurves, } from '@babylonjs/core'; import { PlacementManager } from './PlacementManager'; import { ShopInventoryUi } from './ShopInventoryUi'; @@ -1885,9 +1886,41 @@ export class BabylonScene { } if (typeof patch.sunIntensity === 'number' && this._sunLight) { this._sunLight.intensity = Math.max(0, patch.sunIntensity); + this._sunIntensity = patch.sunIntensity; } if (typeof patch.hemiIntensity === 'number' && this._hemiLight) { this._hemiLight.intensity = Math.max(0, patch.hemiIntensity); + this._hemiIntensity = patch.hemiIntensity; + } + // Окружающий свет (scene.ambientColor) — отдельный множитель. + // Применяется ко всем материалам через ambient*ambient. + if (typeof patch.sceneAmbient === 'number') { + const v = Math.max(0, Math.min(1, patch.sceneAmbient)); + this.scene.ambientColor = new Color3(v, v, v); + this._sceneAmbient = v; + } + // Цветокоррекция — экспозиция, контраст, насыщенность через + // imageProcessingConfiguration (включает HDR pipeline). + if (typeof patch.exposure === 'number' || typeof patch.contrast === 'number' + || typeof patch.saturation === 'number') { + const ipc = this.scene.imageProcessingConfiguration; + ipc.isEnabled = true; + if (typeof patch.exposure === 'number') { + ipc.exposure = Math.max(0.1, Math.min(3, patch.exposure)); + this._exposure = ipc.exposure; + } + if (typeof patch.contrast === 'number') { + ipc.contrast = Math.max(0.5, Math.min(2.5, patch.contrast)); + this._contrast = ipc.contrast; + } + if (typeof patch.saturation === 'number') { + // colorCurves для saturation (стандартный Babylon приём) + if (!ipc.colorCurves) ipc.colorCurves = new ColorCurves(); + const s = Math.max(-100, Math.min(100, (patch.saturation - 1) * 100)); + ipc.colorCurves.globalSaturation = s; + ipc.colorCurvesEnabled = true; + this._saturation = patch.saturation; + } } if (this.environment && typeof this.environment.setFog === 'function') { // Текущие значения берём из Environment, поверх накладываем patch diff --git a/src/editor/engine/PrimitiveManager.js b/src/editor/engine/PrimitiveManager.js index d0471ad..8d7d899 100644 --- a/src/editor/engine/PrimitiveManager.js +++ b/src/editor/engine/PrimitiveManager.js @@ -506,11 +506,9 @@ export class PrimitiveManager { _applyMaterial(mesh, typeDef, color, material, textureUrl) { const matName = `${mesh.name}_mat`; const mat = new StandardMaterial(matName, this.scene); - const dc = Color3.FromHexString(color || '#888888'); - mat.diffuseColor = dc; - // ambient = 40% от цвета. Roblox-look: тень окрашена, но не - // суммируется с прямым светом в пересвет. Белые остаются белыми. - mat.ambientColor = new Color3(dc.r * 0.4, dc.g * 0.4, dc.b * 0.4); + mat.diffuseColor = Color3.FromHexString(color || '#888888'); + // ambient = default (0,0,0). Освещение настраивается через + // глобальную панель «Свет и атмосфера» (sun/hemi/saturation). // Если задан textureUrl — подгружаем PNG как diffuseTexture. Это // используется для GD-скинов куба (например /gd/skins/cube_smile.png). diff --git a/src/editor/engine/SelectionManager.js b/src/editor/engine/SelectionManager.js index f20b397..834197f 100644 --- a/src/editor/engine/SelectionManager.js +++ b/src/editor/engine/SelectionManager.js @@ -282,6 +282,11 @@ export class SelectionManager { fogColor: env ? `#${[env.fogColor?.[0] ?? 0.7, env.fogColor?.[1] ?? 0.8, env.fogColor?.[2] ?? 0.9].map(c => Math.round(Math.max(0, Math.min(1, c)) * 255).toString(16).padStart(2, '0')).join('')}` : '#b0c8e6', shadowQuality: this._scene3d.getShadowQuality?.() || 'soft', ssaoEnabled: this._scene3d.getSsaoEnabled?.() || false, + // Новые: глобальный ambient + image processing + sceneAmbient: this._scene3d._sceneAmbient ?? 0.3, + exposure: this._scene3d._exposure ?? 1.0, + contrast: this._scene3d._contrast ?? 1.0, + saturation: this._scene3d._saturation ?? 1.0, }; this._notifyChange(); }