Skip to content

点材质

🕒 Published at:

展示线

关键代码

js
// 创建球体
const sphere = new THREE.SphereGeometry(150, 20, 20);
const material = new THREE.MeshBasicMaterial({
    wireframe: true,
    color: 0xffffff
});
const mesh = new THREE.Mesh(sphere, material);
mesh.position.set(0, 0, 0);
scene.add(mesh);

如上所见,我们渲染一个几何体其实说白了都是一些顶点连接而成的

点材质

如果我们只想渲染这些点,而不要线呢,也就是下面这样

我们可以通过点材质来实现

关键代码

js
const sphere = new THREE.SphereGeometry(150, 20, 20);
const pointsMmaterial = new THREE.PointsMaterial();
pointsMmaterial.size = 3.5;
pointsMmaterial.color = new THREE.Color(0xffff00);
// 近大远小的感觉 默认是  false就是一样大
// pointsMmaterial.sizeAttenuation = false;
const points = new THREE.Points(sphere, pointsMmaterial);
scene.add(points);

星空效果

看到这里,想起来我们之前学过的自定义顶点,那么我们是不是可以用自定义顶点来实现一个星空效果呢

关键代码

js
const geometry = new THREE.BufferGeometry();
const vertices = [];
const colors = [];

for (let i = 0; i < 10000; i++) {
    const x = Math.random() * 2000 - 1000;
    const y = Math.random() * 2000 - 1000;
    const z = Math.random() * 2000 - 1000;
    vertices.push(x, y, z);
    colors.push(Math.random(), Math.random(), Math.random());

}
// 给自定义顶点设置颜色
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
// 给自定义顶点设置位置 
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
const pointsMmaterial = new THREE.PointsMaterial();
pointsMmaterial.size = 3.5;
// 设置了颜色默认是不生效,必须开启自定义着色器
pointsMmaterial.vertexColors = true;
pointsMmaterial.color = new THREE.Color(0xffff00);
// 近大远小的感觉 默认是  false就是一样大
// pointsMmaterial.sizeAttenuation = false;
const points = new THREE.Points(geometry, pointsMmaterial);
scene.add(points);

星空效果升级

做到这里,发现都是正方形的星星,太丑了,利用图片贴图,美化下

关键代码

js
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load(star);

const geometry = new THREE.BufferGeometry();
const vertices = [];
const colors = [];

for (let i = 0; i < 10000; i++) {
    const x = Math.random() * 2000 - 1000;
    const y = Math.random() * 2000 - 1000;
    const z = Math.random() * 2000 - 1000;
    vertices.push(x, y, z);
    colors.push(Math.random(), Math.random(), Math.random());
}
// 给自定义顶点设置颜色
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
// 给自定义顶点设置位置
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
const pointsMmaterial = new THREE.PointsMaterial();
pointsMmaterial.map = texture;
// 开启透明
pointsMmaterial.transparent = true;
// 设置透明贴图
pointsMmaterial.alphaMap = texture;
pointsMmaterial.depthWrite = false;

pointsMmaterial.size = 6.5;
// 设置了颜色默认是不生效,必须开启自定义着色器
pointsMmaterial.vertexColors = true;
pointsMmaterial.color = new THREE.Color(0xffff00);
// 近大远小的感觉 默认是  false就是一样大
// pointsMmaterial.sizeAttenuation = false;
const points = new THREE.Points(geometry, pointsMmaterial);
scene.add(points);

雪花飞舞

在之前星空的贴图下其实可以实现雪花飞舞的效果,换个图片,让雪花动起来就可以了

关键代码

js
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load(xuehua);
const geometry = new THREE.BufferGeometry();
const vertices = [];
const colors = [];
for (let i = 0; i < 100000; i++) {
    const x = Math.random() * 2000 - 1000;
    const y = Math.random() * 2000 - 1000;
    const z = Math.random() * 2000 - 1000;
    vertices.push(x, y, z);
    colors.push(255, 255, 255);
}
// 给自定义顶点设置颜色
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
// 给自定义顶点设置位置
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
const pointsMmaterial = new THREE.PointsMaterial();
pointsMmaterial.map = texture;
// 开启透明
pointsMmaterial.transparent = true;
// 设置透明贴图
pointsMmaterial.alphaMap = texture;
pointsMmaterial.depthWrite = false;
pointsMmaterial.size = 14.5;
// 设置了颜色默认是不生效,必须开启自定义着色器
pointsMmaterial.vertexColors = true;
// 近大远小的感觉 默认是  false就是一样大
// pointsMmaterial.sizeAttenuation = false;
const points = new THREE.Points(geometry, pointsMmaterial);
scene.add(points);

以上雪花就完成了,怎么动起来的呢? 在render函数改变下位置就行了

js
xuehuapoints.rotation.x += 0.003;
xuehuapoints.rotation.y += 0.002;

完整代码

html
<template>
  <div id="canvas"></div>
</template>

<script setup>
import * as THREE from 'three';
import { onMounted } from 'vue';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { useRoute } from 'vue-router';
import star from '../assets/star.png';
import xuehua from '../assets/xuehua.png';

const route = useRoute();

