Browse Source

更新场景,增加一期沉砂池模型,修复图标点击不转跳的问题

WQQ 2 weeks ago
parent
commit
3a02408303

BIN
public/scene/NoLod_0.glb


+ 1 - 1
public/scene/scenetree.json

@@ -1 +1 @@
-{"scenes":[{"children":[{"id":"a1d0c6e83f027327d8461063f4ac58a6","name":"DX","sphere":[-2177719.745781851,4388735.40600303,4070060.6347709335,26250.620994359226],"type":"element"}],"id":"45c48cce2e2d7fbdea1afc51c7c6ad26","name":"场景拆分版2","sphere":[-2177719.745781851,4388735.40600303,4070060.6347709335,26250.620994359226],"type":"node"}]}
+{"scenes":[{"children":[{"id":"a1d0c6e83f027327d8461063f4ac58a6","name":"DX001","sphere":[-2177719.8828741927,4388735.682944644,4070060.8932239935,26249.88515454758],"type":"element"}],"id":"45c48cce2e2d7fbdea1afc51c7c6ad26","name":"一期沉砂池终版","sphere":[-2177719.8828741927,4388735.682944644,4070060.8932239935,26249.88515454758],"type":"node"}]}

+ 1 - 1
public/scene/tileset.json

@@ -1 +1 @@
-{"asset":{"generatetool":"cesiumlab3@www.cesiumlab.com/model2tiles","version":"1.1"},"extras":{"scenetree":"scenetree.json"},"geometricError":15385.826170017943,"properties":null,"refine":"REPLACE","root":{"boundingVolume":{"box":[-31.594920691335574,10.475845690118149,-15.068455416709185,7692.913085008971,0,0,0,7387.598367458908,0,0,0,25.901169101707637]},"children":[{"boundingVolume":{"box":[-31.533750000000055,10.468281250000473,-7.902099151611415,7678.0,0,0,0,7387.499999999999,0,0,0,24.15320312500004]},"content":{"uri":"NoLod_0.glb"},"geometricError":0.0,"refine":"REPLACE"}],"geometricError":15385.826170017943,"transform":[-0.8957798079969456,-0.44449807151995063,0.0,0.0,0.2851642479174557,-0.5746805028278432,0.7670877859666446,0.0,-0.3409690415486823,0.6871417496300031,0.6415421487484598,0.0,-2177749.4494034126,4388734.4144854965,4070062.242923888,1.0]}}
+{"asset":{"generatetool":"cesiumlab3@www.cesiumlab.com/model2tiles","version":"1.1"},"extras":{"scenetree":"scenetree.json"},"geometricError":15385.826170013053,"properties":null,"refine":"REPLACE","root":{"boundingVolume":{"box":[-31.594920690986328,10.475689440499991,-14.664846805855632,7692.913085006527,0,0,0,7387.598367458675,0,0,0,25.49755951669067]},"children":[{"boundingVolume":{"box":[-31.533750000000055,10.468124999999873,-7.5604957580567245,7678.0,0,0,0,7387.499999999998,0,0,0,24.494807128906288]},"content":{"uri":"NoLod_0.glb"},"geometricError":0.0,"refine":"REPLACE"}],"geometricError":15385.826170013053,"transform":[-0.8957798079969456,-0.44449807151995063,0.0,0.0,0.2851642479174557,-0.5746805028278432,0.7670877859666446,0.0,-0.3409690415486823,0.6871417496300031,0.6415421487484598,0.0,-2177749.4494034126,4388734.4144854965,4070062.242923888,1.0]}}

BIN
src/assets/water02.glb


+ 69 - 6
src/config/sceneConfig.ts

@@ -89,6 +89,17 @@ export const modelTransformMap: Record<string, ModelTransform> = {
     scaleY: 16,
     scaleZ: 1,
   },
