Reduce draw calls for box with image texture on one face

I’d like to make box meshes with image texture on one face like this.

var textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load('path/to/image.jpg');
var material = new THREE.MeshBasicMaterial();
var mesh = new THREE.Mesh(
    new THREE.BoxGeometry(5, 5, 5),
    [
        material,
        material,
        material,
        material,
        new THREE.MeshBasicMaterial( { map: texture } ),
        material
    ]
);

This does make a box mesh with an image on one face. However, it seems this requires 6 draw calls for each box.
It doesn’t make a big difference when you have just one box but it matters when having many boxes.
Is there any way to achieve this with just one draw call? (or less than 6 calls each box)

Thank you in advance.


Try setting the material index

2 Likes

One way to get this down to 1 draw call would be to create a clever UV layout so that only one face is textured, and the others get their color from a single pixel somewhere on the image. With that UV layout you can assign any image you want. Probably easier to do in Blender. Example:

BoxSingleSideUVs.glb (1.6 KB)

Without changing the default UVs, I think the best you can do here is 2 draw calls, by modifying the buffer geometry draw groups: three.js docs

Or, if you’re drawing the same image on many boxes, you could also split it into two parts with InstancedMesh. Draw all the textured faces with one InstancedMesh, and all the solid parts of the boxes with a second InstancedMesh. 2 draw calls total, for as many boxes as you want.

4 Likes

For 2 draw calls on one box, not several:

var textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load(‘images/grass.jpg’);
var material = new THREE.MeshBasicMaterial();
var mesh = new THREE.Mesh(
new THREE.BoxGeometry(5, 5, 5),
[
material,
new THREE.MeshBasicMaterial( { map: texture } )
]
);
mesh.geometry.groups=[{start:0,count:30,materialIndex:0},{start:30,count:6,materialIndex:1}];

2 Likes

Merged 1.000 boxes and only 2 draw calls: mat_draw_calls.zip (1.2 MB)

image

1 Like

Draw all the textured faces with one InstancedMesh, and all the solid parts of the boxes with a second InstancedMesh.

This is actually what I originally came up with and I think this is the simplest solution in terms of readability thus maintainability IMO.

Thank you all for your ideas!