2024-11-01 09:12:14 +00:00
|
|
|
<template>
|
|
|
|
<div ref="threeContainer"></div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
import * as THREE from 'three';
|
|
|
|
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
|
|
|
|
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader';
|
|
|
|
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
|
2024-11-08 09:05:21 +00:00
|
|
|
import { CSS3DObject, CSS3DRenderer } from 'three/examples/jsm/Addons.js';
|
2024-11-01 09:12:14 +00:00
|
|
|
import { onMounted, ref } from 'vue';
|
|
|
|
|
|
|
|
const threeContainer = ref(null);
|
2024-11-08 09:05:21 +00:00
|
|
|
let camera, scene, renderer, model, controls, cssRenderer;
|
2024-11-01 09:12:14 +00:00
|
|
|
let width = 1920;
|
|
|
|
let height = 1080;
|
2024-11-08 09:05:21 +00:00
|
|
|
let text = ref('标注1');
|
2024-11-01 09:12:14 +00:00
|
|
|
const init = () => {
|
|
|
|
scene = new THREE.Scene();
|
|
|
|
// scene.background = new THREE.Color(null);//0x100c2a
|
|
|
|
// scene.background.setAlpha(0);
|
|
|
|
camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 2000);
|
2024-11-05 09:07:21 +00:00
|
|
|
camera.position.set(40, 300, 200);
|
2024-11-01 09:12:14 +00:00
|
|
|
|
|
|
|
renderer = new THREE.WebGLRenderer({
|
2024-11-05 09:07:21 +00:00
|
|
|
antialias: true,
|
|
|
|
alpha: true
|
|
|
|
});
|
2024-11-01 09:12:14 +00:00
|
|
|
renderer.setSize(width, height);
|
|
|
|
threeContainer.value.appendChild(renderer.domElement);
|
|
|
|
|
2024-11-08 09:05:21 +00:00
|
|
|
cssRenderer = initLabelRenderer(threeContainer.value);
|
2024-11-01 09:12:14 +00:00
|
|
|
const objLoader = new OBJLoader();
|
|
|
|
let mtlLoader = new MTLLoader();
|
|
|
|
mtlLoader.load('/src/assets/obj/goats_R&D.mtl', function (materials) {
|
|
|
|
materials.preload();
|
|
|
|
objLoader.setMaterials(materials);
|
|
|
|
objLoader.load('/src/assets/obj/goats_R&D.obj', function (obj) {
|
2024-11-05 09:07:21 +00:00
|
|
|
var scale = 0.07 / obj.scale.x;
|
2024-11-01 09:12:14 +00:00
|
|
|
obj.scale.set(scale, scale, scale);
|
|
|
|
model = obj;
|
|
|
|
const box = new THREE.Box3().setFromObject(model);
|
|
|
|
const size = box.getSize(new THREE.Vector3())
|
|
|
|
// console.log(size,'-----');
|
2024-11-05 09:07:21 +00:00
|
|
|
obj.position.set(-size.x * 0.5, -size.y * 0.1, -size.z * 0.5);
|
2024-11-01 09:12:14 +00:00
|
|
|
obj.children.forEach((child) => {
|
|
|
|
const c = child;
|
|
|
|
const cm = c.material;
|
|
|
|
cm.emissive = cm.color;
|
|
|
|
cm.emissiveMap = cm.map;
|
|
|
|
});
|
2024-11-08 09:05:21 +00:00
|
|
|
addMarks(text.value);
|
2024-11-01 09:12:14 +00:00
|
|
|
scene.add(model);
|
|
|
|
animate();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
// loader.load(
|
|
|
|
// '/src/assets/obj/goats_R&D.obj',
|
|
|
|
// (obj) => {
|
|
|
|
// var scale = 0.1 / obj.scale.x;
|
|
|
|
// obj.scale.set(scale, scale, scale);
|
|
|
|
// model = obj;
|
|
|
|
// // 添加光照
|
|
|
|
// // scene.add(new THREE.AmbientLight(0x404040));
|
|
|
|
// scene.add(new THREE.DirectionalLight());
|
|
|
|
// scene.add(model);
|
|
|
|
// },
|
|
|
|
// (xhr) => {
|
|
|
|
// console.log((xhr.loaded / xhr.total * 100) + '% loaded');
|
|
|
|
// },
|
|
|
|
// (error) => {
|
|
|
|
// console.error('An error happened: ', error);
|
|
|
|
// }
|
|
|
|
// );
|
|
|
|
|
2024-11-08 09:05:21 +00:00
|
|
|
controls = new OrbitControls(camera, cssRenderer.domElement);
|
2024-11-01 09:12:14 +00:00
|
|
|
controls.enableDamping = true;
|
|
|
|
|
|
|
|
animate();
|
|
|
|
};
|
|
|
|
|
2024-11-08 09:05:21 +00:00
|
|
|
// 初始化标注渲染器
|
|
|
|
const initLabelRenderer = boxElement => {
|
|
|
|
const labelRenderer = new CSS3DRenderer();
|
|
|
|
labelRenderer.setSize(width, height);
|
|
|
|
labelRenderer.domElement.style.position = 'absolute';
|
|
|
|
labelRenderer.domElement.style.top = 0;
|
|
|
|
boxElement.appendChild(labelRenderer.domElement);
|
|
|
|
return labelRenderer;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
function addMarks(text) {
|
|
|
|
//把传入的标注文字通过 canvas 修改为可以添加到场景中的 texture
|
|
|
|
const offScreenCanvas = document.createElement('canvas');
|
|
|
|
const offScreenCtx = offScreenCanvas.getContext('2d');
|
|
|
|
// 配置字体、大小、颜色等
|
|
|
|
offScreenCtx.font = '16px 黑体';
|
|
|
|
const txt = text;
|
|
|
|
const textWidth = offScreenCtx.measureText(txt).width;
|
|
|
|
const canvas = document.createElement('canvas');
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
if (ctx !== null) {
|
|
|
|
// pixelRatio: 像素密度
|
|
|
|
canvas.width = (5 + textWidth + 5) * 2;
|
|
|
|
canvas.height = 18 * 2;
|
|
|
|
ctx.setTransform(2, 0, 0, 2, 0, 0);
|
|
|
|
ctx.font = '16px 黑体';
|
|
|
|
ctx.fillStyle = '#fff'; //标注背景颜色
|
|
|
|
ctx.fillRect(0, 0, 5 + textWidth + 5, 18);
|
|
|
|
ctx.fillStyle = '#000'; //标注字体颜色
|
|
|
|
ctx.fillText(txt, 5, 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 将标注变成可以添加到场景中的 texture 对象
|
|
|
|
const texture = new THREE.CanvasTexture(canvas);
|
|
|
|
|
|
|
|
|
|
|
|
var geometry2 = new THREE.BufferGeometry();
|
|
|
|
var material = new THREE.LineBasicMaterial({ vertexColors: true });
|
|
|
|
var color1 = new THREE.Color(0xffffff), color2 = new THREE.Color(0xffffff);
|
|
|
|
//定义第一条线
|
|
|
|
var p3 = new THREE.Vector3(0, 50, 40);
|
|
|
|
var p4 = new THREE.Vector3(4, 23.5, 10);
|
|
|
|
const points = [];
|
|
|
|
points.push(p3);
|
|
|
|
points.push(p4);
|
|
|
|
// geometry2.vertices.push(p3);
|
|
|
|
// geometry2.vertices.push(p4);
|
|
|
|
// geometry2.colors.push(color1, color2);
|
|
|
|
geometry2.setFromPoints(points);
|
|
|
|
//把线条添加到场景中
|
|
|
|
var line2 = new THREE.Line(geometry2, material, THREE.LinePieces);
|
|
|
|
scene.add(line2);
|
|
|
|
//定义第一个标签
|
|
|
|
/**精灵图 */
|
|
|
|
// var spriteMaterial2 = new THREE.SpriteMaterial({ map: texture, color: 0xffffff });
|
|
|
|
// var sprite2 = new THREE.Sprite(spriteMaterial2);
|
|
|
|
// sprite2.position.set(0, 50, 40);
|
|
|
|
// sprite2.scale.set(15, 5, 0);
|
|
|
|
// scene.add(sprite2);
|
|
|
|
|
|
|
|
|
|
|
|
/** CSS3D */
|
|
|
|
const label = new CSS3DObject(document.createElement('div'));
|
|
|
|
label.position.set(0, 50, 40);
|
|
|
|
label.scale.set(0.5, 0.5, 0.5);
|
|
|
|
label.element.style.backgroundColor = '#fff';
|
|
|
|
label.element.innerText = text;
|
|
|
|
scene.add(label);
|
|
|
|
|
|
|
|
|
|
|
|
//定义标记点
|
|
|
|
var radius = 0.5, segemnt = 16, rings = 16;
|
|
|
|
var sphereMaterial = new THREE.MeshLambertMaterial({ color: 0x9afc00 });
|
|
|
|
var sphere101 = new THREE.Mesh(new THREE.SphereGeometry(radius, segemnt, rings), sphereMaterial);
|
|
|
|
sphere101.position.set(4, 23.5, 10);
|
|
|
|
scene.add(sphere101);
|
|
|
|
|
|
|
|
// var group = new THREE.Object3D();
|
|
|
|
// group.add(line2);
|
|
|
|
// group.add(sphere101);
|
|
|
|
// group.add(sprite2);
|
|
|
|
// scene.add(group);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-11-01 09:12:14 +00:00
|
|
|
const animate = () => {
|
|
|
|
requestAnimationFrame(animate);
|
|
|
|
renderer.render(scene, camera);
|
2024-11-08 09:05:21 +00:00
|
|
|
cssRenderer.render(scene, camera);
|
2024-11-01 09:12:14 +00:00
|
|
|
controls.update();
|
|
|
|
};
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
init();
|
2024-11-08 09:05:21 +00:00
|
|
|
|
2024-11-01 09:12:14 +00:00
|
|
|
window.addEventListener('resize', onWindowResize);
|
|
|
|
});
|
|
|
|
|
|
|
|
const onWindowResize = () => {
|
|
|
|
camera.aspect = window.innerWidth / window.innerHeight;
|
|
|
|
camera.updateProjectionMatrix();
|
|
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
|
|
};
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
window.removeEventListener('resize', onWindowResize);
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style>
|
|
|
|
#threeContainer {
|
|
|
|
width: 1920px;
|
|
|
|
height: 1080px;
|
|
|
|
/* 根据需要调整位置 */
|
|
|
|
overflow: hidden;
|
|
|
|
}
|
|
|
|
</style>
|