diff --git a/src/assets/Models/carton.glb b/src/assets/Models/carton.glb
new file mode 100644
index 0000000..1f5efa7
Binary files /dev/null and b/src/assets/Models/carton.glb differ
diff --git a/src/assets/Models/carton.jpg b/src/assets/Models/carton.jpg
new file mode 100644
index 0000000..681f48c
Binary files /dev/null and b/src/assets/Models/carton.jpg differ
diff --git a/src/components/Model3DView.vue b/src/components/Model3DView.vue
index e87bbcd..a93385d 100644
--- a/src/components/Model3DView.vue
+++ b/src/components/Model3DView.vue
@@ -2,7 +2,7 @@
+ :show-file-list="false" accept=".fbx,.obj,.mtl,.3ds,.glb,.gltf" action="" :auto-upload="false">
打开模型
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)
}
diff --git a/src/core/ModelUtils.ts b/src/core/ModelUtils.ts
index ecd4081..32b988e 100644
--- a/src/core/ModelUtils.ts
+++ b/src/core/ModelUtils.ts
@@ -10,6 +10,7 @@ import axios from 'axios'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { TDSLoader } from 'three/examples/jsm/loaders/TDSLoader'
+import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
export function setUserDataForItem(item: ItemJson, object: Object3DLike) {
if (!object.name && item.name) {
@@ -494,6 +495,14 @@ export async function loadByUrl(url): Promise {
})
}
+export async function loadGlbModule(url: string): Promise {
+ const response = await axios.get(url, {
+ responseType: 'arraybuffer'
+ })
+ const rt = await new GLTFLoader().parseAsync(response.data, '')
+ return rt.scene
+}
+
export function loadTexture(url: string) {
return new THREE.TextureLoader().loadAsync(url)
}
@@ -519,3 +528,42 @@ export function load3DModule(arrayBuffer: ArrayBuffer | string, ext: string) {
return null
}
}
+
+export async function generateMaterialWithTexture(color: number, quality: number, info: any, textureInfos: any) {
+ let materialClone
+
+ let url = color?.toString() + ' ' + JSON.stringify(textureInfos) + ' ' + quality + ' ' + (info == undefined ? '' : JSON.stringify(info))
+
+ if (!this.materialsWithTextureMap[url]) {
+ let meterialTmp = await this.generateMaterial(color, quality, info)
+ for (let textureInfo of textureInfos) {
+ if (textureInfo.path != undefined && textureInfo.repeatX != undefined && textureInfo.repeatY != undefined) {
+ let textureTmp = await this.generateTexture(textureInfo.path, textureInfo.repeatX, textureInfo.repeatY)
+
+ if (textureInfo.rotation != undefined) {
+ textureTmp.rotation = textureInfo.rotation
+ }
+ if (textureInfo.normalMapType != undefined) {
+ textureTmp.normalMapType = textureInfo.normalMapType
+ }
+
+ if (textureInfo.type == Model.TextureTypeEnum.NormalMap) {
+ if (quality != Model.MaterialQualityEnum.Low) {
+ meterialTmp.normalMap = textureTmp
+ }
+ } else if (textureInfo.type == Model.TextureTypeEnum.AlphaMap) {
+ meterialTmp.alphaMap = textureTmp
+ } else if (textureInfo.type == Model.TextureTypeEnum.Map) {
+ meterialTmp.map = textureTmp
+ } else {
+ meterialTmp.map = textureTmp
+ }
+ meterialTmp.needsUpdate = true
+ }
+ }
+ this.materialsWithTextureMap[url] = meterialTmp
+ }
+ materialClone = this.materialsWithTextureMap[url]
+
+ return materialClone
+}
diff --git a/src/core/manager/WorldModel.ts b/src/core/manager/WorldModel.ts
index 35a8bbb..3378f36 100644
--- a/src/core/manager/WorldModel.ts
+++ b/src/core/manager/WorldModel.ts
@@ -7,6 +7,7 @@ import Gstore from '@/modules/gstore'
import Rack from '@/modules/rack'
import Pallet from "@/modules/pallet"
import Tote from "@/modules/tote"
+import Carton from "@/modules/carton"
import Ptr from "@/modules/ptr"
import Clx from "@/modules/clx"
import Charger from "@/modules/charger"
@@ -74,6 +75,7 @@ export default class WorldModel {
Rack,
Pallet,
Tote,
+ Carton,
Ptr,
Clx,
Charger
diff --git a/src/example/ExampleUtil.js b/src/example/ExampleUtil.js
index 1017118..7c61487 100644
--- a/src/example/ExampleUtil.js
+++ b/src/example/ExampleUtil.js
@@ -18,7 +18,7 @@ export function buildPointPerformanceData(t, rows, cols) {
node.tf[0][1] = 0.01
node.tf[0][2] = col * spacingZ
node.tf[1] = [0, 0, 0]
- node.tf[2] = [1, 0.01, 1]
+ node.tf[2] = [1, 0.4, 1]
data.set(node.id, node)
}
}
diff --git a/src/example/example1.js b/src/example/example1.js
index f699de4..91774a7 100644
--- a/src/example/example1.js
+++ b/src/example/example1.js
@@ -326,10 +326,10 @@ export default {
catalogCode: 'f3', t: 'floor',
items: [
{
- id: 'tote1',
- t: 'pallet',
+ id: 'carton1',
+ t: 'carton',
v: true,
- tf: [[0, 0.1, 0], [0, 0, 0], [1.0, 0.1, 1.0]],
+ tf: [[0, 0.1, 0], [0, 0, 0], [1.0, 1.0, 1.0]],
dt: { in: [], out: [], center: [], storeWidth: 1.4, storeDepth: 1.4 }
}
]
@@ -340,7 +340,7 @@ export default {
},
{
catalogCode: '__f2', t: 'floor',
- items: buildPointPerformanceData('gstore', 100, 100)
+ items: buildPointPerformanceData('carton', 100, 100)
}
],
elevator: [], // 电梯
diff --git a/src/modules/carton/CartonEntity.ts b/src/modules/carton/CartonEntity.ts
new file mode 100644
index 0000000..9cf671f
--- /dev/null
+++ b/src/modules/carton/CartonEntity.ts
@@ -0,0 +1,5 @@
+import BaseEntity from '@/core/base/BaseItemEntity.ts'
+
+export default class PalletEntity extends BaseEntity {
+
+}
diff --git a/src/modules/carton/CartonInteraction.ts b/src/modules/carton/CartonInteraction.ts
new file mode 100644
index 0000000..c01c91b
--- /dev/null
+++ b/src/modules/carton/CartonInteraction.ts
@@ -0,0 +1,22 @@
+import BaseInteraction from '@/core/base/BaseInteraction.ts'
+import * as THREE from 'three'
+
+export default class PalletInteraction extends BaseInteraction {
+
+ get isSinglePointMode(): boolean {
+ return true
+ }
+
+ constructor(itemTypeName: string) {
+ super(itemTypeName)
+ }
+
+ createPointOfItem(item: ItemJson, point: THREE.Vector3): ItemJson {
+ item = super.createPointOfItem(item, point)
+
+ // 创建一个地堆货架
+ item.dt.palletWidth = 1 // 宽度
+ item.dt.palletDepth = 1.2 // 深度
+ return item
+ }
+}
diff --git a/src/modules/carton/CartonPropertySetter.ts b/src/modules/carton/CartonPropertySetter.ts
new file mode 100644
index 0000000..4a5cfc9
--- /dev/null
+++ b/src/modules/carton/CartonPropertySetter.ts
@@ -0,0 +1,20 @@
+import type { PropertySetter } from "@/core/base/PropertyTypes.ts";
+import { basicFieldsSetter } from "@/editor/widgets/property/PropertyPanelConstant.ts";
+
+const propertySetter: PropertySetter = {
+ flatten: {
+ fields: [
+ ...basicFieldsSetter,
+ {
+ dataPath: 'dt.palletWidth', label: '托盘宽度', input: 'InputNumber',
+ inputProps: {},
+ },
+ {
+ dataPath: 'dt.palletDepth', label: '托盘深度', input: 'InputNumber',
+ inputProps: {},
+ },
+ ],
+ },
+};
+
+export default propertySetter;
diff --git a/src/modules/carton/CartonRenderer.ts b/src/modules/carton/CartonRenderer.ts
new file mode 100644
index 0000000..c8c6dd8
--- /dev/null
+++ b/src/modules/carton/CartonRenderer.ts
@@ -0,0 +1,83 @@
+import * as THREE from 'three'
+import BaseRenderer from '@/core/base/BaseRenderer.ts'
+import Constract from '@/core/Constract.ts'
+import InstancePointManager from '@/core/manager/InstancePointManager.ts'
+import type { Object3DLike } from '@/types/ModelTypes.ts'
+import MODULE_GLB_File from '@/assets/Models/carton.glb?url'
+import MODULE_3DS_TEX from '@/assets/Models/carton.jpg?url'
+import { load3DModule, loadByUrl, loadGlbModule, loadTexture } from '@/core/ModelUtils.ts'
+
+/**
+ * 货架货位渲染器
+ */
+export default class PalletRenderer extends BaseRenderer {
+ static POINT_NAME = 'carton_point'
+
+ /**
+ * 默认点的高度, 防止和地面重合
+ */
+ readonly defulePositionY: number = Constract.HEIGHT_WAY
+ readonly defaultScale: THREE.Vector3 = new THREE.Vector3(1, 1, 1)
+ readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(0, 0, 0)
+ readonly defaultUserData = {
+ color: 0xc29a70
+ }
+
+ cartonGeometry: THREE.BufferGeometry
+ cartonMaterial: THREE.Material
+
+ init() {
+ return Promise.all([
+ super.init(),
+ loadGlbModule(MODULE_GLB_File),
+ loadTexture(MODULE_3DS_TEX)
+
+ ]).then(([_, glbGroup, cartonTexture]) => {
+ const mesh = glbGroup.children[0] as THREE.Mesh
+ this.cartonGeometry = mesh.geometry
+ this.cartonMaterial = new THREE.MeshPhongMaterial({ color: 0xc29a70 }) // mesh.material as THREE.Material
+ this.cartonGeometry.scale(0.01, 0.01, 0.01)
+ this.cartonGeometry.rotateX(Math.PI / 2)
+
+ cartonTexture.wrapS = THREE.RepeatWrapping
+ cartonTexture.wrapT = THREE.RepeatWrapping
+ cartonTexture.repeat.set(1, 1)
+ //@ts-ignore
+ this.cartonMaterial.map = cartonTexture
+ //@ts-ignore
+ this.cartonMaterial.color.set(this.defaultUserData.color)
+
+ this.cartonMaterial.needsUpdate = true
+ })
+ }
+
+ createPointBasic(item: ItemJson, option?: RendererCudOption): Object3DLike {
+ return this.pointManager.createPoint(item)
+ }
+
+ get pointManager(): InstancePointManager {
+ if (!this.tempViewport) {
+ throw new Error('tempViewport is not set.')
+ }
+ return this.tempViewport.getOrCreatePointManager(this.itemTypeName, () =>
+ // 构建 InstanceMesh 代理对象
+ InstancePointManager.create(this.itemTypeName,
+ this.tempViewport,
+ this.cartonGeometry,
+ this.cartonMaterial,
+ Constract.MAX_PALLET_INSTANCES)
+ )
+ }
+
+ dispose() {
+ super.dispose()
+ if (this.cartonGeometry) {
+ this.cartonGeometry.dispose()
+ this.cartonGeometry = undefined
+ }
+ if (this.cartonMaterial) {
+ this.cartonMaterial.dispose()
+ this.cartonMaterial = undefined
+ }
+ }
+}
diff --git a/src/modules/carton/index.ts b/src/modules/carton/index.ts
new file mode 100644
index 0000000..f38fc5d
--- /dev/null
+++ b/src/modules/carton/index.ts
@@ -0,0 +1,15 @@
+import { defineModule } from '@/core/manager/ModuleManager.ts'
+import CartonRenderer from './CartonRenderer.ts'
+import CartonEntity from './CartonEntity.ts'
+import CartonInteraction from './CartonInteraction.ts'
+import propertySetter from "./CartonPropertySetter.ts";
+
+export const ITEM_TYPE_NAME = 'carton'
+
+export default defineModule({
+ name: ITEM_TYPE_NAME,
+ renderer: new CartonRenderer(ITEM_TYPE_NAME),
+ interaction: new CartonInteraction(ITEM_TYPE_NAME),
+ setter: propertySetter,
+ entity: CartonEntity,
+})
diff --git a/src/types/ModelTypes.ts b/src/types/ModelTypes.ts
index 3238fc4..8669692 100644
--- a/src/types/ModelTypes.ts
+++ b/src/types/ModelTypes.ts
@@ -72,3 +72,12 @@ export type Object3DLike = Object3D | LineManageWrap | PointManageWrap
* 坐标的范指型, 可以是 THREE.Vector3 或者三元数组
*/
export type Vector3Like = THREE.Vector3 | number[]
+
+/**
+ * 材质质量枚举
+ */
+export const MaterialQualityEnum = {
+ High: 0,
+ Middle: 1,
+ Low: 2,
+};