|
|
|
@ -2,7 +2,7 @@ |
|
|
|
<div class="model3d-view"> |
|
|
|
<el-space :gutter="10" class="toolbar"> |
|
|
|
<el-upload :on-change="handleFileChange" |
|
|
|
:show-file-list="false" accept=".fbx,.obj,.mtl,.3ds" action="" :auto-upload="false"> |
|
|
|
:show-file-list="false" accept=".fbx,.obj,.mtl,.3ds,.glb,.gltf" action="" :auto-upload="false"> |
|
|
|
<el-button type="primary">打开模型</el-button> |
|
|
|
</el-upload> |
|
|
|
<el-upload :on-change="handleTextureUpload" |
|
|
|
@ -80,15 +80,16 @@ import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader' |
|
|
|
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader' |
|
|
|
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js' |
|
|
|
import { TDSLoader } from 'three/examples/jsm/loaders/TDSLoader' |
|
|
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader' |
|
|
|
import * as dat from 'three/examples/jsm/libs/lil-gui.module.min.js' |
|
|
|
import Stats from 'three/examples/jsm/libs/stats.module' |
|
|
|
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js' |
|
|
|
import Split from '@/components/split/split.vue' |
|
|
|
import SplitArea from '@/components/split/split-area.vue' |
|
|
|
import { renderIcon } from '@/utils/webutils.js' |
|
|
|
import rackPlatUrl from "@/assets/images/conveyor/shapes/RackPlatform.png"; |
|
|
|
import rackBlue from "@/assets/images/conveyor/shapes/Rack-blue.png"; |
|
|
|
import triangleUrl from "@/assets/images/conveyor/shapes/triangle.png"; |
|
|
|
import rackPlatUrl from '@/assets/images/conveyor/shapes/RackPlatform.png' |
|
|
|
import rackBlue from '@/assets/images/conveyor/shapes/Rack-blue.png' |
|
|
|
import triangleUrl from '@/assets/images/conveyor/shapes/triangle.png' |
|
|
|
|
|
|
|
// DOM refs |
|
|
|
const canvasContainer = ref(null) |
|
|
|
@ -168,118 +169,120 @@ watch(() => restate.mode, (newVal) => { |
|
|
|
tcontrols.setMode(newVal) |
|
|
|
} |
|
|
|
}) |
|
|
|
function addConveyor(){ |
|
|
|
const conveyorLength = 10; // 长度 |
|
|
|
const conveyorWidth = 0.8; // 宽度 |
|
|
|
const conveyorHeight = 0.08; // 厚度 |
|
|
|
const wallHeight = conveyorHeight + 0.15; // 挡板高出输送线 0.2 米 |
|
|
|
|
|
|
|
const legWidth = 0.1; // 柱子宽度(X) |
|
|
|
const legDepth = 0.1; // 柱子深度(Z) |
|
|
|
const legHeight = 0.8; // 柱子高度(Y) |
|
|
|
function addConveyor() { |
|
|
|
const conveyorLength = 10 // 长度 |
|
|
|
const conveyorWidth = 0.8 // 宽度 |
|
|
|
const conveyorHeight = 0.08 // 厚度 |
|
|
|
const wallHeight = conveyorHeight + 0.15 // 挡板高出输送线 0.2 米 |
|
|
|
|
|
|
|
const legWidth = 0.1 // 柱子宽度(X) |
|
|
|
const legDepth = 0.1 // 柱子深度(Z) |
|
|
|
const legHeight = 0.8 // 柱子高度(Y) |
|
|
|
|
|
|
|
// 创建输送线底部板子(灰色) |
|
|
|
const conveyorGeometry = new THREE.BoxGeometry(conveyorWidth, conveyorHeight, conveyorLength); |
|
|
|
const conveyorMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a }); |
|
|
|
const conveyor = new THREE.Mesh(conveyorGeometry, conveyorMaterial); |
|
|
|
conveyor.position.y = conveyorHeight / 2; |
|
|
|
const conveyorGeometry = new THREE.BoxGeometry(conveyorWidth, conveyorHeight, conveyorLength) |
|
|
|
const conveyorMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a }) |
|
|
|
const conveyor = new THREE.Mesh(conveyorGeometry, conveyorMaterial) |
|
|
|
conveyor.position.y = conveyorHeight / 2 |
|
|
|
|
|
|
|
// 添加两侧挡板(灰色) |
|
|
|
const wallWidth = 0.05; |
|
|
|
const wallGeometry = new THREE.BoxGeometry(wallWidth, wallHeight, conveyorLength); |
|
|
|
const wallMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a }); |
|
|
|
const wallWidth = 0.05 |
|
|
|
const wallGeometry = new THREE.BoxGeometry(wallWidth, wallHeight, conveyorLength) |
|
|
|
const wallMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a }) |
|
|
|
|
|
|
|
const leftWall = new THREE.Mesh(wallGeometry, wallMaterial); |
|
|
|
leftWall.position.set(-(conveyorWidth / 2 + wallWidth / 2), wallHeight / 2, 0); |
|
|
|
const leftWall = new THREE.Mesh(wallGeometry, wallMaterial) |
|
|
|
leftWall.position.set(-(conveyorWidth / 2 + wallWidth / 2), wallHeight / 2, 0) |
|
|
|
|
|
|
|
const rightWall = new THREE.Mesh(wallGeometry, wallMaterial); |
|
|
|
rightWall.position.set((conveyorWidth / 2 + wallWidth / 2), wallHeight / 2, 0); |
|
|
|
const rightWall = new THREE.Mesh(wallGeometry, wallMaterial) |
|
|
|
rightWall.position.set((conveyorWidth / 2 + wallWidth / 2), wallHeight / 2, 0) |
|
|
|
|
|
|
|
// 创建柱子(灰色,类似桌腿) |
|
|
|
const legGeometry = new THREE.BoxGeometry(legWidth, legHeight, legDepth); |
|
|
|
const legMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a }); // 灰色 |
|
|
|
const legGeometry = new THREE.BoxGeometry(legWidth, legHeight, legDepth) |
|
|
|
const legMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a }) // 灰色 |
|
|
|
|
|
|
|
const legPositions = [ |
|
|
|
[conveyorWidth / 2 - legWidth / 2, -(conveyorLength / 2 - legDepth / 2)], // 右前 |
|
|
|
[-conveyorWidth / 2 + legWidth / 2, -(conveyorLength / 2 - legDepth / 2)], // 左前 |
|
|
|
[conveyorWidth / 2 - legWidth / 2, +(conveyorLength / 2 - legDepth / 2)], // 右后 |
|
|
|
[-conveyorWidth / 2 + legWidth / 2, +(conveyorLength / 2 - legDepth / 2)] // 左后 |
|
|
|
]; |
|
|
|
] |
|
|
|
|
|
|
|
const legs = []; |
|
|
|
const legs = [] |
|
|
|
|
|
|
|
legPositions.forEach(pos => { |
|
|
|
const leg = new THREE.Mesh(legGeometry, legMaterial); |
|
|
|
const leg = new THREE.Mesh(legGeometry, legMaterial) |
|
|
|
leg.position.set( |
|
|
|
pos[0], |
|
|
|
-legHeight / 2, |
|
|
|
pos[1] |
|
|
|
); |
|
|
|
legs.push(leg); |
|
|
|
}); |
|
|
|
) |
|
|
|
legs.push(leg) |
|
|
|
}) |
|
|
|
|
|
|
|
// ====== 新增部分:顶部带圆角的长方体(胶囊型)====== |
|
|
|
const beamWidth = conveyorWidth; // 和输送线一样宽(0.8米) |
|
|
|
const beamLength = conveyorLength-conveyorHeight/2;// 和输送线一样长(10米) |
|
|
|
const beamHeight = 0.08; // 高度(0.1米) |
|
|
|
const beamWidth = conveyorWidth // 和输送线一样宽(0.8米) |
|
|
|
const beamLength = conveyorLength - conveyorHeight / 2// 和输送线一样长(10米) |
|
|
|
const beamHeight = 0.08 // 高度(0.1米) |
|
|
|
|
|
|
|
// 创建 Shape(二维路径) |
|
|
|
const shape = new THREE.Shape(); |
|
|
|
const shape = new THREE.Shape() |
|
|
|
|
|
|
|
const radius = beamHeight / 2; // 圆角半径 = 一半宽度 |
|
|
|
const radius = beamHeight / 2 // 圆角半径 = 一半宽度 |
|
|
|
|
|
|
|
// 左侧半圆(从顶部开始,顺时针) |
|
|
|
shape.absarc(-beamLength / 2, 0, radius, Math.PI / 2, -Math.PI / 2, false); |
|
|
|
shape.absarc(-beamLength / 2, 0, radius, Math.PI / 2, -Math.PI / 2, false) |
|
|
|
|
|
|
|
// 右侧半圆(从底部开始,顺时针) |
|
|
|
shape.absarc(beamLength / 2, 0, radius, -Math.PI / 2, Math.PI / 2, false); |
|
|
|
shape.absarc(beamLength / 2, 0, radius, -Math.PI / 2, Math.PI / 2, false) |
|
|
|
|
|
|
|
shape.closePath(); // 封闭路径 |
|
|
|
shape.closePath() // 封闭路径 |
|
|
|
|
|
|
|
// 拉伸成三维几何体 |
|
|
|
const extrudeSettings = { |
|
|
|
depth: beamWidth, |
|
|
|
steps: 16, |
|
|
|
bevelEnabled: false |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
const beamGeometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); |
|
|
|
const beamMaterial = new THREE.MeshBasicMaterial({ color: 0x032702 }); // 粉色 |
|
|
|
const beamGeometry = new THREE.ExtrudeGeometry(shape, extrudeSettings) |
|
|
|
const beamMaterial = new THREE.MeshBasicMaterial({ color: 0x032702 }) // 粉色 |
|
|
|
|
|
|
|
const beam = new THREE.Mesh(beamGeometry, beamMaterial); |
|
|
|
beam.rotation.x = Math.PI / 2; |
|
|
|
const beam = new THREE.Mesh(beamGeometry, beamMaterial) |
|
|
|
beam.rotation.x = Math.PI / 2 |
|
|
|
beam.rotation.z = Math.PI / 2 |
|
|
|
beam.rotation.y = Math.PI / 2 |
|
|
|
beam.position.y = beamHeight+conveyorHeight/2; // 底部贴着输送线顶部 |
|
|
|
beam.position.x = -beamWidth/2; |
|
|
|
addMarkerAt(0, legHeight+beamHeight+conveyorHeight,0,triangleUrl,1,false); |
|
|
|
addMarkerAt(beamWidth/2+wallWidth+0.01, legHeight+wallHeight/2,0,triangleUrl,.5,true); |
|
|
|
addMarkerAt(beamWidth/2+wallWidth+0.01, legHeight+wallHeight/2,conveyorLength/4,triangleUrl,.5,true); |
|
|
|
addMarkerAt(beamWidth/2+wallWidth+0.01, legHeight+wallHeight/2,-conveyorLength/4,triangleUrl,.5,true); |
|
|
|
|
|
|
|
addMarkerAt(-(beamWidth/2+wallWidth+0.01), legHeight+wallHeight/2,0,triangleUrl,.5,true); |
|
|
|
addMarkerAt(-(beamWidth/2+wallWidth+0.01), legHeight+wallHeight/2,conveyorLength/4,triangleUrl,.5,true); |
|
|
|
addMarkerAt(-(beamWidth/2+wallWidth+0.01), legHeight+wallHeight/2,-conveyorLength/4,triangleUrl,.5,true); |
|
|
|
beam.position.y = beamHeight + conveyorHeight / 2 // 底部贴着输送线顶部 |
|
|
|
beam.position.x = -beamWidth / 2 |
|
|
|
addMarkerAt(0, legHeight + beamHeight + conveyorHeight, 0, triangleUrl, 1, false) |
|
|
|
addMarkerAt(beamWidth / 2 + wallWidth + 0.01, legHeight + wallHeight / 2, 0, triangleUrl, .5, true) |
|
|
|
addMarkerAt(beamWidth / 2 + wallWidth + 0.01, legHeight + wallHeight / 2, conveyorLength / 4, triangleUrl, .5, true) |
|
|
|
addMarkerAt(beamWidth / 2 + wallWidth + 0.01, legHeight + wallHeight / 2, -conveyorLength / 4, triangleUrl, .5, true) |
|
|
|
|
|
|
|
addMarkerAt(-(beamWidth / 2 + wallWidth + 0.01), legHeight + wallHeight / 2, 0, triangleUrl, .5, true) |
|
|
|
addMarkerAt(-(beamWidth / 2 + wallWidth + 0.01), legHeight + wallHeight / 2, conveyorLength / 4, triangleUrl, .5, true) |
|
|
|
addMarkerAt(-(beamWidth / 2 + wallWidth + 0.01), legHeight + wallHeight / 2, -conveyorLength / 4, triangleUrl, .5, true) |
|
|
|
// 将所有元素组合成一个组 |
|
|
|
const group = new THREE.Group(); |
|
|
|
group.add(conveyor); |
|
|
|
group.add(leftWall); |
|
|
|
group.add(rightWall); |
|
|
|
legs.forEach(leg => group.add(leg)); |
|
|
|
group.add(beam); // 添加新长方体 |
|
|
|
const group = new THREE.Group() |
|
|
|
group.add(conveyor) |
|
|
|
group.add(leftWall) |
|
|
|
group.add(rightWall) |
|
|
|
legs.forEach(leg => group.add(leg)) |
|
|
|
group.add(beam) // 添加新长方体 |
|
|
|
// 设置组沿Z轴向上移动的距离,例如 1 米 |
|
|
|
group.position.y = legHeight; // 修改这里的值来改变提升的高度 |
|
|
|
scene.add(group); |
|
|
|
group.position.y = legHeight // 修改这里的值来改变提升的高度 |
|
|
|
scene.add(group) |
|
|
|
} |
|
|
|
function addMarkerAt(x, y,z,textUrl, scale = 1,lip) { |
|
|
|
const loader = new THREE.TextureLoader(); |
|
|
|
|
|
|
|
function addMarkerAt(x, y, z, textUrl, scale = 1, lip) { |
|
|
|
const loader = new THREE.TextureLoader() |
|
|
|
loader.load(textUrl, (texture) => { |
|
|
|
// 创建一个平面作为标记(大小可以调整) |
|
|
|
let markerGeometry |
|
|
|
if(lip){ |
|
|
|
markerGeometry=new THREE.PlaneGeometry(.25 * scale, .25 * scale); |
|
|
|
}else{ |
|
|
|
markerGeometry = new THREE.PlaneGeometry(.45 * scale, .3 * scale); // 宽高比例保持一致 |
|
|
|
if (lip) { |
|
|
|
markerGeometry = new THREE.PlaneGeometry(.25 * scale, .25 * scale) |
|
|
|
} else { |
|
|
|
markerGeometry = new THREE.PlaneGeometry(.45 * scale, .3 * scale) // 宽高比例保持一致 |
|
|
|
} |
|
|
|
|
|
|
|
const markerMaterial = new THREE.MeshBasicMaterial({ |
|
|
|
@ -288,193 +291,193 @@ function addMarkerAt(x, y,z,textUrl, scale = 1,lip) { |
|
|
|
opacity: 1, |
|
|
|
depthWrite: false, |
|
|
|
side: THREE.DoubleSide |
|
|
|
}); |
|
|
|
}) |
|
|
|
|
|
|
|
const marker = new THREE.Mesh(markerGeometry, markerMaterial); |
|
|
|
let yHeight=y+0.01 |
|
|
|
const marker = new THREE.Mesh(markerGeometry, markerMaterial) |
|
|
|
let yHeight = y + 0.01 |
|
|
|
// 设置位置:位于输送线表面(Y轴略高于输送线一点) |
|
|
|
marker.position.set(x, yHeight, z); // Y = 输送线高度 + 一点间距 |
|
|
|
marker.position.set(x, yHeight, z) // Y = 输送线高度 + 一点间距 |
|
|
|
|
|
|
|
// 旋转为 X/Z 平面方向(与输送线一致) |
|
|
|
marker.rotation.x = -Math.PI / 2; // 和 conveyorBelt 一样旋转角度 |
|
|
|
marker.rotation.z = Math.PI / 2; // 在平面上旋转 90 度 |
|
|
|
if(lip){ |
|
|
|
marker.rotation.y = Math.PI / 2; // 在平面上旋转 90 度 |
|
|
|
}else{ |
|
|
|
marker.rotation.y = Math.PI; |
|
|
|
marker.rotation.x = -Math.PI / 2 // 和 conveyorBelt 一样旋转角度 |
|
|
|
marker.rotation.z = Math.PI / 2 // 在平面上旋转 90 度 |
|
|
|
if (lip) { |
|
|
|
marker.rotation.y = Math.PI / 2 // 在平面上旋转 90 度 |
|
|
|
} else { |
|
|
|
marker.rotation.y = Math.PI |
|
|
|
} |
|
|
|
scene.add(marker); |
|
|
|
}); |
|
|
|
scene.add(marker) |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
function createShelf(){//创建货架 |
|
|
|
const shelfLength = 5; |
|
|
|
const shelfWidth = 0.8; |
|
|
|
const shelfThickness = 0.02; |
|
|
|
const rows = 3; |
|
|
|
const columns = 4; |
|
|
|
const spacingY = 1; // 每行之间的间距 |
|
|
|
const gapBetweenPlanks = 0.1; // 层板之间的间隙宽度 |
|
|
|
const baseHeight = 0; // 地面高度设为0 |
|
|
|
function createShelf() {//创建货架 |
|
|
|
const shelfLength = 5 |
|
|
|
const shelfWidth = 0.8 |
|
|
|
const shelfThickness = 0.02 |
|
|
|
const rows = 3 |
|
|
|
const columns = 4 |
|
|
|
const spacingY = 1 // 每行之间的间距 |
|
|
|
const gapBetweenPlanks = 0.1 // 层板之间的间隙宽度 |
|
|
|
const baseHeight = 0 // 地面高度设为0 |
|
|
|
|
|
|
|
const unitLength = (shelfLength - (columns - 1) * gapBetweenPlanks) / columns; |
|
|
|
const unitLength = (shelfLength - (columns - 1) * gapBetweenPlanks) / columns |
|
|
|
|
|
|
|
const textureLoader = new THREE.TextureLoader(); |
|
|
|
const textureLoader = new THREE.TextureLoader() |
|
|
|
const shelfTexture = textureLoader.load(rackPlatUrl, () => { |
|
|
|
renderer.render(scene, camera); |
|
|
|
}); |
|
|
|
renderer.render(scene, camera) |
|
|
|
}) |
|
|
|
const redPoleTexture = textureLoader.load(rackBlue, () => { |
|
|
|
renderer.render(scene, camera); // 确保贴图加载后重新渲染 |
|
|
|
}); |
|
|
|
renderer.render(scene, camera) // 确保贴图加载后重新渲染 |
|
|
|
}) |
|
|
|
|
|
|
|
shelfTexture.wrapS = THREE.RepeatWrapping; |
|
|
|
shelfTexture.wrapT = THREE.RepeatWrapping; |
|
|
|
shelfTexture.repeat.set(1, 20); |
|
|
|
shelfTexture.rotation = Math.PI / 2; |
|
|
|
shelfTexture.wrapS = THREE.RepeatWrapping |
|
|
|
shelfTexture.wrapT = THREE.RepeatWrapping |
|
|
|
shelfTexture.repeat.set(1, 20) |
|
|
|
shelfTexture.rotation = Math.PI / 2 |
|
|
|
|
|
|
|
const shelfMaterial = new THREE.MeshPhongMaterial({ |
|
|
|
map: shelfTexture, |
|
|
|
color: 0x999999, |
|
|
|
shininess: 60 |
|
|
|
}); |
|
|
|
}) |
|
|
|
|
|
|
|
// 垂直柱子材质 |
|
|
|
const poleMaterial = new THREE.MeshPhongMaterial({ |
|
|
|
map: shelfTexture, |
|
|
|
color: 0x333333, |
|
|
|
shininess: 60 |
|
|
|
}); |
|
|
|
}) |
|
|
|
|
|
|
|
// 柱子尺寸 |
|
|
|
const poleSize = gapBetweenPlanks; // 柱子的宽度和深度都等于缝隙宽度 |
|
|
|
const totalHeight = rows * spacingY; // 柱子总高度 |
|
|
|
const poleSize = gapBetweenPlanks // 柱子的宽度和深度都等于缝隙宽度 |
|
|
|
const totalHeight = rows * spacingY // 柱子总高度 |
|
|
|
|
|
|
|
for (let row = 0; row < rows; row++) { |
|
|
|
let currentXOffset = -shelfLength / 2; |
|
|
|
let currentXOffset = -shelfLength / 2 |
|
|
|
|
|
|
|
for (let col = 0; col < columns; col++) { |
|
|
|
const geometry = new THREE.BoxGeometry(unitLength, shelfThickness, shelfWidth); |
|
|
|
const mesh = new THREE.Mesh(geometry, shelfMaterial); |
|
|
|
const geometry = new THREE.BoxGeometry(unitLength, shelfThickness, shelfWidth) |
|
|
|
const mesh = new THREE.Mesh(geometry, shelfMaterial) |
|
|
|
|
|
|
|
const x = currentXOffset + unitLength / 2; |
|
|
|
const x = currentXOffset + unitLength / 2 |
|
|
|
// 计算层板的 Y 坐标,使其基于地面高度 |
|
|
|
const y = baseHeight + row * spacingY + shelfThickness / 2; |
|
|
|
const z = 0; |
|
|
|
const y = baseHeight + row * spacingY + shelfThickness / 2 |
|
|
|
const z = 0 |
|
|
|
|
|
|
|
mesh.position.set(x, y, z); |
|
|
|
scene.add(mesh); |
|
|
|
mesh.position.set(x, y, z) |
|
|
|
scene.add(mesh) |
|
|
|
|
|
|
|
if (row === 0) { // 只在第一层添加垂直柱子 |
|
|
|
// 最左侧柱子 |
|
|
|
if (col === 0) { |
|
|
|
const leftPoleX = currentXOffset - poleSize / 2; |
|
|
|
const leftPoleY = baseHeight + totalHeight / 2; |
|
|
|
const leftPoleZ = z - shelfWidth / 2 + poleSize / 2; |
|
|
|
const leftPoleX = currentXOffset - poleSize / 2 |
|
|
|
const leftPoleY = baseHeight + totalHeight / 2 |
|
|
|
const leftPoleZ = z - shelfWidth / 2 + poleSize / 2 |
|
|
|
|
|
|
|
// 黑色柱子 |
|
|
|
const leftPole = new THREE.Mesh( |
|
|
|
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), |
|
|
|
poleMaterial |
|
|
|
); |
|
|
|
leftPole.position.set(leftPoleX, leftPoleY, leftPoleZ); |
|
|
|
scene.add(leftPole); |
|
|
|
) |
|
|
|
leftPole.position.set(leftPoleX, leftPoleY, leftPoleZ) |
|
|
|
scene.add(leftPole) |
|
|
|
|
|
|
|
// // 红色柱子 |
|
|
|
const redLeftPoleZ = z + shelfWidth / 2 - poleSize / 2; |
|
|
|
const redLeftPoleZ = z + shelfWidth / 2 - poleSize / 2 |
|
|
|
const redLeftPole = new THREE.Mesh( |
|
|
|
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), |
|
|
|
new THREE.MeshPhongMaterial({ |
|
|
|
map: redPoleTexture, |
|
|
|
color: 0xffffff, // 颜色可保留作为叠加色 |
|
|
|
shininess: 60, |
|
|
|
transparent: true, |
|
|
|
transparent: true |
|
|
|
}) |
|
|
|
// new THREE.MeshPhongMaterial({ color: 0xff0000, shininess: 60 }) |
|
|
|
); |
|
|
|
redLeftPole.position.set(leftPoleX, leftPoleY, redLeftPoleZ); |
|
|
|
scene.add(redLeftPole); |
|
|
|
) |
|
|
|
redLeftPole.position.set(leftPoleX, leftPoleY, redLeftPoleZ) |
|
|
|
scene.add(redLeftPole) |
|
|
|
} |
|
|
|
|
|
|
|
// 层板间隙中的柱子 |
|
|
|
if (col < columns - 1) { |
|
|
|
const gapStartX = currentXOffset + unitLength; |
|
|
|
const gapStartX = currentXOffset + unitLength |
|
|
|
|
|
|
|
// 原有灰色柱子(居中) |
|
|
|
const poleX = gapStartX + poleSize / 2; |
|
|
|
const poleY = baseHeight + totalHeight / 2; |
|
|
|
const poleZ = z- shelfWidth / 2+poleSize/2; |
|
|
|
const poleX = gapStartX + poleSize / 2 |
|
|
|
const poleY = baseHeight + totalHeight / 2 |
|
|
|
const poleZ = z - shelfWidth / 2 + poleSize / 2 |
|
|
|
|
|
|
|
const pole = new THREE.Mesh( |
|
|
|
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), |
|
|
|
poleMaterial |
|
|
|
); |
|
|
|
pole.position.set(poleX, poleY, poleZ); |
|
|
|
scene.add(pole); |
|
|
|
) |
|
|
|
pole.position.set(poleX, poleY, poleZ) |
|
|
|
scene.add(pole) |
|
|
|
|
|
|
|
// 新增红色柱子,在原有柱子的前面或后面并排 |
|
|
|
const redPoleX = poleX; // 和灰柱 X 相同 |
|
|
|
const redPoleY = poleY; // 和灰柱 Y 相同 |
|
|
|
const redPoleZ = z + shelfWidth / 2-poleSize/2; // 在前方 |
|
|
|
const redPoleX = poleX // 和灰柱 X 相同 |
|
|
|
const redPoleY = poleY // 和灰柱 Y 相同 |
|
|
|
const redPoleZ = z + shelfWidth / 2 - poleSize / 2 // 在前方 |
|
|
|
|
|
|
|
const redPoleMaterial = new THREE.MeshPhongMaterial({ |
|
|
|
color: 0xff0000, |
|
|
|
shininess: 60 |
|
|
|
}); |
|
|
|
}) |
|
|
|
|
|
|
|
const redPole = new THREE.Mesh( |
|
|
|
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), |
|
|
|
redPoleMaterial |
|
|
|
); |
|
|
|
redPole.position.set(redPoleX, redPoleY, redPoleZ); |
|
|
|
scene.add(redPole); |
|
|
|
) |
|
|
|
redPole.position.set(redPoleX, redPoleY, redPoleZ) |
|
|
|
scene.add(redPole) |
|
|
|
} |
|
|
|
|
|
|
|
// 最右侧柱子 |
|
|
|
if (col === columns - 1) { |
|
|
|
const rightPoleX = currentXOffset + unitLength + gapBetweenPlanks - poleSize / 2; |
|
|
|
const rightPoleY = baseHeight + totalHeight / 2; |
|
|
|
const rightPoleZ = z - shelfWidth / 2 + poleSize / 2; |
|
|
|
const rightPoleX = currentXOffset + unitLength + gapBetweenPlanks - poleSize / 2 |
|
|
|
const rightPoleY = baseHeight + totalHeight / 2 |
|
|
|
const rightPoleZ = z - shelfWidth / 2 + poleSize / 2 |
|
|
|
|
|
|
|
// 黑色柱子 |
|
|
|
const rightPole = new THREE.Mesh( |
|
|
|
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), |
|
|
|
poleMaterial |
|
|
|
); |
|
|
|
rightPole.position.set(rightPoleX, rightPoleY, rightPoleZ); |
|
|
|
scene.add(rightPole); |
|
|
|
) |
|
|
|
rightPole.position.set(rightPoleX, rightPoleY, rightPoleZ) |
|
|
|
scene.add(rightPole) |
|
|
|
|
|
|
|
// 红色柱子 |
|
|
|
const redRightPoleZ = z + shelfWidth / 2 - poleSize / 2; |
|
|
|
const redRightPoleZ = z + shelfWidth / 2 - poleSize / 2 |
|
|
|
const redRightPole = new THREE.Mesh( |
|
|
|
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), |
|
|
|
new THREE.MeshPhongMaterial({ color: 0xff0000, shininess: 60 }) |
|
|
|
); |
|
|
|
redRightPole.position.set(rightPoleX, rightPoleY, redRightPoleZ); |
|
|
|
scene.add(redRightPole); |
|
|
|
) |
|
|
|
redRightPole.position.set(rightPoleX, rightPoleY, redRightPoleZ) |
|
|
|
scene.add(redRightPole) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
currentXOffset += unitLength + gapBetweenPlanks; |
|
|
|
currentXOffset += unitLength + gapBetweenPlanks |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 光源 |
|
|
|
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); |
|
|
|
scene.add(ambientLight); |
|
|
|
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); |
|
|
|
directionalLight.position.set(5, 10, 7); |
|
|
|
scene.add(directionalLight); |
|
|
|
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5) |
|
|
|
scene.add(ambientLight) |
|
|
|
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8) |
|
|
|
directionalLight.position.set(5, 10, 7) |
|
|
|
scene.add(directionalLight) |
|
|
|
} |
|
|
|
|
|
|
|
function createGroundStore() { |
|
|
|
const planeGeometry = new THREE.PlaneGeometry(1, 1); |
|
|
|
const planeGeometry = new THREE.PlaneGeometry(1, 1) |
|
|
|
const material = new THREE.MeshBasicMaterial({ |
|
|
|
color: 0x00ff00, |
|
|
|
side: THREE.DoubleSide // 双面渲染:ml-citation{ref="5,8" data="citationList"} |
|
|
|
}); |
|
|
|
const planeMesh = new THREE.Mesh(planeGeometry, material); |
|
|
|
}) |
|
|
|
const planeMesh = new THREE.Mesh(planeGeometry, material) |
|
|
|
planeMesh.rotateX(Math.PI / 2) |
|
|
|
scene.add(planeMesh); |
|
|
|
scene.add(planeMesh) |
|
|
|
} |
|
|
|
|
|
|
|
function initThree() { |
|
|
|
@ -837,7 +840,6 @@ function handleFileChange(file) { |
|
|
|
|
|
|
|
system.clearLoading() |
|
|
|
} |
|
|
|
reader.readAsArrayBuffer(file) |
|
|
|
|
|
|
|
} else if (fileName.endsWith('.obj')) { |
|
|
|
reader.readAsText(file) |
|
|
|
@ -861,11 +863,26 @@ function handleFileChange(file) { |
|
|
|
|
|
|
|
system.clearLoading() |
|
|
|
} |
|
|
|
reader.readAsArrayBuffer(file) |
|
|
|
|
|
|
|
} else if (fileName.endsWith('.glb') || fileName.endsWith('.gltf')) { |
|
|
|
reader.onload = () => { |
|
|
|
const loader = new GLTFLoader() |
|
|
|
const arrayBuffer = reader.result |
|
|
|
//@ts-ignore |
|
|
|
loader.parseAsync(arrayBuffer, '').then((content) => { |
|
|
|
debugger |
|
|
|
addGroupToScene(content.scene) |
|
|
|
}) |
|
|
|
|
|
|
|
system.clearLoading() |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
alert('不支持的文件类型!') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
reader.readAsArrayBuffer(file) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|