Browse Source

carton 纸箱模型

master
修宁 6 months ago
parent
commit
faeaa55386
  1. BIN
      src/assets/Models/carton.glb
  2. BIN
      src/assets/Models/carton.jpg
  3. 335
      src/components/Model3DView.vue
  4. 48
      src/core/ModelUtils.ts
  5. 2
      src/core/manager/WorldModel.ts
  6. 2
      src/example/ExampleUtil.js
  7. 8
      src/example/example1.js
  8. 5
      src/modules/carton/CartonEntity.ts
  9. 22
      src/modules/carton/CartonInteraction.ts
  10. 20
      src/modules/carton/CartonPropertySetter.ts
  11. 83
      src/modules/carton/CartonRenderer.ts
  12. 15
      src/modules/carton/index.ts
  13. 9
      src/types/ModelTypes.ts

BIN
src/assets/Models/carton.glb

Binary file not shown.

BIN
src/assets/Models/carton.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

335
src/components/Model3DView.vue

@ -2,7 +2,7 @@
<div class="model3d-view"> <div class="model3d-view">
<el-space :gutter="10" class="toolbar"> <el-space :gutter="10" class="toolbar">
<el-upload :on-change="handleFileChange" <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-button type="primary">打开模型</el-button>
</el-upload> </el-upload>
<el-upload :on-change="handleTextureUpload" <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 { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js' import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js'
import { TDSLoader } from 'three/examples/jsm/loaders/TDSLoader' 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 * as dat from 'three/examples/jsm/libs/lil-gui.module.min.js'
import Stats from 'three/examples/jsm/libs/stats.module' import Stats from 'three/examples/jsm/libs/stats.module'
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js' import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js'
import Split from '@/components/split/split.vue' import Split from '@/components/split/split.vue'
import SplitArea from '@/components/split/split-area.vue' import SplitArea from '@/components/split/split-area.vue'
import { renderIcon } from '@/utils/webutils.js' import { renderIcon } from '@/utils/webutils.js'
import rackPlatUrl from "@/assets/images/conveyor/shapes/RackPlatform.png"; import rackPlatUrl from '@/assets/images/conveyor/shapes/RackPlatform.png'
import rackBlue from "@/assets/images/conveyor/shapes/Rack-blue.png"; import rackBlue from '@/assets/images/conveyor/shapes/Rack-blue.png'
import triangleUrl from "@/assets/images/conveyor/shapes/triangle.png"; import triangleUrl from '@/assets/images/conveyor/shapes/triangle.png'
// DOM refs // DOM refs
const canvasContainer = ref(null) const canvasContainer = ref(null)
@ -168,118 +169,120 @@ watch(() => restate.mode, (newVal) => {
tcontrols.setMode(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 function addConveyor() {
const legDepth = 0.1; // Z const conveyorLength = 10 //
const legHeight = 0.8; // Y 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 conveyorGeometry = new THREE.BoxGeometry(conveyorWidth, conveyorHeight, conveyorLength)
const conveyorMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a }); const conveyorMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a })
const conveyor = new THREE.Mesh(conveyorGeometry, conveyorMaterial); const conveyor = new THREE.Mesh(conveyorGeometry, conveyorMaterial)
conveyor.position.y = conveyorHeight / 2; conveyor.position.y = conveyorHeight / 2
// //
const wallWidth = 0.05; const wallWidth = 0.05
const wallGeometry = new THREE.BoxGeometry(wallWidth, wallHeight, conveyorLength); const wallGeometry = new THREE.BoxGeometry(wallWidth, wallHeight, conveyorLength)
const wallMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a }); const wallMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a })
const leftWall = new THREE.Mesh(wallGeometry, wallMaterial); const leftWall = new THREE.Mesh(wallGeometry, wallMaterial)
leftWall.position.set(-(conveyorWidth / 2 + wallWidth / 2), wallHeight / 2, 0); leftWall.position.set(-(conveyorWidth / 2 + wallWidth / 2), wallHeight / 2, 0)
const rightWall = new THREE.Mesh(wallGeometry, wallMaterial); const rightWall = new THREE.Mesh(wallGeometry, wallMaterial)
rightWall.position.set((conveyorWidth / 2 + wallWidth / 2), wallHeight / 2, 0); rightWall.position.set((conveyorWidth / 2 + wallWidth / 2), wallHeight / 2, 0)
// //
const legGeometry = new THREE.BoxGeometry(legWidth, legHeight, legDepth); const legGeometry = new THREE.BoxGeometry(legWidth, legHeight, legDepth)
const legMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a }); // const legMaterial = new THREE.MeshBasicMaterial({ color: 0x6a6a6a }) //
const legPositions = [ 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)], //
[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 => { legPositions.forEach(pos => {
const leg = new THREE.Mesh(legGeometry, legMaterial); const leg = new THREE.Mesh(legGeometry, legMaterial)
leg.position.set( leg.position.set(
pos[0], pos[0],
-legHeight / 2, -legHeight / 2,
pos[1] pos[1]
); )
legs.push(leg); legs.push(leg)
}); })
// ====== ====== // ====== ======
const beamWidth = conveyorWidth; // 线0.8 const beamWidth = conveyorWidth // 线0.8
const beamLength = conveyorLength-conveyorHeight/2;// 线10 const beamLength = conveyorLength - conveyorHeight / 2// 线10
const beamHeight = 0.08; // 0.1 const beamHeight = 0.08 // 0.1
// Shape // 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 = { const extrudeSettings = {
depth: beamWidth, depth: beamWidth,
steps: 16, steps: 16,
bevelEnabled: false bevelEnabled: false
}; }
const beamGeometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); const beamGeometry = new THREE.ExtrudeGeometry(shape, extrudeSettings)
const beamMaterial = new THREE.MeshBasicMaterial({ color: 0x032702 }); // const beamMaterial = new THREE.MeshBasicMaterial({ color: 0x032702 }) //
const beam = new THREE.Mesh(beamGeometry, beamMaterial); const beam = new THREE.Mesh(beamGeometry, beamMaterial)
beam.rotation.x = Math.PI / 2; beam.rotation.x = Math.PI / 2
beam.rotation.z = Math.PI / 2 beam.rotation.z = Math.PI / 2
beam.rotation.y = Math.PI / 2 beam.rotation.y = Math.PI / 2
beam.position.y = beamHeight+conveyorHeight/2; // 线 beam.position.y = beamHeight + conveyorHeight / 2 // 线
beam.position.x = -beamWidth/2; beam.position.x = -beamWidth / 2
addMarkerAt(0, legHeight+beamHeight+conveyorHeight,0,triangleUrl,1,false); 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, 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,-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, 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,-conveyorLength/4,triangleUrl,.5,true); addMarkerAt(-(beamWidth / 2 + wallWidth + 0.01), legHeight + wallHeight / 2, -conveyorLength / 4, triangleUrl, .5, true)
// //
const group = new THREE.Group(); const group = new THREE.Group()
group.add(conveyor); group.add(conveyor)
group.add(leftWall); group.add(leftWall)
group.add(rightWall); group.add(rightWall)
legs.forEach(leg => group.add(leg)); legs.forEach(leg => group.add(leg))
group.add(beam); // group.add(beam) //
// 沿Z 1 // 沿Z 1
group.position.y = legHeight; // group.position.y = legHeight //
scene.add(group); 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) => { loader.load(textUrl, (texture) => {
// //
let markerGeometry let markerGeometry
if(lip){ if (lip) {
markerGeometry=new THREE.PlaneGeometry(.25 * scale, .25 * scale); markerGeometry = new THREE.PlaneGeometry(.25 * scale, .25 * scale)
}else{ } else {
markerGeometry = new THREE.PlaneGeometry(.45 * scale, .3 * scale); // markerGeometry = new THREE.PlaneGeometry(.45 * scale, .3 * scale) //
} }
const markerMaterial = new THREE.MeshBasicMaterial({ const markerMaterial = new THREE.MeshBasicMaterial({
@ -288,193 +291,193 @@ function addMarkerAt(x, y,z,textUrl, scale = 1,lip) {
opacity: 1, opacity: 1,
depthWrite: false, depthWrite: false,
side: THREE.DoubleSide side: THREE.DoubleSide
}); })
const marker = new THREE.Mesh(markerGeometry, markerMaterial); const marker = new THREE.Mesh(markerGeometry, markerMaterial)
let yHeight=y+0.01 let yHeight = y + 0.01
// 线Y线 // 线Y线
marker.position.set(x, yHeight, z); // Y = 线 + marker.position.set(x, yHeight, z) // Y = 线 +
// X/Z 线 // X/Z 线
marker.rotation.x = -Math.PI / 2; // conveyorBelt marker.rotation.x = -Math.PI / 2 // conveyorBelt
marker.rotation.z = Math.PI / 2; // 90 marker.rotation.z = Math.PI / 2 // 90
if(lip){ if (lip) {
marker.rotation.y = Math.PI / 2; // 90 marker.rotation.y = Math.PI / 2 // 90
}else{ } else {
marker.rotation.y = Math.PI; marker.rotation.y = Math.PI
} }
scene.add(marker); scene.add(marker)
}); })
} }
function createShelf(){// function createShelf() {//
const shelfLength = 5; const shelfLength = 5
const shelfWidth = 0.8; const shelfWidth = 0.8
const shelfThickness = 0.02; const shelfThickness = 0.02
const rows = 3; const rows = 3
const columns = 4; const columns = 4
const spacingY = 1; // const spacingY = 1 //
const gapBetweenPlanks = 0.1; // const gapBetweenPlanks = 0.1 //
const baseHeight = 0; // 0 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, () => { const shelfTexture = textureLoader.load(rackPlatUrl, () => {
renderer.render(scene, camera); renderer.render(scene, camera)
}); })
const redPoleTexture = textureLoader.load(rackBlue, () => { const redPoleTexture = textureLoader.load(rackBlue, () => {
renderer.render(scene, camera); // renderer.render(scene, camera) //
}); })
shelfTexture.wrapS = THREE.RepeatWrapping; shelfTexture.wrapS = THREE.RepeatWrapping
shelfTexture.wrapT = THREE.RepeatWrapping; shelfTexture.wrapT = THREE.RepeatWrapping
shelfTexture.repeat.set(1, 20); shelfTexture.repeat.set(1, 20)
shelfTexture.rotation = Math.PI / 2; shelfTexture.rotation = Math.PI / 2
const shelfMaterial = new THREE.MeshPhongMaterial({ const shelfMaterial = new THREE.MeshPhongMaterial({
map: shelfTexture, map: shelfTexture,
color: 0x999999, color: 0x999999,
shininess: 60 shininess: 60
}); })
// //
const poleMaterial = new THREE.MeshPhongMaterial({ const poleMaterial = new THREE.MeshPhongMaterial({
map: shelfTexture, map: shelfTexture,
color: 0x333333, color: 0x333333,
shininess: 60 shininess: 60
}); })
// //
const poleSize = gapBetweenPlanks; // const poleSize = gapBetweenPlanks //
const totalHeight = rows * spacingY; // const totalHeight = rows * spacingY //
for (let row = 0; row < rows; row++) { for (let row = 0; row < rows; row++) {
let currentXOffset = -shelfLength / 2; let currentXOffset = -shelfLength / 2
for (let col = 0; col < columns; col++) { for (let col = 0; col < columns; col++) {
const geometry = new THREE.BoxGeometry(unitLength, shelfThickness, shelfWidth); const geometry = new THREE.BoxGeometry(unitLength, shelfThickness, shelfWidth)
const mesh = new THREE.Mesh(geometry, shelfMaterial); const mesh = new THREE.Mesh(geometry, shelfMaterial)
const x = currentXOffset + unitLength / 2; const x = currentXOffset + unitLength / 2
// Y 使 // Y 使
const y = baseHeight + row * spacingY + shelfThickness / 2; const y = baseHeight + row * spacingY + shelfThickness / 2
const z = 0; const z = 0
mesh.position.set(x, y, z); mesh.position.set(x, y, z)
scene.add(mesh); scene.add(mesh)
if (row === 0) { // if (row === 0) { //
// //
if (col === 0) { if (col === 0) {
const leftPoleX = currentXOffset - poleSize / 2; const leftPoleX = currentXOffset - poleSize / 2
const leftPoleY = baseHeight + totalHeight / 2; const leftPoleY = baseHeight + totalHeight / 2
const leftPoleZ = z - shelfWidth / 2 + poleSize / 2; const leftPoleZ = z - shelfWidth / 2 + poleSize / 2
// //
const leftPole = new THREE.Mesh( const leftPole = new THREE.Mesh(
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), new THREE.BoxGeometry(poleSize, totalHeight, poleSize),
poleMaterial poleMaterial
); )
leftPole.position.set(leftPoleX, leftPoleY, leftPoleZ); leftPole.position.set(leftPoleX, leftPoleY, leftPoleZ)
scene.add(leftPole); scene.add(leftPole)
// // // //
const redLeftPoleZ = z + shelfWidth / 2 - poleSize / 2; const redLeftPoleZ = z + shelfWidth / 2 - poleSize / 2
const redLeftPole = new THREE.Mesh( const redLeftPole = new THREE.Mesh(
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), new THREE.BoxGeometry(poleSize, totalHeight, poleSize),
new THREE.MeshPhongMaterial({ new THREE.MeshPhongMaterial({
map: redPoleTexture, map: redPoleTexture,
color: 0xffffff, // color: 0xffffff, //
shininess: 60, shininess: 60,
transparent: true, transparent: true
}) })
// new THREE.MeshPhongMaterial({ color: 0xff0000, shininess: 60 }) // new THREE.MeshPhongMaterial({ color: 0xff0000, shininess: 60 })
); )
redLeftPole.position.set(leftPoleX, leftPoleY, redLeftPoleZ); redLeftPole.position.set(leftPoleX, leftPoleY, redLeftPoleZ)
scene.add(redLeftPole); scene.add(redLeftPole)
} }
// //
if (col < columns - 1) { if (col < columns - 1) {
const gapStartX = currentXOffset + unitLength; const gapStartX = currentXOffset + unitLength
// //
const poleX = gapStartX + poleSize / 2; const poleX = gapStartX + poleSize / 2
const poleY = baseHeight + totalHeight / 2; const poleY = baseHeight + totalHeight / 2
const poleZ = z- shelfWidth / 2+poleSize/2; const poleZ = z - shelfWidth / 2 + poleSize / 2
const pole = new THREE.Mesh( const pole = new THREE.Mesh(
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), new THREE.BoxGeometry(poleSize, totalHeight, poleSize),
poleMaterial poleMaterial
); )
pole.position.set(poleX, poleY, poleZ); pole.position.set(poleX, poleY, poleZ)
scene.add(pole); scene.add(pole)
// //
const redPoleX = poleX; // X const redPoleX = poleX // X
const redPoleY = poleY; // Y const redPoleY = poleY // Y
const redPoleZ = z + shelfWidth / 2-poleSize/2; // const redPoleZ = z + shelfWidth / 2 - poleSize / 2 //
const redPoleMaterial = new THREE.MeshPhongMaterial({ const redPoleMaterial = new THREE.MeshPhongMaterial({
color: 0xff0000, color: 0xff0000,
shininess: 60 shininess: 60
}); })
const redPole = new THREE.Mesh( const redPole = new THREE.Mesh(
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), new THREE.BoxGeometry(poleSize, totalHeight, poleSize),
redPoleMaterial redPoleMaterial
); )
redPole.position.set(redPoleX, redPoleY, redPoleZ); redPole.position.set(redPoleX, redPoleY, redPoleZ)
scene.add(redPole); scene.add(redPole)
} }
// //
if (col === columns - 1) { if (col === columns - 1) {
const rightPoleX = currentXOffset + unitLength + gapBetweenPlanks - poleSize / 2; const rightPoleX = currentXOffset + unitLength + gapBetweenPlanks - poleSize / 2
const rightPoleY = baseHeight + totalHeight / 2; const rightPoleY = baseHeight + totalHeight / 2
const rightPoleZ = z - shelfWidth / 2 + poleSize / 2; const rightPoleZ = z - shelfWidth / 2 + poleSize / 2
// //
const rightPole = new THREE.Mesh( const rightPole = new THREE.Mesh(
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), new THREE.BoxGeometry(poleSize, totalHeight, poleSize),
poleMaterial poleMaterial
); )
rightPole.position.set(rightPoleX, rightPoleY, rightPoleZ); rightPole.position.set(rightPoleX, rightPoleY, rightPoleZ)
scene.add(rightPole); scene.add(rightPole)
// //
const redRightPoleZ = z + shelfWidth / 2 - poleSize / 2; const redRightPoleZ = z + shelfWidth / 2 - poleSize / 2
const redRightPole = new THREE.Mesh( const redRightPole = new THREE.Mesh(
new THREE.BoxGeometry(poleSize, totalHeight, poleSize), new THREE.BoxGeometry(poleSize, totalHeight, poleSize),
new THREE.MeshPhongMaterial({ color: 0xff0000, shininess: 60 }) new THREE.MeshPhongMaterial({ color: 0xff0000, shininess: 60 })
); )
redRightPole.position.set(rightPoleX, rightPoleY, redRightPoleZ); redRightPole.position.set(rightPoleX, rightPoleY, redRightPoleZ)
scene.add(redRightPole); scene.add(redRightPole)
} }
} }
currentXOffset += unitLength + gapBetweenPlanks; currentXOffset += unitLength + gapBetweenPlanks
} }
} }
// //
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
scene.add(ambientLight); scene.add(ambientLight)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
directionalLight.position.set(5, 10, 7); directionalLight.position.set(5, 10, 7)
scene.add(directionalLight); scene.add(directionalLight)
} }
function createGroundStore() { function createGroundStore() {
const planeGeometry = new THREE.PlaneGeometry(1, 1); const planeGeometry = new THREE.PlaneGeometry(1, 1)
const material = new THREE.MeshBasicMaterial({ const material = new THREE.MeshBasicMaterial({
color: 0x00ff00, color: 0x00ff00,
side: THREE.DoubleSide // :ml-citation{ref="5,8" data="citationList"} 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) planeMesh.rotateX(Math.PI / 2)
scene.add(planeMesh); scene.add(planeMesh)
} }
function initThree() { function initThree() {
@ -837,7 +840,6 @@ function handleFileChange(file) {
system.clearLoading() system.clearLoading()
} }
reader.readAsArrayBuffer(file)
} else if (fileName.endsWith('.obj')) { } else if (fileName.endsWith('.obj')) {
reader.readAsText(file) reader.readAsText(file)
@ -861,11 +863,26 @@ function handleFileChange(file) {
system.clearLoading() 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 { } else {
alert('不支持的文件类型!') alert('不支持的文件类型!')
return
} }
reader.readAsArrayBuffer(file)
} }

48
src/core/ModelUtils.ts

@ -10,6 +10,7 @@ import axios from 'axios'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader' import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader' import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { TDSLoader } from 'three/examples/jsm/loaders/TDSLoader' import { TDSLoader } from 'three/examples/jsm/loaders/TDSLoader'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
export function setUserDataForItem(item: ItemJson, object: Object3DLike) { export function setUserDataForItem(item: ItemJson, object: Object3DLike) {
if (!object.name && item.name) { if (!object.name && item.name) {
@ -494,6 +495,14 @@ export async function loadByUrl(url): Promise<any> {
}) })
} }
export async function loadGlbModule(url: string): Promise<THREE.Group> {
const response = await axios.get(url, {
responseType: 'arraybuffer'
})
const rt = await new GLTFLoader().parseAsync(response.data, '')
return rt.scene
}
export function loadTexture(url: string) { export function loadTexture(url: string) {
return new THREE.TextureLoader().loadAsync(url) return new THREE.TextureLoader().loadAsync(url)
} }
@ -519,3 +528,42 @@ export function load3DModule(arrayBuffer: ArrayBuffer | string, ext: string) {
return null 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
}

2
src/core/manager/WorldModel.ts

@ -7,6 +7,7 @@ import Gstore from '@/modules/gstore'
import Rack from '@/modules/rack' import Rack from '@/modules/rack'
import Pallet from "@/modules/pallet" import Pallet from "@/modules/pallet"
import Tote from "@/modules/tote" import Tote from "@/modules/tote"
import Carton from "@/modules/carton"
import Ptr from "@/modules/ptr" import Ptr from "@/modules/ptr"
import Clx from "@/modules/clx" import Clx from "@/modules/clx"
import Charger from "@/modules/charger" import Charger from "@/modules/charger"
@ -74,6 +75,7 @@ export default class WorldModel {
Rack, Rack,
Pallet, Pallet,
Tote, Tote,
Carton,
Ptr, Ptr,
Clx, Clx,
Charger Charger

2
src/example/ExampleUtil.js

@ -18,7 +18,7 @@ export function buildPointPerformanceData(t, rows, cols) {
node.tf[0][1] = 0.01 node.tf[0][1] = 0.01
node.tf[0][2] = col * spacingZ node.tf[0][2] = col * spacingZ
node.tf[1] = [0, 0, 0] 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) data.set(node.id, node)
} }
} }

