5 changed files with 1286 additions and 559 deletions
@ -0,0 +1,484 @@ |
|||||
|
import * as THREE from 'three' |
||||
|
import {mergeGeometries} from 'three/addons/utils/BufferGeometryUtils.js' |
||||
|
import {BufferGeometry} 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 Rack3dObject extends THREE.Object3D { |
||||
|
|
||||
|
private rackVerticalBarWidth = 0.1 |
||||
|
private rackVerticalBarDepth = 0.08 |
||||
|
private static rackVerticalBarColor = 0xFF35499C |
||||
|
private static rackVerticalBarGeometryMap: Map<number, BufferGeometry> = new Map<number, BufferGeometry>() |
||||
|
private static rackVerticalBarMaterial: Material = null |
||||
|
|
||||
|
private static rackLinkBarColor = 0xFF35499C |
||||
|
private static rackLinkBarGeometryMap: Map<LinkBarKey, BufferGeometry> = new Map<LinkBarKey, BufferGeometry>() |
||||
|
private static rackLinkBarMaterial: Material = null |
||||
|
|
||||
|
private rackHorizontalBarWidth = 0.1 |
||||
|
private rackHorizontalBarDepth = 0.08 |
||||
|
private static rackHorizontalBarColor = 0xFFF97F27 |
||||
|
private static rackHorizontalBarGeometryMap: Map<number, BufferGeometry> = new Map<number, BufferGeometry>() |
||||
|
private static rackHorizontalBarMaterial: Material = null |
||||
|
|
||||
|
bottomBarHeight = 0.2 |
||||
|
bottomLinkHeight = 0.2 |
||||
|
topLinkDistance = 0.2 |
||||
|
|
||||
|
private static barSectionPoints = [ |
||||
|
{ x: -0.05, y: -0.05 }, |
||||
|
{ x: -0.025, y: -0.05 }, |
||||
|
{ x: -0.01, y: -0.045 }, |
||||
|
{ x: 0.01, y: -0.045 }, |
||||
|
{ x: 0.025, y: -0.05 }, |
||||
|
{ x: 0.05, y: -0.05 }, |
||||
|
{ x: 0.05, y: 0.042 }, |
||||
|
{ x: 0.042, y: 0.05 }, |
||||
|
{ x: 0.025, y: 0.05 }, |
||||
|
{ x: 0.025, y: 0.042 }, |
||||
|
{ x: 0.042, y: 0.042 }, |
||||
|
{ x: 0.042, y: -0.042 }, |
||||
|
{ x: -0.042, y: -0.042 }, |
||||
|
{ x: -0.042, y: 0.042 }, |
||||
|
{ x: -0.025, y: 0.042 }, |
||||
|
{ x: -0.025, y: 0.05 }, |
||||
|
{ x: -0.042, y: 0.05 }, |
||||
|
{ x: -0.05, y: 0.042 }, |
||||
|
{ x: -0.05, y: -0.05 } |
||||
|
] |
||||
|
|
||||
|
private static linkSectionPoints = [ |
||||
|
{ x: -0.05, y: -0.05 }, |
||||
|
{ x: -0.05, y: 0.05 }, |
||||
|
{ x: 0, y: 0.05 }, |
||||
|
{ x: 0, y: 0.06 }, |
||||
|
{ x: -0.06, y: 0.06 }, |
||||
|
{ x: -0.06, y: -0.05 }, |
||||
|
{ x: -0.05, y: -0.05 } |
||||
|
] |
||||
|
|
||||
|
private static linkBarSectionPoints = [ |
||||
|
{ x: -0.025, y: -0.025 }, |
||||
|
{ x: 0.025, y: -0.025 }, |
||||
|
{ x: 0.025, y: 0.025 }, |
||||
|
{ x: -0.025, y: 0.025 }, |
||||
|
{ x: -0.025, y: -0.025 } |
||||
|
] |
||||
|
|
||||
|
private createVerticalBar(length): THREE.BufferGeometry { |
||||
|
|
||||
|
// 创建一个形状 柱子的截面形状
|
||||
|
const shape = new THREE.Shape() |
||||
|
shape.moveTo(Rack3dObject.barSectionPoints[0].x, Rack3dObject.barSectionPoints[0].y) |
||||
|
for (let i = 1; i < Rack3dObject.barSectionPoints.length; i++) { |
||||
|
shape.lineTo(Rack3dObject.barSectionPoints[i].x, Rack3dObject.barSectionPoints[i].y) |
||||
|
} |
||||
|
|
||||
|
// 拉伸轨迹线
|
||||
|
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 createVerticalBarMaterial(): THREE.Material { |
||||
|
|
||||
|
let textureLoader = new THREE.TextureLoader() |
||||
|
|
||||
|
// 加载纹理
|
||||
|
const textureHole = textureLoader.load(storageBar_PNG) // 孔洞
|
||||
|
const textureMaterial = textureLoader.load(Plastic_Rough_JPG) // 表面材质
|
||||
|
|
||||
|
textureHole.repeat.set(10, 18) // X轴重复,Y轴重复
|
||||
|
textureMaterial.repeat.set(2, 2) // X轴重复,Y轴重复
|
||||
|
// textureHole.offset.set(0.5, 0)
|
||||
|
// textureHole.center.set(0.5, 0)
|
||||
|
|
||||
|
// 必须设置包裹模式为重复
|
||||
|
textureHole.wrapS = THREE.RepeatWrapping |
||||
|
textureHole.wrapT = THREE.RepeatWrapping |
||||
|
textureMaterial.wrapS = THREE.RepeatWrapping |
||||
|
textureMaterial.wrapT = THREE.RepeatWrapping |
||||
|
|
||||
|
const material = new THREE.MeshPhongMaterial() |
||||
|
material.alphaMap = textureHole |
||||
|
material.normalMap = textureMaterial |
||||
|
material.color.setHex(Rack3dObject.rackVerticalBarColor, 'srgb') |
||||
|
material.specular.setHex(0xff6d6d6d, 'srgb') |
||||
|
material.transparent = true |
||||
|
material.needsUpdate = true |
||||
|
|
||||
|
return material |
||||
|
} |
||||
|
|
||||
|
private createLinkBar(height: number, depth: number): THREE.BufferGeometry { |
||||
|
|
||||
|
const bgs: BufferGeometry[] = [] |
||||
|
// 创建一个形状 柱子的截面形状
|
||||
|
const shape = new THREE.Shape() |
||||
|
shape.moveTo(Rack3dObject.linkBarSectionPoints[0].x, Rack3dObject.linkBarSectionPoints[0].y) |
||||
|
for (let i = 1; i < Rack3dObject.linkBarSectionPoints.length; i++) { |
||||
|
shape.lineTo(Rack3dObject.linkBarSectionPoints[i].x, Rack3dObject.linkBarSectionPoints[i].y) |
||||
|
} |
||||
|
|
||||
|
// 拉伸轨迹线 横向 底部
|
||||
|
const curveHBottom = new THREE.CatmullRomCurve3( |
||||
|
[new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, depth)], |
||||
|
false, // 闭合曲线
|
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
// 挤出几何图形 参数
|
||||
|
const optionsHBottom = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: curveHBottom // 设置挤出轨迹
|
||||
|
} |
||||
|
|
||||
|
// 拉伸轨迹线 横向 底部
|
||||
|
const curveHTop = new THREE.CatmullRomCurve3( |
||||
|
[new THREE.Vector3(0, height, 0), new THREE.Vector3(0, height, depth)], |
||||
|
false, // 闭合曲线
|
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
// 挤出几何图形 参数
|
||||
|
const optionsHTop = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: curveHTop // 设置挤出轨迹
|
||||
|
} |
||||
|
|
||||
|
// 创建挤出几何体
|
||||
|
const geometryHBottom = new THREE.ExtrudeGeometry(shape, optionsHBottom) |
||||
|
const geometryHTop = new THREE.ExtrudeGeometry(shape, optionsHTop) |
||||
|
bgs.push(geometryHBottom, geometryHTop) |
||||
|
|
||||
|
// 需要创建斜杆
|
||||
|
|
||||
|
for (let i = 0; i < Math.floor(height / depth); i++) { |
||||
|
// 拉伸轨迹线 斜向
|
||||
|
const curveD = new THREE.CatmullRomCurve3( |
||||
|
(i % 2 == 0) ? [new THREE.Vector3(0, depth * i, 0), new THREE.Vector3(0, depth * (i + 1), depth)] |
||||
|
: [new THREE.Vector3(0, depth * (i + 1), 0), new THREE.Vector3(0, depth * (i), depth)], |
||||
|
false, // 闭合曲线
|
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
const optionsD = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: curveD // 设置挤出轨迹
|
||||
|
} |
||||
|
|
||||
|
const geometryD = new THREE.ExtrudeGeometry(shape, optionsD) |
||||
|
bgs.push(geometryD) |
||||
|
} |
||||
|
|
||||
|
if (height > depth) { |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
// 调整uv方便正确贴图
|
||||
|
// resetUVs(geometry);
|
||||
|
return mergeGeometries(bgs) |
||||
|
} |
||||
|
|
||||
|
private createLinkBarMaterial(): THREE.Material { |
||||
|
|
||||
|
const material = new THREE.MeshPhongMaterial() |
||||
|
material.color.setHex(Rack3dObject.rackLinkBarColor, 'srgb') |
||||
|
material.specular.setHex(0xff6d6d6d, 'srgb') |
||||
|
material.transparent = true |
||||
|
material.needsUpdate = true |
||||
|
|
||||
|
return material |
||||
|
} |
||||
|
|
||||
|
private createHorizontalBar(length): THREE.BufferGeometry { |
||||
|
|
||||
|
// 创建一个形状 柱子的截面形状
|
||||
|
const shape = new THREE.Shape() |
||||
|
shape.moveTo(Rack3dObject.barSectionPoints[0].x, Rack3dObject.barSectionPoints[0].y) |
||||
|
for (let i = 1; i < Rack3dObject.barSectionPoints.length; i++) { |
||||
|
shape.lineTo(Rack3dObject.barSectionPoints[i].x, Rack3dObject.barSectionPoints[i].y) |
||||
|
} |
||||
|
|
||||
|
// 拉伸轨迹线
|
||||
|
const curve = new THREE.CatmullRomCurve3( |
||||
|
[new THREE.Vector3(0.05, 0, 0), new THREE.Vector3(length - 0.05, 0, 0)], |
||||
|
false, // 闭合曲线
|
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
// 挤出几何图形 参数
|
||||
|
const options = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: curve // 设置挤出轨迹
|
||||
|
} |
||||
|
// 创建挤出几何体
|
||||
|
const geometry = new THREE.ExtrudeGeometry(shape, options) |
||||
|
|
||||
|
const linkShapeL = new THREE.Shape() |
||||
|
const linkShapeR = new THREE.Shape() |
||||
|
linkShapeL.moveTo(Rack3dObject.linkSectionPoints[0].x, Rack3dObject.linkSectionPoints[0].y) |
||||
|
linkShapeR.moveTo(Rack3dObject.linkSectionPoints[0].x + (length), Rack3dObject.linkSectionPoints[0].y) |
||||
|
for (let i = 1; i < Rack3dObject.linkSectionPoints.length; i++) { |
||||
|
linkShapeL.lineTo(Rack3dObject.linkSectionPoints[i].x, Rack3dObject.linkSectionPoints[i].y) |
||||
|
linkShapeR.lineTo(Rack3dObject.linkSectionPoints[i].x + (length), Rack3dObject.linkSectionPoints[i].y) |
||||
|
} |
||||
|
|
||||
|
// 拉伸轨迹线
|
||||
|
const linkCurve = new THREE.CatmullRomCurve3( |
||||
|
[new THREE.Vector3(0, 0, -0.08), new THREE.Vector3(0, 0, 0.08)], |
||||
|
false, // 闭合曲线
|
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
// 挤出几何图形 参数
|
||||
|
const linkOptions = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: linkCurve // 设置挤出轨迹
|
||||
|
} |
||||
|
// 创建挤出几何体
|
||||
|
const linkGeometryL = new THREE.ExtrudeGeometry(linkShapeL, linkOptions) |
||||
|
linkGeometryL.rotateZ(-Math.PI / 2) |
||||
|
const linkGeometryR = new THREE.ExtrudeGeometry(linkShapeR, linkOptions) |
||||
|
linkGeometryR.rotateX(-Math.PI) |
||||
|
linkGeometryR.rotateZ(-Math.PI / 2) |
||||
|
|
||||
|
// 调整uv方便正确贴图
|
||||
|
// resetUVs(geometry);
|
||||
|
return mergeGeometries([geometry, linkGeometryL, linkGeometryR]) |
||||
|
} |
||||
|
|
||||
|
private createHorizontalBarMaterial(): THREE.Material { |
||||
|
|
||||
|
const material = new THREE.MeshPhongMaterial() |
||||
|
material.color.setHex(Rack3dObject.rackHorizontalBarColor, 'srgb') |
||||
|
material.specular.setHex(0xff6d6d6d, 'srgb') |
||||
|
material.transparent = true |
||||
|
material.needsUpdate = true |
||||
|
|
||||
|
return material |
||||
|
} |
||||
|
|
||||
|
constructor(item: ItemJson, option?: RendererCudOption) { |
||||
|
super(); |
||||
|
|
||||
|
const rackWidth = decimalSumBy(item.dt.bays, (b: any) => b.bayWidth) |
||||
|
const rackDepth = item.dt.rackDepth |
||||
|
const heights = [] |
||||
|
for (let i = 0; i < item.dt.bays.length; i++) { |
||||
|
const bay = item.dt.bays[i] |
||||
|
const bayHeight = decimalSumBy(bay.levelHeight) |
||||
|
heights.push(bayHeight) |
||||
|
} |
||||
|
const rackHeight = _.max(heights) |
||||
|
|
||||
|
// 计算立住坐标点和长度
|
||||
|
const vBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = [] |
||||
|
|
||||
|
// 计算
|
||||
|
const linkBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = [] |
||||
|
|
||||
|
let distanceX = 0, distanceY = 0 |
||||
|
|
||||
|
for (let i = -1; i < item.dt.bays.length; i++) { |
||||
|
if (i >= 0) { |
||||
|
const bay = item.dt.bays[i] |
||||
|
distanceX += bay.bayWidth |
||||
|
} |
||||
|
vBarMatrix.push({ |
||||
|
x: distanceX - rackWidth / 2, |
||||
|
y: 0, |
||||
|
z: -rackDepth / 2, |
||||
|
sx: 0.8, |
||||
|
sy: 1, |
||||
|
sz: 1, |
||||
|
rx: 0, |
||||
|
ry: Math.PI / 2, |
||||
|
rz: 0, |
||||
|
l: rackHeight |
||||
|
}) |
||||
|
vBarMatrix.push({ |
||||
|
x: distanceX - rackWidth / 2, |
||||
|
y: 0, |
||||
|
z: item.dt.rackDepth - rackDepth / 2, |
||||
|
sx: 0.8, |
||||
|
sy: 1, |
||||
|
sz: 1, |
||||
|
rx: 0, |
||||
|
ry: -Math.PI / 2, |
||||
|
rz: 0, |
||||
|
l: rackHeight |
||||
|
}) |
||||
|
linkBarMatrix.push({ |
||||
|
x: distanceX - rackWidth / 2, |
||||
|
y: this.bottomLinkHeight, |
||||
|
z: i % 2 == 0 ? (item.dt.rackDepth - rackDepth / 2) : -rackDepth / 2, |
||||
|
sx: 1, |
||||
|
sy: 1, |
||||
|
sz: 1, |
||||
|
rx: 0, |
||||
|
ry: i % 2 == 0 ? Math.PI : 0, |
||||
|
rz: 0, |
||||
|
l: rackHeight |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 计算横梁数量
|
||||
|
const hBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = [] |
||||
|
distanceX = 0 |
||||
|
for (let i = 0; i < item.dt.bays.length; i++) { |
||||
|
distanceY = this.bottomBarHeight |
||||
|
const bay = item.dt.bays[i] |
||||
|
for (let j = 0; j < bay.levelHeight.length; j++) { |
||||
|
const levelHeight = bay.levelHeight[j] |
||||
|
if (distanceY <= 0) { |
||||
|
continue |
||||
|
} |
||||
|
hBarMatrix.push({ |
||||
|
x: distanceX - rackWidth / 2, |
||||
|
y: distanceY, |
||||
|
z: -rackDepth / 2, |
||||
|
sx: 1, |
||||
|
sy: 0.8, |
||||
|
sz: 1, |
||||
|
rx: Math.PI / 2, |
||||
|
ry: 0, |
||||
|
rz: 0, |
||||
|
l: bay.bayWidth |
||||
|
}) |
||||
|
hBarMatrix.push({ |
||||
|
x: distanceX - rackWidth / 2, |
||||
|
y: distanceY, |
||||
|
z: item.dt.rackDepth - rackDepth / 2, |
||||
|
sx: 1, |
||||
|
sy: 0.8, |
||||
|
sz: 1, |
||||
|
rx: -Math.PI / 2, |
||||
|
ry: 0, |
||||
|
rz: 0, |
||||
|
l: bay.bayWidth |
||||
|
}) |
||||
|
distanceY += levelHeight |
||||
|
} |
||||
|
distanceX += bay.bayWidth |
||||
|
} |
||||
|
|
||||
|
const meshes: InstancedMesh[] = [] |
||||
|
|
||||
|
if (vBarMatrix.length > 0) { |
||||
|
if (!Rack3dObject.rackVerticalBarGeometryMap.get(vBarMatrix[0].l)) { |
||||
|
Rack3dObject.rackVerticalBarGeometryMap.set(vBarMatrix[0].l, this.createVerticalBar(vBarMatrix[0].l)) |
||||
|
} |
||||
|
if (!Rack3dObject.rackVerticalBarMaterial) { |
||||
|
Rack3dObject.rackVerticalBarMaterial = this.createVerticalBarMaterial() |
||||
|
} |
||||
|
const rackVerticalBarGeometry = Rack3dObject.rackVerticalBarGeometryMap.get(vBarMatrix[0].l) |
||||
|
const rackVerticalBarMaterial = Rack3dObject.rackVerticalBarMaterial |
||||
|
const dummy = new THREE.Object3D() |
||||
|
const vBarMesh = new THREE.InstancedMesh(rackVerticalBarGeometry, rackVerticalBarMaterial, vBarMatrix.length) |
||||
|
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) |
||||
|
} |
||||
|
|
||||
|
if (linkBarMatrix.length > 0) { |
||||
|
const linkBarKey: LinkBarKey = new LinkBarKey(rackHeight - this.bottomLinkHeight - this.topLinkDistance, item.dt.rackDepth) |
||||
|
if (!Rack3dObject.rackLinkBarGeometryMap.get(linkBarKey)) { |
||||
|
Rack3dObject.rackLinkBarGeometryMap.set(linkBarKey, this.createLinkBar(linkBarKey.height, linkBarKey.depth)) |
||||
|
} |
||||
|
const rackLinkBarGeometry = Rack3dObject.rackLinkBarGeometryMap.get(linkBarKey) |
||||
|
if (!Rack3dObject.rackLinkBarMaterial) { |
||||
|
Rack3dObject.rackLinkBarMaterial = this.createLinkBarMaterial() |
||||
|
} |
||||
|
const rackLinkBarMaterial = Rack3dObject.rackLinkBarMaterial |
||||
|
const dummy = new THREE.Object3D() |
||||
|
const linkBarMesh = new THREE.InstancedMesh(rackLinkBarGeometry, rackLinkBarMaterial, linkBarMatrix.length) |
||||
|
for (let i = 0; i < linkBarMatrix.length; i++) { |
||||
|
const lp = linkBarMatrix[i] |
||||
|
dummy.position.set(lp.x, lp.y, lp.z) |
||||
|
dummy.rotation.set(lp.rx, lp.ry, lp.rz) |
||||
|
dummy.scale.set(lp.sx, lp.sy, lp.sz) |
||||
|
dummy.updateMatrix() |
||||
|
linkBarMesh.setMatrixAt(i, dummy.matrix) |
||||
|
} |
||||
|
meshes.push(linkBarMesh) |
||||
|
} |
||||
|
|
||||
|
if (hBarMatrix.length > 0) { |
||||
|
if (!Rack3dObject.rackHorizontalBarGeometryMap.get(hBarMatrix[0].l)) { |
||||
|
Rack3dObject.rackHorizontalBarGeometryMap.set(hBarMatrix[0].l, this.createHorizontalBar(hBarMatrix[0].l)) |
||||
|
} |
||||
|
const rackHorizontalBarGeometry = Rack3dObject.rackHorizontalBarGeometryMap.get(hBarMatrix[0].l) |
||||
|
if (!Rack3dObject.rackHorizontalBarMaterial) { |
||||
|
Rack3dObject.rackHorizontalBarMaterial = this.createHorizontalBarMaterial() |
||||
|
} |
||||
|
const rackHorizontalBarMaterial = Rack3dObject.rackHorizontalBarMaterial |
||||
|
const dummy = new THREE.Object3D() |
||||
|
const hBarMesh = new THREE.InstancedMesh(rackHorizontalBarGeometry, rackHorizontalBarMaterial, hBarMatrix.length) |
||||
|
for (let i = 0; i < hBarMatrix.length; i++) { |
||||
|
const hp = hBarMatrix[i] |
||||
|
dummy.position.set(hp.x, hp.y, hp.z) |
||||
|
dummy.rotation.set(hp.rx, hp.ry, hp.rz) |
||||
|
dummy.scale.set(hp.sx, hp.sy, hp.sz) |
||||
|
dummy.updateMatrix() |
||||
|
hBarMesh.setMatrixAt(i, dummy.matrix) |
||||
|
} |
||||
|
meshes.push(hBarMesh) |
||||
|
} |
||||
|
|
||||
|
meshes.forEach(mesh => { |
||||
|
this.add(mesh) |
||||
|
mesh.instanceMatrix.needsUpdate = true |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
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,760 @@ |
|||||
|
import * as THREE from 'three' |
||||
|
import { BufferGeometry } from 'three' |
||||
|
import BaseRenderer from '@/core/base/BaseRenderer.ts' |
||||
|
import { decimalSumBy } from '@/core/ModelUtils' |
||||
|
import Constract from '@/core/Constract.ts' |
||||
|
import Plastic_Rough_JPG from '@/assets/Models/Plastic_Rough.jpg?inline' |
||||
|
import storageBar_PNG from '@/assets/Models/storageBar.png?inline' |
||||
|
import { Material } from 'three/src/materials/Material' |
||||
|
import { InstancedMesh } from 'three/src/objects/InstancedMesh' |
||||
|
//@ts-ignore |
||||
|
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js' |
||||
|
import type Viewport from '@/core/engine/Viewport.ts' |
||||
|
import type { Object3DLike } from '@/types/ModelTypes.ts' |
||||
|
|
||||
|
/** |
||||
|
* 货架货位渲染器 |
||||
|
*/ |
||||
|
export default class RackRenderer extends BaseRenderer { |
||||
|
static POINT_NAME = 'rack' |
||||
|
|
||||
|
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]) |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D { |
||||
|
throw new Error('not allow store line.') |
||||
|
} |
||||
|
|
||||
|
updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { |
||||
|
throw new Error('not allow store line.') |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取物品存放在货架后的位置和旋转角度 |
||||
|
* item.dt.storeAt 必须存在, 比如 { item:'货架ID', bay:0, level:1, cell:0 } |
||||
|
*/ |
||||
|
getStorePlacement(viewport: Viewport, item: ItemJson): { position: [number, number, number], rotation: [number, number, number] } { |
||||
|
if (!item.dt?.storeAt?.item) { |
||||
|
// 没有定义存储位置,返回空对象 |
||||
|
//@ts-ignore |
||||
|
return {} |
||||
|
} |
||||
|
|
||||
|
const bay = item.dt?.storeAt?.bay || 0 |
||||
|
const level = item.dt?.storeAt?.level || 0 |
||||
|
// 暂时不用算格子 const cell = item.dt?.storeAt?.cell || 0 |
||||
|
|
||||
|
// 目标货架 |
||||
|
const rack = viewport.stateManager.findItemById(item.dt.storeAt.item) |
||||
|
const rackWidth = decimalSumBy(rack.dt.bays, (b: any) => b.bayWidth) |
||||
|
const bays = rack.dt.bays |
||||
|
const levelHeights = rack.dt.bays[bay]?.levelHeight |
||||
|
|
||||
|
// 局部坐标系下的偏移量 |
||||
|
let localX = 0 |
||||
|
for (let i = 0; i < bay; i++) { |
||||
|
localX += bays[i]?.bayWidth || 0 |
||||
|
} |
||||
|
localX += bays[bay].bayWidth / 2 // 居中 |
||||
|
|
||||
|
let localY = 0 |
||||
|
for (let i = 0; i < level; i++) { |
||||
|
localY += levelHeights[i] |
||||
|
} |
||||
|
|
||||
|
// 构建局部偏移向量 |
||||
|
const rackPos = new THREE.Vector3(...rack.tf[0]) |
||||
|
const offset = new THREE.Vector3( |
||||
|
localX - rackWidth / 2, // 相对坐标从最左边开始, |
||||
|
localY, 0) |
||||
|
|
||||
|
// 应用货架的旋转 |
||||
|
const q = new THREE.Quaternion() |
||||
|
q.setFromEuler(new THREE.Euler( |
||||
|
THREE.MathUtils.degToRad(rack.tf[1][0]), |
||||
|
THREE.MathUtils.degToRad(rack.tf[1][1]), |
||||
|
THREE.MathUtils.degToRad(rack.tf[1][2]) |
||||
|
)) |
||||
|
|
||||
|
offset.applyQuaternion(q) |
||||
|
const worldPosition = rackPos.clone().add(offset) |
||||
|
|
||||
|
return { |
||||
|
position: [ |
||||
|
worldPosition.x, |
||||
|
worldPosition.y + this.bottomBarHeight + 0.1, // 加上横梁高度 |
||||
|
worldPosition.z |
||||
|
], |
||||
|
rotation: [ |
||||
|
// 托盘旋转90度才能放进货架 |
||||
|
rack.tf[1][0], |
||||
|
rack.tf[1][1] + 90, |
||||
|
rack.tf[1][2] |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
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] = item.dt.rackWidth |
||||
|
item.tf[2][1] = item.dt.rackHeight |
||||
|
|
||||
|
|
||||
|
// 更新放在内部的所有箱子 |
||||
|
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(viewport, subItem) |
||||
|
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 { |
||||
|
// 创建平面几何体 |
||||
|
if (!item.dt.bays || !item.dt.rackDepth) { |
||||
|
system.showErrorDialog('RackRenderer field bays / rackDepth is null!') |
||||
|
return null |
||||
|
} |
||||
|
|
||||
|
const group = new THREE.Group() |
||||
|
group.name = RackRenderer.POINT_NAME |
||||
|
|
||||
|
const rackWidth = decimalSumBy(item.dt.bays, (b: any) => b.bayWidth) |
||||
|
const heights = [] |
||||
|
for (let i = 0; i < item.dt.bays.length; i++) { |
||||
|
const bay = item.dt.bays[i] |
||||
|
const bayHeight = decimalSumBy(bay.levelHeight) |
||||
|
heights.push(bayHeight) |
||||
|
} |
||||
|
const rackHeight = _.max(heights) |
||||
|
// // 绘制背景矩形框 |
||||
|
// const planeGeometry = new THREE.PlaneGeometry(rackWidth, item.dt.rackDepth) |
||||
|
// |
||||
|
// planeGeometry.rotateX(Math.PI / 2) |
||||
|
// |
||||
|
// const planeMaterial = new THREE.MeshBasicMaterial({ |
||||
|
// color: '#9a9090', |
||||
|
// transparent: true, // 启用透明 |
||||
|
// opacity: 0.5, // 50%透明度 |
||||
|
// depthWrite: false, // 防止深度冲突 |
||||
|
// side: THREE.DoubleSide // 双面渲染:ml-citation{ref="5,8" data="citationList"} |
||||
|
// }) |
||||
|
// const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial) |
||||
|
// group.add(planeMesh) |
||||
|
// |
||||
|
// |
||||
|
// // 绘制边框 |
||||
|
// const lineXLen = rackWidth - this.defaultLineWidth |
||||
|
// const lineYLen = item.dt.rackDepth - this.defaultLineWidth |
||||
|
// |
||||
|
// const lineGeometry = new LineGeometry().setPositions([ |
||||
|
// -(lineXLen / 2), 0, -(lineYLen / 2), |
||||
|
// lineXLen / 2, 0, -(lineYLen / 2), |
||||
|
// lineXLen / 2, 0, lineYLen / 2, |
||||
|
// -(lineXLen / 2), 0, lineYLen / 2, |
||||
|
// -(lineXLen / 2), 0, -(lineYLen / 2) |
||||
|
// ]) |
||||
|
// const lineMaterial = new LineMaterial({ |
||||
|
// color: '#0d89a5', |
||||
|
// linewidth: this.defaultLineWidth, |
||||
|
// worldUnits: true, |
||||
|
// resolution: new THREE.Vector2(window.innerWidth, window.innerHeight), |
||||
|
// side: THREE.DoubleSide |
||||
|
// }) |
||||
|
// const line = new Line2(lineGeometry, lineMaterial) |
||||
|
// group.add(line as THREE.Object3D) |
||||
|
// |
||||
|
// let lineDistanceX = 0 |
||||
|
// |
||||
|
// for (let i = 0; item.dt.bays.length > 1 && i < item.dt.bays.length - 1; i++) { |
||||
|
// const bay = item.dt.bays[i] |
||||
|
// lineDistanceX += bay.bayWidth |
||||
|
// const lineGeometryT = new LineGeometry().setPositions([ |
||||
|
// -(lineDistanceX) + (lineXLen / 2), 0, lineYLen / 2, |
||||
|
// -(lineDistanceX) + (lineXLen / 2), 0, -(lineYLen / 2) |
||||
|
// ]) |
||||
|
// const lineT = new Line2(lineGeometryT, lineMaterial) |
||||
|
// group.add(lineT as THREE.Object3D) |
||||
|
// } |
||||
|
|
||||
|
const meshes = this.createRack(item, option) |
||||
|
|
||||
|
meshes.forEach(mesh => { |
||||
|
group.add(mesh) |
||||
|
mesh.instanceMatrix.needsUpdate = true |
||||
|
}) |
||||
|
|
||||
|
// 设置位置 |
||||
|
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]) |
||||
|
) |
||||
|
|
||||
|
item.dt.rackWidth = rackWidth |
||||
|
item.dt.rackHeight = rackHeight |
||||
|
|
||||
|
item.tf[2][0] = item.dt.rackWidth |
||||
|
item.tf[2][1] = item.dt.rackHeight |
||||
|
|
||||
|
return group |
||||
|
} |
||||
|
|
||||
|
dispose() { |
||||
|
super.dispose() |
||||
|
this.pointMaterial?.dispose() |
||||
|
} |
||||
|
|
||||
|
rackVerticalBarWidth = 0.1 |
||||
|
rackVerticalBarDepth = 0.08 |
||||
|
rackVerticalBarColor = 0xFF35499C |
||||
|
rackVerticalBarGeometry: BufferGeometry = null |
||||
|
rackVerticalBarMaterial: Material = null |
||||
|
|
||||
|
rackLinkBarColor = 0xFF35499C |
||||
|
rackLinkBarGeometry: BufferGeometry = null |
||||
|
rackLinkBarMaterial: Material = null |
||||
|
|
||||
|
rackHorizontalBarWidth = 0.1 |
||||
|
rackHorizontalBarDepth = 0.08 |
||||
|
rackHorizontalBarColor = 0xFFF97F27 |
||||
|
rackHorizontalBarGeometry: BufferGeometry = null |
||||
|
rackHorizontalBarMaterial: Material = null |
||||
|
|
||||
|
bottomBarHeight = 0.2 |
||||
|
bottomLinkHeight = 0.2 |
||||
|
|
||||
|
barSectionPoints = [ |
||||
|
{ x: -0.05, y: -0.05 }, |
||||
|
{ x: -0.025, y: -0.05 }, |
||||
|
{ x: -0.01, y: -0.045 }, |
||||
|
{ x: 0.01, y: -0.045 }, |
||||
|
{ x: 0.025, y: -0.05 }, |
||||
|
{ x: 0.05, y: -0.05 }, |
||||
|
{ x: 0.05, y: 0.042 }, |
||||
|
{ x: 0.042, y: 0.05 }, |
||||
|
{ x: 0.025, y: 0.05 }, |
||||
|
{ x: 0.025, y: 0.042 }, |
||||
|
{ x: 0.042, y: 0.042 }, |
||||
|
{ x: 0.042, y: -0.042 }, |
||||
|
{ x: -0.042, y: -0.042 }, |
||||
|
{ x: -0.042, y: 0.042 }, |
||||
|
{ x: -0.025, y: 0.042 }, |
||||
|
{ x: -0.025, y: 0.05 }, |
||||
|
{ x: -0.042, y: 0.05 }, |
||||
|
{ x: -0.05, y: 0.042 }, |
||||
|
{ x: -0.05, y: -0.05 } |
||||
|
] |
||||
|
|
||||
|
linkSectionPoints = [ |
||||
|
{ x: -0.05, y: -0.05 }, |
||||
|
{ x: -0.05, y: 0.05 }, |
||||
|
{ x: 0, y: 0.05 }, |
||||
|
{ x: 0, y: 0.06 }, |
||||
|
{ x: -0.06, y: 0.06 }, |
||||
|
{ x: -0.06, y: -0.05 }, |
||||
|
{ x: -0.05, y: -0.05 } |
||||
|
] |
||||
|
|
||||
|
linkBarSectionPoints = [ |
||||
|
{ x: -0.025, y: -0.025 }, |
||||
|
{ x: 0.025, y: -0.025 }, |
||||
|
{ x: 0.025, y: 0.025 }, |
||||
|
{ x: -0.025, y: 0.025 }, |
||||
|
{ x: -0.025, y: -0.025 } |
||||
|
] |
||||
|
|
||||
|
createVerticalBar(x, y, z, length): THREE.BufferGeometry { |
||||
|
|
||||
|
// 创建一个形状 柱子的截面形状 |
||||
|
const shape = new THREE.Shape() |
||||
|
shape.moveTo(this.barSectionPoints[0].x, this.barSectionPoints[0].y) |
||||
|
for (let i = 1; i < this.barSectionPoints.length; i++) { |
||||
|
shape.lineTo(this.barSectionPoints[i].x, this.barSectionPoints[i].y) |
||||
|
} |
||||
|
|
||||
|
// 拉伸轨迹线 |
||||
|
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方便正确贴图 |
||||
|
this.resetUVs(geometry) |
||||
|
return geometry |
||||
|
} |
||||
|
|
||||
|
createVerticalBarMaterial(): THREE.Material { |
||||
|
|
||||
|
let textureLoader = new THREE.TextureLoader() |
||||
|
|
||||
|
// 加载纹理 |
||||
|
const textureHole = textureLoader.load(storageBar_PNG) // 孔洞 |
||||
|
const textureMaterial = textureLoader.load(Plastic_Rough_JPG) // 表面材质 |
||||
|
|
||||
|
textureHole.repeat.set(10, 18) // X轴重复,Y轴重复 |
||||
|
textureMaterial.repeat.set(2, 2) // X轴重复,Y轴重复 |
||||
|
// textureHole.offset.set(0.5, 0) |
||||
|
// textureHole.center.set(0.5, 0) |
||||
|
|
||||
|
// 必须设置包裹模式为重复 |
||||
|
textureHole.wrapS = THREE.RepeatWrapping |
||||
|
textureHole.wrapT = THREE.RepeatWrapping |
||||
|
textureMaterial.wrapS = THREE.RepeatWrapping |
||||
|
textureMaterial.wrapT = THREE.RepeatWrapping |
||||
|
|
||||
|
const material = new THREE.MeshPhongMaterial() |
||||
|
material.alphaMap = textureHole |
||||
|
material.normalMap = textureMaterial |
||||
|
material.color.setHex(this.rackVerticalBarColor, 'srgb') |
||||
|
material.specular.setHex(0xff6d6d6d, 'srgb') |
||||
|
material.transparent = true |
||||
|
material.needsUpdate = true |
||||
|
|
||||
|
return material |
||||
|
} |
||||
|
|
||||
|
createLinkBar(x, y, z, vBarLength, depth, bottomDistance, topDistance): THREE.BufferGeometry { |
||||
|
|
||||
|
const bgs: BufferGeometry[] = [] |
||||
|
const top = vBarLength - topDistance |
||||
|
// 创建一个形状 柱子的截面形状 |
||||
|
const shape = new THREE.Shape() |
||||
|
shape.moveTo(this.linkBarSectionPoints[0].x, this.linkBarSectionPoints[0].y) |
||||
|
for (let i = 1; i < this.linkBarSectionPoints.length; i++) { |
||||
|
shape.lineTo(this.linkBarSectionPoints[i].x, this.linkBarSectionPoints[i].y) |
||||
|
} |
||||
|
|
||||
|
// 拉伸轨迹线 横向 底部 |
||||
|
const curveHBottom = new THREE.CatmullRomCurve3( |
||||
|
[new THREE.Vector3(0, bottomDistance, 0), new THREE.Vector3(0, bottomDistance, depth)], |
||||
|
false, // 闭合曲线 |
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
// 挤出几何图形 参数 |
||||
|
const optionsHBottom = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: curveHBottom // 设置挤出轨迹 |
||||
|
} |
||||
|
|
||||
|
// 拉伸轨迹线 横向 底部 |
||||
|
const curveHTop = new THREE.CatmullRomCurve3( |
||||
|
[new THREE.Vector3(0, top, 0), new THREE.Vector3(0, top, depth)], |
||||
|
false, // 闭合曲线 |
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
// 挤出几何图形 参数 |
||||
|
const optionsHTop = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: curveHTop // 设置挤出轨迹 |
||||
|
} |
||||
|
|
||||
|
// 创建挤出几何体 |
||||
|
const geometryHBottom = new THREE.ExtrudeGeometry(shape, optionsHBottom) |
||||
|
const geometryHTop = new THREE.ExtrudeGeometry(shape, optionsHTop) |
||||
|
bgs.push(geometryHBottom, geometryHTop) |
||||
|
|
||||
|
let remainingHeight = vBarLength - bottomDistance - topDistance |
||||
|
|
||||
|
// 需要创建斜杆 |
||||
|
|
||||
|
for (let i = 0; i < Math.floor(remainingHeight / depth); i++) { |
||||
|
// 拉伸轨迹线 斜向 |
||||
|
const curveD = new THREE.CatmullRomCurve3( |
||||
|
(i % 2 == 0) ? [new THREE.Vector3(0, bottomDistance + depth * i, 0), new THREE.Vector3(0, bottomDistance + depth * (i + 1), depth)] |
||||
|
: [new THREE.Vector3(0, bottomDistance + depth * (i + 1), 0), new THREE.Vector3(0, bottomDistance + depth * (i), depth)], |
||||
|
false, // 闭合曲线 |
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
const optionsD = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: curveD // 设置挤出轨迹 |
||||
|
} |
||||
|
|
||||
|
const geometryD = new THREE.ExtrudeGeometry(shape, optionsD) |
||||
|
bgs.push(geometryD) |
||||
|
} |
||||
|
|
||||
|
if (vBarLength - bottomDistance - topDistance > depth) { |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
// 调整uv方便正确贴图 |
||||
|
// this.resetUVs(geometry); |
||||
|
return mergeGeometries(bgs) |
||||
|
} |
||||
|
|
||||
|
createLinkBarMaterial(): THREE.Material { |
||||
|
|
||||
|
const material = new THREE.MeshPhongMaterial() |
||||
|
material.color.setHex(this.rackLinkBarColor, 'srgb') |
||||
|
material.specular.setHex(0xff6d6d6d, 'srgb') |
||||
|
material.transparent = true |
||||
|
material.needsUpdate = true |
||||
|
|
||||
|
return material |
||||
|
} |
||||
|
|
||||
|
createHorizontalBar(x, y, z, length): THREE.BufferGeometry { |
||||
|
|
||||
|
// 创建一个形状 柱子的截面形状 |
||||
|
const shape = new THREE.Shape() |
||||
|
shape.moveTo(this.barSectionPoints[0].x, this.barSectionPoints[0].y) |
||||
|
for (let i = 1; i < this.barSectionPoints.length; i++) { |
||||
|
shape.lineTo(this.barSectionPoints[i].x, this.barSectionPoints[i].y) |
||||
|
} |
||||
|
|
||||
|
// 拉伸轨迹线 |
||||
|
const curve = new THREE.CatmullRomCurve3( |
||||
|
[new THREE.Vector3(0.05, 0, 0), new THREE.Vector3(length - 0.05, 0, 0)], |
||||
|
false, // 闭合曲线 |
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
// 挤出几何图形 参数 |
||||
|
const options = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: curve // 设置挤出轨迹 |
||||
|
} |
||||
|
// 创建挤出几何体 |
||||
|
const geometry = new THREE.ExtrudeGeometry(shape, options) |
||||
|
|
||||
|
const linkShapeL = new THREE.Shape() |
||||
|
const linkShapeR = new THREE.Shape() |
||||
|
linkShapeL.moveTo(this.linkSectionPoints[0].x, this.linkSectionPoints[0].y) |
||||
|
linkShapeR.moveTo(this.linkSectionPoints[0].x + (length), this.linkSectionPoints[0].y) |
||||
|
for (let i = 1; i < this.linkSectionPoints.length; i++) { |
||||
|
linkShapeL.lineTo(this.linkSectionPoints[i].x, this.linkSectionPoints[i].y) |
||||
|
linkShapeR.lineTo(this.linkSectionPoints[i].x + (length), this.linkSectionPoints[i].y) |
||||
|
} |
||||
|
|
||||
|
// 拉伸轨迹线 |
||||
|
const linkCurve = new THREE.CatmullRomCurve3( |
||||
|
[new THREE.Vector3(0, 0, -0.08), new THREE.Vector3(0, 0, 0.08)], |
||||
|
false, // 闭合曲线 |
||||
|
'catmullrom', |
||||
|
0 |
||||
|
) |
||||
|
|
||||
|
// 挤出几何图形 参数 |
||||
|
const linkOptions = { |
||||
|
steps: 1, |
||||
|
bevelEnabled: false, |
||||
|
extrudePath: linkCurve // 设置挤出轨迹 |
||||
|
} |
||||
|
// 创建挤出几何体 |
||||
|
const linkGeometryL = new THREE.ExtrudeGeometry(linkShapeL, linkOptions) |
||||
|
linkGeometryL.rotateZ(-Math.PI / 2) |
||||
|
const linkGeometryR = new THREE.ExtrudeGeometry(linkShapeR, linkOptions) |
||||
|
linkGeometryR.rotateX(-Math.PI) |
||||
|
linkGeometryR.rotateZ(-Math.PI / 2) |
||||
|
|
||||
|
// 调整uv方便正确贴图 |
||||
|
// this.resetUVs(geometry); |
||||
|
return mergeGeometries([geometry, linkGeometryL, linkGeometryR]) |
||||
|
} |
||||
|
|
||||
|
createHorizontalBarMaterial(): THREE.Material { |
||||
|
|
||||
|
const material = new THREE.MeshPhongMaterial() |
||||
|
material.color.setHex(this.rackHorizontalBarColor, 'srgb') |
||||
|
material.specular.setHex(0xff6d6d6d, 'srgb') |
||||
|
material.transparent = true |
||||
|
material.needsUpdate = true |
||||
|
|
||||
|
return material |
||||
|
} |
||||
|
|
||||
|
createRack(item: ItemJson, option?: RendererCudOption): InstancedMesh[] { |
||||
|
if (!item.dt.bays || !item.dt.rackDepth) { |
||||
|
system.showErrorDialog('RackRenderer field bays / rackDepth is null!') |
||||
|
return null |
||||
|
} |
||||
|
|
||||
|
const rackPoint = { |
||||
|
x: item.tf[0][0], |
||||
|
y: item.tf[0][1], |
||||
|
z: item.tf[0][2] |
||||
|
} |
||||
|
|
||||
|
const rackWidth = decimalSumBy(item.dt.bays, (b: any) => b.bayWidth) |
||||
|
const rackDepth = item.dt.rackDepth |
||||
|
const heights = [] |
||||
|
for (let i = 0; i < item.dt.bays.length; i++) { |
||||
|
const bay = item.dt.bays[i] |
||||
|
const bayHeight = decimalSumBy(bay.levelHeight) |
||||
|
heights.push(bayHeight) |
||||
|
} |
||||
|
const rackHeight = _.max(heights) |
||||
|
|
||||
|
// 计算立住坐标点和长度 |
||||
|
const vBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = [] |
||||
|
|
||||
|
// 计算 |
||||
|
const linkBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = [] |
||||
|
|
||||
|
let distanceX = 0, distanceY = 0 |
||||
|
|
||||
|
for (let i = -1; i < item.dt.bays.length; i++) { |
||||
|
if (i >= 0) { |
||||
|
const bay = item.dt.bays[i] |
||||
|
distanceX += bay.bayWidth |
||||
|
} |
||||
|
vBarMatrix.push({ |
||||
|
x: distanceX - rackWidth / 2, |
||||
|
y: 0, |
||||
|
z: -rackDepth / 2, |
||||
|
sx: 0.8, |
||||
|
sy: 1, |
||||
|
sz: 1, |
||||
|
rx: 0, |
||||
|
ry: Math.PI / 2, |
||||
|
rz: 0, |
||||
|
l: rackHeight |
||||
|
}) |
||||
|
vBarMatrix.push({ |
||||
|
x: distanceX - rackWidth / 2, |
||||
|
y: 0, |
||||
|
z: item.dt.rackDepth - rackDepth / 2, |
||||
|
sx: 0.8, |
||||
|
sy: 1, |
||||
|
sz: 1, |
||||
|
rx: 0, |
||||
|
ry: -Math.PI / 2, |
||||
|
rz: 0, |
||||
|
l: rackHeight |
||||
|
}) |
||||
|
linkBarMatrix.push({ |
||||
|
x: distanceX - rackWidth / 2, |
||||
|
y: 0, |
||||
|
z: i % 2 == 0 ? (item.dt.rackDepth - rackDepth / 2) : -rackDepth / 2, |
||||
|
sx: 1, |
||||
|
sy: 1, |
||||
|
sz: 1, |
||||
|
rx: 0, |
||||
|
ry: i % 2 == 0 ? Math.PI : 0, |
||||
|
rz: 0, |
||||
|
l: rackHeight |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 计算横梁数量 |
||||
|
const hBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = [] |
||||
|
distanceX = 0 |
||||
|
for (let i = 0; i < item.dt.bays.length; i++) { |
||||
|
distanceY = this.bottomBarHeight |
||||
|
const bay = item.dt.bays[i] |
||||
|
for (let j = 0; j < bay.levelHeight.length; j++) { |
||||
|
const levelHeight = bay.levelHeight[j] |
||||
|
if (distanceY <= 0) { |
||||
|
continue |
||||
|
} |
||||
|
hBarMatrix.push({ |
||||
|
x: distanceX - rackWidth / 2, |
||||
|
y: distanceY, |
||||
|
z: -rackDepth / 2, |
||||
|
sx: 1, |
||||
|
sy: 0.8, |
||||
|
sz: 1, |
||||
|
rx: Math.PI / 2, |
||||
|
ry: 0, |
||||
|
rz: 0, |
||||
|
l: bay.bayWidth |
||||
|
}) |
||||
|
hBarMatrix.push({ |
||||
|
x: distanceX - rackWidth / 2, |
||||
|
y: distanceY, |
||||
|
z: item.dt.rackDepth - rackDepth / 2, |
||||
|
sx: 1, |
||||
|
sy: 0.8, |
||||
|
sz: 1, |
||||
|
rx: -Math.PI / 2, |
||||
|
ry: 0, |
||||
|
rz: 0, |
||||
|
l: bay.bayWidth |
||||
|
}) |
||||
|
distanceY += levelHeight |
||||
|
} |
||||
|
distanceX += bay.bayWidth |
||||
|
} |
||||
|
|
||||
|
const meshes: InstancedMesh[] = [] |
||||
|
|
||||
|
if (vBarMatrix.length > 0) { |
||||
|
if (!this.rackVerticalBarGeometry) { |
||||
|
this.rackVerticalBarGeometry = this.createVerticalBar(vBarMatrix[0].x, vBarMatrix[0].y, vBarMatrix[0].z, vBarMatrix[0].l) |
||||
|
} |
||||
|
if (!this.rackVerticalBarMaterial) { |
||||
|
this.rackVerticalBarMaterial = this.createVerticalBarMaterial() |
||||
|
} |
||||
|
const dummy = new THREE.Object3D() |
||||
|
const vBarMesh = new THREE.InstancedMesh(this.rackVerticalBarGeometry, this.rackVerticalBarMaterial, vBarMatrix.length) |
||||
|
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) |
||||
|
} |
||||
|
|
||||
|
if (linkBarMatrix.length > 0) { |
||||
|
if (!this.rackLinkBarGeometry) { |
||||
|
this.rackLinkBarGeometry = this.createLinkBar(linkBarMatrix[0].x, linkBarMatrix[0].y, linkBarMatrix[0].z, rackHeight, item.dt.rackDepth, this.bottomLinkHeight, 0.2) |
||||
|
} |
||||
|
if (!this.rackLinkBarMaterial) { |
||||
|
this.rackLinkBarMaterial = this.createLinkBarMaterial() |
||||
|
} |
||||
|
const dummy = new THREE.Object3D() |
||||
|
const linkBarMesh = new THREE.InstancedMesh(this.rackLinkBarGeometry, this.rackLinkBarMaterial, linkBarMatrix.length) |
||||
|
for (let i = 0; i < linkBarMatrix.length; i++) { |
||||
|
const lp = linkBarMatrix[i] |
||||
|
dummy.position.set(lp.x, lp.y, lp.z) |
||||
|
dummy.rotation.set(lp.rx, lp.ry, lp.rz) |
||||
|
dummy.scale.set(lp.sx, lp.sy, lp.sz) |
||||
|
dummy.updateMatrix() |
||||
|
linkBarMesh.setMatrixAt(i, dummy.matrix) |
||||
|
} |
||||
|
meshes.push(linkBarMesh) |
||||
|
} |
||||
|
|
||||
|
if (hBarMatrix.length > 0) { |
||||
|
if (!this.rackHorizontalBarGeometry) { |
||||
|
this.rackHorizontalBarGeometry = this.createHorizontalBar(hBarMatrix[0].x, hBarMatrix[0].y, hBarMatrix[0].z, hBarMatrix[0].l) |
||||
|
} |
||||
|
if (!this.rackHorizontalBarMaterial) { |
||||
|
this.rackHorizontalBarMaterial = this.createHorizontalBarMaterial() |
||||
|
} |
||||
|
const dummy = new THREE.Object3D() |
||||
|
const hBarMesh = new THREE.InstancedMesh(this.rackHorizontalBarGeometry, this.rackHorizontalBarMaterial, hBarMatrix.length) |
||||
|
for (let i = 0; i < hBarMatrix.length; i++) { |
||||
|
const hp = hBarMatrix[i] |
||||
|
dummy.position.set(hp.x, hp.y, hp.z) |
||||
|
dummy.rotation.set(hp.rx, hp.ry, hp.rz) |
||||
|
dummy.scale.set(hp.sx, hp.sy, hp.sz) |
||||
|
dummy.updateMatrix() |
||||
|
hBarMesh.setMatrixAt(i, dummy.matrix) |
||||
|
} |
||||
|
meshes.push(hBarMesh) |
||||
|
} |
||||
|
return meshes |
||||
|
} |
||||
|
|
||||
|
|
||||
|
resetUVs(geometry: THREE.ExtrudeGeometry) { |
||||
|
if (geometry == undefined) return |
||||
|
const pos = geometry.getAttribute('position'), |
||||
|
nor = geometry.getAttribute('normal'), |
||||
|
uvs = geometry.getAttribute('uv') |
||||
|
|
||||
|
for (let i = 0; i < pos.count; i++) { |
||||
|
let x = 0, y = 0 |
||||
|
|
||||
|
const nx = Math.abs(nor.getX(i)), ny = Math.abs(nor.getY(i)), nz = Math.abs(nor.getZ(i)) |
||||
|
|
||||
|
// if facing X |
||||
|
if (nx >= ny && nx >= nz) { |
||||
|
x = pos.getZ(i) |
||||
|
y = pos.getY(i) |
||||
|
} |
||||
|
|
||||
|
// if facing Y |
||||
|
if (ny >= nx && ny >= nz) { |
||||
|
x = pos.getX(i) |
||||
|
y = pos.getZ(i) |
||||
|
} |
||||
|
|
||||
|
// if facing Z |
||||
|
if (nz >= nx && nz >= ny) { |
||||
|
x = pos.getX(i) |
||||
|
y = pos.getY(i) |
||||
|
} |
||||
|
uvs.setXY(i, x, y) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue