Displaying 500 Basic Textured Models Performantly? (InstancedMesh or another method)

Hey there!

I’m working on a project where we’d like to have 500 low-poly cars in a basic scene. I have some questions on the best approach.

We’re basically looking to achieve:

  • Each car body can have it’s own color (the tires/windows can stay the same)
  • Each car can animate it’s position, rotation

Here is a screenshot of an example 3D model we hope to purchase once some of this is figured out.
image

I assumed that displaying 500 of these cars with a typical model import may cause performance issues, as this demo will be running on an average laptop. Am I right to assume that?

So I started going down the road of using an InstancedMesh and testing with some cubes for now until I get the models.

Performance seems great, but a big unknown has come up.

Since each car would need to share the same mesh/material, how can I change each individual car body color without the wheels/windows also becoming that color? (e.g. I’d like the car body to be blue, but the wheels/windows to be grey)

Is this possible to achieve with InstancedMesh possibly using a texture? Maybe the wheels/windows could be part of the texture and the body could just be transparent showing the material color?

Is using InstancedMesh the right thing for this scenario? Would there be another method to displaying 500 of these cars in a performant way that offers me more control over individual color?

Thanks a bunch guys. Any info appreciated.

Hi!
And front wheels of each car has to have individual steering (left/straight/right)?

Hi! Nope wheels can stay locked forward! The entire car mesh can be static.

Really just need to color the car body differently, with the wheels, and window always the same color

Just an option from the scratch: use InstancedMesh with three instanced buffer attributes for colors of body, window and wheels for each car, processing them in material’s shader :thinking:

Example: https://codepen.io/prisoner849/pen/jOBzPYr?editors=0010
Picture:

2 Likes

Wow unreal @prisoner849! That’s a really neat solution and could definitely work.

So this same approach could apply to a 3d model as well?

I have to admit I have 0 knowledge of shaders lol. Would you mind elaporating on how you’re targeting each part of the mesh separately?

let m = new THREE.MeshLambertMaterial({
  vertexColors: true,
  onBeforeCompile: shader => {
    shader.vertexShader = `
      attribute float colorIndex;
      attribute vec3 color0;
      attribute vec3 color1;
      attribute vec3 color2;
      
      ${shader.vertexShader}
    `.replace(
      `#include <color_vertex>`,
      `
        float cIndex = floor(colorIndex + 0.1);
        vColor = cIndex == 0. ? color0 : cIndex == 1. ? color1 : color2;
      `
    );
  }
});

Assuming that this is the magic here.

 float cIndex = floor(colorIndex + 0.1);
  vColor = cIndex == 0. ? color0 : cIndex == 1. ? color1 : color2;

Anything I should keep in mind when applying this method to a model?

Thanks a ton. This is extremely helpful

Vertices of each part has specific color index. See, what I do in makeCart() function.
I create a primitive, adding to it that colorIndex attribute in setGroup() function. After all, I merge all the geometries (parts) into one.

Got it, thanks!

I’ll need to play with how to import the model and merge the 3 pieces together. (e.g. can I use 1 single 3d model and access the sub-meshes to apply these color indexes to?). That’s another topic tho (but if you had any quick tips to the approach that’d be great!)

Appreciate the help!

Any chance to share the model in this topic?

InstancedMesh also has a setColorAt method. If you use a white material for the base model and then set a different color for each instance it’ll multiply out:

#FFF x <instanceColor> = <instanceColor>.

If you only want to color parts of the car, all of the car bodies could be one InstancedMesh, and all of the non-colored parts another InstancedMesh. Avoids the work of setting up a ShaderMaterial.

3 Likes

@prisoner849 I just purchased the model and uploaded it here. It is not prepped at all yet (nothing separated), so not sure how helpful it may be. I can circle back in the near future once I have more of the model work done as well.

Thanks @donmccurdy! Having multiple InstancedMeshs is definitely a way to go. This was going to be my fallback plan, as I fear it would add some additional complexities to the state management of how our app is structured. Definitely a viable option tho

@stuffedmotion
Well, the model is a single mesh, that contains a geometry and a material with vertexColors: true. I’ve got no idea how to split it into three parts with three.js :thinking:

That’s exacty my first thought since the beginning of this topic:) Worth a try.

@prisoner849 No worries, I figured it would require some love and care in Blender before it’s usable.

I’ll tinker with these 2 suggestions! Thanks a bunch guys

Tried with two instanced meshes and hierarchical objects. Seems it works somehow :sweat_smile:

Example: https://codepen.io/prisoner849/pen/ZEexpVb
Picture:

2 Likes

Haha nice one! That opens more options for sure. That actually will be useful for some other parts of the project I’m working on.