Any go-to textures for imperfect surfaces?

I’m working on a virtual art gallery – basically a very long “room” to navigate, with art hanging on the walls.

Photographic textures (like those at TextureHaven) tile too obviously for long walls. The built-in procedural textures look neat, but are too distracting. And plain material colors are just too “plastic.”

Does anyone have a go-to method for creating a texture with some subtle “interest” and imperfection to it, but that won’t look obviously repeated along a long mesh?

I’m thinking something like drywall – a slight random texture to give it some grain and roughness, maybe some optional gloss, with a configurable color.

The closest I’ve come up with is to use the NoiseProceduralTexture combined with the PBRMetallicRoughnessMaterial to create something akin to a “brushed metal” look by playing with the scales.

Here’s what I have so far:

https://www.babylonjs-playground.com/#VFW3YR#2

This works, but I’d rather have something that just has some subtle “roughness” to it rather than streaking – again, like the sort of texture you’d see on drywall, or leather, or smooth beach sand. Using the noise texture without scales ends up looking more like “splotches” than subtle static. I’ve played with the persistence, octaves, etc., but no luck yet.

Maybe @PatrickRyan will have some hints for you.

@richardtallent, I took some time to devise a way that you could virtually eliminate the look of the tiling of a texture. It does rely on two tiling baked normal maps which are generated with procedural noise. They look like this:

Once I have the two normal textures, I created a node material to blend them together:

There is one tricky bit in there which is the actual blending of normal textures. This is due to the fact that the normal textures are an array of vector3s stored in each pixel and when you combine two normal textures, you don’t want to do a simple math operation or you will be changing the vectors in ways that make you lose some of the range of the delta between the lowest and highest point in the texture. So you need to do multiple operations per channel to retain the lowest and highest points of the maps, which looks like this:

Luckily, you don’t have to recreate this every time you want to blend normal textures because we have saved this out as a custom node you can use and you can learn about how to use custom nodes in our docs.

So now that we have all this preliminary stuff set up, what are we actually doing? Well, we are blending between the two normal textures in such a way as to break up any patterns that the eye can see. At the basic level, we want to create a pattern to break up how we are blending the textures together which is where this part of the node material comes in:

Which ends up giving us a mask that looks like this if tiled in a 2 x 3 pattern. What this is used for is blend where full black is the first normal texture and full white is the second normal texture and the gray values are a mix of the two depending on the value (i.e. 0.2 is mostly the first texture where 0.8 is mostly the second).

But we have the power to tile it in other ways to make the geometry look like we want, such as a 1 x 4:

I used this to create an orange peel texture on the wall, and you can see for the sphere, I created a separate tiling so that the texture would be larger on the sphere:

There are exposed parameters on the node material that allow you to tweak UV tiling (non-square) and change roughness and base color easily in the inspector or in code:

image

This is subtle, and you need directionality in your lighting to see it (as you would any textured wall in your house). The rest of the material is just a non-metallic, mid-roughness, off-white color like you might find in a museum. The updated playground is here

And this is simply just an effect in the normal texture for the material. If you wanted the effect to be more pronounced, you could reinforce it with your base color, by using the noise texture you generated the normal with as a mask between two colors for the wall, one lighter for the peaks and one darker for the valleys to suggest either dirt in the texture or just scuffing on the raised texture on the wall. Or even a bake out an AO map from the normal to create a bleaching effect where the light has faded the tops of the texture due to the lighting in the room. There are a lot of things you can do here to create realism.

But the main thing to remember here is to start with textures where you have a hard time discerning the patterning in the tiling. Procedural textures can do this, but when you are talking about a wall, I would not want to rely on creating that at runtime due to the fact that you want it to be in the bump of the wall texture and converting a float texture into a bump texture in the shader at runtime is more expensive than just loading a couple of clean tiling textures and blending between them to create a somewhat random pattern to break up the eye finding the repeating texture.

In your case, since you are talking about a hallway, this technique should work just fine as the user won’t be able to get far enough back to see the whole wall and be able to pick out the textures. Not to mention that as you get farther away, the subtle texture will blend away before the eye can see the repeats. If you were doing something with more contrast, like a grass texture, I would want to use more of a splat map to blend the textures, which you can do by creating a noise texture with node material in procedural texture mode. You can then pump this into another node material by assigning it to a texture node in your shader doing the texture blending.

I hope this gives you some ideas for how to generate some textures for your walls. Let me know if you have more questions.

3 Likes

Patrick, this looks great! I think I get the gist of it, hopefully I’ll get a chance to play with it this weekend. I’m definitely going to have to take some time to sit and dig into the details.

3 Likes