循环顶点时未完全绘制粒子球体

时间:2017-09-30 18:18:54

标签: three.js

我在THREEJS中绘制一个带有粒子的球体。这很好。

然而,我将这些点循环到动画(重新定位它们)。当我使用50以下的widthSegments(WidthSegement是第二个参数)时工作得很好。超过50的任何东西都将停止被吸引。

供参考:

SphereGeometry(radius, widthSegments, heightSegments)

这样可以正常工作:

let geometry = new THREE.SphereGeometry(30, 50, 20);

并产生这种效果:Sphere with arguments(30,50,20)

如果我使用100个段,例如我会得到这个结果: enter image description here

然而,这只发生在我通过点循环以改变它们的位置时。

它仍然激发了现有的观点。但不是任何其他人。



//Related to the audio api
let AudioContext = window.AudioContext || window.webkitAudioContext,
  ctxAudio = new AudioContext(),
  sampleRate = ctxAudio.sampleRate,
  audio = document.getElementById("sound"),
  audioSrc = ctxAudio.createMediaElementSource(audio),
  analyser = ctxAudio.createAnalyser(),
  bufferLength = analyser.frequencyBinCount,
  dataArray = new Uint8Array(bufferLength);
analyser.fftSize = 2048 * 2;
analyser.smoothingTimeConstant = 0.75;
audioSrc.connect(analyser);
audioSrc.connect(ctxAudio.destination);

//Setting up the renderer
let renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

//Defining the objects in the scene
let geometry = new THREE.SphereGeometry(30, 100, 20);
let loader = new THREE.TextureLoader();
loader.crossOrigin = true;
let particleTexture = loader.load('https://threejs.org/examples/textures/particle2.png');
let material = new THREE.PointsMaterial({
  color: 0x20C9BD,
  size: 1,
  transparent: true,
  blending: THREE.AdditiveBlending,
  map: particleTexture,
  depthWrite: false
});

let points = new THREE.Points(geometry, material);
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);


//Setting the scene
scene.add(points);
camera.position.z = 100;

//Copy the default sphere into a vector
const def = new THREE.Vector3;
for (let i = 0; i < geometry.vertices.length; i++) {
  def[i] = {
    x: geometry.vertices[i].x,
    y: geometry.vertices[i].y,
    z: geometry.vertices[i].z
  };
}

//Render the scene(looping through it 60 times a second)
//This is where the issue is
function render() {
  requestAnimationFrame(render);
  analyser.getByteFrequencyData(dataArray);
  camera.lookAt(points.position);
  for (let i = 0; i < geometry.vertices.length; i++) {
    let particle = geometry.vertices[i];
    let dx = def[i].x * (dataArray[i] / 255.0) + def[i].x;
    let dy = def[i].y * (dataArray[i] / 255.0) + def[i].y;
    let dz = def[i].z * (dataArray[i] / 255.0) + def[i].z;
    particle.set(dx, dy, dz); //<--this is where the issue is.
  }
  geometry.verticesNeedUpdate = true;
  renderer.render(scene, camera);
}
render();
&#13;
<script src="https://rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../js/three.js"></script>
</head>

<body>
  <audio id="sound" controls src="http://tackj.happyvisocoders.be/audio/DieForYou-Starset.mp3"></audio>
</body>

</html>
&#13;
&#13;
&#13;

如果你注释掉了particle.set(dx,dy,dz),它会完美地绘制。 然而,这会使粒子与音乐一起移动。因此保持这一部分非常重要。

为什么球体没有完全绘制,我该如何解决这个问题呢?

1 个答案:

答案 0 :(得分:2)

这实际上与three.js关系不大,但与webaudio-API有关。

当您创建FFT大小为2048的分析仪时,您将获得1024个频率区间(请参阅analyzer.frequencyBinCount),但您的几何体有1902个顶点。因此,对于索引为1024到1901的顶点,dataArray[i]未定义,计算全部解析为NaN。现在你将向量设置为vector.set(NaN, NaN, NaN)并且三个.js不知道该怎么做,所以这些点不会被渲染。

因此,如果用

替换循环的那部分
let fftValue = (dataArray[i] / 255.0) || 0;
let dx = def[i].x * fftValue + def[i].x;
let dy = def[i].y * fftValue + def[i].y;
let dz = def[i].z * fftValue + def[i].z;
particle.set(dx, dy, dz);

甚至更简单:

let fftValue = (dataArray[i] / 255.0) || 0;
geometry.vertices[i]
  .copy(def)
  .multiplyScalar(1 + fftValue)

你应该没事。