THREE.js 粒子没有出现在形状内

THREE.js particles not showing up inside a shape

我一直在尝试修改这个 demo。目前粒子被放置在文本几何体中,我的最终目标是相反的。我想:

  1. 用长方体、圆锥体和球体替换文本几何体。
  2. 用数字替换粒子。

所以基本上,将数字放在其中一个形状内,并设置粒子动画以延迟形成下一个形状。

首先,我尝试改变形状,让粒子和其他一切保持原样。但是,由于某种原因,粒子没有出现。我不确定为什么不渲染粒子?控制台未记录 错误

此外,将数字作为粒子的最快方法是什么?如果有人能指出我正确的方向,那就太好了。谢谢!

修改后的代码如下:

// Options
const shapes = [{
      "geoCode": new THREE.ConeGeometry(25, 50, 30),
      "color": 0x11659C,
    },
    {
      "geoCode": new THREE.SphereGeometry(25, 33, 33),
      "color": 0x8F3985,
    },
    {
      "geoCode": new THREE.BoxGeometry(50, 50, 50),
      "color": 0x029894,
    }
  ],
  triggers = document.getElementsByTagName('span'),
  particleCount = 1000,
  particleSize = .3,
  defaultAnimationSpeed = 1,
  morphAnimationSpeed = 18,
  color = '#FFFFFF';

// Renderer
const renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Ensure Full Screen on Resize
function fullScreen() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

window.addEventListener('resize', fullScreen, false)

// Scene
const scene = new THREE.Scene();

// Camera and position
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);

camera.position.y = -45;
camera.position.z = 45;

// Lighting
const light = new THREE.AmbientLight(0xFFFFFF, 1);
scene.add(light);

// Particle Vars
const particles = new THREE.Geometry();

const pMaterial = new THREE.PointsMaterial({
  size: particleSize,
});

// Texts
const loader = new THREE.FontLoader();
const typeface = 'https://dl.dropboxusercontent.com/s/bkqic142ik0zjed/swiss_black_cond.json?';

//CONTINUE

loader.load(typeface, (font) => {
  Array.from(shapes).forEach((shape, idx) => {
    shapes[idx].geometry = shapes[idx].geoCode;
    const material = new THREE.MeshLambertMaterial({
      color: shapes[idx].color,
      opacity: .5,
      transparent: true,
      wireframe: true
    });
    const mesh = new THREE.Mesh(shapes[idx].geometry, material);
    //THREE.GeometryUtils.center(shapes[idx].geometry)
    scene.add(mesh);
    shapes[idx].particles = new THREE.Geometry();
    shapes[idx].points = THREE.GeometryUtils.randomPointsInGeometry(shapes[idx].geometry, particleCount);
    createVertices(shapes[idx].particles, shapes[idx].points)
    enableTrigger(shape, idx, triggers[idx]);
  });
});

// Particles
for (var i = 0; i < shapes; i++) {

  const vertex = new THREE.Vector3();
  vertex.x = 0;
  vertex.y = 0;
  vertex.z = 0;
  particles.vertices.push(vertex);
}

function createVertices(emptyArray, points) {
  for (var p = 0; p < particleCount; p++) {
    const vertex = new THREE.Vector3();
    vertex.x = points[p]['x'];
    vertex.y = points[p]['y'];
    vertex.z = points[p]['z'];

    emptyArray.vertices.push(vertex);
  }
}

function enableTrigger(trigger, idx, el) {
  el.setAttribute('data-disabled', false);

  el.addEventListener('click', () => {
    morphTo(shapes[idx].particles, el.dataset.color);
  })

  if (idx == 0) {
    morphTo(shapes[idx].particles, el.dataset.color);
  }
}

const particleSystem = new THREE.Points(
  particles,
  pMaterial
);

particleSystem.sortParticles = true;

// Add the particles to the scene
scene.add(particleSystem);

// Animate
const normalSpeed = (defaultAnimationSpeed / 100),
  fullSpeed = (morphAnimationSpeed / 100)