onMounted(() => {
  const scene = new THREE.Scene();

  // 查看线的构成几何体
  if (route.query.type === '1') {
    // 创建球体
    const sphere = new THREE.SphereGeometry(150, 20, 20);
    const material = new THREE.MeshBasicMaterial({
      wireframe: true,
      color: 0xffffff
    });
    const mesh = new THREE.Mesh(sphere, material);
    mesh.position.set(0, 0, 0);
    scene.add(mesh);
  }

  // 查看点
  if (route.query.type === '2') {
    const sphere = new THREE.SphereGeometry(150, 20, 20);
    const pointsMmaterial = new THREE.PointsMaterial();
    pointsMmaterial.size = 3.5;
    pointsMmaterial.color = new THREE.Color(0xffff00);
    // 近大远小的感觉 默认是  false就是一样大
    // pointsMmaterial.sizeAttenuation = false;
    const points = new THREE.Points(sphere, pointsMmaterial);
    scene.add(points);
  }

  // 利用自定义顶点生成星河的感觉
  if (route.query.type === '3') {
    const geometry = new THREE.BufferGeometry();
    const vertices = [];
    const colors = [];

    for (let i = 0; i < 10000; i++) {
      const x = Math.random() * 2000 - 1000;
      const y = Math.random() * 2000 - 1000;
      const z = Math.random() * 2000 - 1000;
      vertices.push(x, y, z);
      colors.push(Math.random(), Math.random(), Math.random());
    }
    // 给自定义顶点设置颜色
    geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
    // 给自定义顶点设置位置
    geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
    const pointsMmaterial = new THREE.PointsMaterial();
    pointsMmaterial.size = 3.5;
    // 设置了颜色默认是不生效,必须开启自定义着色器
    pointsMmaterial.vertexColors = true;
    pointsMmaterial.color = new THREE.Color(0xffff00);
    // 近大远小的感觉 默认是  false就是一样大
    // pointsMmaterial.sizeAttenuation = false;
    const points = new THREE.Points(geometry, pointsMmaterial);
    scene.add(points);
  }
  // 贴个星星图 看上去更好看
  if (route.query.type === '4') {
    const textureLoader = new THREE.TextureLoader();
    const texture = textureLoader.load(star);

    const geometry = new THREE.BufferGeometry();
    const vertices = [];
    const colors = [];

    for (let i = 0; i < 10000; i++) {
      const x = Math.random() * 2000 - 1000;
      const y = Math.random() * 2000 - 1000;
      const z = Math.random() * 2000 - 1000;
      vertices.push(x, y, z);
      colors.push(Math.random(), Math.random(), Math.random());
    }
    // 给自定义顶点设置颜色
    geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
    // 给自定义顶点设置位置
    geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
    const pointsMmaterial = new THREE.PointsMaterial();
    pointsMmaterial.map = texture;
    // 开启透明
    pointsMmaterial.transparent = true;
    // 设置透明贴图
    pointsMmaterial.alphaMap = texture;
    pointsMmaterial.depthWrite = false;

    pointsMmaterial.size = 6.5;
    // 设置了颜色默认是不生效,必须开启自定义着色器
    pointsMmaterial.vertexColors = true;
    pointsMmaterial.color = new THREE.Color(0xffff00);
    // 近大远小的感觉 默认是  false就是一样大
    // pointsMmaterial.sizeAttenuation = false;
    const points = new THREE.Points(geometry, pointsMmaterial);
    scene.add(points);
  }
  let xuehuapoints = null;
  // 做个雪花飞舞的感觉
  if (route.query.type === '5') {
    const textureLoader = new THREE.TextureLoader();
    const texture = textureLoader.load(xuehua);
    const geometry = new THREE.BufferGeometry();
    const vertices = [];
    const colors = [];
    for (let i = 0; i < 100000; i++) {
      const x = Math.random() * 2000 - 1000;
      const y = Math.random() * 2000 - 1000;
      const z = Math.random() * 2000 - 1000;
      vertices.push(x, y, z);
      colors.push(255, 255, 255);
    }
    // 给自定义顶点设置颜色
    geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
    // 给自定义顶点设置位置
    geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
    const pointsMmaterial = new THREE.PointsMaterial();
    pointsMmaterial.map = texture;
    // 开启透明
    pointsMmaterial.transparent = true;
    // 设置透明贴图
    pointsMmaterial.alphaMap = texture;
    pointsMmaterial.depthWrite = false;
    pointsMmaterial.size = 14.5;
    // 设置了颜色默认是不生效,必须开启自定义着色器
    pointsMmaterial.vertexColors = true;
    // 近大远小的感觉 默认是  false就是一样大
    // pointsMmaterial.sizeAttenuation = false;
    const points = new THREE.Points(geometry, pointsMmaterial);
    xuehuapoints = points;
    scene.add(points);
  }

  // 创建渲染器
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.shadowMap.enabled = true;
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 注意 位置不要太大  不然可能会让后面的往上飞的感觉
  const camera = new THREE.PerspectiveCamera(60, 
  window.innerWidth / window.innerHeight, 1, 
  route.query.type === '5' ? 300 : 3000);
  camera.position.set(2, 142, 407);
  camera.lookAt(0, 0, 0);

  const controls = new OrbitControls(camera, renderer.domElement);
  document.getElementById('canvas').appendChild(renderer.domElement);

  function render() {
    renderer.render(scene, camera);
    // 让雪花动起来
    if (route.query.type === '5') {
      xuehuapoints.rotation.x += 0.003;
      xuehuapoints.rotation.y += 0.002;
      //   xuehuapoints.rotation.z += 0.002;
    }
    requestAnimationFrame(render);
  }
  render();

  window.onresize = () => {
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
  };
});
</script>