8
src/example/example1.js

@ -326,10 +326,10 @@ export default {
catalogCode: 'f3', t: 'floor', catalogCode: 'f3', t: 'floor',
items: [ items: [
{ {
id: 'tote1', id: 'carton1',
t: 'pallet', t: 'carton',
v: true, 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 } dt: { in: [], out: [], center: [], storeWidth: 1.4, storeDepth: 1.4 }
} }
] ]
@ -340,7 +340,7 @@ export default {
}, },
{ {
catalogCode: '__f2', t: 'floor', catalogCode: '__f2', t: 'floor',
items: buildPointPerformanceData('gstore', 100, 100) items: buildPointPerformanceData('carton', 100, 100)
} }
], ],
elevator: [], // 电梯 elevator: [], // 电梯

5
src/modules/carton/CartonEntity.ts

@ -0,0 +1,5 @@
import BaseEntity from '@/core/base/BaseItemEntity.ts'
export default class PalletEntity extends BaseEntity {
}

22
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
}
}

20
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;

83
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
}
}
}

15
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,
})

9
src/types/ModelTypes.ts

@ -72,3 +72,12 @@ export type Object3DLike = Object3D | LineManageWrap | PointManageWrap
* , THREE.Vector3 * , THREE.Vector3
*/ */
export type Vector3Like = THREE.Vector3 | number[] export type Vector3Like = THREE.Vector3 | number[]
/**
*
*/
export const MaterialQualityEnum = {
High: 0,
Middle: 1,
Low: 2,
};

Loading…
Cancel
Save