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(); }