fix: v2.6 组合画布选中根因修复+右键菜单+3D 三场景
- 选中失效根因: Vue3 布尔 prop 缺省转换(editable 缺省→false)
withDefaults 默认 true 修复, 左键选中/右键选中/菜单动作全链路打通
- 右键菜单: 右键单元弹操作菜单(顺/逆旋转/镜像/底边对齐/删除)
动作 emit('ctx') 由父组件统一执行, document 级委托
- 3D 三场景: 室内(窗后墙+木地板)/室外(外墙+草地)/影棚(网格)
场景联动背景色, 真实浏览器截图验证三场景渲染
- 菜单动作行为级验证: 旋转后 1600x1800 宽高互换✓ 删除清空✓
This commit is contained in:
@@ -26,7 +26,11 @@
|
||||
</div>
|
||||
<div class="p-row">
|
||||
<span class="p-label">场景</span>
|
||||
<el-checkbox v-model="showWall" size="small" @change="rebuild">墙体</el-checkbox>
|
||||
<el-radio-group v-model="scene3d" size="small" @change="rebuild">
|
||||
<el-radio-button value="indoor">室内</el-radio-button>
|
||||
<el-radio-button value="outdoor">室外</el-radio-button>
|
||||
<el-radio-button value="studio">影棚</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-checkbox v-model="autoRotate" size="small">自动旋转</el-checkbox>
|
||||
<el-button size="small" text type="primary" @click="screenshot">截图</el-button>
|
||||
</div>
|
||||
@@ -69,7 +73,8 @@ const autoPlay = ref(false)
|
||||
const hasOpenable = ref(false)
|
||||
const lightMode = ref<'day' | 'dusk' | 'night'>('day')
|
||||
const viewMode = ref<'front' | 'deg45' | 'side' | 'indoor'>('deg45')
|
||||
const showWall = ref(true)
|
||||
const scene3d = ref<'indoor' | 'outdoor' | 'studio'>('outdoor')
|
||||
const SCENE_BG = { indoor: 0xf5efe6, outdoor: 0xbcd9f0, studio: 0xf2f4f7 } as const
|
||||
const autoRotate = ref(false)
|
||||
|
||||
let renderer: THREE.WebGLRenderer | null = null
|
||||
@@ -153,7 +158,7 @@ function applyLight() {
|
||||
dirLight.position.set(p.pos[0], p.pos[1], p.pos[2])
|
||||
}
|
||||
if (scene) {
|
||||
scene.background = new THREE.Color(p.bg)
|
||||
scene.background = new THREE.Color(SCENE_BG[scene3d.value])
|
||||
scene.traverse(o => {
|
||||
if ((o as THREE.AmbientLight).isAmbientLight) (o as THREE.AmbientLight).intensity = p.ambient
|
||||
})
|
||||
@@ -219,6 +224,7 @@ function build(drawing: DrawingData) {
|
||||
const sashMat = new THREE.MeshStandardMaterial({ color: 0x84898f, roughness: 0.4, metalness: 0.55 })
|
||||
const wallMat = new THREE.MeshStandardMaterial({ color: 0xe8e2d6, roughness: 0.95 })
|
||||
const groundMat = new THREE.MeshStandardMaterial({ color: 0xcfc9bd, roughness: 1 })
|
||||
const floorMat = new THREE.MeshStandardMaterial({ color: 0xb59b74, roughness: 0.9 })
|
||||
const glassMat = new THREE.MeshPhysicalMaterial({
|
||||
color: 0xd8ecf5, transparent: true, opacity: 0.4, roughness: 0.06,
|
||||
metalness: 0.1, side: THREE.DoubleSide, envMapIntensity: 1.2,
|
||||
@@ -324,8 +330,9 @@ function build(drawing: DrawingData) {
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 墙体洞口 + 地面(世界单位:窗体约 1 单位见方)----
|
||||
if (showWall.value) {
|
||||
// ---- 环境场景(室内/室外/影棚)----
|
||||
if (scene3d.value === 'outdoor') {
|
||||
// 室外: 建筑外墙围绕窗洞 + 草地
|
||||
const hw = gw * S / 2 + 0.05 // 窗洞半宽
|
||||
const hh = gh * S / 2 + 0.05 // 窗洞半高
|
||||
const side = 0.55 // 上下墙高度/左右墙宽度
|
||||
@@ -347,7 +354,19 @@ function build(drawing: DrawingData) {
|
||||
ground.position.set(0, -hh - side - 0.02, DEPTH * 2)
|
||||
ground.receiveShadow = true
|
||||
sceneRoot.add(ground)
|
||||
} else if (scene3d.value === 'indoor') {
|
||||
// 室内: 窗后整墙 + 室内地板(木色)
|
||||
const wall = new THREE.Mesh(new THREE.BoxGeometry(gw * S + 1.4, gh * S + 1.2, 0.02), wallMat)
|
||||
wall.position.set(0, 0, -DEPTH)
|
||||
wall.receiveShadow = true
|
||||
wall.userData.isWall = true
|
||||
sceneRoot.add(wall)
|
||||
const floor = new THREE.Mesh(new THREE.BoxGeometry(gw * S + 1.4, 0.02, gh * S + 1.2), floorMat)
|
||||
floor.position.set(0, -gh * S / 2 - DEPTH, 0)
|
||||
floor.receiveShadow = true
|
||||
sceneRoot.add(floor)
|
||||
}
|
||||
// 影棚(studio): 仅网格地面(下方已添加)
|
||||
sceneRoot.traverse(o => {
|
||||
const m = o as THREE.Mesh
|
||||
if (m.isMesh) { m.castShadow = !m.userData.isWall; m.receiveShadow = true }
|
||||
|
||||
Reference in New Issue
Block a user