ThreeJS |
您所在的位置:网站首页 › 圣诞节卡通卡片 › ThreeJS |
import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader"; import { Water } from "three/examples/jsm/objects/Water2"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import gsap from "gsap"; export default { name: "HOME", components: { // vueQr, // glHome, }, data() { return {}; }, mounted() { //使用控制器控制3D拖动旋转OrbitControls //控制3D物体移动 //1.创建场景 const scene = new THREE.Scene(); //2.创建相机 const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 20000 ); //设置相机位置 camera.position.set(0, 0, 10); //将相机添加到场景 scene.add(camera); //初始化渲染器 const render = new THREE.WebGLRenderer({ //设置抗锯齿,防失真 antialis: true, //对数深度缓冲区,防止模型闪烁 logarithmicdepthbuffer: true, }); /*设置场景渲染编码threejs将贴图的编码都默认设置为THREE.LinearEncoding, *导致图片色彩失真(色彩不像正常那么鲜艳,会灰蒙蒙的),所以务必将场景中的所有贴图的编码都调整为THREE.sRGBEncoding */ render.outputEncoding = THREE.sRGBEncoding; //设置渲染器的尺寸 render.setSize(window.innerWidth, window.innerHeight); //清除默认设置颜色 render.setClearColor("#000"); //设置曝光类型(电影类型、文本类型、游戏类型),电影类型 render.toneMapping = THREE.ACESFilmicToneMapping; //曝光强度 render.toneMappingExposure = 0.5; //开启物理灯光 render.physicallyCorrectLights = true; //创建轨道控制器,可以拖动,控制的是摄像头 const controls = new OrbitControls(camera, render.domElement); //控制器焦点,需要随着相机的更新而更新 controls.target.set(-8, 2, 0); //设置控制阻尼,让控制器有更真实的效果 controls.enableDamping = true; //将webgl渲染的canvas内容添加到body上 document.getElementById("three_div").appendChild(render.domElement); //渲染下一帧的时候就会调用回调函数 let renderFun = () => { //更新阻尼数据 controls.update(); //需要重新绘制canvas画布 render.render(scene, camera); //监听屏幕刷新(60HZ,120HZ),每次刷新触发一次requestAnimationFrame回调函数 //但是requestAnimationFrame的回调函数注册生命只有一次,因此需要循环注册,才能达到一直调用的效果 window.requestAnimationFrame(renderFun); }; // window.requestAnimationFrame(renderFun); renderFun(); //添加灯光 const light = new THREE.DirectionalLight(0xffffff, 1); scene.add(light); //加载模型 const sceneLoader = new GLTFLoader().setPath("three/glb/"); //创建解码器 const dencoderLoader = new DRACOLoader().setDecoderPath( "three/draco/gltf/" ); sceneLoader.setDRACOLoader(dencoderLoader); sceneLoader.load("christmas .glb", (loader) => { console.log(loader); const model = loader.scene; model.traverse((child) => { //隐藏模型水面 if (child.name == "Plane") { child.visible = false; } if (child.isMesh) { child.castShadow = true; child.receiveShadow = true; } }); scene.add(model); }); //加入自己的水面 const waterPlane = new THREE.CircleBufferGeometry(400, 100); const textureLoader = new THREE.TextureLoader(); const waterMesh = new Water(waterPlane, { textureWidth: 1024, textureHeight: 1024, color: 0xeeeeff, flowDirection: new THREE.Vector2(1, 1), scale: 100, flowMap: textureLoader.load("three/textures/water/Water_1_M_Flow.webp"), normalMap1: textureLoader.load( "three/textures/water/Water_1_M_Normal.webp" ), normalMap2: textureLoader.load( "three/textures/water/Water_2_M_Normal.webp" ), }); waterMesh.rotation.x = -Math.PI / 2; waterMesh.position.y = -0.7; scene.add(waterMesh); //添加场景背景 const rgbeLoader = new RGBELoader(); rgbeLoader.loadAsync("three/christmas-sky.hdr").then((load) => { //将用于等距圆柱投影的环境贴图,也被叫做经纬线映射贴图。 //等距圆柱投影贴图表示沿着其水平中线360°的视角,以及沿着其垂直轴向180°的视角。 //贴图顶部和底部的边缘分别对应于它所映射的球体的北极和南极。 load.mapping = THREE.EquirectangularReflectionMapping; scene.background = load; scene.environment = load; }); //屋子创建灯光 const hotelLight = new THREE.PointLight(0xffffff, 1); hotelLight.position.set(0, 2.4, 0); scene.add(hotelLight); render.shadowMap.enabled = true; //开启灯光动态投影 hotelLight.castShadow = true; //创建灯光组 const lightGroup = new THREE.Group(); lightGroup.position.set(-8, 2.5, -1.5); for (let index = 0; index < 3; index++) { const geometry = new THREE.SphereBufferGeometry(0.2, 50, 5); const material = new THREE.MeshBasicMaterial({ color: 0xffffff, emissive: 0xffffff, emissiveintensity: 10, }); const mesh = new THREE.Mesh(geometry, material); const light = new THREE.PointLight(0xffff, 1); mesh.add(light); mesh.position.set( Math.cos(Math.random()) * 3, Math.cos(Math.random()) * 1, Math.sin(Math.random()) * 3 ); lightGroup.add(mesh); } console.log("组", lightGroup); scene.add(lightGroup); let options = { angle: 0, }; gsap.to(options, { angle: Math.PI * 2, duration: 10, repeat: -1, //无线循环 ease: "linear", onUpdate: () => { lightGroup.children.forEach((elem, index) => { elem.position.set( Math.cos(options.angle + (Math.PI / 2) * index) * 3, Math.cos(3 * options.angle) * 1, Math.sin(options.angle + (Math.PI / 2) * index) * 3 ); }); }, }); // 使用补间动画移动相机 let timeLine1 = gsap.timeline(); let timeline2 = gsap.timeline(); // 定义相机移动函数 function translateCamera(position, target) { timeLine1.to(camera.position, { x: position.x, y: position.y, z: position.z, duration: 1, ease: "power2.inOut", }); timeline2.to(controls.target, { x: target.x, y: target.y, z: target.z, duration: 1, ease: "power2.inOut", }); } // 实例化创建漫天星星 let starsInstance = new THREE.InstancedMesh( new THREE.SphereGeometry(0.1, 32, 32), new THREE.MeshStandardMaterial({ color: 0xffffff, emissive: 0xffffff, emissiveIntensity: 10, }), 100 ); // 星星随机到天上 let starsArr = []; let endArr = []; for (let i = 0; i < 100; i++) { let x = Math.random() * 100 - 50; let y = Math.random() * 100 - 50; let z = Math.random() * 100 - 50; starsArr.push(new THREE.Vector3(x, y, z)); let matrix = new THREE.Matrix4(); matrix.setPosition(x, y, z); starsInstance.setMatrixAt(i, matrix); } scene.add(starsInstance); // 创建爱心路径 let heartShape = new THREE.Shape(); heartShape.moveTo(25, 25); heartShape.bezierCurveTo(25, 25, 20, 0, 0, 0); heartShape.bezierCurveTo(-30, 0, -30, 35, -30, 35); heartShape.bezierCurveTo(-30, 55, -10, 77, 25, 95); heartShape.bezierCurveTo(60, 77, 80, 55, 80, 35); heartShape.bezierCurveTo(80, 35, 80, 0, 50, 0); heartShape.bezierCurveTo(35, 0, 25, 25, 25, 25); // 根据爱心路径获取点 let center = new THREE.Vector3(0, 2, 10); for (let i = 0; i < 100; i++) { let point = heartShape.getPoint(i / 100); endArr.push( new THREE.Vector3( point.x * 0.1 + center.x, point.y * 0.1 + center.y, center.z ) ); } // 创建爱心动画 function makeHeart() { let params = { time: 0, }; gsap.to(params, { time: 1, duration: 1, onUpdate: () => { for (let i = 0; i < 100; i++) { let x = starsArr[i].x + (endArr[i].x - starsArr[i].x) * params.time; let y = starsArr[i].y + (endArr[i].y - starsArr[i].y) * params.time; let z = starsArr[i].z + (endArr[i].z - starsArr[i].z) * params.time; let matrix = new THREE.Matrix4(); matrix.setPosition(x, y, z); starsInstance.setMatrixAt(i, matrix); } starsInstance.instanceMatrix.needsUpdate = true; }, }); } function restoreHeart() { let params = { time: 0, }; gsap.to(params, { time: 1, duration: 1, onUpdate: () => { for (let i = 0; i < 100; i++) { let x = endArr[i].x + (starsArr[i].x - endArr[i].x) * params.time; let y = endArr[i].y + (starsArr[i].y - endArr[i].y) * params.time; let z = endArr[i].z + (starsArr[i].z - endArr[i].z) * params.time; let matrix = new THREE.Matrix4(); matrix.setPosition(x, y, z); starsInstance.setMatrixAt(i, matrix); } starsInstance.instanceMatrix.needsUpdate = true; }, }); } let scenes = [ { text: "圣诞快乐", callback: () => { // 执行函数切换位置 translateCamera( new THREE.Vector3(-3.23, 3, 4.06), new THREE.Vector3(-8, 2, 0) );
}, }, { text: "感谢在这么大的世界里遇见了你", callback: () => { // 执行函数切 translateCamera( new THREE.Vector3(7, 0, 23), new THREE.Vector3(0, 0, 0) ); }, }, { text: "愿与你探寻世界的每一个角落", callback: () => { // 执行函数切 translateCamera( new THREE.Vector3(10, 3, 0), new THREE.Vector3(5, 2, 0) ); }, }, { text: "愿将天上的星星送给你", callback: () => { // 执行函数切 translateCamera( new THREE.Vector3(7, 0, 23), new THREE.Vector3(0, 0, 0) ); makeHeart(); }, }, { text: "愿疫情结束,大家健康快乐!", callback: () => { // 执行函数切 translateCamera( new THREE.Vector3(-20, 1.3, 6.6), new THREE.Vector3(5, 2, 0) ); }, }, ]; let index = 0; let isAnimate = false; //创建滑轮滚动切换摄像头位置 window, addEventListener("wheel", (e) => { if (isAnimate) return; isAnimate = true; if (e.deltaY > 0) { index++; index %= scenes.length; if(index == 0){ restoreHeart(); } console.log(index); } scenes[index].callback(); setTimeout(() => { isAnimate = false; }, 1000); }); //画布全屏 window.addEventListener("dblclick", () => { if (document.fullscreenElement) { document.exitFullscreen(); } else { //document.documentElement.requestFullscreen(); render.domElement.requestFullscreen(); } }); //监听画面变化,更新渲染画面,(自适应的大小) window.addEventListener("resize", () => { //更新摄像机的宽高比 camera.aspect = window.innerWidth / window.innerHeight; //更新摄像机的投影矩阵 camera.updateProjectionMatrix(); //更新渲染器宽度和高度 render.setSize(window.innerWidth, window.innerHeight); //设置渲染器的像素比 render.setPixelRatio(window.devicePixelRatio); }); }, methods: {}, }; * { margin: 0; padding: 0; } .home-content { position: fixed; top: 0; right: 20px; } .select-item-color { width: 50px; height: 50px; border: 1px solid #ccc; margin: 10px; display: inline-block; cursor: pointer; border-radius: 10px; } .select { display: flex; } |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |