How to repeat texture properly?

Hi,
I am trying to create some generic mesh using boxGeometry, where the dimensions will be given as an input. It would use a texture (that I just downloaded from polyHaven for now…)

Although, whatever I try it gets stretched at least on one side:

What I have tried


const repeatTextures = (textures, width, height) => {
	textures.forEach((t) => {
		// t.repeat.set(2, 2);
		t.wrapS = THREE.RepeatWrapping;
		t.WrapT = THREE.RepeatWrapping;
		t.needsUpdate = true;
	});
};

export function genericMesh(props) {
	const { position, width = 1000, height = 1000, depth = 100 } = props;

	const [colorMap, aoMap, dispMap, normMap, roughMap] = useTexture([
		"./asset/metal/green_metal_rust_diff_1k.jpg",
		"./asset/metal/green_metal_rust_ao_1k.jpg",
		"./asset/metal/green_metal_rust_disp_1k.png",
		"./asset/metal/green_metal_rust_nor_gl_1k.jpg",
		"./asset/metal/green_metal_rust_rough_1k.jpg",
	]);
	repeatTextures(
		[colorMap, aoMap, dispMap, normMap, roughMap],
		width,
		height
	);

	const material = useMemo(() => {
		return new THREE.MeshPhysicalMaterial({
			side: THREE.DoubleSide,
			map: colorMap,
			aoMap,
			displacementMap: dispMap,
			normalMap: normMap,
			roughnessMap: roughMap,
		});
	}, [colorMap, aoMap, dispMap, normMap, roughMap]);

	return (
		<group>
			<mesh position={[0, 500, 0]} material={material}>
				<boxGeometry args={[width, height, depth]}></boxGeometry>
			</mesh>
		</group>
	);
}

Adding back the repeat texture it gets even worse

Can someone point out what did I misunderstood or I am doing wrong?

Many thanks,
Mat

You may try one of these two approaches:

  • change the UV coordinates so that the texture looks good on all sides (demo)
  • use clones of the texture for different sides with different repeat values (demo)
3 Likes

How to repeat texture properly? Like so:

texture texture texture

On a more serious note, at @PavelBoytchev alluded to, your issue is not with the texture, but with your geometry. UV is a set of coordinates for every vertex on your geometry that specifies which part of the image to use for that vertex. These coordinates are XY (confusingly named U and V respectively) and they are normalized to 0…1 range.

If the sides of your panel-like geometry in the screenshot are rather short, but they span a large UV gap - it will result in “squashed” looking texture just as you’re observing.

image

You can edit UVs in software like Blender, here’s how.

Since in your example you’re using r3f to generate the geometry, I’m not sure what you can do. I would recommend maybe creatign custom geometry in something like Blender and importing that instead.

1 Like

I’ve tried to use the first example, but using

 var x = sx * (pos.getX(i)+0.5),
     y = sy * (pos.getY(i)+0.5),
     z = sz * (pos.getZ(i)+0.5);

confused me a bit, shouldn’t be the uv coordinates between 0…1 ? These will produce UV-s bigger, than 1 and the result is just a plain green geometry (because the texture is stretched I think?)

Oh, if you copy the code as it is, most likely it will not work. The demo uses a “small” texture that is stamped many times over the surface. In your case you need the opposite – a “big” texture that is partially stamped onto the surface. But the underlying algorithm is the same – the UV coordinates of the vertices are adjusted to the shape size.

I will make a new example and will post it here in an hour.

Edit: here it is, the texture of the right cube is not shrinking/expanding. For your specific case, you need to adjust values in the code. If you still cannot fix the texture, you may try to share a live minimal debuggable example.

https://codepen.io/boytchev/full/LYMgZPq

image

5 Likes