0

So i've been stuck for a while because i've been having trouble dynamically changing the shape of the vertices in a place geometry according to the frequency data of an mp3, I've been having 2 main problems:

1)The array generated by the mp3 has too many values and it is impossible to render out the vertices that fast and accordingly, i am getting the frequency data with this code.

var frequencyData = new Uint8Array(analyser.frequencyBinCount);

2) Re-Rendering the plane everytime frequencyData changes causes extreme performance issues to the point it does not render out anymore

I've been using simplex noise to cause the vertices to morph, and it does work until obviously i pass in frequency data and everything breaks, this is the code i'm trying to use to morph the vertices of the plane according to the music.

function adjustVertices() {

      for (var i = 0; i < 100; i++) {
          for (var j = 0; j < 100; j++) {
              var ex = 0.5;
              pgeom.vertices[i + j * 100].z =
                  (noise.simplex2(i / 100, j / 100) +
                      noise.simplex2((i + 500) / 50, j / 50) * Math.pow(ex, frequencyData[2]) +
                      noise.simplex2((i + 400) / 25, j / 25) * Math.pow(ex, frequencyData[2]) +
                      noise.simplex2((i + 600) / 12.5, j / 12.5) * Math.pow(ex, frequencyData[2]) +
                      +(noise.simplex2((i + 800) / 6.25, j / 6.25) * Math.pow(ex, frequencyData[2]))) /
                  2;
              pgeom.verticesNeedUpdate = true;
              pgeom.computeVertexNormals();
          }
      }

  }

This is my plane object:

var pgeom = new THREE.PlaneGeometry(5, 5, 99, 99);
 var plane = THREE.SceneUtils.createMultiMaterialObject(pgeom, [
 new THREE.MeshPhongMaterial({
  color: 0x33ff33,
  specular: 0x773300,
  side: THREE.DoubleSide,
  shading: THREE.FlatShading,
  shininess: 3,
}),
]);



 scene.add(plane);

I am very grateful for the help, I am just doing my best in mastering three.js :)

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
Alex
  • 39
  • 5
  • I'm unfamiliar with THREE.SceneUtils.createMultiMaterialObject .. afaik you can pass a material array into the mesh constructor... so: plane = new THREE.Mesh(pgeom,[new THREE.MeshPhong.. Does multimaterialonbject do something special? – manthrax Jul 31 '18 at 12:08
  • 1
    My apologies, initially i was going to use multi material object to add multiple materials however i did some research and found out that it has been removed and you can now pass multiple materials in a material array, so i will DEFO be updating that. – Alex Jul 31 '18 at 12:12
  • 1
    I bet the computeVertexNormals calculation is what's slowing things down in that setup. That's a relatively expensive operation since three has to first compute face normals, then vertex normals by accumulating all the face normals sharing the vertex.. – manthrax Jul 31 '18 at 12:14
  • But That's all just a wild guess.. the bottleneck could be elsewhere. I'd have to see some running code to have a better idea. – manthrax Jul 31 '18 at 12:28

2 Answers2

1

I would check if the computeVertexNormals is what is taking the most time in that render loop, and then look into optimizing it, if you still require it.

You can optimize the normal calculation by building the mesh topology once at startup, since it doesn't change at runtime, making the recalc run in constant time.

Then reduce the vertex count until things become manageable. :)

manthrax
  • 4,918
  • 1
  • 17
  • 16
1

The first answer is correct. Most likely computing vertex normals is causing the hit, and it's most likely happening because the Geometry method which you seem to be using creates a lot of new THREE.Vector3. If you profile this i imagine you'd see a lot of GC activity and not so much of computation time.

One more thing to consider since you only map one variable, is to move this computation in the shader. You could write your values to a texture and only update that. You would not have to refresh the vertex and normal buffers which are much larger than the texture you'd need to store just the input variable. You would also be able to do this computation in parallel.

pailhead
  • 5,162
  • 2
  • 25
  • 46
  • Yep. I thought about that but then OP will have to do normal generation in the shader as well... and that can be tricky if you don't have a straight forward function to get derivatives. – manthrax Jul 31 '18 at 23:00
  • But you're right about memory in computeVertexNormals.. would be relatively straightforward to preallocate the list of faces sharing each vertex, and reducing the normal generation to a few constant lookups, adds and 1 normalize per vertex with no allocation. – manthrax Jul 31 '18 at 23:02