赞
踩
地球预览视频效果
TweenJS
(动画库)用来做相机转场的动画Jquery
(这里只用到一个 each 循环方法,可以使用 js 去写)ThreeJS
(3D 地球制作)100000.json
(全国城市经纬度)d3.v6.js
用来设置平面转3D效果(本来考虑做成3D的中国地图板块,最后因效果看起来比较美观还是考虑用线条嵌入球体的方式去实现,这里有小伙伴考虑制作3D的地图板块可以下载这个库)用于获取地图的位置以及到下一个目的地的总路程,可以将实际路程转成自己配置的路程,以及正在路上的标识,可以用头像表示,经过的地方可以嵌入链接点击进行跳转
<div id="map">
<canvas id="c3d" class="c2d"></canvas>
</div>
<div id="demo"></div>
const Dom = document.querySelector("#c3d");
const width = Dom.clientWidth;
const height = Dom.clientHeight;
如果是 Vue 写的话需要从onMounted
生命周期中获取 Dom 元素
// 纹理加载器 const loader = new THREE.TextureLoader(); // 渲染器 let renderer; // 相机 let camera; // 场景 let scene; // 灯光 let light; // 相机控制 let controls; // 动画 let tween; // 其他 let earthMesh, stars, radius, labelRenderer, label, labels, labelsable, labelimg;
/** * 初始化渲染器 * */ function initRenderer() { // antialias: true, alpha: true 抗锯齿设置 renderer = new THREE.WebGLRenderer({ canvas: Dom, antialias: true, alpha: true, }); // window.devicePixelRatio 设备像素比 renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(width, height); labelRenderer = new CSS2DRenderer(); labelRenderer.domElement.style.position = "absolute"; labelRenderer.domElement.style.top = "0px"; labelRenderer.domElement.style.pointerEvents = "none"; labelRenderer.setSize(width, height); document.getElementById("map").appendChild(labelRenderer.domElement); } /** * 初始化相机 */ function initCamera() { camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000); camera.position.set(0, 0, 10); camera.lookAt(0, 0, 0); window.camera = camera; } /** * 初始化场景 */ function initScene() { scene = new THREE.Scene(); scene.background = new THREE.Color(0x1c3262); // 雾 // scene.fog = new THREE.Fog(0x020924, 200, 1000) window.scene = scene; } /** * 初始化 相机控制 */ function initControls() { controls = new OrbitControls(camera, renderer.domElement); // 阻尼惯性 controls.enableDamping = true; controls.dampingFactor = 0.1; controls.enableZoom = true; controls.autoRotate = false; controls.rotateSpeed = 0.1; controls.autoRotateSpeed = 1; controls.enablePan = true; controls.addEventListener("change", function () { //相机位置与目标观察点距离 const dis = controls.getDistance(); console.log(camera.position); }); } /** * 初始化光 */ function initLight() { // 环境光 const ambientLight = new THREE.AmbientLight(0xcccccc, 0.2); scene.add(ambientLight); // 平行光 let directionalLight = new THREE.DirectionalLight(0xffffff, 0.2); directionalLight.position.set(1, 0.1, 0).normalize(); // 平行光2 let directionalLight2 = new THREE.DirectionalLight(0xff2ffff, 0.2); directionalLight2.position.set(1, 0.1, 0.1).normalize(); scene.add(directionalLight); scene.add(directionalLight2); // 半球光 let hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 1); hemiLight.position.set(0, 1, 0); scene.add(hemiLight); // 平行光3 let directionalLight3 = new THREE.DirectionalLight(0xffffff); directionalLight3.position.set(1, -200, -20); let directionalLight4 = new THREE.DirectionalLight(0xffffff); directionalLight4.position.set(0, 500, 500); // 开启阴影 directionalLight3.castShadow = true; // 设置光边界 directionalLight3.shadow.camera.top = 18; directionalLight3.shadow.camera.bottom = -10; directionalLight3.shadow.camera.left = -52; directionalLight3.shadow.camera.right = 12; scene.add(directionalLight3); }
// 旋转队列 const rotateSlowArr = []; // 放大并透明 队列 const bigByOpacityArr = []; // 移动 队列 const moveArr = []; // 边界 绘制点集合 const lines = []; // 炫光粒子 几何体 const geometryLz = new THREE.BufferGeometry(); // 炫光粒子 透明度 let opacitys = []; /** * 渲染函数 * */ function renders(time) { time *= 0.0; // 3D对象 旋转 // _y 初始坐标 _s 旋转速度 rotateSlowArr.forEach((obj) => { obj.rotation.y = obj._y + time * obj._s; }); bigByOpacityArr.forEach(function (mesh) { // 目标 圆环放大 并 透明 mesh._s += 0.01; mesh.scale.set(1 * mesh._s, 1 * mesh._s, 1 * mesh._s); if (mesh._s <= 2) { mesh.material.opacity = 2 - mesh._s; } else { mesh._s = 1; } }); moveArr.forEach(function (mesh) { mesh._s += 0.01; let tankPosition = new THREE.Vector3(); tankPosition = mesh.curve.getPointAt(mesh._s % 1); mesh.position.set(tankPosition.x, tankPosition.y, tankPosition.z); }); if (geometryLz.attributes.position) { geometryLz.currentPos += geometryLz.pointSpeed; for (let i = 0; i < geometryLz.pointSpeed; i++) { opacitys[(geometryLz.currentPos - i) % lines.length] = 0; } for (let i = 0; i < 200; i++) { opacitys[(geometryLz.currentPos + i) % lines.length] = i / 50 > 2 ? 2 : i / 50; } geometryLz.attributes.aOpacity.needsUpdate = true; } renderer.clear(); labelRenderer.render(scene, camera); renderer.render(scene, camera); // requestAnimationFrame(renders) // earthMesh.rotation.y += 0.01 stars.rotation.y += 0.001; }
用于制作开始场景镜头动画(由远到近并附带略微旋转)
let p1 = { x: 100, y: 200, z: 200 }; function initTWEEN() { let tweena = cameraCon({ x: 100, y: 200, z: 200 }, 1000); let tweenb = cameraCon({ x: 0, y: 0, z: 10 }, 4000); tweena.chain(tweenb); // tweenb.chain(tweenc); tweenb.onComplete(function () { console.log("结束"); drawChart(); //相机位置与观察目标点最小值 controls.minDistance = 7; //相机位置与观察目标点最大值 controls.maxDistance = 50; // 上下旋转范围 /* controls.minPolarAngle = -Math.PI /6; controls.maxPolarAngle = Math.PI /4; */ // 左右旋转范围 controls.minAzimuthAngle = -Math.PI / 6; controls.maxAzimuthAngle = Math.PI / 6; }); tweena.start(); } function cameraCon(p2 = { x: p1.x, y: p1.y, z: p1.z }, time = 5000) { var tween1 = new TWEEN.Tween(p1) .to(p2, time) .easing(TWEEN.Easing.Sinusoidal.InOut); var update = function () { camera.position.set(p1.x, p1.y, p1.z); }; tween1.onUpdate(update); return tween1; } function cameraCon2( p2 = { x: camera.position.x, y: camera.position.y, z: camera.position.z }, time = 2000 ) { var tween1 = new TWEEN.Tween(camera.position) .to(p2, time) .easing(TWEEN.Easing.Sinusoidal.Out); var update = function () { camera.position.set( camera.position.x, camera.position.y, camera.position.z ); }; tween1.onUpdate(update); return tween1; } function animate() { window.requestAnimationFrame((time) => { if (controls) controls.update(); TWEEN.update(); renders(time); animate(); }); }
cameraCon2
这个动画在后面会用到,是根据滚动下方内容进行左右镜头旋转的动画效果
/** * 创建 方形纹理 * */ function generateSprite() { const canvas = document.createElement("canvas"); canvas.width = 16; canvas.height = 16; const context = canvas.getContext("2d"); // 创建颜色渐变 const gradient = context.createRadialGradient( canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2 ); gradient.addColorStop(0, "rgba(255,255,255,1)"); gradient.addColorStop(0.2, "rgba(0,255,255,1)"); gradient.addColorStop(0.4, "rgba(0,0,64,1)"); gradient.addColorStop(1, "rgba(0,0,0,1)"); // 绘制方形 context.fillStyle = gradient; context.fillRect(0, 0, canvas.width, canvas.height); // 转为纹理 const texture = new THREE.Texture(canvas); texture.needsUpdate = true; return texture; } /** * 背景绘制 * */ function bg() { const positions = []; const colors = []; // 创建 几何体 const geometry = new THREE.BufferGeometry(); for (let i = 0; i < 10000; i++) { let vertex = new THREE.Vector3(); vertex.x = Math.random() * 2 - 1; vertex.y = Math.random() * 2 - 1; vertex.z = Math.random() * 2 - 1; positions.push(vertex.x, vertex.y, vertex.z); } // 对几何体 设置 坐标 和 颜色 geometry.setAttribute( "position", new THREE.Float32BufferAttribute(positions, 3) ); // 默认球体 geometry.computeBoundingSphere(); // ------------- 1 ---------- // 星星资源图片 // ParticleBasicMaterial 点基础材质 var starsMaterial = new THREE.ParticleBasicMaterial({ map: generateSprite(), size: 2, transparent: true, opacity: 1, //true:且该几何体的colors属性有值,则该粒子会舍弃第一个属性--color,而应用该几何体的colors属性的颜色 // vertexColors: true, blending: THREE.AdditiveBlending, sizeAttenuation: true, }); // 粒子系统 网格 stars = new THREE.ParticleSystem(geometry, starsMaterial); stars.scale.set(300, 300, 300); scene.add(stars); }
此时星空就已经搭建好了,可以左右旋转试试效果
其实也就是创建一个球,然后贴个准确的贴图放在圆上调整一些光感即可
// 地球,月亮 3D层 const landOrbitObject = new THREE.Object3D(); // 地球3D层 const earthObject = new THREE.Object3D(); // 月亮3D层 const moonObject = new THREE.Object3D(); // 地球半径 const globeRadius = 5; /** * 球相关加载 * */ function earth() { radius = globeRadius; const widthSegments = 100; const heightSegments = 100; const sphereGeometry = new THREE.SphereGeometry( radius, widthSegments, heightSegments ); function shine() { var texture = loader.load("./images/blue.png"); var spriteMaterial = new THREE.SpriteMaterial({ map: texture, transparent: true, opacity: 0.5, depthWrite: false, }); var sprite = new THREE.Sprite(spriteMaterial); sprite.scale.set(radius * 3, radius * 3, 1); sprite.rotation.set(-Math.PI / 2, 0, 0); scene.add(sprite); } shine(); // 地球 const earthTexture = loader.load("./images/微信图片_20230711093004 (1).jpg"); const earthMaterial = new THREE.MeshStandardMaterial({ map: earthTexture, }); earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial); // 月球 const moonTexture = loader.load("./images/yueqiu.jpg"); const moonMaterial = new THREE.MeshPhongMaterial({ map: moonTexture }); const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial); moonMesh.scale.set(0.1, 0.1, 0.1); moonMesh.position.x = 10; moonObject.add(moonMesh); // 加入动画队列 moonObject._y = 0; moonObject._s = 1; rotateSlowArr.push(moonObject); // 地球加入 地球3D层 earthObject.add(earthMesh); earthObject.rotation.set(0.5, 2.9, 0.1); earthObject._y = 2.0; earthObject._s = 0.1; // 加入动画队列 // rotateSlowArr.push(earthObject) // 加入 地球3D层 landOrbitObject.add(earthObject); // 加入 月亮3D层 landOrbitObject.add(moonObject); scene.add(landOrbitObject); } /** * 经维度 转换坐标 * THREE.Spherical 球类坐标 * lng:经度 * lat:维度 * radius:地球半径 */ function lglt2xyz(lng, lat, radius) { // 以z轴正方向为起点的水平方向弧度值 const theta = (90 + lng) * (Math.PI / 180); // 以y轴正方向为起点的垂直方向弧度值 const phi = (90 - lat) * (Math.PI / 180); return new THREE.Vector3().setFromSpherical( new THREE.Spherical(radius, phi, theta) ); }
/** * 绘制 目标点 * */ function spotCircle(spot) { // 圆 const geometry1 = new THREE.CircleGeometry(0.02, 100); const material1 = new THREE.MeshBasicMaterial({ color: 0xff0000, side: THREE.DoubleSide, }); const circle = new THREE.Mesh(geometry1, material1); circle.position.set(spot[0], spot[1], spot[2]); // mesh在球面上的法线方向(球心和球面坐标构成的方向向量) var coordVec3 = new THREE.Vector3(spot[0], spot[1], spot[2]).normalize(); // mesh默认在XOY平面上,法线方向沿着z轴new THREE.Vector3(0, 0, 1) var meshNormal = new THREE.Vector3(0, 0, 1); // 四元数属性.quaternion表示mesh的角度状态 //.setFromUnitVectors();计算两个向量之间构成的四元数值 circle.quaternion.setFromUnitVectors(meshNormal, coordVec3); earthObject.add(circle); // 圆环 const geometry2 = new THREE.RingGeometry(0.03, 0.04, 100); // transparent 设置 true 开启透明 const material2 = new THREE.MeshBasicMaterial({ color: 0xff0000, side: THREE.DoubleSide, transparent: true, }); const circleY = new THREE.Mesh(geometry2, material2); circleY.position.set(spot[0], spot[1], spot[2]); // 指向圆心 circleY.lookAt(new THREE.Vector3(0, 0, 0)); earthObject.add(circleY); label.position.set(spot[0] - 0.15, spot[1] + 0.04, spot[2]); // 加入动画队列 bigByOpacityArr.push(circleY); }
/** * 绘制 两个目标点并连线 * */ function lineConnect(posStart, posEnd) { const v0 = lglt2xyz(posStart[0], posStart[1], globeRadius); const v3 = lglt2xyz(posEnd[0], posEnd[1], globeRadius); // angleTo() 计算向量的夹角 const angle = v0.angleTo(v3); let vtop = v0.clone().add(v3); // multiplyScalar 将该向量与所传入的 标量进行相乘 vtop = vtop.normalize().multiplyScalar(globeRadius); let n; if (angle <= 1) { n = (globeRadius / 3) * angle; } else if (angle > 1 && angle < 2) { n = (globeRadius / 3) * Math.pow(angle, 2); } else { n = (globeRadius / 3) * Math.pow(angle, 1.5); } const v1 = v0 .clone() .add(vtop) .normalize() .multiplyScalar(globeRadius + n); const v2 = v3 .clone() .add(vtop) .normalize() .multiplyScalar(globeRadius + n); // 三维三次贝塞尔曲线(v0起点,v1第一个控制点,v2第二个控制点,v3终点) const curve = new THREE.CubicBezierCurve3(v0, v1, v2, v3); // 绘制 目标位置 spotCircle([v0.x, v0.y, v0.z]); spotCircle([v3.x, v3.y, v3.z]); // 线上移动物体 moveSpot(curve); const lineGeometry = new THREE.BufferGeometry(); // 获取曲线 上的50个点 var points = curve.getPoints(50); var positions = []; var colors = []; var color = new THREE.Color(); // 给每个顶点设置演示 实现渐变 for (var j = 0; j < points.length; j++) { if (j < 25 || j == 25) { color.set(0xffffff); // 粉色 } else if (j < 50 && j > 25) { color.set(0xfffdaa); // 粉色 } colors.push(color.r, color.g, color.b); positions.push(points[j].x, points[j].y, points[j].z); } // 放入顶点 和 设置顶点颜色 lineGeometry.addAttribute( "position", new THREE.BufferAttribute(new Float32Array(positions), 3, true) ); lineGeometry.addAttribute( "color", new THREE.BufferAttribute(new Float32Array(colors), 3, true) ); const material = new THREE.LineBasicMaterial({ vertexColors: true, side: THREE.DoubleSide, }); const line = new THREE.Line(lineGeometry, material); earthObject.add(line); }
/** * 线上移动物体 * */ function moveSpot(curve) { // 线上的移动物体 const aGeo = new THREE.SphereGeometry(0.04, 0.04, 0.04); const aMater = new THREE.MeshPhongMaterial({ color: 0xff0000, side: THREE.DoubleSide, }); const aMesh = new THREE.Mesh(aGeo, aMater); // 保存曲线实例 aMesh.curve = curve; aMesh._s = 0; moveArr.push(aMesh); earthObject.add(aMesh); }
/** * 画图 * */ function drawChart() { const loader = new THREE.FileLoader(); let centers; loader.load("./js/100000_full.json", (data) => { // 点与点 let objName = [ { name: "黑龙江省", url: "https://www.baidu.com" }, { name: "内蒙古自治区" }, { name: "四川省" }, { name: "" }, ]; // 线与线 let city = [{ to: "黑龙江省" }, { to: "内蒙古自治区" }, { to: "四川省" }]; // 当前所在地 let location = [{ type: 0 }]; const jsondata = JSON.parse(data); let transformedData = []; // 循环 $.each(jsondata.features, function (index, item) { const { centroid, center, name } = item.properties; /* const point = centroid || center || [0, 0]; const depth = Math.random() * 0.3 + 0.3; */ let proName = item.properties.name; let proName1 = item.properties.name; centers = item.properties.center; objName.forEach((v) => { if (v.name == proName) { labels = createLabel(name, v.url); earthObject.add(labels); if (centers != undefined) { let markPos = lglt2xyz(centers[0], centers[1], 5); spotCircle([markPos.x, markPos.y, markPos.z]); } // lineConnect(item.properties.center,[150,100,100]) } }); let lastIndex = city.length - 2; city.map((v, index) => { if (v.to == proName1) { v.tojwd = item.properties.center; let indexNum = index + 1; if (indexNum < city.length) { let formCity = city[index]; let toCity = city[index + 1]; setTimeout(() => { let combinedCity = { to: formCity.to, tojwd: v.tojwd, form: toCity.to, formjwd: toCity.tojwd, }; if (combinedCity.formjwd != []) { let distance = getDistance( combinedCity.tojwd[0], combinedCity.tojwd[1], combinedCity.formjwd[0], combinedCity.formjwd[1] ); combinedCity.dist = distance; transformedData.push(combinedCity); const coordinates = kilometersToCoordinates( distance, combinedCity.tojwd[1], combinedCity.tojwd[0] ); console.log( "从" + combinedCity.to + "到" + combinedCity.form + "的距离为" + distance + "公里" ); // 输出两个坐标之间的距离,单位为公里 // 示例用法 if (index == lastIndex) { sessionStorage.setItem("last", JSON.stringify(combinedCity)); let par = JSON.parse(sessionStorage.getItem("last")); } else { lineConnect(combinedCity.tojwd, combinedCity.formjwd); } // lineConnect(transformedData[0].tojwd, transformedData[0].formjwd) } }, 100); } } }); location.forEach((i) => { if (i.type == item.properties.subFeatureIndex) { setTimeout(() => { let last = JSON.parse(sessionStorage.getItem("last")); console.log(last.dist); // 更换自定义路线(公里) last.dist = 300; // 将经纬度转换为三维坐标 const point1 = last.tojwd; const point2 = last.formjwd; // 个人的总步数(公里) let lucheng = 100; let bfb = lucheng / last.dist; let s = point1[0] + (point2[0] - point1[0]) * bfb * 1; let d = point1[1] + (point2[1] - point1[1]) * bfb * 1; const div = document.createElement("div"); div.style.color = "#fff"; div.style.fontSize = "14px"; div.style.textShadow = "1px 1px 2px #047cd6"; div.innerHTML = `<img style="width:30px;border-radius:50%" src="./images/head.jpg" />`; labelimg = new CSS2DObject(div); labelimg.scale.set(0.01, 0.01, 0.01); let markPos = lglt2xyz(s, d, 5); labelimg.position.set(markPos.x - 0.1, markPos.y + 0.04, markPos.z); earthObject.add(labelimg); // 定义距离为1000公里 setTimeout(() => { lineConnect(point1, [s, d]); }, 101); }, 200); } }); }); }); } function getDistance(lat1, lon1, lat2, lon2) { const R = 6371; // 地球半径,单位为公里 const rLat1 = toRadians(lat1); const rLat2 = toRadians(lat2); const deltaLat = toRadians(lat2 - lat1); const deltaLon = toRadians(lon2 - lon1); const a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + Math.cos(rLat1) * Math.cos(rLat2) * Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); const distance = R * c; return distance; } function kilometersToCoordinates(distance, latitude, longitude) { const earthRadius = 6371.393; // 地球半径,单位为公里 // 计算纬度差值 const latDiff = distance / earthRadius; // 根据纬度计算经度差值 const lonDiff = distance / (earthRadius * Math.cos((Math.PI * latitude) / 180)); // 计算新的经度和纬度 const newLatitude = latitude + latDiff * (180 / Math.PI); const newLongitude = longitude + lonDiff * (180 / Math.PI); // 返回经度和纬度 return { latitude: newLatitude, longitude: newLongitude }; }
// 将角度转换为弧度
function toRadians(degree) {
return degree * (Math.PI / 180);
}
const createLabel = (name, url) => { const div = document.createElement("div"); div.style.color = "#fff"; div.style.fontSize = "10px"; div.style.textShadow = "1px 1px 2px #047cd6"; div.textContent = name; div.style.pointerEvents = "auto"; div.style.cursor = "pointer"; label = new CSS2DObject(div); div.addEventListener("click", function (event) { if (url != undefined) { window.location.href = url; } else { return; } }); label.scale.set(0.01, 0.01, 0.01); return label; };
const vertexShader = ` attribute float aOpacity; uniform float uSize; varying float vOpacity; void main(){ gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0); gl_PointSize = uSize; vOpacity=aOpacity; } `; const fragmentShader = ` varying float vOpacity; uniform vec3 uColor; float invert(float n){ return 1.-n; } void main(){ if(vOpacity <=0.2){ discard; } vec2 uv=vec2(gl_PointCoord.x,invert(gl_PointCoord.y)); vec2 cUv=2.*uv-1.; vec4 color=vec4(1./length(cUv)); color*=vOpacity; color.rgb*=uColor; gl_FragColor=color; } `; /** * 边界炫光路径 * */ function dazzleLight() { const loader = new THREE.FileLoader(); loader.load("./js/100000.json", (data) => { const jsondata = JSON.parse(data); console.log(jsondata); // 中国边界 const feature = jsondata.features[0]; const province = new THREE.Object3D(); province.properties = feature.properties.name; // 点数据 const coordinates = feature.geometry.coordinates; coordinates.forEach((coordinate) => { // coordinate 多边形数据 coordinate.forEach((rows) => { // 绘制线 // const line = lineDraw(rows, 0xaa381e) const line = lineDraw(rows, 0xaa381e); province.add(line); }); }); // 添加地图边界 earthObject.add(province); // 拉平 为一维数组 const positions = new Float32Array(lines.flat(1)); // 设置顶点 geometryLz.setAttribute( "position", new THREE.BufferAttribute(positions, 3) ); // 设置 粒子透明度为 0 opacitys = new Float32Array(positions.length).map(() => 0); geometryLz.setAttribute("aOpacity", new THREE.BufferAttribute(opacitys, 1)); geometryLz.currentPos = 0; // 炫光移动速度 geometryLz.pointSpeed = 10; // 控制 颜色和粒子大小 const params = { pointSize: 2.0, pointColor: "#4ec0e9", }; // 创建着色器材质 const material = new THREE.ShaderMaterial({ vertexShader: vertexShader, fragmentShader: fragmentShader, transparent: true, // 设置透明 uniforms: { uSize: { value: params.pointSize, }, uColor: { value: new THREE.Color(params.pointColor), }, }, }); const points = new THREE.Points(geometryLz, material); earthObject.add(points); }); } /** * 边框 图形绘制 * @param polygon 多边形 点数组 * @param color 材质颜色 * */ let indexBol = true; function lineDraw(polygon, color) { const lineGeometry = new THREE.BufferGeometry(); const pointsArray = new Array(); polygon.forEach((row) => { // 转换坐标 const xyz = lglt2xyz(row[0], row[1], globeRadius); // 创建三维点 pointsArray.push(xyz); if (indexBol) { // 为了好看 这里只要内陆边界 lines.push([xyz.x, xyz.y, xyz.z]); } }); indexBol = false; // 放入多个点 lineGeometry.setFromPoints(pointsArray); const lineMaterial = new THREE.LineBasicMaterial({ color: color, }); return new THREE.Line(lineGeometry, lineMaterial); }
最后当 ul 中的 li 发生滚动时调用前面所执行的相机转场动画的效果
let { scrollY } = window; let currentSection = 0; window.addEventListener("scroll", () => { scrollY = window.scrollY; const newSection = Math.round(scrollY / height); console.log(newSection); console.log(camera.position); if (newSection !== currentSection) { currentSection = newSection; console.log(currentSection); if (currentSection == 0) { currentSection = newSection; // console.log('changed', currentSection) let tweena = cameraCon2(camera.position, 1000); console.log(camera.position); let tweenb = cameraCon2({ x: 0, y: 1, z: 10 }, 1000); tweena.chain(tweenb); tweena.start(); } else { currentSection = newSection; // console.log('changed', currentSection) let tweena = cameraCon2(camera.position, 1000); console.log(camera.position); let tweenb = cameraCon2({ x: 0, y: -1, z: 10 }, 1000); tweena.chain(tweenb); tweena.start(); } } });
window.onload = () => {
// 初始化
initTWEEN();
initRenderer();
initCamera();
initScene();
initLight();
initControls();
// 绘制
bg();
earth();
dazzleLight();
// 渲染
animate();
};
完整代码地址 earthling ,此项目仅用于交流学习
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。