最近成都找工作太难了,找工作的途中看到了很多需要熟练ThreeJS的公司,正好想起了在公司时老板提的一个要求,我需要一个星空背景;具体效果如下展示:
直接进入正题
1、创建vue项目(vue官方网站上面去看,这一步略过)
2、引入ThreeJs
npm instll three
接下来就是代码环节了
首先我们要创建一个vue的模板,在模板中需要创建一div的容器,然后给上Id为 containerStar
<div id="containerStar"></div>
引入threejs
import * as THREE from "three";
// 注意要使用控制器,需要导入OribitControls而且是在js文件当中导入
// 创建控制器的时候也是直接 new Orbitcontrols
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
创建需要使用的初始数据
data() {
return {
positions: [],
colors: [],
triangles: 10000,
};
},
初始化
初始化的时候需要创建场景对象、创建粒子系统、相机设置、创建渲染器
init() {
// 创建场景对象Scene
this.scene = new THREE.Scene();
this.creatGeometry() // 创建粒子系统
//点光源
let point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
this.scene.add(point); //点光源添加到场景中
//环境光
let ambient = new THREE.AmbientLight(0xffffff);
this.scene.add(ambient);
/**
* 相机设置
*/
let container = document.getElementById("containerStar");
this.camera = new THREE.PerspectiveCamera(70,container.clientWidth / container.clientHeight,1,100000);
// this.camera.position.set(0, 0, 0); //设置相机位置
this.camera.lookAt(this.scene.position);
// this.camera.position.z = 1;
/**
* 创建渲染器对象
*/
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setSize(container.clientWidth, container.clientHeight);
this.renderer.setClearColor(0x000000, 1); //设置背景颜色
container.appendChild(this.renderer.domElement);
//创建控件对象
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
},
创建粒子系统
creatGeometry() {
this.triangles = 10000;
this.geometry = new THREE.BufferGeometry();
this.positions = [];
this.normals = [];
this.colors = [];
const color = new THREE.Color();
const n = 800,n2 = n / 2; // triangles spread in the cube
const d = 1,d2 = d / 2; // individual triangle size
const pA = new THREE.Vector3();
const pB = new THREE.Vector3();
const pC = new THREE.Vector3();
const cb = new THREE.Vector3();
const ab = new THREE.Vector3();
for (let i = 0; i < this.triangles; i++) {
// positions
const x = Math.random() * n - n2;
const y = Math.random() * n - n2;
const z = Math.random() * n - n2;
const ax = x + Math.random() * d - d2;
const ay = y + Math.random() * d - d2;
const az = z + Math.random() * d - d2;
const bx = x + Math.random() * d - d2;
const by = y + Math.random() * d - d2;
const bz = z + Math.random() * d - d2;
const cx = x + Math.random() * d - d2;
const cy = y + Math.random() * d - d2;
const cz = z + Math.random() * d - d2;
this.positions.push(ax, ay, az);
// this.positions.push(bx, by, bz);
// this.positions.push(cx, cy, cz);
// flat face normals
pA.set(ax, ay, az);
pB.set(bx, by, bz);
pC.set(cx, cy, cz);
cb.subVectors(pC, pB);
ab.subVectors(pA, pB);
cb.cross(ab);
cb.normalize();
const nx = cb.x;
const ny = cb.y;
const nz = cb.z;
this.normals.push(nx, ny, nz);
// this.normals.push(nx, ny, nz);
// this.normals.push(nx, ny, nz);
// colors
const vx = x / n + 0.5;
const vy = y / n + 0.5;
const vz = z / n + 0.5;
color.setRGB(vx, vy, vz);
// const alpha = Math.random();
this.colors.push(color.r, color.g, color.b);
// this.colors.push(color.r, color.g, color.b);
// this.colors.push(color.r, color.g, color.b);
}
this.geometry.setAttribute("position",new THREE.Float32BufferAttribute(this.positions, 3));
this.geometry.setAttribute("color",new THREE.Float32BufferAttribute(this.colors, 3));
this.geometry.setAttribute("normal",new THREE.Float32BufferAttribute(this.normals, 3) );
this.geometry.computeBoundingSphere();
const material = new THREE.PointsMaterial({
color: 0xffffff,
size: 0.5,
alphaMap: 0x000000,
sizeAttenuation: true,
// morphTargets: false,
map: this.generateSprite(), //给粒子转变形状
});
this.mesh = new THREE.Points(this.geometry, material);
// this.mesh.matrix = true
// console.log(this.mesh,this.mesh.geometry.attributes.position );
this.group = new THREE.Group();
this.group.add(this.mesh);
this.scene.add(this.group);
},
粒子虽然已经创建了,但是还是圆形的,与我们想要的星星是不一样的,星星在运动的时候是有光晕或者尾气的。所以我们需要给粒子变形
generateSprite() {
this.canvas = document.createElement("canvas");
this.canvas.width = 20;
this.canvas.height = 20;
var context = this.canvas.getContext("2d");
var gradient = context.createRadialGradient(
this.canvas.width / 2,
this.canvas.height / 2,
0,
this.canvas.width / 2,
this.canvas.height / 2,
this.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, this.canvas.width, this.canvas.height);
var texture = new THREE.Texture(this.canvas);
texture.needsUpdate = true;
return texture;
},
最后一步就是让所有的粒子都动起来了
animate() {
requestAnimationFrame(this.animate);
this.renderer.clear();
let data = this.mesh.geometry.attributes.position.array;
// // let dataView = new DataView( buffer );
let normalData = [];
for (let i = 0; i < data.length / 3; i++) {
normalData[3 * i] = data[3 * i];
normalData[3 * i + 1] = data[3 * i + 1];
if (data[3 * i + 2] > 400) {
normalData[3 * i + 2] = -400;
} else {
normalData[3 * i + 2] = data[3 * i + 2] + 1;
}
}
this.geometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(normalData, 3)
);
this.mesh.geometry.attributes.position.needsUpdate = true;
this.renderer.render(this.scene, this.camera);
},
结语:第一次写文章不知道怎么弄就直接贴代码了,希望能满足你们的一个需求,谢谢