ThreeJs能力演示——图层导入导出
1、支持图层信息导入导出
1)支持将图层信息及图层中的内容导出
本示例导出其实存在信息缺失,因为导出的模型没有把子图层,以及图层中几何体具体形状、材质给导出来。
function exportLayers() {
const exportData = {
layers: []
};
for (let layer of layers) {
const layerData = {
visible: layer.visible,
objects: []
};
for (let object3D of layer.children) {
layerData.objects.push({
name: object3D.name,
position: object3D.position.toArray(),
rotation: object3D.rotation.toArray(),
scale: object3D.scale.toArray()
});
}
exportData.layers.push(layerData);
}
const dataStr = JSON.stringify(exportData);
const blob = new Blob([dataStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'layersData.json';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
2)支持将导出的内容重新导回
本导入导出方案不是特别完善,都是序列化成json格式,很多信息想要存下来都比较麻烦。
未来应该考虑更优的适配比较少的序列化方案。
因为对于很多3D项目来说,缓存工程是一个很正常的诉求。如果序列化适配这么麻烦将导致缓存工程信息丢失、适配量大。
function importLayers() {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'application/json';
input.addEventListener('change', (event) => {
const file = event.target.files[0];
const reader = new FileReader();
reader.readAsText(file);
reader.onload = () => {
const importData = JSON.parse(reader.result);
for (let i = 0; i < layers.length; i++) {
layers[i].visible = importData.layers[i].visible;
while (layers[i].children.length > 0) {
layers[i].remove(layers[i].children[0]);
}
for (let objectData of importData.layers[i].objects) {
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
cube.name = objectData.name;
cube.position.fromArray(objectData.position);
cube.rotation.fromArray(objectData.rotation);
cube.scale.fromArray(objectData.scale);
layers[i].add(cube);
}
}
};
});
input.click();
}
2、整体代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Three.js 几何体操作示例</title>
<style>
body { margin: 0; overflow: hidden; }
#camera-info {
position: absolute;
top: 10px;
left: 10px;
background-color: rgba(0, 0, 0, 0.5);
color: white;
padding: 10px;
font-family: Arial, sans-serif;
}
</style>
</head>
<body>
<div id="camera-info"></div>
<script type="importmap">
{
"imports": {
"three": "./three.js-master/build/three.module.js",
"three/addons/": "./three.js-master/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from "three"
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
// 1) 创建画布
const scene = new THREE.Scene();
scene.background = new THREE.Color( 0xa0a0a0 );
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 2) 设置 camera 位置,朝向角度
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 20); // 设置相机位置
camera.lookAt(scene.position); // 让相机朝向场景中心
// 设置控制轨道
const controls = new OrbitControls( camera, renderer.domElement );
controls.target.set( 0, 0.1, 0 );
controls.update();
controls.minDistance = 0.5;
controls.maxDistance = 1000;
controls.maxPolarAngle = 0.5 * Math.PI;
// 5) 支持动态显示摄像头位置、角度、缩放信息
const cameraInfo = document.getElementById('camera-info');
function updateCameraInfo() {
cameraInfo.innerHTML = `
摄像头信息:<br>
位置: (${camera.position.x.toFixed(2)}, ${camera.position.y.toFixed(2)}, ${camera.position.z.toFixed(2)})<br>
角度: (${camera.rotation.x.toFixed(2)}, ${camera.rotation.y.toFixed(2)}, ${camera.rotation.z.toFixed(2)})<br>
缩放: ${camera.zoom.toFixed(2)}
`;
}
updateCameraInfo();
// 渲染循环
function animate() {
requestAnimationFrame(animate);
updateCameraInfo();
renderer.render(scene, camera);
}
animate();
// 创建图层信息
const layer0 = new THREE.Object3D()
const layer0_1 = new THREE.Object3D()
layer0.add(layer0_1)
const layer1 = new THREE.Object3D()
const layer2 = new THREE.Object3D()
const layers = [layer0, layer1, layer2]
// 存储创建的几何体列表
createCube(0, layer0)
createCube(1, layer1)
createCube(2, layer2)
createCube(0.5, layer0_1)
for (let layer of layers) {
scene.add(layer)
}
// 创建正方体
function createCube(place, layerObj) {
const geometry = new THREE.BoxGeometry(1, 1, 1 );
const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
const cube = new THREE.Mesh( geometry, material );
cube.name = 'Cube${layerIndex}';
cube.position.set(place*2, place*2, place*2)
layerObj.add(cube)
return cube;
}
// GUI控制显示图层
const gui = new GUI();
const layerFolders = [];
for (let i = 0; i < 3; i++) {
const layerFolder = gui.addFolder(`Layer ${i}`);
const layerEnabled = layerFolder.add({enabled: true}, 'enabled').name('可见性');
layerEnabled.onChange((value) => {
console.log(`index ${i} enabled: ${value}`)
layers[i].visible = value
});
layerFolders.push(layerFolder);
}
// 添加导入导出功能的 GUI
const importExportFolder = gui.addFolder('Import/Export');
const exportDataButton = importExportFolder.add({ exportData: () => exportLayers() }, 'exportData').name('导出图层信息');
const importDataButton = importExportFolder.add({ importData: () => importLayers() }, 'importData').name('导入图层信息');
const clearLayersButton = importExportFolder.add({ clearLayers: () => clearAllLayers() }, 'clearLayers').name('清空所有图层');
function exportLayers() {
const exportData = {
layers: []
};
for (let layer of layers) {
const layerData = {
visible: layer.visible,
objects: []
};
for (let object3D of layer.children) {
layerData.objects.push({
name: object3D.name,
position: object3D.position.toArray(),
rotation: object3D.rotation.toArray(),
scale: object3D.scale.toArray()
});
}
exportData.layers.push(layerData);
}
const dataStr = JSON.stringify(exportData);
const blob = new Blob([dataStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'layersData.json';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
function importLayers() {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'application/json';
input.addEventListener('change', (event) => {
const file = event.target.files[0];
const reader = new FileReader();
reader.readAsText(file);
reader.onload = () => {
const importData = JSON.parse(reader.result);
for (let i = 0; i < layers.length; i++) {
layers[i].visible = importData.layers[i].visible;
while (layers[i].children.length > 0) {
layers[i].remove(layers[i].children[0]);
}
for (let objectData of importData.layers[i].objects) {
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
cube.name = objectData.name;
cube.position.fromArray(objectData.position);
cube.rotation.fromArray(objectData.rotation);
cube.scale.fromArray(objectData.scale);
layers[i].add(cube);
}
}
};
});
input.click();
}
function clearAllLayers() {
for (let layer of layers) {
while (layer.children.length > 0) {
layer.remove(layer.children[0]);
}
}
}
</script>
</body>
</html>
原文地址:https://blog.csdn.net/u010595191/article/details/145193608
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!