threejs 你是我心中最亮的星

threejs 你是我心中最亮的星

研究threejs,随便搞了个demo,稍微改了改默认代码就变成下面这样了。

效果图如下:

用到了一个素材,更像是陨石或者星星。中间有个小太阳,隐隐约约泛着洁白的光晕。

素材如下:

项目地址

参考地址

项目基于vue+threejs。

思路

大体思路如下:

  1. 在屏幕中间画一个球。
  2. 在球的后边在画一个球,这个球的颜色根据时间变化忽亮忽暗。
  3. 增加很多很多的陨石。
  4. 更新陨石的位置让他们动起来,整体再来一点点小旋转。
  5. 不行了,我有点头晕。

实践

增加一个太阳

在屏幕中间画一个球。

javascript 复制代码
<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>

增加一个光晕效果

javascript 复制代码
// 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);

并在更新动画中更新时间。

javascript 复制代码
haloMaterial.uniforms.time.value += 0.005;

增加很多很多的陨石

其中这个材质需要设置成透明的,要不然总是有个小黑边不太好看。

javascript 复制代码
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;
});

让陨石动起来

整体加个旋转就更晕了,非常好~

javascript 复制代码
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;

完整代码

javascript 复制代码
<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>

最后

也是在学习过程中,如果有什么问题,欢迎在评论区留言。

如果有什么比较好的想法想做出更加晕眩的效果,也欢迎提出来,共同研究一下。

相关推荐
答案—answer3 天前
开源项目:Three.js3D模型可视化编辑系统
javascript·3d·开源·开源项目·three.js·three.js编辑器
贝格前端工场3 天前
困在像素里:我的可视化大屏项目与前端价值觉醒
前端·three.js
全栈王校长4 天前
Three.js 材质进阶
webgl·three.js
全栈王校长4 天前
Three.js Geometry进阶
webgl·three.js
烛阴5 天前
3D字体TextGeometry
前端·webgl·three.js
全栈王校长5 天前
Three.js 开发快速入门
three.js
全栈王校长5 天前
Three.js 环境搭建与开发初识
three.js
DaMu5 天前
Dreamcore3D ARPG IDE “手搓”游戏引擎,轻量级实时3D创作工具,丝滑操作,即使小白也能轻松愉快的创作出属于你自己的游戏世界!
前端·架构·three.js
烛阴7 天前
从“无”到“有”:手动实现一个 3D 渲染循环全过程
前端·webgl·three.js
烛阴8 天前
拒绝配置地狱!5 分钟搭建 Three.js + Parcel 完美开发环境
前端·webgl·three.js