import { ref } from "vue"; import { Scene, PerspectiveCamera, Clock, WebGLRenderer, AmbientLight, Color, PlaneGeometry, Mesh, HemisphereLight, Group, Raycaster, Vector2, // PointLight, // PointLightHelper, // FogExp2, // Vector2, } from "three"; import { OrbitControls } from "three/addons/controls/OrbitControls.js"; // import Stats from "three/addons/libs/stats.module.js"; import { getImg } from "@/utils"; import { Reflector } from "three/examples/jsm/objects/Reflector.js"; import { getBottomMaterial } from "./material"; import { modelGroup, initModels } from "./models"; import { lineGroup, lineLabelGroup, initBuildGirdLines } from "./lines"; import { vfxGroup } from "./vfx"; import { CSS3DRenderer } from "three/examples/jsm/renderers/CSS3DRenderer.js"; import { Easing, Tween, update } from "@tweenjs/tween.js"; // import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js"; // import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass.js"; // import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js"; // import { OutputPass } from "three/examples/jsm/postprocessing/OutputPass.js"; export function useScene({ modelClick }: { modelClick: (model: any) => void }) { //@ts-ignore let stats: any, clock: any, controls: any; let camera: any, scene: any, renderer: any, mixer: any, verticalMirror: any, geometry: any, css3Renderer: any; // bloomComposer: any, // finalComposer: any; const containerRef = ref(null); const raycaster = new Raycaster(); const mouse = new Vector2(); // const params = { // threshold: 0, // strength: 1, // radius: 0.5, // exposure: 1, // }; function init() { // console.log([containerRef.value], containerRef.value!.clientWidth,containerRef.value!.clientHeight); camera = new PerspectiveCamera( 25, containerRef.value!.clientWidth / containerRef.value!.clientHeight, 1, 1000 ); camera.position.set( 18.416546632171155, 12.90089079540779, -16.681357401983476 ); scene = new Scene(); // @ts-ignore window.scene = scene; // scene.background = new Color(0xefd1b5); clock = new Clock(); const group = new Group(); group.name = "智慧能源"; //雾-指数 // scene.fog = new FogExp2(0xcccccc, 0.002); //加载模型 initModels(); //线 initBuildGirdLines(); group.add(modelGroup, lineGroup, lineLabelGroup, vfxGroup); scene.add(group); //环境光 const ambientLight = new AmbientLight(0xffffff, 0.6); scene.add(ambientLight); //半球光 const directionalLight = new HemisphereLight(0xffffff, 0x080820, 1); directionalLight.position.set(0, 1000, 0); scene.add(directionalLight); //底部平面 geometry = new PlaneGeometry(1, 1); // 创建材质,可以设置贴图 let material = getBottomMaterial( "#ffffff", // 设置模型的颜色 getImg("models/bg.png"), 1, 5 ); // 创建平面网格 let plane = new Mesh(geometry, material); plane.scale.set(192, 108, 108); plane.position.y = 0.01; plane.rotateX(-Math.PI / 2); let plane2 = plane.clone(); plane2.material = getBottomMaterial( "#ffffff", // 设置模型的颜色 getImg("models/bg.png"), 2, 5 ); scene.add(plane2); scene.add(plane); //镜面 verticalMirror = new Reflector(geometry, { clipBias: 0.003, textureWidth: containerRef.value!.clientWidth * window.devicePixelRatio * 0.5, textureHeight: containerRef.value!.clientHeight * window.devicePixelRatio * 0.5, color: new Color("#326973"), }); verticalMirror.scale.set(100, 100, 100); verticalMirror.position.y = 0; verticalMirror.position.z = 0; verticalMirror.rotateX(-Math.PI / 2); scene.add(verticalMirror); //渲染器 renderer = new WebGLRenderer({ antialias: true }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize( containerRef.value!.clientWidth, containerRef.value!.clientHeight ); containerRef.value!.appendChild(renderer.domElement); //控制器 controls = new OrbitControls(camera, renderer.domElement); controls.screenSpacePanning = false; controls.maxPolarAngle = Math.PI / 2.1; controls.minDistance = 5; controls.maxDistance = 40; setControlsVeiw( { x: -4.92927755506738, y: 1.9591040557652486e-19, z: -3.0835424654787844, }, { x: 21.791887493897622, y: 15.919334531990208, z: -21.407410138122152, } ); // controls.target.set(-4.7582917376881415, 0, -2.9423607740176285); // controls.update(); // const renderScene = new RenderPass(scene, camera); // const bloomPass = new UnrealBloomPass( // new Vector2(window.innerWidth, window.innerHeight), // 1.5, // 0.4, // 0.85 // ); // bloomPass.threshold = params.threshold; // bloomPass.strength = params.strength; // bloomPass.radius = params.radius; // bloomComposer = new EffectComposer(renderer); // bloomComposer.renderToScreen = false; // bloomComposer.addPass(renderScene); // bloomComposer.addPass(bloomPass); // const outputPass = new OutputPass(); // finalComposer = new EffectComposer(renderer); // finalComposer.addPass(renderScene); // finalComposer.addPass(outputPass); // @ts-ignore // window.camera = camera; // // @ts-ignore // window.controls = controls; window.getCamera = () => { return [controls.target, controls.object.position]; }; //性能监控 // stats = new Stats(); // stats.dom.style.position = "absolute"; // stats.dom.style.top = "10%"; // stats.dom.style.left = "25%"; // containerRef.value!.appendChild(stats.dom); // 创建一个CSS3渲染器CSS3DRenderer css3Renderer = new CSS3DRenderer(); css3Renderer.setSize( containerRef.value!.clientWidth, containerRef.value!.clientHeight ); // HTML标签
外面父元素叠加到canvas画布上且重合 css3Renderer.domElement.style.position = "absolute"; css3Renderer.domElement.style.top = "0px"; //设置.pointerEvents=none,解决HTML元素标签对threejs canvas画布鼠标事件的遮挡 css3Renderer.domElement.style.pointerEvents = "none"; css3Renderer.domElement.style.className = "css3Renderer"; containerRef.value!.appendChild(css3Renderer.domElement); //监听窗口变化 window.addEventListener("resize", onWindowResize); window.addEventListener("click", onMouseClick); } function onMouseClick(event: any) { // calculate mouse position in normalized device coordinates // (-1 to +1) for both components mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; // 通过鼠标点的位置和当前相机的矩阵计算出raycaster raycaster.setFromCamera(mouse, camera); // 获取raycaster直线和所有模型相交的数组集合 let intersects = raycaster.intersectObjects(modelGroup.children); // console.log(intersects); //将所有的相交的模型的颜色设置为红色 // for (let i = 0; i < intersects.length; i++) { // //@ts-ignore // intersects[i].object.material.color.set(0xff0000); // } if (intersects.length > 0) modelClick(intersects[0].object); } function flyTo(target: any) { new Tween(controls.object.position) .to(target.position, target.time || 500) // Move to (300, 200) in 1 second. .easing(Easing.Quadratic.InOut) // Use an easing function to make the animation smooth. .onUpdate(() => {}) .start(); // Start the tween immediately.; new Tween(controls.target) .to(target.targetContent, target.time || 500) // Move to (300, 200) in 1 second. .easing(Easing.Quadratic.InOut) // Use an easing function to make the animation smooth. .onUpdate(() => {}) .start(); // Start the tween immediately.;; } function onWindowResize() { camera.aspect = containerRef.value!.clientWidth / containerRef.value!.clientHeight; camera.updateProjectionMatrix(); css3Renderer.setSize( containerRef.value!.clientWidth, containerRef.value!.clientHeight ); renderer.setSize( containerRef.value!.clientWidth, containerRef.value!.clientHeight ); verticalMirror .getRenderTarget() .setSize( containerRef.value!.clientWidth * window.devicePixelRatio, containerRef.value!.clientHeight * window.devicePixelRatio ); } function animate() { update(); controls.update(); requestAnimationFrame(animate); render(); // stats.update(); } function render() { const delta = clock.getDelta(); if (mixer !== undefined) { mixer.update(delta); } // bloomComposer.render(); // finalComposer.render(); css3Renderer.render(scene, camera); renderer.render(scene, camera); } function setControlsVeiw(targetContent: any, position: any) { flyTo({ targetContent, position }); // controls.target.set(targetContent.x, targetContent.y, targetContent.z); // controls.object.position.set(position.x, position.y, position.z); // controls.update(); } return { containerRef, init, animate, setControlsVeiw, }; }