Add water surface displacement option in App and update document migration & validation

This commit is contained in:
2026-04-07 07:11:15 +02:00
parent e32c00e0ef
commit 66bb99b5ac
3 changed files with 39 additions and 3 deletions

View File

@@ -1024,6 +1024,7 @@ export function App({ store, initialStatusMessage }: AppProps) {
const [boxVolumeWaterFoamContactLimitDraft, setBoxVolumeWaterFoamContactLimitDraft] = useState(
String(DEFAULT_BOX_BRUSH_WATER_FOAM_CONTACT_LIMIT)
);
const [boxVolumeWaterSurfaceDisplacementEnabledDraft, setBoxVolumeWaterSurfaceDisplacementEnabledDraft] = useState(false);
const [boxVolumeFogColorDraft, setBoxVolumeFogColorDraft] = useState("#9cb7c7");
const [boxVolumeFogDensityDraft, setBoxVolumeFogDensityDraft] = useState("0.08");
const [boxVolumeFogPaddingDraft, setBoxVolumeFogPaddingDraft] = useState("0.2");
@@ -1190,6 +1191,7 @@ export function App({ store, initialStatusMessage }: AppProps) {
setSizeDraft(createVec3Draft(DEFAULT_BOX_BRUSH_SIZE));
setBoxVolumeModeDraft("none");
setBoxVolumeWaterFoamContactLimitDraft(String(DEFAULT_BOX_BRUSH_WATER_FOAM_CONTACT_LIMIT));
setBoxVolumeWaterSurfaceDisplacementEnabledDraft(false);
return;
}
@@ -1204,6 +1206,7 @@ export function App({ store, initialStatusMessage }: AppProps) {
setBoxVolumeWaterSurfaceOpacityDraft(String(selectedBrush.volume.water.surfaceOpacity));
setBoxVolumeWaterWaveStrengthDraft(String(selectedBrush.volume.water.waveStrength));
setBoxVolumeWaterFoamContactLimitDraft(String(selectedBrush.volume.water.foamContactLimit));
setBoxVolumeWaterSurfaceDisplacementEnabledDraft(selectedBrush.volume.water.surfaceDisplacementEnabled);
}
if (selectedBrush.volume.mode === "fog") {
@@ -2282,7 +2285,8 @@ export function App({ store, initialStatusMessage }: AppProps) {
colorHex: boxVolumeWaterColorDraft,
surfaceOpacity: readNonNegativeNumberDraft(boxVolumeWaterSurfaceOpacityDraft, "Water surface opacity"),
waveStrength: readNonNegativeNumberDraft(boxVolumeWaterWaveStrengthDraft, "Water wave strength"),
foamContactLimit: readWaterFoamContactLimitDraft(boxVolumeWaterFoamContactLimitDraft)
foamContactLimit: readWaterFoamContactLimitDraft(boxVolumeWaterFoamContactLimitDraft),
surfaceDisplacementEnabled: boxVolumeWaterSurfaceDisplacementEnabledDraft
}
};
}
@@ -2315,7 +2319,8 @@ export function App({ store, initialStatusMessage }: AppProps) {
colorHex: boxVolumeWaterColorDraft,
surfaceOpacity: readNonNegativeNumberDraft(boxVolumeWaterSurfaceOpacityDraft, "Water surface opacity"),
waveStrength: readNonNegativeNumberDraft(boxVolumeWaterWaveStrengthDraft, "Water wave strength"),
foamContactLimit: readWaterFoamContactLimitDraft(boxVolumeWaterFoamContactLimitDraft)
foamContactLimit: readWaterFoamContactLimitDraft(boxVolumeWaterFoamContactLimitDraft),
surfaceDisplacementEnabled: boxVolumeWaterSurfaceDisplacementEnabledDraft
}
}),
"Set box water settings",
@@ -2335,7 +2340,8 @@ export function App({ store, initialStatusMessage }: AppProps) {
colorHex,
surfaceOpacity: readNonNegativeNumberDraft(boxVolumeWaterSurfaceOpacityDraft, "Water surface opacity"),
waveStrength: readNonNegativeNumberDraft(boxVolumeWaterWaveStrengthDraft, "Water wave strength"),
foamContactLimit: readWaterFoamContactLimitDraft(boxVolumeWaterFoamContactLimitDraft)
foamContactLimit: readWaterFoamContactLimitDraft(boxVolumeWaterFoamContactLimitDraft),
surfaceDisplacementEnabled: boxVolumeWaterSurfaceDisplacementEnabledDraft
}
}),
"Set box water color",
@@ -7457,6 +7463,18 @@ export function App({ store, initialStatusMessage }: AppProps) {
onPointerUp={(event) => handleNumberInputPointerUp(event, applyBoxWaterSettings)}
/>
</label>
<label className="form-field form-field--toggle">
<span className="label">Vertical Surface Motion</span>
<input
data-testid="brush-water-surface-displacement-enabled"
type="checkbox"
checked={boxVolumeWaterSurfaceDisplacementEnabledDraft}
onChange={(event) => {
setBoxVolumeWaterSurfaceDisplacementEnabledDraft(event.currentTarget.checked);
scheduleDraftCommit(() => applyBoxWaterSettings());
}}
/>
</label>
</>
) : null}

View File

@@ -72,6 +72,7 @@ import {
SPATIAL_AUDIO_SCENE_DOCUMENT_VERSION,
SCENE_DOCUMENT_VERSION,
TRIGGER_ACTION_TARGET_FOUNDATION_SCENE_DOCUMENT_VERSION,
WATER_SURFACE_DISPLACEMENT_SCENE_DOCUMENT_VERSION,
WHITEBOX_BOX_VOLUME_SCENE_DOCUMENT_VERSION,
WHITEBOX_FLOAT_TRANSFORM_SCENE_DOCUMENT_VERSION,
WHITEBOX_GEOMETRY_SCENE_DOCUMENT_VERSION,
@@ -402,6 +403,11 @@ function readBoxBrushVolumeSettings(value: unknown, label: string): BoxBrushVolu
`${label}.water.foamContactLimit`,
defaults.foamContactLimit,
MAX_BOX_BRUSH_WATER_FOAM_CONTACT_LIMIT
),
surfaceDisplacementEnabled: readOptionalBoolean(
water.surfaceDisplacementEnabled,
`${label}.water.surfaceDisplacementEnabled`,
defaults.surfaceDisplacementEnabled
)
}
};
@@ -1720,6 +1726,7 @@ export function migrateSceneDocument(source: unknown): SceneDocument {
}
if (
source.version !== WATER_SURFACE_DISPLACEMENT_SCENE_DOCUMENT_VERSION &&
source.version !== WHITEBOX_BOX_VOLUME_SCENE_DOCUMENT_VERSION &&
source.version !== WHITEBOX_FLOAT_TRANSFORM_SCENE_DOCUMENT_VERSION &&
source.version !== WHITEBOX_GEOMETRY_SCENE_DOCUMENT_VERSION

View File

@@ -1434,6 +1434,17 @@ export function validateSceneDocument(document: SceneDocument): SceneDocumentVal
)
);
}
if (typeof water.surfaceDisplacementEnabled !== "boolean") {
diagnostics.push(
createDiagnostic(
"error",
"invalid-box-water-surface-displacement-enabled",
"Water surface displacement must be enabled or disabled explicitly.",
`${path}.volume.water.surfaceDisplacementEnabled`
)
);
}
}
}