7 changed files with 424 additions and 1 deletions
@ -0,0 +1,219 @@ |
|||||
|
import * as THREE from 'three' |
||||
|
import {mergeGeometries} from 'three/addons/utils/BufferGeometryUtils.js' |
||||
|
import {BufferGeometry, MathUtils} from "three"; |
||||
|
import {Material} from "three/src/materials/Material"; |
||||
|
import storageBar_PNG from "@/assets/Models/storageBar.png"; |
||||
|
import Plastic_Rough_JPG from "@/assets/Models/Plastic_Rough.jpg"; |
||||
|
import {InstancedMesh} from "three/src/objects/InstancedMesh"; |
||||
|
import {decimalSumBy, resetUVs} from "@/core/ModelUtils"; |
||||
|
|
||||
|
export default class Bracket3dObject extends THREE.Object3D { |
||||
|
|
||||
|
|
||||
|
private bracketVerticalBarLength = 0.32 |
||||
|
private bracketHorizontalBarWidth = 0.85 |
||||
|
|
||||
|
private static bracketColor = 0xFF666666 |
||||
|
private static bracketBarGeometryMap: Map<number, BufferGeometry> = new Map<number, BufferGeometry>() |
||||
|
private static bracketBarMaterial: Material = null |
||||
|
|
||||
|
private static bracketCenterPlateGeometry: BufferGeometry = null |
||||
|
|
||||
|
private static barSectionPoints = [ |
||||
|
{x: -0.015, y: -0.012}, |
||||
|
{x: -0.012, y: -0.015}, |
||||
|
{x: 0.012, y: -0.015}, |
||||
|
{x: 0.015, y: -0.012}, |
||||
|
{x: 0.015, y: 0.012}, |
||||
|
{x: 0.012, y: 0.015}, |
||||
|
{x: -0.012, y: 0.015}, |
||||
|
{x: -0.015, y: 0.012} |
||||
|
] |
||||
|
|
||||
|
private static centerSectionPoints = [ |
||||
|
{x: -0.1, y: -0.1}, |
||||
|
{x: -0.1, y: 0.1}, |
||||
|
{x: 0.1, y: 0.1}, |
||||
|
{x: 0.1, y: -0.1} |
||||
|
] |
||||
|
|
||||
|
|
||||
|
private createBracketBar(length): THREE.BufferGeometry { |
||||
|
|
||||
|
// 创建一个形状 柱子的截面形状
|
||||
|
const shape = new THREE.Shape() |
||||
|
shape.moveTo(Bracket3dObject.barSectionPoints[0].x, Bracket3dObject.barSectionPoints[0].y) |
||||
|
for (let i = 1; i < Bracket3dObject.barSectionPoints.length; i++) { |
||||
|
shape.lineTo(Bracket3dObject.barSectionPoints[i].x, Bracket3dObject.barSectionPoints[i].y) |
||||
|
} |
||||
|
shape.closePath() |
||||
|
|
||||
|
// 拉伸轨迹线
|
||||
|
const curve = new THREE.CatmullRomCurve3( |
||||
|
[new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, length, 0)], |
||||
|
false, // 闭合曲线
|
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
// 挤出几何图形 参数
|
||||
|
const options = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: curve // 设置挤出轨迹
|
||||
|
} |
||||
|
// 创建挤出几何体
|
||||
|
const geometry = new THREE.ExtrudeGeometry(shape, options) |
||||
|
// 调整uv方便正确贴图
|
||||
|
resetUVs(geometry) |
||||
|
return geometry |
||||
|
} |
||||
|
|
||||
|
private createBracketBarMaterial(): THREE.Material { |
||||
|
|
||||
|
let textureLoader = new THREE.TextureLoader() |
||||
|
|
||||
|
// 加载纹理
|
||||
|
const textureMaterial = textureLoader.load(Plastic_Rough_JPG) // 表面材质
|
||||
|
|
||||
|
textureMaterial.repeat.set(2, 2) // X轴重复,Y轴重复
|
||||
|
// textureHole.offset.set(0.5, 0)
|
||||
|
// textureHole.center.set(0.5, 0)
|
||||
|
|
||||
|
|
||||
|
textureMaterial.wrapS = THREE.RepeatWrapping |
||||
|
textureMaterial.wrapT = THREE.RepeatWrapping |
||||
|
|
||||
|
const material = new THREE.MeshPhongMaterial() |
||||
|
material.normalMap = textureMaterial |
||||
|
material.color.setHex(Bracket3dObject.bracketColor, 'srgb') |
||||
|
material.specular.setHex(0xff6d6d6d, 'srgb') |
||||
|
material.transparent = true |
||||
|
material.needsUpdate = true |
||||
|
|
||||
|
return material |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private createCenterPlate(length): THREE.BufferGeometry { |
||||
|
|
||||
|
// 创建一个形状 柱子的截面形状
|
||||
|
const shape = new THREE.Shape() |
||||
|
shape.moveTo(Bracket3dObject.centerSectionPoints[0].x, Bracket3dObject.centerSectionPoints[0].y) |
||||
|
for (let i = 1; i < Bracket3dObject.centerSectionPoints.length; i++) { |
||||
|
shape.lineTo(Bracket3dObject.centerSectionPoints[i].x, Bracket3dObject.centerSectionPoints[i].y) |
||||
|
} |
||||
|
shape.closePath() |
||||
|
|
||||
|
// 拉伸轨迹线
|
||||
|
const curve = new THREE.CatmullRomCurve3( |
||||
|
[new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0.005, 0)], |
||||
|
false, // 闭合曲线
|
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
// 挤出几何图形 参数
|
||||
|
const options = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: curve // 设置挤出轨迹
|
||||
|
} |
||||
|
// 创建挤出几何体
|
||||
|
const geometry = new THREE.ExtrudeGeometry(shape, options) |
||||
|
|
||||
|
return geometry |
||||
|
} |
||||
|
|
||||
|
constructor(item: ItemJson, option?: RendererCudOption) { |
||||
|
super(); |
||||
|
const width = 0.85 |
||||
|
const depth = 0.85 |
||||
|
const height = 0.35 |
||||
|
|
||||
|
if (!Bracket3dObject.bracketBarGeometryMap.get(this.bracketVerticalBarLength)) { |
||||
|
Bracket3dObject.bracketBarGeometryMap.set(this.bracketVerticalBarLength, this.createBracketBar(this.bracketVerticalBarLength)) |
||||
|
} |
||||
|
if (!Bracket3dObject.bracketBarGeometryMap.get(this.bracketHorizontalBarWidth)) { |
||||
|
Bracket3dObject.bracketBarGeometryMap.set(this.bracketHorizontalBarWidth, this.createBracketBar(this.bracketHorizontalBarWidth)) |
||||
|
} |
||||
|
if (!Bracket3dObject.bracketBarMaterial) { |
||||
|
Bracket3dObject.bracketBarMaterial = this.createBracketBarMaterial() |
||||
|
} |
||||
|
if (!Bracket3dObject.bracketCenterPlateGeometry) { |
||||
|
Bracket3dObject.bracketCenterPlateGeometry = this.createCenterPlate(height) |
||||
|
} |
||||
|
|
||||
|
const vBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = [] |
||||
|
const hBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = [] |
||||
|
|
||||
|
vBarMatrix.push({x: 0.41, y: 0, z: 0.41, rx: 0, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketVerticalBarLength}) |
||||
|
vBarMatrix.push({x: 0.41, y: 0, z: -0.41, rx: 0, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketVerticalBarLength}) |
||||
|
vBarMatrix.push({x: -0.41, y: 0, z: -0.41, rx: 0, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketVerticalBarLength}) |
||||
|
vBarMatrix.push({x: -0.41, y: 0, z: 0.41, rx: 0, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketVerticalBarLength}) |
||||
|
|
||||
|
hBarMatrix.push({x: -0.41, y: 0.335, z: width/2, rx: -Math.PI/2, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) |
||||
|
hBarMatrix.push({x: -0.1, y: 0.335, z: width/2, rx: -Math.PI/2, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) |
||||
|
hBarMatrix.push({x: 0.1, y: 0.335, z: width/2, rx: -Math.PI/2, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) |
||||
|
hBarMatrix.push({x: 0.41, y: 0.335, z: width/2, rx: -Math.PI/2, ry: 0, rz: 0, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) |
||||
|
|
||||
|
hBarMatrix.push({x: width/2, y: 0.335, z: -0.41, rx: 0, ry: 0, rz: Math.PI/2, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) |
||||
|
hBarMatrix.push({x: width/2, y: 0.335, z: -0.1, rx: 0, ry: 0, rz: Math.PI/2, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) |
||||
|
hBarMatrix.push({x: width/2, y: 0.335, z: 0.1, rx: 0, ry: 0, rz: Math.PI/2, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) |
||||
|
hBarMatrix.push({x: width/2, y: 0.335, z: 0.41, rx: 0, ry: 0, rz: Math.PI/2, sx: 1, sy: 1, sz: 1, l: this.bracketHorizontalBarWidth}) |
||||
|
|
||||
|
|
||||
|
const meshes: InstancedMesh[] = [] |
||||
|
const bracketVerticalBarGeometry = Bracket3dObject.bracketBarGeometryMap.get(this.bracketVerticalBarLength) |
||||
|
const vBarMesh = new THREE.InstancedMesh(bracketVerticalBarGeometry, Bracket3dObject.bracketBarMaterial, vBarMatrix.length) |
||||
|
|
||||
|
const bracketHorizontalBarGeometry = Bracket3dObject.bracketBarGeometryMap.get(this.bracketHorizontalBarWidth) |
||||
|
const hBarMesh = new THREE.InstancedMesh(bracketHorizontalBarGeometry, Bracket3dObject.bracketBarMaterial, hBarMatrix.length) |
||||
|
|
||||
|
const centerMesh = new THREE.Mesh(Bracket3dObject.bracketCenterPlateGeometry, Bracket3dObject.bracketBarMaterial) |
||||
|
|
||||
|
|
||||
|
const dummy = new THREE.Object3D() |
||||
|
for (let i = 0; i < vBarMatrix.length; i++) { |
||||
|
const vp = vBarMatrix[i] |
||||
|
dummy.position.set(vp.x, vp.y, vp.z) |
||||
|
dummy.rotation.set(vp.rx, vp.ry, vp.rz) |
||||
|
dummy.scale.set(vp.sx, vp.sy, vp.sz) |
||||
|
dummy.updateMatrix() |
||||
|
vBarMesh.setMatrixAt(i, dummy.matrix) |
||||
|
} |
||||
|
meshes.push(vBarMesh) |
||||
|
for (let i = 0; i < hBarMatrix.length; i++) { |
||||
|
const vp = hBarMatrix[i] |
||||
|
dummy.position.set(vp.x, vp.y, vp.z) |
||||
|
dummy.rotation.set(vp.rx, vp.ry, vp.rz) |
||||
|
dummy.scale.set(vp.sx, vp.sy, vp.sz) |
||||
|
dummy.updateMatrix() |
||||
|
hBarMesh.setMatrixAt(i, dummy.matrix) |
||||
|
} |
||||
|
meshes.push(hBarMesh) |
||||
|
|
||||
|
meshes.forEach(mesh => { |
||||
|
this.add(mesh) |
||||
|
mesh.instanceMatrix.needsUpdate = true |
||||
|
}) |
||||
|
this.add(centerMesh) |
||||
|
centerMesh.position.set(0, 0.325, 0) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
class LinkBarKey { |
||||
|
height: number |
||||
|
depth: number |
||||
|
|
||||
|
constructor(height: number, depth: number) { |
||||
|
this.height = height |
||||
|
this.depth = depth |
||||
|
} |
||||
|
|
||||
|
equals(other: LinkBarKey): boolean { |
||||
|
return this.height == other.height && this.depth == other.depth |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,5 @@ |
|||||
|
import BaseEntity from '@/core/base/BaseItemEntity.ts' |
||||
|
|
||||
|
export default class BracketEntity extends BaseEntity { |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
import BaseInteraction from '@/core/base/BaseInteraction.ts' |
||||
|
import * as THREE from 'three' |
||||
|
|
||||
|
export default class BracketInteraction 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.rackWidth = 3 // 宽度
|
||||
|
item.dt.rackDepth = 1 // 深度
|
||||
|
return item |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
import type { PropertySetter } from "@/core/base/PropertyTypes.ts"; |
||||
|
import { basicFieldsSetter } from "@/editor/widgets/property/PropertyPanelConstant.ts"; |
||||
|
|
||||
|
const propertySetter: PropertySetter = { |
||||
|
flatten: { |
||||
|
fields: [ |
||||
|
...basicFieldsSetter |
||||
|
] |
||||
|
}, |
||||
|
groups: [ |
||||
|
{ |
||||
|
title: '存储位置', expand: true, size: 'small', |
||||
|
fields: [ |
||||
|
{ |
||||
|
dataPath: 'dt.storeAt.item', label: '货架', input: 'Input', |
||||
|
inputProps: {} |
||||
|
}, |
||||
|
{ |
||||
|
dataPath: 'dt.storeAt.bay', label: '列', input: 'InputNumber', |
||||
|
inputProps: {} |
||||
|
}, |
||||
|
{ |
||||
|
dataPath: 'dt.storeAt.level', label: '层', input: 'InputNumber', |
||||
|
inputProps: {} |
||||
|
}, |
||||
|
{ |
||||
|
dataPath: 'dt.storeAt.cell', label: '格', input: 'InputNumber', |
||||
|
inputProps: {} |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
] |
||||
|
}; |
||||
|
|
||||
|
export default propertySetter; |
||||
@ -0,0 +1,128 @@ |
|||||
|
import * as THREE from 'three' |
||||
|
import BaseRenderer from '@/core/base/BaseRenderer.ts' |
||||
|
import { decimalSumBy } from '@/core/ModelUtils' |
||||
|
import Constract from '@/core/Constract.ts' |
||||
|
import type Viewport from '@/core/engine/Viewport.ts' |
||||
|
import Bracket3dObject from "@/modules/bracket/Bracket3dObject"; |
||||
|
|
||||
|
/** |
||||
|
* 货架货位渲染器 |
||||
|
*/ |
||||
|
export default class BracketRenderer extends BaseRenderer { |
||||
|
static POINT_NAME = 'bracket' |
||||
|
|
||||
|
pointMaterial: THREE.Material |
||||
|
|
||||
|
/** |
||||
|
* 默认点的高度, 防止和地面重合 |
||||
|
*/ |
||||
|
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 defaultLineWidth: number = 0.05 |
||||
|
|
||||
|
constructor(itemTypeName: string) { |
||||
|
super(itemTypeName) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 所有的点,必须使用 storeWidth/storeDepth, 改TF无效 |
||||
|
*/ |
||||
|
override afterCreateOrUpdatePoint(item: ItemJson, option: RendererCudOption, object: THREE.Object3D) { |
||||
|
super.afterCreateOrUpdatePoint(item, option, object) |
||||
|
|
||||
|
const point = object |
||||
|
point.position.y = this.defulePositionY |
||||
|
|
||||
|
//point.scale.set(_.sumBy(item.dt.bays, b=>b.bayWidth), this.defaultScale.y, item.dt.rackDepth)
|
||||
|
point.rotation.set( |
||||
|
THREE.MathUtils.degToRad(item.tf[1][0]), |
||||
|
THREE.MathUtils.degToRad(item.tf[1][1]), |
||||
|
THREE.MathUtils.degToRad(item.tf[1][2]) |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
createLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { |
||||
|
// throw new Error('not allow store line.')
|
||||
|
} |
||||
|
|
||||
|
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType) { |
||||
|
// throw new Error('not allow store line.')
|
||||
|
} |
||||
|
|
||||
|
updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { |
||||
|
// throw new Error('not allow store line.')
|
||||
|
} |
||||
|
|
||||
|
getStorePlacement(me: ItemJson, bay = 0, level = 0, cell = 0): { position: [number, number, number], rotation: [number, number, number] } { |
||||
|
// 将这个物品添加到库存中
|
||||
|
// const me = viewport.entityManager.findItemById(item.dt.storeAt.item)
|
||||
|
return { position: me.tf[0], rotation: me.tf[1] } |
||||
|
} |
||||
|
|
||||
|
updatePoint(item: ItemJson, group: THREE.Group, option?: RendererCudOption): THREE.Group { |
||||
|
group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2]) |
||||
|
group.rotation.set( |
||||
|
THREE.MathUtils.degToRad(item.tf[1][0]), |
||||
|
THREE.MathUtils.degToRad(item.tf[1][1]), |
||||
|
THREE.MathUtils.degToRad(item.tf[1][2]) |
||||
|
) |
||||
|
// group.scale 不允许修改!!
|
||||
|
// 禁止缩放,
|
||||
|
item.tf[2][0] = 0.85 |
||||
|
item.tf[2][1] = 0.35 |
||||
|
item.tf[2][3] = 0.85 |
||||
|
|
||||
|
|
||||
|
// 更新放在内部的所有箱子
|
||||
|
const subItems = this.tempViewport.runtimeManager.getItemsByRack(item.id) |
||||
|
const viewport = this.tempViewport |
||||
|
|
||||
|
if (subItems) { |
||||
|
_.defer(() => { |
||||
|
viewport.stateManager.update(({ getEntity, putEntity, deleteEntity, addEntity }) => { |
||||
|
for (const subItemId of subItems) { |
||||
|
const subItem = getEntity(subItemId) |
||||
|
if (subItem) { |
||||
|
const { position, rotation } = this.getStorePlacement(item, subItem.dt.storeAt.bay, subItem.dt.storeAt.level, subItem.dt.storeAt.cell) |
||||
|
if (position) { |
||||
|
subItem.tf[0][0] = position[0] |
||||
|
subItem.tf[0][1] = position[1] |
||||
|
subItem.tf[0][2] = position[2] |
||||
|
subItem.tf[1][0] = rotation[0] |
||||
|
subItem.tf[1][1] = rotation[1] |
||||
|
subItem.tf[1][2] = rotation[2] |
||||
|
putEntity(subItem) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
return group |
||||
|
} |
||||
|
|
||||
|
createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D { |
||||
|
// 创建几何体
|
||||
|
const group = new Bracket3dObject(item, option) |
||||
|
group.name = BracketRenderer.POINT_NAME |
||||
|
|
||||
|
// 设置位置
|
||||
|
group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2]) |
||||
|
|
||||
|
group.rotation.set( |
||||
|
THREE.MathUtils.degToRad(item.tf[1][0]), |
||||
|
THREE.MathUtils.degToRad(item.tf[1][1]), |
||||
|
THREE.MathUtils.degToRad(item.tf[1][2]) |
||||
|
) |
||||
|
|
||||
|
return group |
||||
|
} |
||||
|
|
||||
|
dispose() { |
||||
|
super.dispose() |
||||
|
this.pointMaterial?.dispose() |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
import { defineModule } from '@/core/manager/ModuleManager.ts' |
||||
|
import BracketRenderer from './BracketRenderer.ts' |
||||
|
import BracketInteraction from './BracketInteraction.ts' |
||||
|
import propertySetter from './BracketPropertySetter.ts' |
||||
|
import Bracket3dObject from "@/modules/bracket/Bracket3dObject"; |
||||
|
|
||||
|
export const ITEM_TYPE_NAME = 'bracket' |
||||
|
|
||||
|
export default defineModule(ITEM_TYPE_NAME, () => ({ |
||||
|
renderer: new BracketRenderer(ITEM_TYPE_NAME), |
||||
|
interaction: new BracketInteraction(ITEM_TYPE_NAME), |
||||
|
setter: propertySetter |
||||
|
})) |
||||
Loading…
Reference in new issue