<script setup lang="ts">
import { onMounted, onUnmounted, ref, reactive, watch } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { Sky } from 'three/examples/jsm/objects/Sky.js'
import { StylizedWaterMaterial } from '../materials/waterNew'
import { createWaterFoamUEMaterial } from '../materials/waterFoamUE'
import { createWaterFlowMaterial } from '../materials/waterFlow'
import foamTexUrl from '../assets/texture/T_Waterfall_Foam.PNG'
import directionalFoamTexUrl from '../assets/texture/T_Waterfall_Foam_Directional.PNG'
import flowTexUrl from '../assets/texture/FlowTexture/T_FlowTexture_BC.PNG'
import foamMacroTexUrl from '../assets/texture/FlowTexture/T_FoamMacro_BC.PNG'
import maskTexUrl from '../assets/texture/FlowTexture/MASK_003.PNG'
import flowNormalTexUrl from '../assets/texture/FlowTexture/T_FlowTexture_BC_NORM.PNG'
import foamMacroNormalTexUrl from '../assets/texture/FlowTexture/T_FoamMacro_BC_NORM.PNG'
import langGLBUrl from '../assets/lang.glb'
import cscwaterGLBUrl from '../assets/CSCwater.glb'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { TilesRenderer } from '3d-tiles-renderer'
import { ReorientationPlugin } from '3d-tiles-renderer/plugins'
import WaterLevelLabel from './WaterLevelLabel.vue'
import {
  modelTransformMap as configModelTransformMap,
  defaultWaterParams,
  defaultCscwaterParams,
  defaultFoamMatParams,
  defaultFlowParams,
  type ModelTransform,
  type WaterMaterialParams,
  type CscwaterMaterialParams,
  type FoamMaterialParams,
  type FlowMaterialParams,
  sceneLabels,
  type WaterLevelLabelConfig,
  cameraPresets,
} from '../config/sceneConfig'

// ==================== 外部 Props（嵌入其他项目时使用）====================
const props = withDefaults(defineProps<{
  labelValues?: Record<string, number>
  showDebugTools?: boolean
  tilesetUrl?: string
  cameraPosition?: { x: number; y: number; z: number }
  cameraTarget?: { x: number; y: number; z: number }
}>(), {
  labelValues: () => ({}),
  showDebugTools: false,
  tilesetUrl: '/scene/tileset.json',
  cameraPosition: () => ({ x: -831.56685, y: 40.63456, z: -2225.321 }),
  cameraTarget: () => ({ x: -843.0744, y: 12.01539, z: -2182.06814 }),
})

// 继承 3D Tiles 渲染器，修复 asset 字段缺失的兼容性问题
class SuperMapTilesRenderer extends TilesRenderer {
  preprocessTileset(json: any, url: string, parent = null) {
    if (!json.asset) {
      json.asset = { version: '1.0' }
    }
    const parentProto = Object.getPrototypeOf(Object.getPrototypeOf(this))
    parentProto.preprocessTileset.call(this, json, url, parent)
  }
}

// 3D 场景挂载点的 DOM 引用
const containerRef = ref<HTMLDivElement>()

// 底部提示消息弹窗
function showToast(msg: string) {
  const el = document.createElement('div')
  el.className = 'toast-message'
  el.textContent = msg
  document.body.appendChild(el)
  setTimeout(() => {
    el.classList.add('toast-fade')
    setTimeout(() => el.remove(), 300)
  }, 1500)
}

// 鼠标拾取到的坐标
const pickedPosition = ref<{ x: number; y: number; z: number } | null>({ x: 0, y: 0, z: 0 })
// 相机位置/目标/距离等信息
const cameraInfo = ref({
  position: { x: 0, y: 0, z: 0 },
  target: { x: 0, y: 0, z: 0 },
  distance: 0,
  minDistance: 0,
  maxDistance: 0,
})

// 调试面板的显示开关
const showCoordinatePanel = ref(false)
const showCameraPanel = ref(false)
const showModelPanel = ref(false)
const showMaterialPanel = ref(false)
const showCameraPresetPanel = ref(false)

// ========== 水面材质参数 ==========
const waterParams = ref<WaterMaterialParams>({ ...defaultWaterParams })

// ========== CSCwater 独立材质参数（与主水面分开调节）==========
const cscwaterParams = ref<CscwaterMaterialParams>({ ...defaultCscwaterParams })

// ========== 泡沫片面材质参数 ==========
const foamMatParams = ref<FoamMaterialParams>({ ...defaultFoamMatParams })

// ========== 流动纹理材质参数 ==========
const flowParams = ref<FlowMaterialParams>({ ...defaultFlowParams })

// ---- 从 localStorage 恢复/保存材质默认值 ----

const FLOW_DEFAULTS_KEY = 'flowMatParams_defaults'

function loadFlowDefaults() {
  const saved = localStorage.getItem(FLOW_DEFAULTS_KEY)
  if (saved) {
    try {
      const parsed = JSON.parse(saved)
      Object.assign(flowParams.value, parsed)
    } catch (e) {
      console.warn('Failed to parse flow defaults:', e)
    }
  }
}

function saveFlowDefaults() {
  localStorage.setItem(FLOW_DEFAULTS_KEY, JSON.stringify(flowParams.value))
  showToast('流动纹理材质默认值已保存')
}

// 将 flow 材质参数同步到着色器的 uniform 变量
function syncFlowParams() {
  if (!flowMaterial) return
  const p = flowParams.value
  flowMaterial.uniforms.uColor.value.set(p.colour)
  flowMaterial.uniforms.uSpeedX.value = p.speedX
  flowMaterial.uniforms.uSpeedY.value = p.speedY
  flowMaterial.uniforms.uTilingU.value = p.tilingU
  flowMaterial.uniforms.uTilingV.value = p.tilingV
  flowMaterial.uniforms.uRotationAngle.value = p.rotationAngle
  flowMaterial.uniforms.uPower.value = p.power
  flowMaterial.uniforms.uWaterGate.value = p.waterGate
  flowMaterial.uniforms.uWaterGate02.value = p.waterGate02
  flowMaterial.uniforms.uEdgeMaskIntensity.value = p.edgeMaskIntensity
  flowMaterial.uniforms.uOpaquePower.value = p.opaquePower
  flowMaterial.uniforms.uEdgeFade.value = p.edgeFade
}

// 将 cscwater 材质参数同步到着色器的 uniform 变量
function syncCscwaterParams() {
  if (!cscwaterMaterial) return
  const p = cscwaterParams.value
  cscwaterMaterial.uniforms.alpha.value = p.alpha
  cscwaterMaterial.uniforms.flowSpeed.value = p.flowSpeed
  cscwaterMaterial.uniforms.flowDirection.value.set(p.flowDirectionX, p.flowDirectionY)
  cscwaterMaterial.uniforms.normalRotation.value = p.normalRotation
  cscwaterMaterial.uniforms.waveHeight.value = p.waveHeight
  cscwaterMaterial.uniforms.shallowColor.value.set(p.waterColor)
  cscwaterMaterial.uniforms.deepColor.value.set(p.deepColor)
  cscwaterMaterial.uniforms.foamIntensity.value = p.foamIntensity
  cscwaterMaterial.uniforms.specIntensity.value = p.specIntensity
  cscwaterMaterial.uniforms.specPower.value = p.specPower
  cscwaterMaterial.uniforms.fresnelPower.value = p.fresnelPower
  cscwaterMaterial.uniforms.fresnelIntensity.value = p.fresnelIntensity
  cscwaterMaterial.uniforms.depthRange.value = p.depthRange
  cscwaterMaterial.uniforms.waterNormalStrength.value = p.waterNormalStrength
  cscwaterMaterial.uniforms.waterNormalTiling.value = p.waterNormalTiling
  cscwaterMaterial.uniforms.collisionFoamThreshold.value = p.collisionFoamThreshold
  cscwaterMaterial.uniforms.collisionFoamStrength.value = p.collisionFoamStrength
}

const FOAM_DEFAULTS_KEY = 'foamMatParams_defaults'

function loadFoamDefaults() {
  const saved = localStorage.getItem(FOAM_DEFAULTS_KEY)
  if (saved) {
    try {
      const parsed = JSON.parse(saved)
      Object.assign(foamMatParams.value, parsed)
    } catch (e) {
      console.warn('Failed to parse foam defaults:', e)
    }
  }
}

function saveFoamDefaults() {
  localStorage.setItem(FOAM_DEFAULTS_KEY, JSON.stringify(foamMatParams.value))
  showToast('泡沫材质默认值已保存')
}

const WATER_DEFAULTS_KEY = 'waterParams_defaults'

function loadWaterDefaults() {
  const saved = localStorage.getItem(WATER_DEFAULTS_KEY)
  if (saved) {
    try {
      const parsed = JSON.parse(saved)
      Object.assign(waterParams.value, parsed)
    } catch (e) {
      console.warn('Failed to parse water defaults:', e)
    }
  }
}

function saveWaterDefaults() {
  localStorage.setItem(WATER_DEFAULTS_KEY, JSON.stringify(waterParams.value))
  showToast('水面材质默认值已保存')
}

const CSCWATER_DEFAULTS_KEY = 'cscwaterParams_defaults'

function loadCscwaterDefaults() {
  const saved = localStorage.getItem(CSCWATER_DEFAULTS_KEY)
  if (saved) {
    try {
      const parsed = JSON.parse(saved)
      Object.assign(cscwaterParams.value, parsed)
    } catch (e) {
      console.warn('Failed to parse cscwater defaults:', e)
    }
  }
}

function saveCscwaterDefaults() {
  localStorage.setItem(CSCWATER_DEFAULTS_KEY, JSON.stringify(cscwaterParams.value))
  showToast('CSCwater 材质默认值已保存')
}

const MODEL_DEFAULTS_KEY = 'modelTransform_defaults'

function saveModelDefaults() {
  const t = modelTransform.value
  modelTransformMap[selectedModelKey.value] = {
    positionX: t.positionX,
    positionY: t.positionY,
    positionZ: t.positionZ,
    rotationX: t.rotationX,
    rotationY: t.rotationY,
    rotationZ: t.rotationZ,
    scaleX: t.scaleX,
    scaleY: t.scaleY,
    scaleZ: t.scaleZ,
  }
  const data: Record<string, typeof modelTransformMap.foam> = {}
  for (const key in modelTransformMap) {
    data[key] = { ...modelTransformMap[key] }
  }
  localStorage.setItem(MODEL_DEFAULTS_KEY, JSON.stringify(data))
  showToast('模型变换默认值已保存')
}

// 场景中可调试的模型列表，按 key 索引
const modelList: Record<string, THREE.Object3D | null> = {}
const selectedModelKey = ref('foam')

const materialList: Record<string, THREE.Material | null> = {}
const selectedMaterialKey = ref('water')

// 各模型的初始变换参数（位置/旋转/缩放）
const modelTransformMap: Record<string, ModelTransform> = {}
for (const key of Object.keys(configModelTransformMap)) {
  modelTransformMap[key] = { ...configModelTransformMap[key] }
}

// 当前选中的模型变换值（双向绑定）
const modelTransform = ref({ ...modelTransformMap.foam })

// 将 modelTransform 的数值应用到 Three.js 物体上
function applyModelTransform(key: string) {
  const obj = modelList[key]
  if (!obj) return
  const t = modelTransform.value
  if (key === 'foam' && 'isMesh' in obj) {
    const mesh = obj as THREE.Mesh
    mesh.position.set(t.positionX, t.positionY, t.positionZ)
    mesh.rotation.order = 'YXZ'
    mesh.rotation.set(
      THREE.MathUtils.degToRad(t.rotationX),
      THREE.MathUtils.degToRad(t.rotationY),
      THREE.MathUtils.degToRad(t.rotationZ)
    )
    if (mesh.geometry.type === 'PlaneGeometry') {
      const geom = mesh.geometry as THREE.PlaneGeometry
      geom.dispose()
      mesh.geometry = new THREE.PlaneGeometry(t.scaleX, t.scaleY)
    }
  } else if (key === 'water') {
    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)
    )
  } else if (key === 'water2') {
    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)
    )
  } else if (key === 'flow') {
    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)
  } else if (key === 'cscwater') {
    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)
  }
}

// 切换模型时，加载该模型保存的变换参数
watch(selectedModelKey, (key) => {
  const saved = modelTransformMap[key]
  if (saved) {
    modelTransform.value = { ...saved }
  }
})

// 变换参数变化时实时应用到场景
watch(modelTransform, () => {
  applyModelTransform(selectedModelKey.value)
}, { deep: true })

// 水位标签
interface LabelData {
  config: WaterLevelLabelConfig
  componentRef: ReturnType<typeof ref<InstanceType<typeof WaterLevelLabel> | null>>
}
const labelDataList: LabelData[] = []
const labelValues = reactive<Record<string, number>>({})

function initLabelData() {
  labelDataList.length = 0
  for (const cfg of sceneLabels.main) {
    const externalValue = props.labelValues[cfg.id]
    labelValues[cfg.id] = externalValue !== undefined ? externalValue : cfg.initialValue
    labelDataList.push({
      config: cfg,
      componentRef: ref<InstanceType<typeof WaterLevelLabel> | null>(null),
    })
  }
}
initLabelData()

// ========== Three.js 核心变量声明 ==========
let scene: THREE.Scene
let camera: THREE.PerspectiveCamera
let renderer: THREE.WebGLRenderer
let controls: OrbitControls
let sky: Sky
let waterMesh: THREE.Mesh
let water2Mesh: THREE.Mesh | null = null
let foamMesh: THREE.Mesh | null = null
let foamMaterial: 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 sunDirection: THREE.Vector3
let animationId: number
let tilesRenderer: SuperMapTilesRenderer | null = null
let raycaster: THREE.Raycaster
let mouse: THREE.Vector2
let depthRenderTarget: THREE.WebGLRenderTarget
let sceneInitialized = false

// 创建天空背景（含体积云效果）
function createSky() {
  sky = new Sky()
  sky.scale.setScalar(50000)
  scene.add(sky)

  const uniforms = sky.material.uniforms
  uniforms.turbidity.value = 6
  uniforms.rayleigh.value = 0.1
  uniforms.mieCoefficient.value = 0.005
  uniforms.mieDirectionalG.value = 0.7
  uniforms.sunPosition.value.set(20, 30, 10)

  uniforms.cloudScale.value = 0.0008
  uniforms.cloudSpeed.value = 0.00015
  uniforms.cloudCoverage.value = 0.6
  uniforms.cloudDensity.value = 0.6
  uniforms.cloudElevation.value = 0.9
}

