automatically scaled texture for cuboid

I have cuboids (not cubes, but made by scaling the basic box) on my level and I want to texture them. Say, something like planks - each of a different size, and looking a bit different from each side.

It is easy to solve using UV maps, but that requires separate texture/UV map for each cuboid and makes rescaling them cumbersome. I need tens (or even hundreds on all levels) of them, so it would be much easier to have an automatic, universal texture that will rescale/tile itself to cover whole surfaces of each side.

I suppose there must be an easy way to make a material that will behave this way, but with my limited knowledge I have no idea how (and I even have problems googling, as I have no idea what the correct keywords would be).

Can you point me in the right direction?

Materials scale along with the elements they are applied to unless you did something wierd in the material.

can you provide a few examples of what you mean?

My English failed me.

See the image - there are three cuboids. The one the left is a simple cube, two others are rescaled to be twice as long. When I just rescale the cuboid with a material made using UV map (from Blender) texture becomes strechted (like in the middle cuboid), which is not what I need - I need the texture to tile, like on the third cuboid.

Ok, so essentially the opposite of what I got from reading - which makes more sense.

Still, the behavior and how to achieve this is kind of similar.

You can go several ways about it.

the most “free form” one will be to turn the cube into a blueprint and run the followign things on it.
On construction create a dynamic material instance from its material and save it to a variable.
Subsequently, change a color parameter of the material with “Set Vector Parameter Value”. Pass the scale information of the cube to it - Get Actor Scale 3D, or Get actor Relative Scale 3D depending.

The material will now have that information and can use it to offset your textures - depending on how you code the material. (It’s kind of unnecessary at a base level - so I agree not the BEST solution).

The second way is to just create several Material instances and scale them individually on a cube by cube basis.
This will also illustrate the code for the material.

Let’s start with UV0. press U and click in the material to create that.
From that, let’s Isolate X and Y.
Drag and type Mask. Under math select the Component Mask.
In the details panel uncheck G.
Copy the mask, In the details panel check G and Uncheck R. Connect this back to the TextCoord node.
Drag off either channel and type Multiply
Drag off the B pin and type Scalar (in parameters) This will create a scalar value.
Copy the Multiply to the other Mask node
Create another scalar (name them as you please).
From one of the 2 multiply nodes output drag and type Append. Select append Vector (I think, going by memory).
Plug the other multipy into B.
This output can be used on the texture - UVs pin.

NOTE default parameters generate with a value of 0. 1x0 = 0 Meaning the UV is null. Change the default values to 1.

This is one way to scale the texture indipendently on X and Y axis to match the extent of an object. You decide how much by changing the scalar parameter values.

Third way. (possibly the best).
Right click on the material graph and type Object.
Find Object Scale.
From X or Y drag off and find ADD. - connect both X and Z to the add.
With the code from before put the ADD node into the multiplier for the R mask, and the Z off the objectscale node into the multiplier for G.

This will get the texture to start scaling based on object size.
If you go the BP way, create a Color parameter, add the pins from R and G, and use these as the multiply on the R of the texture coordinate node, and B as the multiplier for G

Once you are done tweaking your material - for performance sake since you mention you’ll have a lot of objects - let’s move the calculations to a custom UV.

Click the material node and type Custom.
In Number of Customized UVs type 1.
Alt click the UV pin inside the texture sample and drag off from the Append Node to the Customized UV0 pin in the material.

Then for the textures create a new TextCoord node (U and click on graph). connect it, and save. <- you don’t even need to, since the UV0 will be used by default, but I like keeping materials organized and ready for change.

Hope that helps.

*** Super important PS ***
Your UVS on the model will matter. Extra shader work will be required with the base cube to include the Y scale. If you just map the cube correctly in a 3d program the scaling of the texture is easier and can work this way.
I’m actually looking into a way to include Y atm, since this can be beneficial for my project as well.

Best way to isolate X Y and Z on the object is to split them into different UVs from the 3d program.
You could even control each face independently this way, by setting up different options for the different UVs.

vertex paint is a decent option, but painting the default cube is challenging at best (seems like vertices are some times shared by the faces, some times not).

Object rotation cross to object position may get me somewhere. Attempting some math around those ideas.

Here it is.

WAY easier then I made it out to be.

Taking the vertex normal from worldspace to local allows you to fix it in place. Then you can just mask the channel you need.
No need to isolate R, since it’s “waht’s left” after you pass the other 2.

The Abs node is necessary since VertexNormal will return 1 and -1 (left and right of pivot). Ceil is necesary, as the vertex nomral is fractal if you scale the item.

This seems to be 100% rotation independent.
Performance is what it is. You can optimize by moving the UV calculations to 3 different UVs and using the 3 different UVs in your material. Not sure you’d gain anything from it. multiplying is as low cost as it gets.

Wow, thanks. Plenty to digest, I hoped just for pointers :slight_smile:

Actually it required some changes - combination of the ceil function and lerp didn’t work as expected because of the rounding errors (coordinates of the normal calculated using TransfromVector are never perfectly zero, so during rotation ceil occasionally yielded 1.0 and the cuboid textures were randomly flickering), so I switched to the if nodes.

At the moment it seems to be working OK. Thanks again.

Turned out it was still a bit wrong now and then - what helped was a third “if” for the VertexNormalWS R channel. I understand the logic behind not using it initially, but somehow whole thing was failing.

Maybe you want the .1 to be something like .0001 ? That error margin would change the flickering I suppose.

otherwise an always accurate way to get the top 2 is
dot product of normalsws and object rotation.
Multiply rotation -1 to get the bottom.

It’s more expensive, but in my testing I never noticed it swapping or flickering.