3d低代码可视化编辑预习
获取3d坐标 进行模型及动画移动-单走和双开
/* 定义接口 */
interface XYZInfo {
x: number | string | null,
y: number | string | null,
z: number | string | null,
}
let camPos = reactive({
x: null,
y: null,
z: null
})
let camPosArr = reactive([{
x: null,
y: null,
z: null,
delay: 0,
duration: 1
}])
let contrPos = reactive({
x: null,
y: null,
z: null
})
let contrPosArr = reactive([{
x: null,
y: null,
z: null
}])
let clickPos = reactive({
x: null,
y: null,
z: null
})
let clickPosArr = reactive([{
x: null,
y: null,
z: null
}])
let movePosArr: any = reactive([
new THREE.Vector3(0, 0, 0)
])
/* 单点位 */
function gsapbolFn() {
/* 相机点位 */
let { x: camX, y: camY, z: camZ } = camera.position;
camPos.x = camX;
camPos.y = camY;
camPos.z = camZ;
camPosArr.push({
x: camPos.x,
y: camPos.y,
z: camPos.z
delay: i,
duration: l
})
/* 指向点位 */
let { x: contrX, y: contrY, z: contrZ } = controls.target;
contrPos.x = contrX;
contrPos.y = contrY;
contrPos.z = contrZ;
contrPosArr.push({
x: contrX,
y: contrY,
z: contrZ
})
}
/* gsap动画 */
function gsapFn() {
gsap.to(camera.position, {
x: camPos.x,
y: camPos.y,
z: camPos.z,
duration: 3,
onUpdate: () => {
controls.target.set(contrPos.x, contrPos.y, contrPos.z);
controls.update()
},
})
}
/* 多重动画 */
function gsapplusFn() {
let gsapt = gsap.timeline()
for (let i = 0; i < camPosArr.length; i++) {
gsapt.to(camera.position, {
x: camPosArr[i].x,
y: camPosArr[i].y,
z: camPosArr[i].z,
delay: camPosArr[i].delay,
duration: camPosArr[i].duration,
onStart: () => {
controls.reset()
},
onUpdate: () => {
controls.target.set(contrPosArr[i].x, contrPosArr[i].y, contrPosArr[i].z);
controls.update()
},
onComplete: () => {
}
})
}
}
/* 3d点位 */
renderer.domElement.addEventListener('click', (event: any) => {
const px = event.offsetX;
const py = event.offsetY;
const x = (px / width) * 2 - 1;
const y = -(py / height) * 2 + 1;
if (!event.ctrlKey) return;
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
const inter = raycaster.intersectObjects(scene.children);
if (inter.length > 0) {
let { x: clickX, y: clickY, z: clickZ } = inter[0].point
clickPos.x = clickX.toFixed(3)
clickPos.y = clickY.toFixed(3)
clickPos.z = clickZ.toFixed(3)
clickPosArr.push({
x: clickPos.x,
y: clickPos.y,
z: clickPos.z
})
let v3pos = new THREE.Vector3(clickX, clickY, clickZ)
movePosArr.push(v3pos)
firePathFn(movePosArr)
} else return void 0;
})
/* 小鹿-妙哉! */
let firePath = new THREE.Group()
const firerouteFn = (movePosArr: any) => {
const posval = new THREE.Vector3(0, 0, 0);
let up = new THREE.Vector3(0, 1, 0);
let pathPointList = new PathPointList();
pathPointList.set(movePosArr, 0.5, 10, up, false);
/* 精灵图 */
const texLoader = new THREE.TextureLoader();
let texture = texLoader.load('/public/mo-image/箭头.png');
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
let geometry = new PathGeometry();
geometry.update(pathPointList, {
width: 3,
arrow: false
});
let material = new THREE.MeshPhongMaterial({
color: '#000000',
depthWrite: true,
transparent: true,
opacity: 1,
side: THREE.DoubleSide,
map: texture
})
firePath.add(new THREE.Mesh(geometry, material))
firePath.position.copy(posval);
firePath.position.y = posval.y + 2;
scene.add(firePath)
gsap.to(texture.offset, {
x: -1,
repeat: -1,
ease: 'none'
})
}
const firePathFn = (movePosArr: any) => {
firerouteFn(movePosArr)
}
/* 拖拽元素之功效-妙哉! */
<el-card style="max-width: 330px">
<template #header>
<div class="card-header">
<strong>拖拽生成</strong>
<span>
<el-button color="#626aef" plain
@click="draggableFn" :loading="btnLoad">开始
</el-button>
</span>
</div>
</template>
<div class="draggable">
<p>模型列表
<img id="box" draggable="true" @dragstart="dragstartFn(1)" src="../../assets/dragg1.jpg" width="50"height="50">
</p>
</div>
</el-card>
const createGround = (size: number) => {
let geometry = new THREE.PlaneGeometry(size, size, 10, 10);
let material = new THREE.MeshLambertMaterial({ color: 0x888888, wireframe: true });
let mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = -Math.PI / 2;
mesh.receiveShadow = true;
return mesh;
}
const groundSize = 1000;
const ground = createGround(groundSize);
scene.add(ground);
/* 拖拽前的羁绊! */
let dragstartFn = (val: any) => {
console.log(val);
}
/*
document.querySelectorAll("p img").forEach((img) => {
img.addEventListener("dragstart", function (event) {
?.
let currentTarget = event.currentTarget;
event.dataTransfer.setData("text", currentTarget.id);
});
});
*/
document.querySelector?.(".web3d")?.addEventListener("dragover", (e) => {
e.preventDefault();
});
document.querySelector?.(".web3d").addEventListener("drop", (e: any) => {
e.preventDefault();
let raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
mouse.x = (e.offsetX / width) * 2 - 1;
mouse.y = -(e.offsetY / height) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
console.log(e.offsetX, e.offsetY);
let inter = raycaster.intersectObject(scene);
if (inter.length > 0 && draggablebol.value) {
const geometry = new THREE.SphereGeometry(30, 32, 16);
const material = new THREE.MeshBasicMaterial({ color: 0x000000 });
sphere = new THREE.Mesh(geometry, material);
let { x, y, z } = inter[0].point;
sphere.position.set(x, y, z)
sphereArr.push(sphere)
scene.add(sphere);
}
})
小猫咪
/* 有辅助3d中心坐标之功效-妙哉! */
const helper = new THREE.CameraHelper(camera);
scene.add(helper);
/* 标签自带拖拽属性-妙哉! */
draggable:true
丢你
let carMod = new THREE.Group()
loaderDraco().load('/mo-Group/魅族.glb', (gltf: any) => {
gltf.scene.scale.set(2, 2, 2)
gltf.scene.rotateY(Math.PI / 1)
carMod.add(gltf.scene)
})
function moveFn() {
let carArr = movePosArr
if (carArr.length < 2) return;
carMod.position.set(carArr[1].x, carArr[1].y, carArr[1].z)
scene.add(carMod)
let carpos = new THREE.CatmullRomCurve3(carArr);
carpos.curveType = 'catmullrom'; // 张力阀门
carpos.tension = 0.9; // 张力
carpos.closed = true; // 闭环
curMoveFn(carpos, carMod, 0.0008)
}
指南针
<div id="compass" style="width: 50px;height:50px">
<img src="/public/mo-image/箭头.png" width="50" height="50" alt="">
</div>
function zhinanFn() {
function render() {
requestAnimationFrame(render)
renderer.render(scene, camera)
const dirx = camera.position.x - controls.target.x
const dirz = camera.position.z - controls.target.z
const theta = Math.atan2(dirx, dirz) * 180 / Math.PI + 140
const compass: any = document.getElementById('compass')
compass.style.transform = 'rotateZ(' + theta + 'deg)';
// 可加入判断,根据不同的场景偏差偏移角度
/* if (dmgroup.visible === true) {
const theta = Math.atan2(dirx, dirz) * 180 / Math.PI + 140
const compass = document.getElementById('compass')
compass.style.transform = 'rotateZ(' + theta + 'deg)'
} else {
const theta = Math.atan2(dirx, dirz) * 180 / Math.PI + 100
const compass = document.getElementById('compass')
compass.style.transform = 'rotateZ(' + theta + 'deg)'
} */
}
render()
}