let animationVars = {
  speed: normalSpeed,
  color: color,
  rotation: 100
}

function animate() {
  particleSystem.rotation.y += animationVars.speed;
  particles.verticesNeedUpdate = true;

  camera.position.z = animationVars.rotation;
  camera.position.y = animationVars.rotation;
  camera.lookAt(scene.position);

  particleSystem.material.color = new THREE.Color(animationVars.color);

  window.requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

animate();

function morphTo(newParticles, color = '#FFFFFF') {

  TweenMax.to(animationVars, 2, {
    ease: Linear.easeNone,
    color: color
  });

  particleSystem.material.color.setHex(color);

  for (const i = 0; i < particles.vertices.length; i++) {
    TweenMax.to(particles.vertices[i], 2, {
      ease: Elastic.easeOut.config(0.1, .3),
      x: newParticles.vertices[i].x,
      y: newParticles.vertices[i].y,
      z: newParticles.vertices[i].z
    })
  }
}
body {
  font-family: 'Titillium Web', sans-serif;
  margin: 0;
  overflow: hidden;
}

.triggers {
  bottom: 20px;
  color: white;
  left: 50%;
  position: absolute;
  text-align: center;
  transform: translateX(-50%);
  width: 100%;
  z-index: 10;
}

.triggers span {
  cursor: pointer;
  display: inline-block;
  font-size: 14px;
  margin: 0 20px;
  padding: 2px 4px;
  transition: opacity 0.5s, color 0.5s;
}

.triggers span[data-disabled="true"] {
  opacity: 0.3;
  pointer-events: none;
}

.triggers span:hover {
  color: red;
}
<div class="triggers">
  <span data-disabled="true" data-color="#3D8CD0">CLICK</span>
  <span data-disabled="true" data-color="#D32A7B">TO</span>
  <span data-disabled="true" data-color="#2AD37A">SWITCH</span>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js" type="text/javascript"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/605067/GeometryUtils.js" type="text/javascript"></script>

编辑: 粒子现在被渲染,更新的代码在这里 --> Fiddle

抱歉,我实际上能够修复不渲染的粒子。我正在迭代 shapes 而不是 particleCount.

// Particles
for (var i = 0; i < shapes; i++) {
                    ^^^^^^
  let vertex = new THREE.Vector3();
  vertex.x = 0;
  vertex.y = 0;
  vertex.z = 0;
  particles.vertices.push(vertex);
}

下面是加载粒子的更新代码。

// Options
const shapes = [{
      "geoCode": new THREE.ConeGeometry(25, 50, 30),
      "color": 0x11659C,
    },
    {
      "geoCode": new THREE.SphereGeometry(25, 33, 33),
      "color": 0x8F3985,
    },
    {
      "geoCode": new THREE.BoxGeometry(50, 50, 50),
      "color": 0x029894,
    }
  ],
  triggers = document.getElementsByTagName('span'),
  particleCount = 1000,
  particleSize = 3,
  defaultAnimationSpeed = 1,
  morphAnimationSpeed = 18,
  color = '#FFFFFF';

// Renderer
const renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Ensure Full Screen on Resize
function fullScreen() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

window.addEventListener('resize', fullScreen, false)

// Scene
const scene = new THREE.Scene();

// Camera and position
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);

camera.position.y = -45;
camera.position.z = 45;

// Lighting
const light = new THREE.AmbientLight(0xFFFFFF, 1);
scene.add(light);

// Particle Vars
const particles = new THREE.Geometry();

const pMaterial = new THREE.PointsMaterial({
  size: particleSize,
});

// Texts
const loader = new THREE.FontLoader();
const typeface = 'https://dl.dropboxusercontent.com/s/bkqic142ik0zjed/swiss_black_cond.json?';

//CONTINUE

loader.load(typeface, (font) => {
  Array.from(shapes).forEach((shape, idx) => {
    shapes[idx].geometry = shapes[idx].geoCode;
    const material = new THREE.MeshLambertMaterial({
      color: shapes[idx].color,
      opacity: .5,
      transparent: true,
      wireframe: true
    });
    const mesh = new THREE.Mesh(shapes[idx].geometry, material);
    //THREE.GeometryUtils.center(shapes[idx].geometry)
    scene.add(mesh);
    shapes[idx].particles = new THREE.Geometry();
    shapes[idx].points = THREE.GeometryUtils.randomPointsInGeometry(shapes[idx].geometry, particleCount);
    createVertices(shapes[idx].particles, shapes[idx].points)
    enableTrigger(shape, idx, triggers[idx]);
  });
});

// Particles
for (var i = 0; i < particleCount; i++) {

  const vertex = new THREE.Vector3();
  vertex.x = 0;
  vertex.y = 0;
  vertex.z = 0;
  particles.vertices.push(vertex);
}

function createVertices(emptyArray, points) {
  for (var p = 0; p < particleCount; p++) {
    const vertex = new THREE.Vector3();
    vertex.x = points[p]['x'];
    vertex.y = points[p]['y'];
    vertex.z = points[p]['z'];

    emptyArray.vertices.push(vertex);
  }
}

function enableTrigger(trigger, idx, el) {
  el.setAttribute('data-disabled', false);

  el.addEventListener('click', () => {
    morphTo(shapes[idx].particles, el.dataset.color);
  })

  if (idx == 0) {
    morphTo(shapes[idx].particles, el.dataset.color);
  }
}

let particleSystem = new THREE.Points(
  particles,
  pMaterial
);

particleSystem.sortParticles = true;

// Add the particles to the scene
scene.add(particleSystem);

// Animate
const normalSpeed = (defaultAnimationSpeed / 100),
  fullSpeed = (morphAnimationSpeed / 100)

let animationVars = {
  speed: normalSpeed,
  color: color,
  rotation: 100
}

function animate() {
  particleSystem.rotation.y += animationVars.speed;
  particles.verticesNeedUpdate = true;

  camera.position.z = animationVars.rotation;
  camera.position.y = animationVars.rotation;
  camera.lookAt(scene.position);

  particleSystem.material.color = new THREE.Color(animationVars.color);

  window.requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

animate();

function morphTo(newParticles, color = '#FFFFFF') {

  TweenMax.to(animationVars, 2, {
    ease: Linear.easeNone,
    color: color
  });

  particleSystem.material.color.setHex(color);

  for (let i = 0; i < particles.vertices.length; i++) {
    TweenMax.to(particles.vertices[i], 2, {
      ease: Elastic.easeOut.config(0.1, .3),
      x: newParticles.vertices[i].x,
      y: newParticles.vertices[i].y,
      z: newParticles.vertices[i].z
    })
  }
}
body {
  font-family: 'Titillium Web', sans-serif;
  margin: 0;
  overflow: hidden;
}

.triggers {
  bottom: 20px;
  color: white;
  left: 50%;
  position: absolute;
  text-align: center;
  transform: translateX(-50%);
  width: 100%;
  z-index: 10;
}

.triggers span {
  cursor: pointer;
  display: inline-block;
  font-size: 14px;
  margin: 0 20px;
  padding: 2px 4px;
  transition: opacity 0.5s, color 0.5s;
}

.triggers span[data-disabled="true"] {
  opacity: 0.3;
  pointer-events: none;
}

.triggers span:hover {
  color: red;
}
<div class="triggers">
  <span data-disabled="true" data-color="#3D8CD0">CLICK</span>
  <span data-disabled="true" data-color="#D32A7B">TO</span>
  <span data-disabled="true" data-color="#2AD37A">SWITCH</span>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js" type="text/javascript"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/605067/GeometryUtils.js" type="text/javascript"></script>

注意这个post只有粒子不渲染的解决方法。我会接受 post,它回答了我应该如何用数字替换粒子。