// 创建水面网格（使用自定义风格化水材质）
function createWaterSurface() {
  const t = modelTransformMap.water
  waterMesh = new THREE.Mesh(
    new THREE.PlaneGeometry(t.scaleX, t.scaleY, 120, 120),
    StylizedWaterMaterial
  )
  waterMesh.rotation.order = 'YXZ'
  waterMesh.rotation.set(
    THREE.MathUtils.degToRad(t.rotationX),
    THREE.MathUtils.degToRad(t.rotationY),
    THREE.MathUtils.degToRad(t.rotationZ)
  )
  waterMesh.position.set(t.positionX, t.positionY, t.positionZ)
  waterMesh.receiveShadow = true
  waterMesh.name = 'water'
  waterMesh.renderOrder = 0
  scene.add(waterMesh)
  modelList['water'] = waterMesh
  materialList['water'] = StylizedWaterMaterial
  StylizedWaterMaterial.uniforms.cameraPos.value.copy(camera.position)
  StylizedWaterMaterial.uniforms.sunDirection.value.copy(sunDirection)
  StylizedWaterMaterial.uniforms.cameraNear.value = camera.near
  StylizedWaterMaterial.uniforms.cameraFar.value = camera.far
  const container = containerRef.value!
  StylizedWaterMaterial.uniforms.iResolution.value.set(container.clientWidth, container.clientHeight)
}

// 创建第二片面（使用与主水面相同的风格化水材质）
function createWater2Surface() {
  const t = modelTransformMap.water2
  water2Mesh = new THREE.Mesh(
    new THREE.PlaneGeometry(t.scaleX, t.scaleY, 120, 120),
    StylizedWaterMaterial
  )
  water2Mesh.rotation.order = 'YXZ'
  water2Mesh.rotation.set(
    THREE.MathUtils.degToRad(t.rotationX),
    THREE.MathUtils.degToRad(t.rotationY),
    THREE.MathUtils.degToRad(t.rotationZ)
  )
  water2Mesh.position.set(t.positionX, t.positionY, t.positionZ)
  water2Mesh.receiveShadow = true
  water2Mesh.name = 'water2'
  water2Mesh.renderOrder = 0
  scene.add(water2Mesh)
  modelList['water2'] = water2Mesh
}

// 创建泡沫片面（瀑布泡沫效果）
function createWaterFoamSurface() {
  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

  foamMaterial = 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.foam
  const geometry = new THREE.PlaneGeometry(t.scaleX, t.scaleY)
  foamMesh = new THREE.Mesh(geometry, foamMaterial)
  foamMesh.rotation.order = 'YXZ'
  foamMesh.rotation.set(
    THREE.MathUtils.degToRad(t.rotationX),
    THREE.MathUtils.degToRad(t.rotationY),
    THREE.MathUtils.degToRad(t.rotationZ)
  )
  foamMesh.position.set(t.positionX, t.positionY, t.positionZ)
  foamMesh.name = 'foam'
  foamMesh.renderOrder = 1
  scene.add(foamMesh)
  modelList['foam'] = foamMesh
  materialList['foam'] = foamMaterial
}

// 加载流动水纹理模型（GLB 模型+流动纹理材质）
function loadWaterFlowModel() {
  const textureLoader = new THREE.TextureLoader()

  const flowTexture = textureLoader.load(flowTexUrl)
  flowTexture.wrapS = THREE.RepeatWrapping
  flowTexture.wrapT = THREE.RepeatWrapping

  const foamMacroTexture = textureLoader.load(foamMacroTexUrl)
  foamMacroTexture.wrapS = THREE.RepeatWrapping
  foamMacroTexture.wrapT = THREE.RepeatWrapping

  const maskTexture = textureLoader.load(maskTexUrl)
  maskTexture.wrapS = THREE.RepeatWrapping
  maskTexture.wrapT = THREE.RepeatWrapping

  const flowNormalTexture = textureLoader.load(flowNormalTexUrl)
  flowNormalTexture.wrapS = THREE.RepeatWrapping
  flowNormalTexture.wrapT = THREE.RepeatWrapping

  const foamMacroNormalTexture = textureLoader.load(foamMacroNormalTexUrl)
  foamMacroNormalTexture.wrapS = THREE.RepeatWrapping
  foamMacroNormalTexture.wrapT = THREE.RepeatWrapping

  flowMaterial = createWaterFlowMaterial({
    flowTexture,
    foamMacroTexture,
    maskTexture,
    flowNormalTexture,
    foamMacroNormalTexture,
  })
  syncFlowParams()

  const loader = new GLTFLoader()
  loader.load(langGLBUrl, (gltf) => {
    const object = gltf.scene
    object.traverse((child) => {
      if ((child as THREE.Mesh).isMesh) {
        const mesh = child as THREE.Mesh
        mesh.material = flowMaterial!
        mesh.castShadow = true
        mesh.receiveShadow = true
        mesh.frustumCulled = false
        mesh.renderOrder = 1
        flowMesh = mesh
      }
    })

    const t = modelTransformMap.flow
    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 = 'flow'
    scene.add(object)
    modelList['flow'] = object
    materialList['flow'] = flowMaterial
  })
}

// 加载 CSCwater.glb 模型
function loadCSCWaterModel() {
  cscwaterMaterial = StylizedWaterMaterial.clone()
  cscwaterMaterial.uniforms = THREE.UniformsUtils.clone(StylizedWaterMaterial.uniforms)
  syncCscwaterParams()

  const loader = new GLTFLoader()
  loader.load(cscwaterGLBUrl, (gltf) => {
    const object = gltf.scene
    object.traverse((child) => {
      if ((child as THREE.Mesh).isMesh) {
        const mesh = child as THREE.Mesh
        mesh.material = cscwaterMaterial!
        mesh.castShadow = true
        mesh.receiveShadow = true
        mesh.frustumCulled = false
        mesh.renderOrder = 1
      }
    })

    const t = modelTransformMap.cscwater
    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 = 'cscwater'
    scene.add(object)
    modelList['cscwater'] = object
    cscwaterModel = object
    materialList['cscwater'] = cscwaterMaterial
  })
}

// 加载超图 3D Tiles 瓦片数据（大范围三维场景）
async function load3DTiles() {
  const tilesetUrl = props.tilesetUrl
  tilesRenderer = new SuperMapTilesRenderer(tilesetUrl)
  tilesRenderer.setCamera(camera)
  tilesRenderer.setResolutionFromRenderer(camera, renderer)

  tilesRenderer.registerPlugin(new ReorientationPlugin())

  scene.add(tilesRenderer.group)

  scene.fog = null

  tilesRenderer.addEventListener('load-error', (evt) => {
    console.error('3D Tiles load error:', evt.error, 'URL:', evt.url)
  })
  tilesRenderer.addEventListener('load-tile', (evt) => {
    console.log('Tile loaded:', evt.tile.content?.uri)
  })
  tilesRenderer.addEventListener('error-tile', (evt) => {
    console.error('Tile error:', evt.tile.content?.uri, evt.error)
  })

  console.log('3D Tiles renderer initialized:', tilesetUrl)
}

// 释放所有 Three.js 资源（可在 initScene 之前和 onUnmounted 时反复调用）
function disposeScene() {
  cancelAnimationFrame(animationId)
  animationId = 0

  labelDataList.forEach(d => d.componentRef.value?.dispose())

  if (tilesRenderer) {
    if (scene) scene.remove(tilesRenderer.group)
    tilesRenderer.dispose?.()
    tilesRenderer = null
  }

  if (foamMesh) {
    if (scene) scene.remove(foamMesh)
    foamMesh.geometry.dispose()
    if (foamMaterial) {
      for (const key of Object.keys(foamMaterial.uniforms)) {
        const val = foamMaterial.uniforms[key].value
        if (val instanceof THREE.Texture) val.dispose()
      }
      foamMaterial.dispose()
    }
    foamMesh = null
    foamMaterial = null
  }

  if (flowMesh) {
    const parent = flowMesh.parent
    if (parent && scene) scene.remove(parent)
    flowMesh.geometry.dispose()
    if (flowMaterial) {
      for (const key of Object.keys(flowMaterial.uniforms)) {
        const val = flowMaterial.uniforms[key].value
        if (val instanceof THREE.Texture) val.dispose()
      }
      flowMaterial.dispose()
    }
    flowMesh = null
    flowMaterial = null
  }

  if (cscwaterModel) {
    if (scene) scene.remove(cscwaterModel)
    cscwaterModel.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()
        }
      }
    })
    cscwaterModel = null
  }
  if (cscwaterMaterial) {
    cscwaterMaterial.dispose()
    cscwaterMaterial = null
  }

  if (waterMesh) {
    if (scene) scene.remove(waterMesh)
    waterMesh.geometry.dispose()
    waterMesh = null
  }

  if (water2Mesh) {
    if (scene) scene.remove(water2Mesh)
    water2Mesh.geometry.dispose()
    water2Mesh = null
  }

  if (StylizedWaterMaterial) {
    StylizedWaterMaterial.dispose()
  }

  if (sky) {
    if (scene) scene.remove(sky)
    sky.material.dispose()
    sky = null
  }

  if (depthRenderTarget) {
    depthRenderTarget.depthTexture?.dispose()
    depthRenderTarget.dispose()
    depthRenderTarget = null
  }

  if (controls) {
    controls.dispose()
    controls = null
  }

  if (renderer) {
    const domEl = renderer.domElement
    if (domEl && domEl.parentNode) {
      domEl.parentNode.removeChild(domEl)
    }
    renderer.forceContextLoss()
    renderer.dispose()
    renderer = null
  }

  if (scene) {
    while (scene.children.length > 0) {
      scene.remove(scene.children[0])
    }
    scene = null
  }

  camera = null
  sceneInitialized = false
}

// 初始化整个 Three.js 场景（带防重入保护）
function initScene() {
  if (sceneInitialized) {
    disposeScene()
  }
  const container = containerRef.value!

  scene = new THREE.Scene()

  camera = new THREE.PerspectiveCamera(60, container.clientWidth / container.clientHeight, 0.1, 100000)
  camera.position.set(props.cameraPosition.x, props.cameraPosition.y, props.cameraPosition.z)

  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize(container.clientWidth, container.clientHeight)
  renderer.domElement.style.width = '100%'
  renderer.domElement.style.height = '100%'
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
  renderer.toneMapping = THREE.ACESFilmicToneMapping
  renderer.toneMappingExposure = 1.0
  renderer.shadowMap.enabled = true
  renderer.shadowMap.type = THREE.PCFShadowMap
  container.appendChild(renderer.domElement)

  const pixelWidth = Math.floor(container.clientWidth * window.devicePixelRatio)
  const pixelHeight = Math.floor(container.clientHeight * window.devicePixelRatio)
  depthRenderTarget = new THREE.WebGLRenderTarget(pixelWidth, pixelHeight)
  depthRenderTarget.depthTexture = new THREE.DepthTexture(pixelWidth, pixelHeight)

  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
  controls.dampingFactor = 0.03
  controls.screenSpacePanning = false
  controls.minDistance = 0
  controls.maxDistance = Infinity
  controls.mouseButtons = {
    LEFT: THREE.MOUSE.PAN,
    MIDDLE: THREE.MOUSE.DOLLY,
    RIGHT: THREE.MOUSE.ROTATE,
  }
  controls.target.set(props.cameraTarget.x, props.cameraTarget.y, props.cameraTarget.z)
  controls.maxPolarAngle = Math.PI / 2.1
  controls.minDistance = 5
  controls.maxDistance = 500

  createSky()

  const hemisphereLight = new THREE.HemisphereLight(0xd4d4d4, 0x3d6b4a, 0.6)
  scene.add(hemisphereLight)

  sunDirection = new THREE.Vector3(20, 30, 10).normalize()

  const sunLight = new THREE.DirectionalLight(0xffeedd, 2.0)
  sunLight.position.set(20, 30, 10)
  sunLight.castShadow = true
  sunLight.shadow.mapSize.width = 2048
  sunLight.shadow.mapSize.height = 2048
  sunLight.shadow.camera.near = 0.5
  sunLight.shadow.camera.far = 60
  sunLight.shadow.camera.left = -20
  sunLight.shadow.camera.right = 20
  sunLight.shadow.camera.top = 20
  sunLight.shadow.camera.bottom = -20
  scene.add(sunLight)

  createWaterSurface()
  createWater2Surface()
  createWaterFoamSurface()
  loadWaterFlowModel()
  loadCSCWaterModel()
  load3DTiles()
  labelDataList.forEach(d => d.componentRef.value?.init(scene, camera))
  initRaycaster()
  sceneInitialized = true
  animate()
}

// 初始化鼠标射线拾取
function initRaycaster() {
  raycaster = new THREE.Raycaster()
  mouse = new THREE.Vector2()
  const container = containerRef.value!
  container.addEventListener('click', onMouseClick)
}

// 鼠标点击获取 3D 场景中的坐标
function onMouseClick(event: MouseEvent) {
  const target = event.target as HTMLElement
  if (target.closest('.panel') || target.closest('.toolbar')) return
  const container = containerRef.value!
  const rect = container.getBoundingClientRect()
  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 intersectObjects: THREE.Object3D[] = []
  if (tilesRenderer?.group) {
    intersectObjects.push(tilesRenderer.group)
  }
  if (waterMesh) {
    intersectObjects.push(waterMesh)
  }
  const intersects = raycaster.intersectObjects(intersectObjects, true)
  if (intersects.length > 0) {
    const point = intersects[0].point
    pickedPosition.value = {
      x: Number(point.x.toFixed(3)),
      y: Number(point.y.toFixed(3)),
      z: Number(point.z.toFixed(3)),
    }
  }
}

// 每帧渲染循环
function animate() {
  animationId = requestAnimationFrame(animate)
  sky.material.uniforms.time.value += 0.001
  controls.update()
  tilesRenderer?.update()

  // 将水面的深度写入深度纹理（用于水面透明交互动效）
  waterMesh.visible = false
  const prevRT = renderer.getRenderTarget()
  renderer.setRenderTarget(depthRenderTarget)
  renderer.render(scene, camera)
  renderer.setRenderTarget(prevRT)
  waterMesh.visible = true

  // 更新各材质的时间 uniform 实现动画
  StylizedWaterMaterial.uniforms.depthSampler.value = depthRenderTarget.depthTexture
  StylizedWaterMaterial.uniforms.iTime.value += 0.016
  StylizedWaterMaterial.uniforms.collisionFoamTime.value += 0.016
  if (foamMaterial) {
    foamMaterial.uniforms.uTime.value += 0.016
    foamMaterial.uniforms.uCameraPos.value.copy(camera.position)
  }
  if (flowMaterial) {
    flowMaterial.uniforms.uTime.value += 0.016
  }
  if (cscwaterMaterial) {
    cscwaterMaterial.uniforms.depthSampler.value = depthRenderTarget.depthTexture
    cscwaterMaterial.uniforms.iTime.value += 0.016
    cscwaterMaterial.uniforms.collisionFoamTime.value += 0.016
    cscwaterMaterial.uniforms.cameraPos.value.copy(camera.position)
  }
  labelDataList.forEach(d => d.componentRef.value?.tick())
  StylizedWaterMaterial.uniforms.cameraPos.value.copy(camera.position)

  // 更新相机信息面板
  cameraInfo.value.position = {
    x: Number(camera.position.x.toFixed(3)),
    y: Number(camera.position.y.toFixed(3)),
    z: Number(camera.position.z.toFixed(3)),
  }
  cameraInfo.value.target = {
    x: Number(controls.target.x.toFixed(3)),
    y: Number(controls.target.y.toFixed(3)),
    z: Number(controls.target.z.toFixed(3)),
  }
  cameraInfo.value.distance = Number(camera.position.distanceTo(controls.target).toFixed(3))
  cameraInfo.value.minDistance = controls.minDistance
  cameraInfo.value.maxDistance = controls.maxDistance

  renderer.render(scene, camera)
}

// 窗口大小变化自适应
function onResize() {
  if (!containerRef.value) return
  const width = containerRef.value.clientWidth
  const height = containerRef.value.clientHeight
  camera.aspect = width / height
  camera.updateProjectionMatrix()
  renderer.setSize(width, height)
  const pixelWidth = Math.floor(width * window.devicePixelRatio)
  const pixelHeight = Math.floor(height * window.devicePixelRatio)
  depthRenderTarget.setSize(pixelWidth, pixelHeight)
  StylizedWaterMaterial.uniforms.iResolution.value.set(width, height)
  if (tilesRenderer) {
    tilesRenderer.setResolutionFromRenderer(camera, renderer)
  }
}

onMounted(() => {
  initScene()
  window.addEventListener('resize', onResize)
})

// 组件销毁时释放所有 Three.js 资源
onUnmounted(() => {
  window.removeEventListener('resize', onResize)
  if (containerRef.value) {
    containerRef.value.removeEventListener('click', onMouseClick)
  }
  disposeScene()
})

// ========== 材质参数的响应式监听，实时同步到着色器 ==========

function syncWaterParams() {
  if (!StylizedWaterMaterial || !StylizedWaterMaterial.uniforms) return
  const p = waterParams.value
  StylizedWaterMaterial.uniforms.alpha.value = p.alpha
  StylizedWaterMaterial.uniforms.flowSpeed.value = p.flowSpeed
  StylizedWaterMaterial.uniforms.flowDirection.value.set(p.flowDirectionX, p.flowDirectionY)
  StylizedWaterMaterial.uniforms.normalRotation.value = p.normalRotation
  StylizedWaterMaterial.uniforms.waveHeight.value = p.waveHeight
  StylizedWaterMaterial.uniforms.shallowColor.value.set(p.waterColor)
  StylizedWaterMaterial.uniforms.deepColor.value.set(p.deepColor)
  StylizedWaterMaterial.uniforms.foamIntensity.value = p.foamIntensity
  StylizedWaterMaterial.uniforms.specIntensity.value = p.specIntensity
  StylizedWaterMaterial.uniforms.specPower.value = p.specPower
  StylizedWaterMaterial.uniforms.fresnelPower.value = p.fresnelPower
  StylizedWaterMaterial.uniforms.fresnelIntensity.value = p.fresnelIntensity
  StylizedWaterMaterial.uniforms.depthRange.value = p.depthRange
  StylizedWaterMaterial.uniforms.waterNormalStrength.value = p.waterNormalStrength
  StylizedWaterMaterial.uniforms.waterNormalTiling.value = p.waterNormalTiling
  StylizedWaterMaterial.uniforms.collisionFoamThreshold.value = p.collisionFoamThreshold
  StylizedWaterMaterial.uniforms.collisionFoamStrength.value = p.collisionFoamStrength
  StylizedWaterMaterial.uniforms.fresnelDistanceNear.value = p.fresnelDistanceNear
  StylizedWaterMaterial.uniforms.fresnelDistanceFar.value = p.fresnelDistanceFar
}

watch(() => waterParams.value, syncWaterParams, { deep: true })
syncWaterParams()

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
}, { deep: true })

watch(() => flowParams.value, () => {
  syncFlowParams()
}, { deep: true })

watch(() => props.labelValues, (levels) => {
  for (const [id, value] of Object.entries(levels)) {
    if (labelValues[id] !== undefined) {
      labelValues[id] = value
    }
  }
}, { deep: true })

// ==================== 对外暴露的 API（供父组件/外部系统调用）====================

function setLabelValue(id: string, value: number) {
  labelValues[id] = value
}

function setLabelValues(levels: Record<string, number>) {
  for (const [id, value] of Object.entries(levels)) {
    labelValues[id] = value
  }
}

function flyTo(
  position: { x: number; y: number; z: number },
  target?: { x: number; y: number; z: number },
  durationMs: number = 1500,
) {
  const startPos = camera.position.clone()
  const endPos = new THREE.Vector3(position.x, position.y, position.z)
  const startTarget = controls.target.clone()
  const endTarget = target
    ? new THREE.Vector3(target.x, target.y, target.z)
    : controls.target.clone()
  const startTime = performance.now()

  function animateFly() {
    const elapsed = performance.now() - startTime
    const t = Math.min(elapsed / durationMs, 1)
    const ease = t * t * (3 - 2 * t)

    camera.position.lerpVectors(startPos, endPos, ease)
    controls.target.lerpVectors(startTarget, endTarget, ease)
    controls.update()

    if (t < 1) requestAnimationFrame(animateFly)
  }
  animateFly()
}

function flyToPreset(presetId: string, durationMs: number = 1500) {
  const preset = cameraPresets.find(p => p.id === presetId)
  if (!preset) {
    console.warn(`Camera preset "${presetId}" not found`)
    return
  }
  flyTo(
    { x: preset.positionX, y: preset.positionY, z: preset.positionZ },
    { x: preset.targetX, y: preset.targetY, z: preset.targetZ },
    durationMs,
  )
}

defineExpose({
  labelDataList,
  labelValues,
  setLabelValue,
  setLabelValues,
  flyTo,
  flyToPreset,
  cameraPresets,
})
</script>

