diff --git a/src/document/brushes.js b/src/document/brushes.js index f3a81d7f..36484fda 100644 --- a/src/document/brushes.js +++ b/src/document/brushes.js @@ -25,6 +25,7 @@ export const BOX_VERTEX_IDS = [ "posX_posY_posZ" ]; export const FACE_UV_ROTATION_QUARTER_TURNS = [0, 1, 2, 3]; +export const BOX_BRUSH_VOLUME_MODES = ["none", "water", "fog"]; export const BOX_FACE_LABELS = { posX: "Right", negX: "Left", @@ -72,6 +73,16 @@ export const DEFAULT_BOX_BRUSH_ROTATION_DEGREES = { y: 0, z: 0 }; +const DEFAULT_BOX_BRUSH_WATER_SETTINGS = { + colorHex: "#4da6d9", + surfaceOpacity: 0.55, + waveStrength: 0.35 +}; +const DEFAULT_BOX_BRUSH_FOG_SETTINGS = { + colorHex: "#9cb7c7", + density: 0.08, + padding: 0.2 +}; export function normalizeBrushName(name) { if (name === undefined || name === null) { return undefined; @@ -231,6 +242,9 @@ export function isBoxVertexId(value) { export function isFaceUvRotationQuarterTurns(value) { return typeof value === "number" && FACE_UV_ROTATION_QUARTER_TURNS.includes(value); } +export function isBoxBrushVolumeMode(value) { + return typeof value === "string" && BOX_BRUSH_VOLUME_MODES.includes(value); +} export function hasPositiveBoxSize(size) { return size.x > 0 && size.y > 0 && size.z > 0; } @@ -300,6 +314,51 @@ export function createDefaultBoxBrushFaces() { } }; } +export function createDefaultBoxBrushWaterSettings() { + return { + colorHex: DEFAULT_BOX_BRUSH_WATER_SETTINGS.colorHex, + surfaceOpacity: DEFAULT_BOX_BRUSH_WATER_SETTINGS.surfaceOpacity, + waveStrength: DEFAULT_BOX_BRUSH_WATER_SETTINGS.waveStrength + }; +} +export function createDefaultBoxBrushFogSettings() { + return { + colorHex: DEFAULT_BOX_BRUSH_FOG_SETTINGS.colorHex, + density: DEFAULT_BOX_BRUSH_FOG_SETTINGS.density, + padding: DEFAULT_BOX_BRUSH_FOG_SETTINGS.padding + }; +} +export function createDefaultBoxBrushVolumeSettings() { + return { + mode: "none" + }; +} +export function cloneBoxBrushVolumeSettings(volume) { + switch (volume.mode) { + case "none": + return { + mode: "none" + }; + case "water": + return { + mode: "water", + water: { + colorHex: volume.water.colorHex, + surfaceOpacity: volume.water.surfaceOpacity, + waveStrength: volume.water.waveStrength + } + }; + case "fog": + return { + mode: "fog", + fog: { + colorHex: volume.fog.colorHex, + density: volume.fog.density, + padding: volume.fog.padding + } + }; + } +} export function createBoxBrush(overrides = {}) { const center = cloneVec3(overrides.center ?? DEFAULT_BOX_BRUSH_CENTER); const rotationDegrees = cloneVec3(overrides.rotationDegrees ?? DEFAULT_BOX_BRUSH_ROTATION_DEGREES); @@ -318,6 +377,7 @@ export function createBoxBrush(overrides = {}) { size, geometry, faces: overrides.faces === undefined ? createDefaultBoxBrushFaces() : cloneBoxBrushFaces(overrides.faces), + volume: overrides.volume === undefined ? createDefaultBoxBrushVolumeSettings() : cloneBoxBrushVolumeSettings(overrides.volume), layerId: overrides.layerId, groupId: overrides.groupId }; diff --git a/src/document/world-settings.ts b/src/document/world-settings.ts index 555cae7b..fa6ee40f 100644 --- a/src/document/world-settings.ts +++ b/src/document/world-settings.ts @@ -5,10 +5,12 @@ export type WorldBackgroundMode = "solid" | "verticalGradient" | "image"; export const ADVANCED_RENDERING_SHADOW_MAP_SIZES = [512, 1024, 2048, 4096] as const; export const ADVANCED_RENDERING_SHADOW_TYPES = ["basic", "pcf", "pcfSoft"] as const; export const ADVANCED_RENDERING_TONE_MAPPING_MODES = ["none", "linear", "reinhard", "cineon", "acesFilmic"] as const; +export const BOX_VOLUME_RENDER_PATHS = ["performance", "quality"] as const; export type AdvancedRenderingShadowMapSize = (typeof ADVANCED_RENDERING_SHADOW_MAP_SIZES)[number]; export type AdvancedRenderingShadowType = (typeof ADVANCED_RENDERING_SHADOW_TYPES)[number]; export type AdvancedRenderingToneMappingMode = (typeof ADVANCED_RENDERING_TONE_MAPPING_MODES)[number]; +export type BoxVolumeRenderPath = (typeof BOX_VOLUME_RENDER_PATHS)[number]; export interface WorldSolidBackgroundSettings { mode: "solid"; @@ -83,6 +85,8 @@ export interface AdvancedRenderingSettings { bloom: AdvancedRenderingBloomSettings; toneMapping: AdvancedRenderingToneMappingSettings; depthOfField: AdvancedRenderingDepthOfFieldSettings; + fogPath: BoxVolumeRenderPath; + waterPath: BoxVolumeRenderPath; } export interface WorldSettings { @@ -109,6 +113,7 @@ const DEFAULT_ADVANCED_RENDERING_TONE_MAPPING_EXPOSURE = 1; const DEFAULT_ADVANCED_RENDERING_DEPTH_OF_FIELD_FOCUS_DISTANCE = 10; const DEFAULT_ADVANCED_RENDERING_DEPTH_OF_FIELD_FOCAL_LENGTH = 0.03; const DEFAULT_ADVANCED_RENDERING_DEPTH_OF_FIELD_BOKEH_SCALE = 1.5; +const DEFAULT_BOX_VOLUME_RENDER_PATH: BoxVolumeRenderPath = "performance"; export function isAdvancedRenderingShadowMapSize(value: unknown): value is AdvancedRenderingShadowMapSize { return ADVANCED_RENDERING_SHADOW_MAP_SIZES.includes(value as AdvancedRenderingShadowMapSize); @@ -122,6 +127,10 @@ export function isAdvancedRenderingToneMappingMode(value: unknown): value is Adv return ADVANCED_RENDERING_TONE_MAPPING_MODES.includes(value as AdvancedRenderingToneMappingMode); } +export function isBoxVolumeRenderPath(value: unknown): value is BoxVolumeRenderPath { + return BOX_VOLUME_RENDER_PATHS.includes(value as BoxVolumeRenderPath); +} + export function createDefaultAdvancedRenderingSettings(): AdvancedRenderingSettings { return { enabled: false, @@ -152,7 +161,9 @@ export function createDefaultAdvancedRenderingSettings(): AdvancedRenderingSetti focusDistance: DEFAULT_ADVANCED_RENDERING_DEPTH_OF_FIELD_FOCUS_DISTANCE, focalLength: DEFAULT_ADVANCED_RENDERING_DEPTH_OF_FIELD_FOCAL_LENGTH, bokehScale: DEFAULT_ADVANCED_RENDERING_DEPTH_OF_FIELD_BOKEH_SCALE - } + }, + fogPath: DEFAULT_BOX_VOLUME_RENDER_PATH, + waterPath: DEFAULT_BOX_VOLUME_RENDER_PATH }; } @@ -241,7 +252,9 @@ export function cloneAdvancedRenderingSettings(settings: AdvancedRenderingSettin }, depthOfField: { ...settings.depthOfField - } + }, + fogPath: settings.fogPath, + waterPath: settings.waterPath }; } @@ -295,7 +308,9 @@ export function areAdvancedRenderingSettingsEqual(left: AdvancedRenderingSetting left.depthOfField.enabled === right.depthOfField.enabled && left.depthOfField.focusDistance === right.depthOfField.focusDistance && left.depthOfField.focalLength === right.depthOfField.focalLength && - left.depthOfField.bokehScale === right.depthOfField.bokehScale + left.depthOfField.bokehScale === right.depthOfField.bokehScale && + left.fogPath === right.fogPath && + left.waterPath === right.waterPath ); }