+  foam2: {
+    positionX: 911.273,
+    positionY: 7.799,
+    positionZ: 1343.336,
+    rotationX: -90,
+    rotationY: 0,
+    rotationZ: 0,
+    scaleX: 10,
+    scaleY: 10,
+    scaleZ: 1,
+  },
   water: {
     positionX: -854.3537,
     positionY: 14.01539,
@@ -133,6 +144,17 @@ export const modelTransformMap: Record<string, ModelTransform> = {
     scaleY: 300,
     scaleZ: 200,
   },
+  water02: {
+    positionX: -25,
+    positionY: 14.5,
+    positionZ: 0,
+    rotationX: 0,
+    rotationY: 180,
+    rotationZ: 0,
+    scaleX: 1,
+    scaleY: 1,
+    scaleZ: 1,
+  },
 }
 
 // ==================== 材质参数默认值 ====================
@@ -332,6 +354,26 @@ export const waterLevelLabels: WaterLevelLabelConfig[] = [
     positionZ: -1657.653,
     initialValue: 2.80,
   },
+  {
+    id: '6602380024',
+    name: '一期沉砂池入库水量监测',
+    type: 'waterLevel',
+    scene: 'main',
+    positionX: 893.77,
+    positionY: 13,
+    positionZ: 1305.4,
+    initialValue: 4.00,
+  },
+  {
+    id: '6602380025',
+    name: '一期沉砂池启闭机房水量监测',
+    type: 'waterLevel',
+    scene: 'main',
+    positionX: 2494.344,
+    positionY: 18.201,
+    positionZ: 1565.741,
+    initialValue: 4.00,
+  },
   {
     id: '渡槽安全监测46+400',
     name: '渡槽安全监测46+400',
@@ -388,13 +430,13 @@ export const cameraPresets: CameraPreset[] = [
   },
   {
     id: '1',
-    name: '期沉砂池入库',
-    positionX: -2337.807,
-    positionY: 129.119,
-    positionZ: -1025.484,
-    targetX: -2240.868,
+    name: '期沉砂池入库',
+    positionX: 785.494,
+    positionY: 80.493,
+    positionZ: 1201.242,
+    targetX: 933.732,
     targetY: 12.015,
-    targetZ: -908.998,
+    targetZ: 1331.79,
   },
   {
     id: '2',
@@ -416,4 +458,25 @@ export const cameraPresets: CameraPreset[] = [
     targetY: 12.015,
     targetZ: -293.213,
   },
+  {
+    id: '4',
+    name: '一期沉砂池启闭机房',
+    positionX: 2584.355,
+    positionY: 61.581,
+    positionZ: 1629.411,
+    targetX: 2467.565,
+    targetY: 12.015,
+    targetZ: 1502.795,
+  },
 ]
+
+/** 标签ID到预设ID的映射(点击标签图标跳转到对应视角) */
+export const labelToPresetMap: Record<string, string> = {
+  '6602380005': '0', // 莫勒切河节制分水闸闸后水量监测 -> 莫勒切河节制分水闸
+  '6602380006': '0', // 莫勒切河引水渠水量监测 -> 莫勒切河节制分水闸
+  '6602380003': '2', // 二期沉砂池入库水量监测 -> 二期沉砂池入库
+  '6602380001': '3', // 二期沉砂池库内水位监测 -> 二期沉砂池出库
+  '6602380004': '3', // 二期沉砂池出库水量监测 -> 二期沉砂池出库
+  '6602380024': '1', // 一期沉砂池入库水量监测 -> 一期沉砂池入库
+  '6602380025': '4', // 一期沉砂池启闭机房水量监测 -> 一期沉砂池启闭机房
+}

+ 401 - 19
src/scenes/Scene3D.vue

@@ -15,6 +15,7 @@ import flowNormalTexUrl from '../assets/texture/FlowTexture/T_FlowTexture_BC_NOR
 import foamMacroNormalTexUrl from '../assets/texture/FlowTexture/T_FoamMacro_BC_NORM.PNG'
 import langGLBUrl from '../assets/lang.glb'
 import cscwaterGLBUrl from '../assets/CSCwater.glb'
+import water02GLBUrl from '../assets/water02.glb'
 import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
 import { TilesRenderer } from '3d-tiles-renderer'
 import { ReorientationPlugin } from '3d-tiles-renderer/plugins'
@@ -33,6 +34,7 @@ import {
   sceneLabels,
   type WaterLevelLabelConfig,
   cameraPresets,
+  labelToPresetMap,
 } from '../config/sceneConfig'
 
 // ==================== 外部 Props(嵌入其他项目时使用)====================
@@ -97,6 +99,9 @@ const showCameraPresetPanel = ref(false)
 // ========== 水面材质参数 ==========
 const waterParams = ref<WaterMaterialParams>({ ...defaultWaterParams })
 
+// ========== water02(一期沉砂池水面)独立材质参数 ==========
+const water02Params = ref<WaterMaterialParams>({ ...defaultWaterParams })
+
 // ========== CSCwater 独立材质参数(与主水面分开调节)==========
 const cscwaterParams = ref<CscwaterMaterialParams>({ ...defaultCscwaterParams })
 
@@ -206,6 +211,25 @@ function saveWaterDefaults() {
   showToast('水面材质默认值已保存')
 }
 
+const WATER02_DEFAULTS_KEY = 'water02Params_defaults'
+
+function loadWater02Defaults() {
+  const saved = localStorage.getItem(WATER02_DEFAULTS_KEY)
+  if (saved) {
+    try {
+      const parsed = JSON.parse(saved)
+      Object.assign(water02Params.value, parsed)
+    } catch (e) {
+      console.warn('Failed to parse water02 defaults:', e)
+    }
+  }
+}
+
+function saveWater02Defaults() {
+  localStorage.setItem(WATER02_DEFAULTS_KEY, JSON.stringify(water02Params.value))
+  showToast('一期沉砂池水面材质默认值已保存')
+}
+
 const CSCWATER_DEFAULTS_KEY = 'cscwaterParams_defaults'
 
 function loadCscwaterDefaults() {
@@ -227,6 +251,22 @@ function saveCscwaterDefaults() {
 
 const MODEL_DEFAULTS_KEY = 'modelTransform_defaults'
 
+function loadModelDefaults() {
+  const saved = localStorage.getItem(MODEL_DEFAULTS_KEY)
+  if (saved) {
+    try {
+      const data = JSON.parse(saved)
+      for (const key in data) {
+        if (modelTransformMap[key]) {
+          Object.assign(modelTransformMap[key], data[key])
+        }
+      }
+    } catch (e) {
+      console.warn('Failed to parse model transform defaults:', e)
+    }
+  }
+}
+
 function saveModelDefaults() {
   const t = modelTransform.value
   modelTransformMap[selectedModelKey.value] = {
@@ -261,6 +301,9 @@ for (const key of Object.keys(configModelTransformMap)) {
   modelTransformMap[key] = { ...configModelTransformMap[key] }
 }
 
+// 加载保存的模型变换默认值
+loadModelDefaults()
+
 // 当前选中的模型变换值(双向绑定)
 const modelTransform = ref({ ...modelTransformMap.foam })
 
@@ -269,7 +312,7 @@ function applyModelTransform(key: string) {
   const obj = modelList[key]
   if (!obj) return
   const t = modelTransform.value
-  if (key === 'foam' && 'isMesh' in obj) {
+  if ((key === 'foam' || key === 'foam2') && 'isMesh' in obj) {
     const mesh = obj as THREE.Mesh
     mesh.position.set(t.positionX, t.positionY, t.positionZ)
     mesh.rotation.order = 'YXZ'
@@ -317,6 +360,15 @@ function applyModelTransform(key: string) {
       THREE.MathUtils.degToRad(t.rotationZ)
     )
     obj.scale.set(t.scaleX, t.scaleY, t.scaleZ)
+  } else if (key === 'water02') {
+    obj.position.set(t.positionX, t.positionY, t.positionZ)
+    obj.rotation.order = 'YXZ'
+    obj.rotation.set(
+      THREE.MathUtils.degToRad(t.rotationX),
+      THREE.MathUtils.degToRad(t.rotationY),
+      THREE.MathUtils.degToRad(t.rotationZ)
+    )
+    obj.scale.set(t.scaleX, t.scaleY, t.scaleZ)
   }
 }
 
@@ -364,10 +416,14 @@ let waterMesh: THREE.Mesh
 let water2Mesh: THREE.Mesh | null = null
 let foamMesh: THREE.Mesh | null = null
 let foamMaterial: THREE.ShaderMaterial | null = null
+let foam2Mesh: THREE.Mesh | null = null
+let foam2Material: THREE.ShaderMaterial | null = null
 let flowMesh: THREE.Mesh | null = null
 let flowMaterial: THREE.ShaderMaterial | null = null
 let cscwaterModel: THREE.Object3D | null = null
 let cscwaterMaterial: THREE.ShaderMaterial | null = null
+let water02Model: THREE.Object3D | null = null
+let water02Material: THREE.ShaderMaterial | null = null
 let sunDirection: THREE.Vector3
 let animationId: number
 let tilesRenderer: SuperMapTilesRenderer | null = null
@@ -495,6 +551,56 @@ function createWaterFoamSurface() {
   materialList['foam'] = foamMaterial
 }
 
+// 创建第二个泡沫片面(一期沉砂池泡沫效果)
+function createWaterFoamSurface2() {
+  const textureLoader = new THREE.TextureLoader()
+  const foamTexture = textureLoader.load(foamTexUrl)
+  foamTexture.wrapS = THREE.RepeatWrapping
+  foamTexture.wrapT = THREE.RepeatWrapping
+
+  const directionalFoamTexture = textureLoader.load(directionalFoamTexUrl)
+  directionalFoamTexture.wrapS = THREE.RepeatWrapping
+  directionalFoamTexture.wrapT = THREE.RepeatWrapping
+
+  foam2Material = createWaterFoamUEMaterial({
+    colour: new THREE.Color(foamMatParams.value.colour),
+    opacity: foamMatParams.value.opacity,
+    waterfallSpeed: foamMatParams.value.waterfallSpeed,
+    edgeMaskTiling: foamMatParams.value.edgeMaskTiling,
+    edgeMaskSpeed: foamMatParams.value.edgeMaskSpeed,
+    fresnelExponent: foamMatParams.value.fresnelExponent,
+    directionalFoamIntensity: foamMatParams.value.directionalFoamIntensity,
+    directionalFoamContrast: foamMatParams.value.directionalFoamContrast,
+    directionalFoam1Intensity: foamMatParams.value.directionalFoam1Intensity,
+    directionalFoam2Intensity: foamMatParams.value.directionalFoam2Intensity,
+    directionalFoam2Tiling: foamMatParams.value.directionalFoam2Tiling,
+    directionalFoam2Speed: foamMatParams.value.directionalFoam2Speed,
+    directionalFoam3Intensity: foamMatParams.value.directionalFoam3Intensity,
+    foamFalloff: foamMatParams.value.foamFalloff,
+    gradientTop: foamMatParams.value.gradientTop,
+    gradientBottom: foamMatParams.value.gradientBottom,
+    gradientPower: foamMatParams.value.gradientPower,
+    foamTexture,
+    directionalFoamTexture,
+  })
+
+  const t = modelTransformMap.foam2
+  const geometry = new THREE.PlaneGeometry(t.scaleX, t.scaleY)
+  foam2Mesh = new THREE.Mesh(geometry, foam2Material)
+  foam2Mesh.rotation.order = 'YXZ'
+  foam2Mesh.rotation.set(
+    THREE.MathUtils.degToRad(t.rotationX),
+    THREE.MathUtils.degToRad(t.rotationY),
+    THREE.MathUtils.degToRad(t.rotationZ)
+  )
+  foam2Mesh.position.set(t.positionX, t.positionY, t.positionZ)
+  foam2Mesh.name = 'foam2'
+  foam2Mesh.renderOrder = 1
+  scene.add(foam2Mesh)
+  modelList['foam2'] = foam2Mesh
+  materialList['foam2'] = foam2Material
+}
+
 // 加载流动水纹理模型(GLB 模型+流动纹理材质)
 function loadWaterFlowModel() {
   const textureLoader = new THREE.TextureLoader()
@@ -596,6 +702,48 @@ function loadCSCWaterModel() {
   })
 }
 
+// 加载 water02.glb 模型
+function loadWater02Model() {
+  water02Material = StylizedWaterMaterial.clone()
+  water02Material.uniforms = THREE.UniformsUtils.clone(StylizedWaterMaterial.uniforms)
+  water02Material.polygonOffset = true
+  water02Material.polygonOffsetFactor = 5
+  water02Material.polygonOffsetUnits = 5
+
+  const loader = new GLTFLoader()
+  loader.load(water02GLBUrl, (gltf) => {
+    const object = gltf.scene
+    object.traverse((child) => {
+      if ((child as THREE.Mesh).isMesh) {
+        const mesh = child as THREE.Mesh
+        mesh.material = water02Material!
+        mesh.castShadow = true
+        mesh.receiveShadow = true
+        mesh.frustumCulled = false
+        mesh.renderOrder = 1
+        mesh.material.polygonOffset = true
+        mesh.material.polygonOffsetFactor = 1
+        mesh.material.polygonOffsetUnits = 1
+      }
+    })
+
+    const t = modelTransformMap.water02
+    object.position.set(t.positionX, t.positionY, t.positionZ)
+    object.rotation.order = 'YXZ'
+    object.rotation.set(
+      THREE.MathUtils.degToRad(t.rotationX),
+      THREE.MathUtils.degToRad(t.rotationY),
+      THREE.MathUtils.degToRad(t.rotationZ)
+    )
+    object.scale.set(t.scaleX, t.scaleY, t.scaleZ)
+    object.name = 'water02'
+    scene.add(object)
+    modelList['water02'] = object
+    water02Model = object
+    materialList['water02'] = water02Material
+  })
+}
+
 // 加载超图 3D Tiles 瓦片数据(大范围三维场景)
 async function load3DTiles() {
   const tilesetUrl = props.tilesetUrl
@@ -684,6 +832,26 @@ function disposeScene() {
     cscwaterMaterial = null
   }
 
+  if (water02Model) {
+    if (scene) scene.remove(water02Model)
+    water02Model.traverse((child) => {
+      const mesh = child as THREE.Mesh
+      if (mesh.isMesh) {
+        mesh.geometry?.dispose()
+        if (Array.isArray(mesh.material)) {
+          mesh.material.forEach(m => m.dispose())
+        } else {
+          mesh.material?.dispose()
+        }
+      }
+    })
+    water02Model = null
+  }
+  if (water02Material) {
+    water02Material.dispose()
+    water02Material = null
+  }
+
   if (waterMesh) {
     if (scene) scene.remove(waterMesh)
     waterMesh.geometry.dispose()
@@ -805,8 +973,10 @@ function initScene() {
   createWaterSurface()
   createWater2Surface()
   createWaterFoamSurface()
+  createWaterFoamSurface2()
   loadWaterFlowModel()
   loadCSCWaterModel()
+  loadWater02Model()
   load3DTiles()
   labelDataList.forEach(d => d.componentRef.value?.init(scene, camera))
   initRaycaster()
@@ -831,6 +1001,27 @@ function onMouseClick(event: MouseEvent) {
   mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
   mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1
   raycaster.setFromCamera(mouse, camera)
+
+  // 首先检测标签精灵(图标)点击
+  const labelSprites: THREE.Object3D[] = []
+  labelDataList.forEach(d => {
+    const sprite = d.componentRef.value?.getSprite()
+    if (sprite) {
+      labelSprites.push(sprite)
+    }
+  })
+  const labelIntersects = raycaster.intersectObjects(labelSprites, true)
+  if (labelIntersects.length > 0) {
+    const clickedSprite = labelIntersects[0].object as THREE.Sprite
+    const labelId = clickedSprite.name.replace('label_', '')
+    const presetId = labelToPresetMap[labelId]
+    if (presetId) {
+      flyToPreset(presetId)
+      return
+    }
+  }
+
+  // 然后检测其他物体
   const intersectObjects: THREE.Object3D[] = []
   if (tilesRenderer?.group) {
     intersectObjects.push(tilesRenderer.group)
@@ -872,6 +1063,10 @@ function animate() {
     foamMaterial.uniforms.uTime.value += 0.016
     foamMaterial.uniforms.uCameraPos.value.copy(camera.position)
   }
+  if (foam2Material) {
+    foam2Material.uniforms.uTime.value += 0.016
+    foam2Material.uniforms.uCameraPos.value.copy(camera.position)
+  }
   if (flowMaterial) {
     flowMaterial.uniforms.uTime.value += 0.016
   }
@@ -881,6 +1076,12 @@ function animate() {
     cscwaterMaterial.uniforms.collisionFoamTime.value += 0.016
     cscwaterMaterial.uniforms.cameraPos.value.copy(camera.position)
   }
+  if (water02Material) {
+    water02Material.uniforms.depthSampler.value = depthRenderTarget.depthTexture
+    water02Material.uniforms.iTime.value += 0.016
+    water02Material.uniforms.collisionFoamTime.value += 0.016
+    water02Material.uniforms.cameraPos.value.copy(camera.position)
+  }
   labelDataList.forEach(d => d.componentRef.value?.tick())
   StylizedWaterMaterial.uniforms.cameraPos.value.copy(camera.position)
 
@@ -962,29 +1163,75 @@ function syncWaterParams() {
 watch(() => waterParams.value, syncWaterParams, { deep: true })
 syncWaterParams()
 
+function syncWater02Params() {
+  if (!water02Material || !water02Material.uniforms) return
+  const p = water02Params.value
+  water02Material.uniforms.alpha.value = p.alpha
+  water02Material.uniforms.flowSpeed.value = p.flowSpeed
+  water02Material.uniforms.flowDirection.value.set(p.flowDirectionX, p.flowDirectionY)
+  water02Material.uniforms.normalRotation.value = p.normalRotation
+  water02Material.uniforms.waveHeight.value = p.waveHeight
+  water02Material.uniforms.shallowColor.value.set(p.waterColor)
+  water02Material.uniforms.deepColor.value.set(p.deepColor)
+  water02Material.uniforms.foamIntensity.value = p.foamIntensity
+  water02Material.uniforms.specIntensity.value = p.specIntensity
+  water02Material.uniforms.specPower.value = p.specPower
+  water02Material.uniforms.fresnelPower.value = p.fresnelPower
+  water02Material.uniforms.fresnelIntensity.value = p.fresnelIntensity
+  water02Material.uniforms.depthRange.value = p.depthRange
+  water02Material.uniforms.waterNormalStrength.value = p.waterNormalStrength
+  water02Material.uniforms.waterNormalTiling.value = p.waterNormalTiling
+  water02Material.uniforms.collisionFoamThreshold.value = p.collisionFoamThreshold
+  water02Material.uniforms.collisionFoamStrength.value = p.collisionFoamStrength
+  water02Material.uniforms.fresnelDistanceNear.value = p.fresnelDistanceNear
+  water02Material.uniforms.fresnelDistanceFar.value = p.fresnelDistanceFar
+}
+
+watch(() => water02Params.value, syncWater02Params, { deep: true })
+
 watch(() => cscwaterParams.value, () => {
   syncCscwaterParams()
 }, { deep: true })
 
 watch(() => foamMatParams.value, (p) => {
-  if (!foamMaterial) return
-  foamMaterial.uniforms.uColour.value.set(p.colour)
-  foamMaterial.uniforms.uOpacity.value = p.opacity
-  foamMaterial.uniforms.uWaterfallSpeed.value = p.waterfallSpeed
-  foamMaterial.uniforms.uEdgeMaskTiling.value = p.edgeMaskTiling
-  foamMaterial.uniforms.uEdgeMaskSpeed.value = p.edgeMaskSpeed
-  foamMaterial.uniforms.uFresnelExponent.value = p.fresnelExponent
-  foamMaterial.uniforms.uDirectionalFoamIntensity.value = p.directionalFoamIntensity
-  foamMaterial.uniforms.uDirectionalFoamContrast.value = p.directionalFoamContrast
-  foamMaterial.uniforms.uDirectionalFoam1Intensity.value = p.directionalFoam1Intensity
-  foamMaterial.uniforms.uDirectionalFoam2Intensity.value = p.directionalFoam2Intensity
-  foamMaterial.uniforms.uDirectionalFoam2Tiling.value = p.directionalFoam2Tiling
-  foamMaterial.uniforms.uDirectionalFoam2Speed.value = p.directionalFoam2Speed
-  foamMaterial.uniforms.uDirectionalFoam3Intensity.value = p.directionalFoam3Intensity
-  foamMaterial.uniforms.uFoamFalloff.value = p.foamFalloff
-  foamMaterial.uniforms.uGradientTop.value = p.gradientTop
-  foamMaterial.uniforms.uGradientBottom.value = p.gradientBottom
-  foamMaterial.uniforms.uGradientPower.value = p.gradientPower
+  if (foamMaterial) {
+    foamMaterial.uniforms.uColour.value.set(p.colour)
+    foamMaterial.uniforms.uOpacity.value = p.opacity
+    foamMaterial.uniforms.uWaterfallSpeed.value = p.waterfallSpeed
+    foamMaterial.uniforms.uEdgeMaskTiling.value = p.edgeMaskTiling
+    foamMaterial.uniforms.uEdgeMaskSpeed.value = p.edgeMaskSpeed
+    foamMaterial.uniforms.uFresnelExponent.value = p.fresnelExponent
+    foamMaterial.uniforms.uDirectionalFoamIntensity.value = p.directionalFoamIntensity
+    foamMaterial.uniforms.uDirectionalFoamContrast.value = p.directionalFoamContrast
+    foamMaterial.uniforms.uDirectionalFoam1Intensity.value = p.directionalFoam1Intensity
+    foamMaterial.uniforms.uDirectionalFoam2Intensity.value = p.directionalFoam2Intensity
+    foamMaterial.uniforms.uDirectionalFoam2Tiling.value = p.directionalFoam2Tiling
+    foamMaterial.uniforms.uDirectionalFoam2Speed.value = p.directionalFoam2Speed
+    foamMaterial.uniforms.uDirectionalFoam3Intensity.value = p.directionalFoam3Intensity
+    foamMaterial.uniforms.uFoamFalloff.value = p.foamFalloff
+    foamMaterial.uniforms.uGradientTop.value = p.gradientTop
+    foamMaterial.uniforms.uGradientBottom.value = p.gradientBottom
+    foamMaterial.uniforms.uGradientPower.value = p.gradientPower
+  }
+  if (foam2Material) {
+    foam2Material.uniforms.uColour.value.set(p.colour)
+    foam2Material.uniforms.uOpacity.value = p.opacity
+    foam2Material.uniforms.uWaterfallSpeed.value = p.waterfallSpeed
+    foam2Material.uniforms.uEdgeMaskTiling.value = p.edgeMaskTiling
+    foam2Material.uniforms.uEdgeMaskSpeed.value = p.edgeMaskSpeed
+    foam2Material.uniforms.uFresnelExponent.value = p.fresnelExponent
+    foam2Material.uniforms.uDirectionalFoamIntensity.value = p.directionalFoamIntensity
+    foam2Material.uniforms.uDirectionalFoamContrast.value = p.directionalFoamContrast
+    foam2Material.uniforms.uDirectionalFoam1Intensity.value = p.directionalFoam1Intensity
+    foam2Material.uniforms.uDirectionalFoam2Intensity.value = p.directionalFoam2Intensity
+    foam2Material.uniforms.uDirectionalFoam2Tiling.value = p.directionalFoam2Tiling
+    foam2Material.uniforms.uDirectionalFoam2Speed.value = p.directionalFoam2Speed
+    foam2Material.uniforms.uDirectionalFoam3Intensity.value = p.directionalFoam3Intensity
+    foam2Material.uniforms.uFoamFalloff.value = p.foamFalloff
+    foam2Material.uniforms.uGradientTop.value = p.gradientTop
+    foam2Material.uniforms.uGradientBottom.value = p.gradientBottom
+    foam2Material.uniforms.uGradientPower.value = p.gradientPower
+  }
 }, { deep: true })
 
 watch(() => flowParams.value, () => {
@@ -1170,7 +1417,9 @@ defineExpose({
       <select v-model="selectedModelKey" class="model-select">
         <option value="water">水面</option>
         <option value="water2">水面2</option>
+        <option value="water02">一期沉砂池水面</option>
         <option value="foam">泡沫片面</option>
+        <option value="foam2">一期沉砂池泡沫</option>
         <option value="flow">流动纹理模型</option>
         <option value="cscwater">CSCwater</option>
       </select>
@@ -1235,6 +1484,7 @@ defineExpose({
       <div class="section-label">选择材质</div>
       <select v-model="selectedMaterialKey" class="model-select">
         <option value="water">水材质</option>
+        <option value="water02">一期沉砂池水面材质</option>
         <option value="foam">泡沫材质</option>
         <option value="flow">流动纹理材质</option>
         <option value="cscwater">CSCwater 材质</option>
@@ -1373,6 +1623,138 @@ defineExpose({
       </div>
     </template>
 
+    <template v-if="selectedMaterialKey === 'water02'">
+      <div class="material-section">
+        <div class="section-label">透明度</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.alpha" min="0" max="1" step="0.01" />
+          <span class="slider-value">{{ water02Params.alpha.toFixed(2) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">浪高</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.waveHeight" min="0" max="2" step="0.05" />
+          <span class="slider-value">{{ water02Params.waveHeight.toFixed(2) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">水流速度</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.flowSpeed" min="0" max="3" step="0.1" />
+          <span class="slider-value">{{ water02Params.flowSpeed.toFixed(1) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">流向 X</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.flowDirectionX" min="-2" max="2" step="0.1" />
+          <span class="slider-value">{{ water02Params.flowDirectionX.toFixed(1) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">流向 Z</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.flowDirectionY" min="-2" max="2" step="0.1" />
+          <span class="slider-value">{{ water02Params.flowDirectionY.toFixed(1) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">法线旋转</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.normalRotation" min="-180" max="180" step="1" />
+          <span class="slider-value">{{ water02Params.normalRotation.toFixed(0) }}°</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">浅水颜色</div>
+        <div class="color-item">
+          <input type="color" v-model="water02Params.waterColor" />
+          <span class="color-value">{{ water02Params.waterColor }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">深水颜色</div>
+        <div class="color-item">
+          <input type="color" v-model="water02Params.deepColor" />
+          <span class="color-value">{{ water02Params.deepColor }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">水深范围</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.depthRange" min="1" max="50" step="0.5" />
+          <span class="slider-value">{{ water02Params.depthRange.toFixed(1) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">水法线强度</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.waterNormalStrength" min="0" max="2" step="0.05" />
+          <span class="slider-value">{{ water02Params.waterNormalStrength.toFixed(2) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">水纹平铺</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.waterNormalTiling" min="0.01" max="5" step="0.01" />
+          <span class="slider-value">{{ water02Params.waterNormalTiling.toFixed(2) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">高光强度</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.specIntensity" min="0" max="5" step="0.1" />
+          <span class="slider-value">{{ water02Params.specIntensity.toFixed(1) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">高光锐度</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.specPower" min="1" max="256" step="1" />
+          <span class="slider-value">{{ water02Params.specPower.toFixed(0) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">菲涅尔功率</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.fresnelPower" min="0.1" max="10" step="0.1" />
+          <span class="slider-value">{{ water02Params.fresnelPower.toFixed(1) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">菲涅尔强度</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.fresnelIntensity" min="0" max="3" step="0.1" />
+          <span class="slider-value">{{ water02Params.fresnelIntensity.toFixed(1) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">泡沫强度</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.foamIntensity" min="0" max="2" step="0.05" />
+          <span class="slider-value">{{ water02Params.foamIntensity.toFixed(2) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">碰撞泡沫阈值</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.collisionFoamThreshold" min="0" max="2" step="0.05" />
+          <span class="slider-value">{{ water02Params.collisionFoamThreshold.toFixed(2) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <div class="section-label">碰撞泡沫强度</div>
+        <div class="slider-item">
+          <input type="range" v-model.number="water02Params.collisionFoamStrength" min="0" max="3" step="0.1" />
+          <span class="slider-value">{{ water02Params.collisionFoamStrength.toFixed(1) }}</span>
+        </div>
+      </div>
+      <div class="material-section">
+        <button class="default-btn" @click="saveWater02Defaults">设置默认值</button>
+      </div>
+    </template>
+
     <template v-if="selectedMaterialKey === 'foam'">
       <div class="material-section">
         <div class="section-label">颜色</div>