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