threejs 你是我心中最亮的星
研究threejs,随便搞了个demo,稍微改了改默认代码就变成下面这样了。
效果图如下:
用到了一个素材,更像是陨石或者星星。中间有个小太阳,隐隐约约泛着洁白的光晕。
素材如下:
项目基于vue+threejs。
思路
大体思路如下:
- 在屏幕中间画一个球。
- 在球的后边在画一个球,这个球的颜色根据时间变化忽亮忽暗。
- 增加很多很多的陨石。
- 更新陨石的位置让他们动起来,整体再来一点点小旋转。
- 不行了,我有点头晕。
实践
增加一个太阳
在屏幕中间画一个球。
<script setup>
import * as THREE from 'three';
import { onMounted } from 'vue';
import pointImage from './assets/point.png'
const scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x4AB0F9, 0.015);
// scene.background = new THREE.Color(0xffffff);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// Create a sphere
var sphereGeometry = new THREE.SphereGeometry(3, 32, 32);
var sphereMaterial = new THREE.MeshBasicMaterial({color: 0xF3DC6B});
sphereMaterial.fog = false
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.position.set(0, 0, -80);
scene.add(sphere);
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
onMounted(() => {
let canvas = document.getElementById('can');
renderer = new THREE.WebGLRenderer({canvas: canvas});
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
<template>
<div id="content">
<canvas id="can"></canvas>
</div>
</template>
<style scoped>
#content {
width: 100%;
height: 100%;
overflow: hidden;
}
#can {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
增加一个光晕效果
// Create a halo
var haloGeometry = new THREE.SphereGeometry(6, 32, 32);
var haloMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0.0 }
},
vertexShader: `
varying vec3 vNormal;
varying vec2 vUv;
void main() {
vUv = uv;
vNormal = normalize(normalMatrix * normal);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
varying vec3 vNormal;
varying vec2 vUv;
uniform float time;
void main() {
float intensity = pow(0.1 + 0.3 * (sin(time * 4.0) + 1.0)/2.0 - dot(vNormal, vec3(0.0, 0.0, 1.0)), 2.0);
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0) * intensity;
}
`,
side: THREE.BackSide,
blending: THREE.AdditiveBlending,
transparent: true
});
var halo = new THREE.Mesh(haloGeometry, haloMaterial);
halo.position.set(0, 0, -81);
scene.add(halo);
并在更新动画中更新时间。
haloMaterial.uniforms.time.value += 0.005;
增加很多很多的陨石
其中这个材质需要设置成透明的,要不然总是有个小黑边不太好看。
import pointImage from './assets/point.png'
var geometry = new THREE.BufferGeometry();
var positionVertices = [];
// Create particles
var particleCount = 5000;
for (var i = 0; i < particleCount; i++) {
var x = THREE.MathUtils.randFloatSpread(200);
var y = THREE.MathUtils.randFloatSpread(200);
var z = THREE.MathUtils.randFloatSpread(200);
positionVertices.push(x, y, z);
}
// Add positionVertices to the geometry
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positionVertices, 3));
// Create a material
var material = new THREE.PointsMaterial({ color: 0xefefef });
material.transparent = true
// Create a points object and add it to the scene
var points = new THREE.Points(geometry, material);
scene.add(points);
const loader = new THREE.TextureLoader();
loader.load(pointImage, function (texture) {
material.map = texture;
material.needsUpdate = true;
});
让陨石动起来
整体加个旋转就更晕了,非常好~
var positions = points.geometry.attributes.position.array;
for (var i = 0; i < positions.length; i += 3) {
positions[i+2] = positions[i+2] + 0.05;
if (positions[i+2] > 100) {
positions[i+2] = -100;
}
}
points.rotation.z += 0.001;
points.geometry.attributes.position.needsUpdate = true;
完整代码
<script setup>
import * as THREE from 'three';
import { onMounted } from 'vue';
import pointImage from './assets/point.png'
const scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x4AB0F9, 0.015);
scene.background = new THREE.Color(0xffffff);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
var geometry = new THREE.BufferGeometry();
var positionVertices = [];
// Create particles
var particleCount = 5000;
for (var i = 0; i < particleCount; i++) {
var x = THREE.MathUtils.randFloatSpread(200);
var y = THREE.MathUtils.randFloatSpread(200);
var z = THREE.MathUtils.randFloatSpread(200);
positionVertices.push(x, y, z);
}
// Add positionVertices to the geometry
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positionVertices, 3));
// Create a material
var material = new THREE.PointsMaterial({ color: 0xefefef });
material.transparent = true
// Create a points object and add it to the scene
var points = new THREE.Points(geometry, material);
scene.add(points);
const loader = new THREE.TextureLoader();
loader.load(pointImage, function (texture) {
material.map = texture;
material.needsUpdate = true;
});
// Create a sphere
var sphereGeometry = new THREE.SphereGeometry(3, 32, 32);
var sphereMaterial = new THREE.MeshBasicMaterial({color: 0xF3DC6B});
sphereMaterial.fog = false
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.position.set(0, 0, -80);
scene.add(sphere);
// Create a halo
var haloGeometry = new THREE.SphereGeometry(6, 32, 32);
var haloMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0.0 }
},
vertexShader: `
varying vec3 vNormal;
varying vec2 vUv;
void main() {
vUv = uv;
vNormal = normalize(normalMatrix * normal);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
varying vec3 vNormal;
varying vec2 vUv;
uniform float time;
void main() {
float intensity = pow(0.1 + 0.3 * (sin(time * 4.0) + 1.0)/2.0 - dot(vNormal, vec3(0.0, 0.0, 1.0)), 2.0);
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0) * intensity;
}
`,
side: THREE.BackSide,
blending: THREE.AdditiveBlending,
transparent: true
});
var halo = new THREE.Mesh(haloGeometry, haloMaterial);
halo.position.set(0, 0, -81);
scene.add(halo);
function animate() {
requestAnimationFrame(animate);
haloMaterial.uniforms.time.value += 0.005;
var positions = points.geometry.attributes.position.array;
for (var i = 0; i < positions.length; i += 3) {
positions[i+2] = positions[i+2] + 0.05;
if (positions[i+2] > 100) {
positions[i+2] = -100;
}
}
points.rotation.z += 0.001;
points.geometry.attributes.position.needsUpdate = true;
renderer.render(scene, camera);
}
animate();
onMounted(() => {
let canvas = document.getElementById('can');
renderer = new THREE.WebGLRenderer({canvas: canvas});
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
<template>
<div id="content">
<canvas id="can"></canvas>
</div>
</template>
<style scoped>
#content {
width: 100%;
height: 100%;
overflow: hidden;
}
#can {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
最后
也是在学习过程中,如果有什么问题,欢迎在评论区留言。
如果有什么比较好的想法想做出更加晕眩的效果,也欢迎提出来,共同研究一下。