|
|
@@ -4,16 +4,48 @@
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import * as THREE from "../Three/Three.js";
|
|
|
+// import * as THREE from "../Three/Three.js";
|
|
|
|
|
|
-import { TEngine } from "../threeTool/ThreeEngine";
|
|
|
-import { allBaseObject } from "../threeTool/ThreeBaseObject";
|
|
|
-import { allLights } from "../threeTool/ThreeLights";
|
|
|
-import { getColor } from "../threeTool/ThreeColor";
|
|
|
-import { ThreeAxes } from "../threeTool/ThreeAxes";
|
|
|
+// import { TEngine } from "../threeTool/ThreeEngine";
|
|
|
+// import { allBaseObject } from "../threeTool/ThreeBaseObject";
|
|
|
+// import { allLights } from "../threeTool/ThreeLights";
|
|
|
+// import { getColor } from "../threeTool/ThreeColor";
|
|
|
+// import { ThreeAxes } from "../threeTool/ThreeAxes";
|
|
|
|
|
|
-import { GLTFLoader } from "../Three/examples/jsm/loaders/GLTFLoader";
|
|
|
-import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
|
|
|
+// import { GLTFLoader } from "../Three/examples/jsm/loaders/GLTFLoader";
|
|
|
+// import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
|
|
|
+
|
|
|
+import * as THREE from "three";
|
|
|
+
|
|
|
+import {
|
|
|
+ WebGLRenderer,
|
|
|
+ Scene,
|
|
|
+ PerspectiveCamera,
|
|
|
+ Vector3,
|
|
|
+ MOUSE,
|
|
|
+ Raycaster,
|
|
|
+ Vector2,
|
|
|
+} from "three";
|
|
|
+
|
|
|
+import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
|
|
+import { TransformControls } from "three/examples/jsm/controls/TransformControls";
|
|
|
+import {
|
|
|
+ CSS3DRenderer,
|
|
|
+ CSS3DObject,
|
|
|
+} from "three/examples/jsm/renderers/CSS3DRenderer";
|
|
|
+
|
|
|
+import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
|
|
+import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
|
|
+import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
|
|
|
+import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
|
|
|
+import { TDSLoader } from "three/examples/jsm/loaders/TDSLoader";
|
|
|
+import { MTLLoader } from "three-obj-mtl-loader";
|
|
|
+
|
|
|
+import { Color } from "../Three/Three.js";
|
|
|
+
|
|
|
+import WebGL from "../threeTool/WebGL";
|
|
|
+
|
|
|
+THREE.Cache.enabled = true;
|
|
|
|
|
|
export default {
|
|
|
name: "ThreeScene",
|
|
|
@@ -21,35 +53,337 @@ export default {
|
|
|
data() {
|
|
|
return {
|
|
|
ThreeEngine: null,
|
|
|
+ scene: null,
|
|
|
+ camera: null,
|
|
|
+ renderer: null,
|
|
|
+ loader: null,
|
|
|
+ baseWidth: 0,
|
|
|
+ baseHeight: 0,
|
|
|
+ orbitControls: null,
|
|
|
+ css3DRenderer: null,
|
|
|
+ animationId: null,
|
|
|
};
|
|
|
},
|
|
|
|
|
|
mounted() {
|
|
|
- this.initThree();
|
|
|
+ this.initLoader();
|
|
|
+ this.initThree({
|
|
|
+ dom: this.$refs.threeCanvas,
|
|
|
+ showGridHelper: true,
|
|
|
+ });
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
- initThree() {
|
|
|
- this.ThreeEngine = new TEngine({
|
|
|
- dom: this.$refs.threeCanvas,
|
|
|
- showGUI: false,
|
|
|
- cameraOptions: {
|
|
|
- fov: 45,
|
|
|
- aspectRatio: window.innerWidth / window.innerHeight,
|
|
|
- near: 0.1,
|
|
|
- far: 99999,
|
|
|
- },
|
|
|
+ initThree(options) {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const parentDom = getComputedStyle(
|
|
|
+ document.querySelector(".el-tabs__content"),
|
|
|
+ null
|
|
|
+ );
|
|
|
+
|
|
|
+ this.baseWidth = parentDom.width ? parseInt(parentDom.width) : 0;
|
|
|
+ this.baseHeight = parentDom.height ? parseInt(parentDom.height) : 0;
|
|
|
+
|
|
|
+ // 创建3D场景对象Scene
|
|
|
+ const scene = new THREE.Scene();
|
|
|
+ scene.background = this.getColor("#add8e6");
|
|
|
+
|
|
|
+ // 相机
|
|
|
+ const camera = new PerspectiveCamera(
|
|
|
+ // 视野角度(fov)
|
|
|
+ options?.cameraOptions?.fov || 75,
|
|
|
+ // 长宽比(aspect ratio)
|
|
|
+ options?.cameraOptions?.aspectRatio ||
|
|
|
+ this.baseWidth / this.baseHeight,
|
|
|
+ // 近截面(near)
|
|
|
+ options?.cameraOptions?.near || 0.1,
|
|
|
+ // 远截面(far)
|
|
|
+ options?.cameraOptions?.far || 1000
|
|
|
+ );
|
|
|
+
|
|
|
+ // 设置摄像机位置和朝向
|
|
|
+ camera.position.set(80, 100, 200); // 调整摄像机位置
|
|
|
+ camera.lookAt(new THREE.Vector3(0, 0, 0)); // 设置摄像机朝向场景中心
|
|
|
+
|
|
|
+ // 渲染器
|
|
|
+ const renderer = new WebGLRenderer({
|
|
|
+ antialias: true, // 开启抗锯齿
|
|
|
+ });
|
|
|
+
|
|
|
+ // 添加灯光
|
|
|
+ const ambientLight = new THREE.AmbientLight(0xffffff, 1);
|
|
|
+ scene.add(ambientLight);
|
|
|
+ const directionalLight1 = new THREE.DirectionalLight(0xffffff, 5);
|
|
|
+ directionalLight1.position.set(0, 0, 1);
|
|
|
+ scene.add(directionalLight1);
|
|
|
+ const directionalLight2 = new THREE.DirectionalLight(0xffffff, 5);
|
|
|
+ directionalLight2.position.set(0, 0, -1);
|
|
|
+ scene.add(directionalLight2);
|
|
|
+ const directionalLight3 = new THREE.DirectionalLight(0xffffff, 5);
|
|
|
+ directionalLight3.position.set(1, 0, 0);
|
|
|
+ scene.add(directionalLight3);
|
|
|
+ const directionalLight4 = new THREE.DirectionalLight(0xffffff, 5);
|
|
|
+ directionalLight4.position.set(-1, 0, 0);
|
|
|
+ scene.add(directionalLight4);
|
|
|
+ const directionalLight5 = new THREE.DirectionalLight(0xffffff, 5);
|
|
|
+ directionalLight5.position.set(0, 1, 0);
|
|
|
+ scene.add(directionalLight5);
|
|
|
+ const directionalLight6 = new THREE.DirectionalLight(0xffffff, 5);
|
|
|
+ directionalLight6.position.set(0, -1, 0);
|
|
|
+ scene.add(directionalLight6);
|
|
|
+
|
|
|
+ // renderer.setSize(window.innerWidth, window.innerHeight);
|
|
|
+ const rendererBox = getComputedStyle(options.dom, null);
|
|
|
+ const renderSizeWidth = parseFloat(rendererBox.width);
|
|
|
+ const renderSizeHeight = parseFloat(rendererBox.height);
|
|
|
+ renderer.setSize(renderSizeWidth, renderSizeHeight);
|
|
|
+
|
|
|
+ options?.dom?.appendChild(renderer.domElement);
|
|
|
+
|
|
|
+ const css3DRenderer = new CSS3DRenderer();
|
|
|
+ css3DRenderer.setSize(renderSizeWidth, renderSizeHeight);
|
|
|
+ css3DRenderer.render(scene, camera);
|
|
|
+ css3DRenderer.domElement.style.position = "absolute";
|
|
|
+ css3DRenderer.domElement.style.top = 0;
|
|
|
+ css3DRenderer.domElement.style.pointerEvents = "none";
|
|
|
+ options.dom.appendChild(css3DRenderer.domElement);
|
|
|
+
|
|
|
+ // 设置鼠标功能键(轨道控制器)
|
|
|
+ const orbitControls = new OrbitControls(camera, renderer.domElement);
|
|
|
+ // 移动带阻尼
|
|
|
+ orbitControls.enableDamping = options.enableDamping || false;
|
|
|
+ // 设置阻尼系数
|
|
|
+ orbitControls.dampingFactor = options.dampingFactor || 0;
|
|
|
+ // 自动旋转
|
|
|
+ orbitControls.autoRotate = options.autoRotate || false;
|
|
|
+
|
|
|
+ orbitControls.mouseButtons = {
|
|
|
+ LEFT: MOUSE.ROTATE, // 左键无功能
|
|
|
+ MIDDLE: MOUSE.PAN, // 中键移动
|
|
|
+ RIGHT: null, // 右键旋转
|
|
|
+ };
|
|
|
+
|
|
|
+ if (options.showGridHelper) {
|
|
|
+ // 底图网格 (总长宽,分多少个网格,颜色,轴线颜色,和网格颜色 #e6e8ed)
|
|
|
+ const gridHelper = new THREE.GridHelper(
|
|
|
+ 2000,
|
|
|
+ 100,
|
|
|
+ this.getColor("#dedede"),
|
|
|
+ this.getColor("#dedede")
|
|
|
+ );
|
|
|
+ gridHelper.name = "网格地板";
|
|
|
+ gridHelper.disalbedDelete = true;
|
|
|
+ scene.add(gridHelper);
|
|
|
+ }
|
|
|
+ // 初始化射线发射器
|
|
|
+ let raycaster = new Raycaster();
|
|
|
+
|
|
|
+ // 渲染循环
|
|
|
+ const animate = () => {
|
|
|
+ this.animationId = requestAnimationFrame(animate);
|
|
|
+ orbitControls.update();
|
|
|
+ css3DRenderer.render(scene, camera);
|
|
|
+ renderer.render(scene, camera);
|
|
|
+ };
|
|
|
+
|
|
|
+ this.scene = scene;
|
|
|
+ this.camera = camera;
|
|
|
+ this.renderer = renderer;
|
|
|
+ this.orbitControls = orbitControls;
|
|
|
+ this.css3DRenderer = css3DRenderer;
|
|
|
+
|
|
|
+ if (WebGL.isWebGLAvailable()) {
|
|
|
+ animate();
|
|
|
+ // 窗口调整大小时更新渲染器
|
|
|
+ window.addEventListener("resize", () => {
|
|
|
+ renderer.setSize(window.innerWidth, window.innerHeight);
|
|
|
+ camera.aspect = window.innerWidth / window.innerHeight;
|
|
|
+ camera.updateProjectionMatrix();
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ const warning = WebGL.getWebGLErrorMessage();
|
|
|
+ options?.dom?.appendChild(warning);
|
|
|
+ }
|
|
|
+
|
|
|
+ this.addModel({ fileName: "SolarPowerPlant" });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 初始化模型加载器
|
|
|
+ initLoader() {
|
|
|
+ this.loader = {
|
|
|
+ glb: new GLTFLoader(),
|
|
|
+ gltf: new GLTFLoader(),
|
|
|
+ obj: new OBJLoader(),
|
|
|
+ fbx: new FBXLoader(),
|
|
|
+ "3ds": new TDSLoader(),
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取颜色
|
|
|
+ getColor(colorHex) {
|
|
|
+ return new Color(colorHex);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 添加模型
|
|
|
+ addModel({ fileType = "glb", fileName }) {
|
|
|
+ const loader = this.loader[fileType];
|
|
|
+ loader.setResourcePath(`./static/model/${fileName}/`);
|
|
|
+ loader.load(`./static/model/${fileName}/model.${fileType}`, (result) => {
|
|
|
+ const model = result.scene;
|
|
|
+
|
|
|
+ const camera = this.camera;
|
|
|
+
|
|
|
+ // model.traverse((child) => {
|
|
|
+ // if (child.material) {
|
|
|
+ // child.material.emissive = child.material.color;
|
|
|
+ // child.material.emissiveMap = child.material.map;
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+
|
|
|
+ // model.children.forEach((item, index) => {
|
|
|
+ // item.castShadow = true;
|
|
|
+ // item.receiveShadow = true;
|
|
|
+ // });
|
|
|
+
|
|
|
+ const baseBoxSize = new THREE.Vector3(100, 100, 100);
|
|
|
+ // 计算模型的包围盒(bounding box)
|
|
|
+ const boundingBox = new THREE.Box3().setFromObject(model);
|
|
|
+ const modelSize = new THREE.Vector3();
|
|
|
+ boundingBox.getSize(modelSize);
|
|
|
+
|
|
|
+ // 计算模型的最大尺寸
|
|
|
+ const maxModelSize = Math.max(modelSize.x, modelSize.y, modelSize.z);
|
|
|
+
|
|
|
+ // 计算缩放比例,使模型尺寸不超过基准盒子的尺寸
|
|
|
+ const scaleFactor = baseBoxSize.clone().divideScalar(maxModelSize);
|
|
|
+
|
|
|
+ // 将模型等比例缩放到适应基准盒子大小
|
|
|
+ model.scale.set(scaleFactor.x, scaleFactor.y, scaleFactor.z);
|
|
|
+
|
|
|
+ camera.position.z = 200;
|
|
|
+ console.log(222, model);
|
|
|
+ this.collectMaterialInfo(model);
|
|
|
+ this.scene.add(model);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ collectMaterialInfo(model) {
|
|
|
+ if (!model) return;
|
|
|
+
|
|
|
+ const info = [];
|
|
|
+ const originalMaterials = new Map();
|
|
|
+
|
|
|
+ let materialCount = 0;
|
|
|
+
|
|
|
+ model.traverse((node) => {
|
|
|
+ if (node.isMesh && node.material) {
|
|
|
+ materialCount++;
|
|
|
+ const materials = Array.isArray(node.material)
|
|
|
+ ? node.material
|
|
|
+ : [node.material];
|
|
|
+
|
|
|
+ materials.forEach((material, index) => {
|
|
|
+ if (material.name === "Mesh_225") {
|
|
|
+
|
|
|
+ }
|
|
|
+ info.push(`材质 ${materialCount}-${index + 1}: ${material.type}`);
|
|
|
+ info.push(` 名称: ${material.name || "未命名"}`);
|
|
|
+ info.push(
|
|
|
+ ` 颜色: ${
|
|
|
+ material.color ? material.color.getHexString() : "无"
|
|
|
+ }`
|
|
|
+ );
|
|
|
+ info.push(` 贴图: ${material.map ? "有" : "无"}`);
|
|
|
+ info.push(` 自发光贴图: ${material.emissiveMap ? "有" : "无"}`);
|
|
|
+ info.push(
|
|
|
+ ` 金属粗糙度贴图: ${material.metalnessMap ? "有" : "无"}`
|
|
|
+ );
|
|
|
+ info.push(` 法线贴图: ${material.normalMap ? "有" : "无"}`);
|
|
|
+ info.push("---");
|
|
|
+
|
|
|
+ // 保存原始材质引用
|
|
|
+ originalMaterials.set(node.uuid + "-" + index, material);
|
|
|
+ });
|
|
|
+ }
|
|
|
});
|
|
|
+ console.log(333, info);
|
|
|
+ },
|
|
|
+
|
|
|
+ overrideMaterials() {
|
|
|
+ if (!model) return;
|
|
|
+
|
|
|
+ model.traverse((node) => {
|
|
|
+ if (node.isMesh) {
|
|
|
+ // 创建新的基本材质
|
|
|
+ const newMaterial = new THREE.MeshStandardMaterial({
|
|
|
+ color: 0x4488ff,
|
|
|
+ metalness: metalness.value,
|
|
|
+ roughness: roughness.value,
|
|
|
+ emissive: new THREE.Color(0x888888).multiplyScalar(
|
|
|
+ emissiveIntensity.value
|
|
|
+ ),
|
|
|
+ wireframe: wireframe.value,
|
|
|
+ });
|
|
|
|
|
|
- this.ThreeEngine.loadModel({
|
|
|
- fileType: "glb",
|
|
|
- dirName: "fjSolo",
|
|
|
- filePath: "./static/model/fjSolo/model.glb",
|
|
|
- }).then((model) => {
|
|
|
- console.log(1122, model);
|
|
|
- this.ThreeEngine.addObject([model]);
|
|
|
+ node.material = newMaterial;
|
|
|
+ }
|
|
|
});
|
|
|
},
|
|
|
+
|
|
|
+ // 废弃
|
|
|
+ initThreeJS() {
|
|
|
+ // 获取容器元素
|
|
|
+ const container = this.$refs.threeCanvas;
|
|
|
+
|
|
|
+ // 创建场景
|
|
|
+ const scene = new THREE.Scene();
|
|
|
+ scene.background = this.getColor("#1a1a2e");
|
|
|
+ // scene.background = this.getColor("#add8e6");
|
|
|
+ scene.add(new THREE.AmbientLight(this.getColor("#ffffff"), 2));
|
|
|
+
|
|
|
+ // 创建相机
|
|
|
+ const camera = new THREE.PerspectiveCamera(
|
|
|
+ 75,
|
|
|
+ container.clientWidth / container.clientHeight,
|
|
|
+ 0.1,
|
|
|
+ 1000
|
|
|
+ );
|
|
|
+ camera.position.z = 5;
|
|
|
+
|
|
|
+ // 创建渲染器
|
|
|
+ const renderer = new THREE.WebGLRenderer({ antialias: true });
|
|
|
+ renderer.setSize(container.clientWidth, container.clientHeight);
|
|
|
+ renderer.setPixelRatio(window.devicePixelRatio);
|
|
|
+ container.appendChild(renderer.domElement);
|
|
|
+
|
|
|
+ // 添加灯光
|
|
|
+ const light = new THREE.DirectionalLight(0xffffff, 1);
|
|
|
+ light.position.set(5, 5, 5).normalize();
|
|
|
+ scene.add(light);
|
|
|
+
|
|
|
+ // 添加轨道控制器
|
|
|
+ const controls = new OrbitControls(camera, renderer.domElement);
|
|
|
+ controls.enableDamping = true;
|
|
|
+
|
|
|
+ this.scene = scene;
|
|
|
+ this.camera = camera;
|
|
|
+ this.renderer = renderer;
|
|
|
+ // this.orbitControls = orbitControls;
|
|
|
+ // this.css3DRenderer = css3DRenderer;
|
|
|
+
|
|
|
+ // 窗口调整大小时更新渲染器
|
|
|
+ window.addEventListener("resize", () => {
|
|
|
+ camera.aspect = container.clientWidth / container.clientHeight;
|
|
|
+ camera.updateProjectionMatrix();
|
|
|
+ renderer.setSize(container.clientWidth, container.clientHeight);
|
|
|
+ });
|
|
|
+
|
|
|
+ // this.addModel({
|
|
|
+ // fileType: "glb",
|
|
|
+ // fileName: "fjSolo",
|
|
|
+ // });
|
|
|
+ },
|
|
|
},
|
|
|
};
|
|
|
</script>
|