threejs 你是我心中最亮的星

threejs 你是我心中最亮的星

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

效果图如下:

threejs 你是我心中最亮的星_第1张图片

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

素材如下:

threejs 你是我心中最亮的星_第2张图片

项目地址

项目基于vue+threejs。

思路

大体思路如下:

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

实践

增加一个太阳

在屏幕中间画一个球。

<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>

最后

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

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

你可能感兴趣的:(threejs,threejs)