<template>
  <!-- 3D 渲染容器 -->
  <div ref="containerRef" class="scene-container" />
  <!-- 水位标签（Sprite + 指针） -->
  <WaterLevelLabel
    v-for="data in labelDataList"
    :key="data.config.id"
    :ref="(el: any) => { if (el) data.componentRef.value = el }"
    :label-id="data.config.id"
    :type="data.config.type"
    :position-x="data.config.positionX"
    :position-y="data.config.positionY"
    :position-z="data.config.positionZ"
    :value="labelValues[data.config.id]"
  />
  <!-- 右上角调试工具栏 -->
  <div v-if="props.showDebugTools" class="toolbar">
    <button class="toolbar-btn" :class="{ active: showCoordinatePanel }" @click="showCoordinatePanel = !showCoordinatePanel">坐标</button>
    <button class="toolbar-btn" :class="{ active: showCameraPanel }" @click="showCameraPanel = !showCameraPanel">相机</button>
    <button class="toolbar-btn" :class="{ active: showModelPanel }" @click="showModelPanel = !showModelPanel">模型</button>
    <button class="toolbar-btn" :class="{ active: showMaterialPanel }" @click="showMaterialPanel = !showMaterialPanel">材质</button>
    <button class="toolbar-btn" :class="{ active: showCameraPresetPanel }" @click="showCameraPresetPanel = !showCameraPresetPanel">视角</button>
  </div>

  <!-- 拾取坐标面板 -->
  <div v-if="props.showDebugTools && showCoordinatePanel && pickedPosition" class="panel coordinate-panel">
    <div class="panel-header">
      <span class="panel-title">拾取坐标 (m)</span>
      <button class="toggle-btn" @click="showCoordinatePanel = false">×</button>
    </div>
    <div class="coordinate-item">
      <span class="coordinate-label">X:</span>
      <span class="coordinate-value">{{ pickedPosition.x }}</span>
    </div>
    <div class="coordinate-item">
      <span class="coordinate-label">Y:</span>
      <span class="coordinate-value">{{ pickedPosition.y }}</span>
    </div>
    <div class="coordinate-item">
      <span class="coordinate-label">Z:</span>
      <span class="coordinate-value">{{ pickedPosition.z }}</span>
    </div>
  </div>

  <!-- 相机信息面板 -->
  <div v-if="props.showDebugTools && showCameraPanel" class="panel camera-panel">
    <div class="panel-header">
      <span class="panel-title">相机信息</span>
      <button class="toggle-btn" @click="showCameraPanel = false">×</button>
    </div>
    <div class="camera-section">
      <div class="section-label">位置 (m)</div>
      <div class="camera-item">
        <span class="camera-label">X:</span>
        <span class="camera-value">{{ cameraInfo.position.x }}</span>
      </div>
      <div class="camera-item">
        <span class="camera-label">Y:</span>
        <span class="camera-value">{{ cameraInfo.position.y }}</span>
      </div>
      <div class="camera-item">
        <span class="camera-label">Z:</span>
        <span class="camera-value">{{ cameraInfo.position.z }}</span>
      </div>
    </div>
    <div class="camera-section">
      <div class="section-label">目标点 (m)</div>
      <div class="camera-item">
        <span class="camera-label">X:</span>
        <span class="camera-value">{{ cameraInfo.target.x }}</span>
      </div>
      <div class="camera-item">
        <span class="camera-label">Y:</span>
        <span class="camera-value">{{ cameraInfo.target.y }}</span>
      </div>
      <div class="camera-item">
        <span class="camera-label">Z:</span>
        <span class="camera-value">{{ cameraInfo.target.z }}</span>
      </div>
    </div>
    <div class="camera-section">
      <div class="section-label">缩放距离 (m)</div>
      <div class="camera-item">
        <span class="camera-label">当前:</span>
        <span class="camera-value">{{ cameraInfo.distance }}</span>
      </div>
      <div class="camera-item">
        <span class="camera-label">最近:</span>
        <span class="camera-value">{{ cameraInfo.minDistance }}m</span>
      </div>
      <div class="camera-item">
        <span class="camera-label">最远:</span>
        <span class="camera-value">{{ cameraInfo.maxDistance }}m</span>
      </div>
    </div>
  </div>

  <!-- 模型变换调试面板 -->
  <div v-if="props.showDebugTools && showModelPanel" class="panel model-panel">
    <div class="panel-header">
      <span class="panel-title">模型变换</span>
      <button class="toggle-btn" @click="showModelPanel = false">×</button>
    </div>
    <div class="model-section">
      <div class="section-label">选择模型</div>
      <select v-model="selectedModelKey" class="model-select">
        <option value="water">水面</option>
        <option value="water2">水面2</option>
        <option value="foam">泡沫片面</option>
        <option value="flow">流动纹理模型</option>
        <option value="cscwater">CSCwater</option>
      </select>
    </div>
    <div class="model-section">
      <div class="section-label">位置</div>
      <div class="input-item">
        <span class="input-label">X</span>
        <input type="number" v-model.number="modelTransform.positionX" step="0.1" class="number-input" />
      </div>
      <div class="input-item">
        <span class="input-label">Y</span>
        <input type="number" v-model.number="modelTransform.positionY" step="0.1" class="number-input" />
      </div>
      <div class="input-item">
        <span class="input-label">Z</span>
        <input type="number" v-model.number="modelTransform.positionZ" step="0.1" class="number-input" />
      </div>
    </div>
    <div class="model-section">
      <div class="section-label">旋转</div>
      <div class="input-item">
        <span class="input-label">X (°)</span>
        <input type="number" v-model.number="modelTransform.rotationX" step="1" class="number-input" />
      </div>
      <div class="input-item">
        <span class="input-label">Y (°)</span>
        <input type="number" v-model.number="modelTransform.rotationY" step="1" class="number-input" />
      </div>
      <div class="input-item">
        <span class="input-label">Z (°)</span>
        <input type="number" v-model.number="modelTransform.rotationZ" step="1" class="number-input" />
      </div>
    </div>
    <div class="model-section">
      <div class="section-label">缩放</div>
      <div class="input-item">
        <span class="input-label">X</span>
        <input type="number" v-model.number="modelTransform.scaleX" step="0.5" class="number-input" />
      </div>
      <div class="input-item">
        <span class="input-label">Y</span>
        <input type="number" v-model.number="modelTransform.scaleY" step="0.5" class="number-input" />
      </div>
      <div class="input-item">
        <span class="input-label">Z</span>
        <input type="number" v-model.number="modelTransform.scaleZ" step="0.5" class="number-input" />
      </div>
    </div>
    <div class="model-section">
      <button class="default-btn" @click="saveModelDefaults">设置默认值</button>
    </div>
  </div>

  <!-- 材质参数调试面板 -->
  <div v-if="props.showDebugTools && showMaterialPanel" class="panel material-panel">
    <div class="panel-header">
      <span class="panel-title">材质参数</span>
      <button class="toggle-btn" @click="showMaterialPanel = false">×</button>
    </div>
    <div class="material-section">
      <div class="section-label">选择材质</div>
      <select v-model="selectedMaterialKey" class="model-select">
        <option value="water">水材质</option>
        <option value="foam">泡沫材质</option>
        <option value="flow">流动纹理材质</option>
        <option value="cscwater">CSCwater 材质</option>
      </select>
    </div>

    <template v-if="selectedMaterialKey === 'water'">
      <div class="material-section">
        <div class="section-label">透明度</div>
        <div class="slider-item">
          <input type="range" v-model.number="waterParams.alpha" min="0" max="1" step="0.01" />
          <span class="slider-value">{{ waterParams.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="waterParams.waveHeight" min="0" max="2" step="0.05" />
          <span class="slider-value">{{ waterParams.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="waterParams.flowSpeed" min="0" max="3" step="0.1" />
          <span class="slider-value">{{ waterParams.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="waterParams.flowDirectionX" min="-2" max="2" step="0.1" />
          <span class="slider-value">{{ waterParams.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="waterParams.flowDirectionY" min="-2" max="2" step="0.1" />
          <span class="slider-value">{{ waterParams.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="waterParams.normalRotation" min="-180" max="180" step="1" />
          <span class="slider-value">{{ waterParams.normalRotation.toFixed(0) }}°</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">浅水颜色</div>
        <div class="color-item">
          <input type="color" v-model="waterParams.waterColor" />
          <span class="color-value">{{ waterParams.waterColor }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">深水颜色</div>
        <div class="color-item">
          <input type="color" v-model="waterParams.deepColor" />
          <span class="color-value">{{ waterParams.deepColor }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">水深范围</div>
        <div class="slider-item">
          <input type="range" v-model.number="waterParams.depthRange" min="1" max="50" step="0.5" />
          <span class="slider-value">{{ waterParams.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="waterParams.waterNormalStrength" min="0" max="2" step="0.05" />
          <span class="slider-value">{{ waterParams.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="waterParams.waterNormalTiling" min="0.01" max="5" step="0.01" />
          <span class="slider-value">{{ waterParams.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="waterParams.specIntensity" min="0" max="5" step="0.1" />
          <span class="slider-value">{{ waterParams.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="waterParams.specPower" min="1" max="256" step="1" />
          <span class="slider-value">{{ waterParams.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="waterParams.fresnelPower" min="0.1" max="10" step="0.1" />
          <span class="slider-value">{{ waterParams.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="waterParams.fresnelIntensity" min="0" max="3" step="0.1" />
          <span class="slider-value">{{ waterParams.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="waterParams.foamIntensity" min="0" max="2" step="0.05" />
          <span class="slider-value">{{ waterParams.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="waterParams.collisionFoamThreshold" min="0" max="2" step="0.05" />
          <span class="slider-value">{{ waterParams.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="waterParams.collisionFoamStrength" min="0" max="3" step="0.1" />
          <span class="slider-value">{{ waterParams.collisionFoamStrength.toFixed(1) }}</span>
        </div>
      </div>
      <div class="material-section">
        <button class="default-btn" @click="saveWaterDefaults">设置默认值</button>
      </div>
    </template>

    <template v-if="selectedMaterialKey === 'foam'">
      <div class="material-section">
        <div class="section-label">颜色</div>
        <div class="color-item">
          <input type="color" v-model="foamMatParams.colour" />
          <span class="color-value">{{ foamMatParams.colour }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">不透明度</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.opacity" min="0" max="1" step="0.01" />
          <span class="slider-value">{{ foamMatParams.opacity.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">瀑布流速</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.waterfallSpeed" min="0" max="2" step="0.01" />
          <span class="slider-value">{{ foamMatParams.waterfallSpeed.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">菲涅尔指数</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.fresnelExponent" min="0" max="20" step="0.1" />
          <span class="slider-value">{{ foamMatParams.fresnelExponent.toFixed(1) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">边缘遮罩平铺</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.edgeMaskTiling" min="0.1" max="2" step="0.01" />
          <span class="slider-value">{{ foamMatParams.edgeMaskTiling.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">边缘遮罩速度</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.edgeMaskSpeed" min="0" max="10" step="0.1" />
          <span class="slider-value">{{ foamMatParams.edgeMaskSpeed.toFixed(1) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">方向泡沫强度</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.directionalFoamIntensity" min="0" max="5" step="0.01" />
          <span class="slider-value">{{ foamMatParams.directionalFoamIntensity.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">方向泡沫对比度</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.directionalFoamContrast" min="0.1" max="10" step="0.1" />
          <span class="slider-value">{{ foamMatParams.directionalFoamContrast.toFixed(1) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">层1强度</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.directionalFoam1Intensity" min="0" max="5" step="0.01" />
          <span class="slider-value">{{ foamMatParams.directionalFoam1Intensity.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">层2强度</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.directionalFoam2Intensity" min="0" max="5" step="0.01" />
          <span class="slider-value">{{ foamMatParams.directionalFoam2Intensity.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">层2平铺</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.directionalFoam2Tiling" min="0.1" max="5" step="0.01" />
          <span class="slider-value">{{ foamMatParams.directionalFoam2Tiling.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">层2速度</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.directionalFoam2Speed" min="0" max="50" step="0.5" />
          <span class="slider-value">{{ foamMatParams.directionalFoam2Speed.toFixed(1) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">层3强度</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.directionalFoam3Intensity" min="0" max="5" step="0.01" />
          <span class="slider-value">{{ foamMatParams.directionalFoam3Intensity.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">泡沫衰减</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.foamFalloff" min="0.1" max="10" step="0.1" />
          <span class="slider-value">{{ foamMatParams.foamFalloff.toFixed(1) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">渐变顶部</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.gradientTop" min="0" max="1" step="0.01" />
          <span class="slider-value">{{ foamMatParams.gradientTop.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">渐变底部</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.gradientBottom" min="0" max="1" step="0.01" />
          <span class="slider-value">{{ foamMatParams.gradientBottom.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">渐变曲线</div>
        <div class="slider-item">
          <input type="range" v-model.number="foamMatParams.gradientPower" min="0.1" max="5" step="0.1" />
          <span class="slider-value">{{ foamMatParams.gradientPower.toFixed(1) }}</span>
        </div>
      </div>
      <div class="material-section">
        <button class="default-btn" @click="saveFoamDefaults">设置默认值</button>
      </div>
    </template>

    <template v-if="selectedMaterialKey === 'flow'">
      <div class="material-section">
        <div class="section-label">颜色</div>
        <div class="color-item">
          <input type="color" v-model="flowParams.colour" />
          <span class="color-value">{{ flowParams.colour }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">流动速度 X</div>
        <div class="slider-item">
          <input type="range" v-model.number="flowParams.speedX" min="-2" max="2" step="0.001" />
          <span class="slider-value">{{ flowParams.speedX.toFixed(3) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">流动速度 Y</div>
        <div class="slider-item">
          <input type="range" v-model.number="flowParams.speedY" min="-2" max="2" step="0.001" />
          <span class="slider-value">{{ flowParams.speedY.toFixed(3) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">平铺 U</div>
        <div class="slider-item">
          <input type="range" v-model.number="flowParams.tilingU" min="-5" max="5" step="0.01" />
          <span class="slider-value">{{ flowParams.tilingU.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">平铺 V</div>
        <div class="slider-item">
          <input type="range" v-model.number="flowParams.tilingV" min="-5" max="5" step="0.01" />
          <span class="slider-value">{{ flowParams.tilingV.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">旋转角度</div>
        <div class="slider-item">
          <input type="range" v-model.number="flowParams.rotationAngle" min="-1" max="1" step="0.01" />
          <span class="slider-value">{{ flowParams.rotationAngle.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">泡沫强度</div>
        <div class="slider-item">
          <input type="range" v-model.number="flowParams.power" min="0" max="5" step="0.01" />
          <span class="slider-value">{{ flowParams.power.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">水闸强度</div>
        <div class="slider-item">
          <input type="range" v-model.number="flowParams.waterGate" min="0" max="200" step="0.5" />
          <span class="slider-value">{{ flowParams.waterGate.toFixed(1) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">水闸翻转</div>
        <div class="slider-item">
          <input type="range" v-model.number="flowParams.waterGate02" min="0" max="1" step="0.01" />
          <span class="slider-value">{{ flowParams.waterGate02.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">边缘遮罩强度</div>
        <div class="slider-item">
          <input type="range" v-model.number="flowParams.edgeMaskIntensity" min="0" max="1" step="0.01" />
          <span class="slider-value">{{ flowParams.edgeMaskIntensity.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">不透明度功率</div>
        <div class="slider-item">
          <input type="range" v-model.number="flowParams.opaquePower" min="0" max="20" step="0.01" />
          <span class="slider-value">{{ flowParams.opaquePower.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">边缘渐变淡出</div>
        <div class="slider-item">
          <input type="range" v-model.number="flowParams.edgeFade" min="0" max="0.5" step="0.01" />
          <span class="slider-value">{{ flowParams.edgeFade.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <button class="default-btn" @click="saveFlowDefaults">设置默认值</button>
      </div>
    </template>

    <template v-if="selectedMaterialKey === 'cscwater'">
      <div class="material-section">
        <div class="section-label">透明度</div>
        <div class="slider-item">
          <input type="range" v-model.number="cscwaterParams.alpha" min="0" max="1" step="0.01" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.waveHeight" min="0" max="2" step="0.05" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.flowSpeed" min="0" max="3" step="0.1" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.flowDirectionX" min="-2" max="2" step="0.1" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.flowDirectionY" min="-2" max="2" step="0.1" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.normalRotation" min="-180" max="180" step="1" />
          <span class="slider-value">{{ cscwaterParams.normalRotation.toFixed(0) }}°</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">浅水颜色</div>
        <div class="color-item">
          <input type="color" v-model="cscwaterParams.waterColor" />
          <span class="color-value">{{ cscwaterParams.waterColor }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">深水颜色</div>
        <div class="color-item">
          <input type="color" v-model="cscwaterParams.deepColor" />
          <span class="color-value">{{ cscwaterParams.deepColor }}</span>
        </div>
      </div>
      <div class="material-section">
        <div class="section-label">水深范围</div>
        <div class="slider-item">
          <input type="range" v-model.number="cscwaterParams.depthRange" min="1" max="50" step="0.5" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.waterNormalStrength" min="0" max="2" step="0.05" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.waterNormalTiling" min="0.01" max="5" step="0.01" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.specIntensity" min="0" max="5" step="0.1" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.specPower" min="1" max="256" step="1" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.fresnelPower" min="0.1" max="10" step="0.1" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.fresnelIntensity" min="0" max="3" step="0.1" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.foamIntensity" min="0" max="2" step="0.05" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.collisionFoamThreshold" min="0" max="1" step="0.01" />
          <span class="slider-value">{{ cscwaterParams.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="cscwaterParams.collisionFoamStrength" min="0" max="2" step="0.05" />
          <span class="slider-value">{{ cscwaterParams.collisionFoamStrength.toFixed(2) }}</span>
        </div>
      </div>
      <div class="material-section">
        <button class="default-btn" @click="saveCscwaterDefaults">设置默认值</button>
      </div>
    </template>
  </div>

  <!-- 视角选择面板 -->
  <div v-if="props.showDebugTools && showCameraPresetPanel" class="panel camera-preset-panel">
    <div class="panel-header">
      <span class="panel-title">视角选择</span>
      <button class="toggle-btn" @click="showCameraPresetPanel = false">×</button>
    </div>
    <div class="preset-list">
      <div
        v-for="preset in cameraPresets"
        :key="preset.id"
        class="preset-item"
        @click="showCameraPresetPanel = false; flyToPreset(preset.id)"
      >
        <span class="preset-name">{{ preset.name }}</span>
      </div>
    </div>
  </div>
</template>

<style scoped>
/* 全屏 3D 渲染容器 */
.scene-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

/* 右上角调试工具栏 */
.toolbar {
  position: fixed;
  top: 20px;
  right: 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 1001;
}

.toolbar-btn {
  padding: 10px 16px;
  border: none;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.85);
  color: #888;
  font-size: 13px;
  font-weight: bold;
  cursor: pointer;
  transition: all 0.2s;
  min-width: 70px;
}

.toolbar-btn:hover {
  background: rgba(30, 30, 30, 0.9);
  color: #fff;
}

.toolbar-btn.active {
  color: #fff;
  box-shadow: 0 0 10px rgba(255, 255, 255, 0.2);
}

.toolbar-btn:nth-child(1).active { color: #4fc3f7; }
.toolbar-btn:nth-child(2).active { color: #ff9800; }
.toolbar-btn:nth-child(3).active { color: #ff4081; }
.toolbar-btn:nth-child(4).active { color: #4dd0e1; }
.toolbar-btn:nth-child(5).active { color: #ffeb3b; }

/* 调试面板通用样式 */
.panel {
  position: fixed;
  top: 20px;
  left: 20px;
  background: rgba(0, 0, 0, 0.85);
  color: white;
  padding: 15px;
  border-radius: 8px;
  font-family: 'Courier New', monospace;
  z-index: 1000;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
}

.coordinate-panel { min-width: 200px; }
.camera-panel { min-width: 200px; }
.model-panel { min-width: 260px; }
.material-panel { min-width: 260px; }

.camera-preset-panel {
  min-width: 200px;
  left: auto;
  right: 20px;
  top: auto;
  bottom: 20px;
}

.preset-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 8px;
}

.preset-item {
  padding: 8px 12px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.08);
  color: #ccc;
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s;
}

.preset-item:hover {
  background: rgba(255, 235, 59, 0.2);
  color: #fff;
}

.preset-name {
  font-family: 'Microsoft YaHei', sans-serif;
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.3);
}

.panel-title {
  font-weight: bold;
  font-size: 14px;
}

.coordinate-panel .panel-title { color: #4fc3f7; }
.camera-panel .panel-title { color: #ff9800; }
.model-panel .panel-title { color: #ff4081; }
.material-panel .panel-title { color: #4dd0e1; }
.camera-preset-panel .panel-title { color: #ffeb3b; }

/* 关闭按钮 */
.toggle-btn {
  width: 22px;
  height: 22px;
  border: none;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.15);
  color: white;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s;
}

.toggle-btn:hover {
  background: rgba(255, 255, 255, 0.3);
}

/* 坐标列表 */
.coordinate-item {
  display: flex;
  justify-content: space-between;
  margin: 5px 0;
}

.coordinate-label {
  color: #81c784;
  font-weight: bold;
}

.coordinate-value {
  color: #fff;
}

/* 相机信息分组 */
.camera-section {
  margin-bottom: 10px;
}

.section-label {
  color: #81c784;
  font-size: 11px;
  margin-bottom: 5px;
  font-weight: bold;
}

.camera-item {
  display: flex;
  justify-content: space-between;
  margin: 3px 0;
}

.camera-label {
  color: #4fc3f7;
}

.camera-value {
  color: #fff;
}

/* 模型/材质分组 */
.model-section,
.material-section {
  margin-bottom: 12px;
}

.model-section .section-label,
.material-section .section-label {
  color: #81c784;
  font-size: 11px;
  margin-bottom: 6px;
  font-weight: bold;
}

/* 下拉选择器 */
.model-select {
  width: 100%;
  padding: 6px 8px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  outline: none;
}

.model-select option {
  background: #222;
  color: #fff;
}

/* 滑条控件 */
.slider-item {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
}

.slider-label {
  font-size: 12px;
  color: #aaa;
  min-width: 32px;
}

.slider-item input[type="range"] {
  flex: 1;
  height: 4px;
  -webkit-appearance: none;
  appearance: none;
  background: rgba(255, 255, 255, 0.15);
  border-radius: 2px;
  outline: none;
}

.slider-item input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #ff4081;
  cursor: pointer;
}

.slider-value {
  min-width: 50px;
  text-align: right;
  color: #fff;
  font-size: 11px;
  font-family: 'Consolas', monospace;
}

/* 数字输入框 */
.input-item {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
}

.input-label {
  font-size: 12px;
  color: #aaa;
  min-width: 32px;
}

.number-input {
  flex: 1;
  padding: 4px 8px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  font-size: 13px;
  font-family: 'Consolas', monospace;
  outline: none;
}

.number-input:focus {
  border-color: #ff4081;
}

/* 颜色拾取器 */
.color-item {
  display: flex;
  align-items: center;
  gap: 10px;
}

.color-item input[type="color"] {
  width: 40px;
  height: 28px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  background: transparent;
}

.color-item input[type="color"]::-webkit-color-swatch-wrapper {
  padding: 0;
}

.color-item input[type="color"]::-webkit-color-swatch {
  border: none;
  border-radius: 4px;
}

.color-value {
  color: #fff;
  font-size: 11px;
  font-family: 'Consolas', monospace;
}

/* 材质面板滑条颜色（区别于模型的粉色，材质用青色） */
.material-section .slider-item input[type="range"] {
  background: rgba(255, 255, 255, 0.15);
}

.material-section .slider-item input[type="range"]::-webkit-slider-thumb {
  background: #4dd0e1;
}

/* 保存默认值按钮 */
.default-btn {
  width: 100%;
  padding: 8px 16px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.08);
  color: #4dd0e1;
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s;
}

.default-btn:hover {
  background: rgba(77, 208, 225, 0.15);
  border-color: #4dd0e1;
}

/* 底部提示消息 */
.toast-message {
  position: fixed;
  bottom: 40px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0, 0, 0, 0.85);
  color: #4dd0e1;
  padding: 10px 24px;
  border-radius: 8px;
  font-size: 14px;
  font-family: 'Microsoft YaHei', sans-serif;
  z-index: 9999;
  pointer-events: none;
  transition: opacity 0.3s ease;
  border: 1px solid rgba(77, 208, 225, 0.3);
}

.toast-message.toast-fade {
  opacity: 0;
}
</style>
