素材:
链接: https://pan.baidu.com/s/1ZmwgNWV-fMO4JrPnCBDLBA
提取码: m1y9
关键代码:
for (let i = 0; i < 30; i++) {
// 实现光柱
let lightPillarTexture = new THREE.TextureLoader().load(
"three/light_column.webp"
);
let lightPillarGeometry = new THREE.PlaneGeometry(1, 5);
let lightPillarMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
map: lightPillarTexture,
alphaMap: lightPillarTexture,
transparent: true,
blending: THREE.AdditiveBlending,
side: THREE.DoubleSide,
depthWrite: false,
});
let lightPillar = new THREE.Mesh(
lightPillarGeometry,
lightPillarMaterial
);
// lightPillar.add(lightPillar.clone().rotateY(Math.PI / 2));
// 创建波纹扩散效果
let circlePlane = new THREE.PlaneGeometry(1, 1);
let circleTexture = new THREE.TextureLoader().load("three/label.webp");
let circleMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
map: circleTexture,
transparent: true,
blending: THREE.AdditiveBlending,
depthWrite: false,
side: THREE.DoubleSide,
});
let circleMesh = new THREE.Mesh(circlePlane, circleMaterial);
circleMesh.rotation.x = -Math.PI / 2;
circleMesh.position.set(0, -7, 0);
lightPillar.add(circleMesh);
gsap.to(circleMesh.scale, {
duration: 1 + Math.random() * 0.5,
x: 2,
y: 2,
z: 2,
repeat: -1,
delay: Math.random() * 0.5,
yoyo: true, //往返
ease: "power2.inOut",
});
// 设置光柱的位置
// lightPillar.position.set(0, 50, 0);
let lat = Math.random() * 180 - 90;
let lon = Math.random() * 360 - 180;
let position = lon2xyz(5, lon, lat);
lightPillar.position.set(position.x, position.y, position.z);
//将物体旋转转到球心O到position的向量方向上
lightPillar.quaternion.setFromUnitVectors(
new THREE.Vector3(0, 1, 0),
position.clone().normalize()
);
scene.add(lightPillar);
}
完整代码:
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
import { Reflector } from "three/examples/jsm/objects/Reflector";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import gsap from "gsap";
const lon2xyz = (R, longitude, latitude) => {
let lon = (longitude * Math.PI) / 180; // 转弧度值
const lat = (latitude * Math.PI) / 180; // 转弧度值
lon = -lon; // js坐标系z坐标轴对应经度-90度,而不是90度
// 经纬度坐标转球面坐标计算公式
const x = R * Math.cos(lat) * Math.cos(lon);
const y = R * Math.sin(lat);
const z = R * Math.cos(lat) * Math.sin(lon);
// 返回球面坐标
return new THREE.Vector3(x, y, z);
};
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 axesHelper = new THREE.AxesHelper(5, 5, 5);
scene.add(axesHelper);
//创建背景
scene.background = new THREE.Color(0x030311);
//创建星空
const vertices = [];
const colors = [];
for (let i = 0; i < 100; i++) {
const vertex = new THREE.Vector3();
vertex.x = Math.random() * 800 - 400;
vertex.y = Math.random() * 800 - 400;
vertex.z = Math.random() * 800 - 400;
vertices.push(vertex.x, vertex.y, vertex.z);
}
//创建点云星图
let starsGeometry = new THREE.BufferGeometry();
starsGeometry.setAttribute(
"position",
new THREE.BufferAttribute(new Float32Array(vertices), 3)
);
//添加纹理
const startsTexture = new THREE.TextureLoader().load("three/stars.webp");
const starsMaterial = new THREE.PointsMaterial({
size: 2,
sizeAttenuation: true, //尺寸衰减
color: 0x4d76cf,
transparent: true,
opacity: 1,
map: startsTexture,
});
let stars = new THREE.Points(starsGeometry, starsMaterial);
scene.add(stars);
// 创建地球
let earthGeometry = new THREE.SphereGeometry(5, 32, 32);
let earthTexture = new THREE.TextureLoader().load("three/map.webp");
let earthMaterial = new THREE.MeshBasicMaterial({
map: earthTexture,
});
let earth = new THREE.Mesh(earthGeometry, earthMaterial);
scene.add(earth);
//创建灯光
// const light = new THREE.DirectionalLight(0xffffff, 1);
// light.position.set(10, 10 , 0);
// scene.add(light);
// const light2 = new THREE.DirectionalLight(0xffffff, 1);
// light2.position.set(-10, 10 , 0);
// scene.add(light2);
// const light3 = new THREE.DirectionalLight(0xffffff, 1);
// light3.position.set(0, 10 , -10);
// scene.add(light3);
// const light4 = new THREE.DirectionalLight(0xffffff, 1);
// light4.position.set(0, 10 , -10);
// scene.add(light4);
// 发光地球
let lightTexture = new THREE.TextureLoader().load("three/earth.webp");
let lightEarthGeometry = new THREE.SphereGeometry(5, 32, 32);
let lightEarthMaterial = new THREE.MeshBasicMaterial({
map: lightTexture,
alphaMap: lightTexture,
blending: THREE.AdditiveBlending, //两个地球物体位置和大小相同使用何种混合模式展示
transparent: true,
});
let lightEarth = new THREE.Mesh(lightEarthGeometry, lightEarthMaterial);
scene.add(lightEarth);
// 添加地球内外发光精灵 一张平面永远正对着我们
//外发光
let spriteTexture = new THREE.TextureLoader().load("three/glow.webp");
let spriteMaterial = new THREE.SpriteMaterial({
map: spriteTexture,
color: 0x4d76cf,
transparent: true,
depthWrite: false,
depthTest: false,
blending: THREE.AdditiveBlending,
});
let sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(18, 18, 18);
scene.add(sprite);
//内发光
let spriteTexture2 = new THREE.TextureLoader().load("three/innerGlow.webp");
let spriteMaterial2 = new THREE.SpriteMaterial({
map: spriteTexture2,
color: 0x4d76cf,
transparent: true,
depthWrite: false,
depthTest: false,
blending: THREE.AdditiveBlending,
});
let sprite2 = new THREE.Sprite(spriteMaterial2);
sprite2.scale.set(14, 14, 14);
scene.add(sprite2);
for (let i = 0; i < 30; i++) {
// 实现光柱
let lightPillarTexture = new THREE.TextureLoader().load(
"three/light_column.webp"
);
let lightPillarGeometry = new THREE.PlaneGeometry(1, 5);
let lightPillarMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
map: lightPillarTexture,
alphaMap: lightPillarTexture,
transparent: true,
blending: THREE.AdditiveBlending,
side: THREE.DoubleSide,
depthWrite: false,
});
let lightPillar = new THREE.Mesh(
lightPillarGeometry,
lightPillarMaterial
);
// lightPillar.add(lightPillar.clone().rotateY(Math.PI / 2));
// 创建波纹扩散效果
let circlePlane = new THREE.PlaneGeometry(1, 1);
let circleTexture = new THREE.TextureLoader().load("three/label.webp");
let circleMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
map: circleTexture,
transparent: true,
blending: THREE.AdditiveBlending,
depthWrite: false,
side: THREE.DoubleSide,
});
let circleMesh = new THREE.Mesh(circlePlane, circleMaterial);
circleMesh.rotation.x = -Math.PI / 2;
circleMesh.position.set(0, -7, 0);
lightPillar.add(circleMesh);
gsap.to(circleMesh.scale, {
duration: 1 + Math.random() * 0.5,
x: 2,
y: 2,
z: 2,
repeat: -1,
delay: Math.random() * 0.5,
yoyo: true, //往返
ease: "power2.inOut",
});
// 设置光柱的位置
// lightPillar.position.set(0, 50, 0);
let lat = Math.random() * 180 - 90;
let lon = Math.random() * 360 - 180;
let position = lon2xyz(5, lon, lat);
lightPillar.position.set(position.x, position.y, position.z);
//将物体旋转转到球心O到position的向量方向上
lightPillar.quaternion.setFromUnitVectors(
new THREE.Vector3(0, 1, 0),
position.clone().normalize()
);
scene.add(lightPillar);
}
// 绕地球运行的月球
let moonTexture = new THREE.TextureLoader().load("three/moon.webp");
let moonMaterial = new THREE.MeshStandardMaterial({
map: moonTexture,
emissive: 0xffffff,
emissiveMap: moonTexture,
});
let moonGeometry = new THREE.SphereGeometry(1, 32, 32);
let moon = new THREE.Mesh(moonGeometry, moonMaterial);
moon.position.set(150, 0, 0);
scene.add(moon);
// 创建月球环
let moonRingTexture = new THREE.TextureLoader().load(
"three/moon_ring.webp"
);
let moonRingMaterial = new THREE.MeshBasicMaterial({
map: moonRingTexture,
transparent: true,
blending: THREE.AdditiveBlending,
side: THREE.DoubleSide,
depthWrite: false,
opacity: 0.5,
});
let moonRingGeometry = new THREE.RingGeometry(9, 18, 100);
let moonRing = new THREE.Mesh(moonRingGeometry, moonRingMaterial);
moonRing.rotation.x = -Math.PI / 2;
scene.add(moonRing);
let time = {
value: 0,
};
gsap.to(time, {
value: 1,
duration: 10,
repeat: -1,
ease: "linear",
onUpdate: () => {
moon.position.x = 18 * Math.cos(time.value * Math.PI * 2);
moon.position.z = 18 * Math.sin(time.value * Math.PI * 2);
moon.rotation.y = time.value * Math.PI * 8;
},
});
//初始化渲染器
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;
//开启物理灯光,使灯光效果更佳真实Correct(准确)
render.physicallyCorrectLights = true;
//创建轨道控制器,可以拖动,控制的是摄像头
const controls = new OrbitControls(camera, render.domElement);
//设置控制阻尼,让控制器有更真实的效果
controls.enableDamping = true;
//自动转起来
// controls.autoRotate = 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();
//画布全屏
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;
}
效果图: