17
$\begingroup$

I want to create some procedural textures that I can quickly reuse to texture objects. For this example I want four sided cubes (ignore top and bottom) that are wrapped in bricks. Example of two "buildings"

But, I want the bricks across different objects to be the same size, even if the objects are different sizes. You will notice in the image above that the "large building" is twice the size of the "small" building and the large building's bricks are also twice the size. I believe this is because the procedural texture in "UV mode" is based on the bounding size of the object, so the brick size does not change regardless of if the scale is normalized. If I use the object node option, but that will not wrap the bricks around the cube. The only way I know to wrap the bricks is to use the Texture Coordinate node and UV as an input.

Here is my material setup.

Original Node Setup

I think the key would be to use some math so the input value nodes to the brick height and width nodes are based on the object bounding box size, but I don't know how to get this as an input to modify my brick size.

I also tried using a different object for the "object node" in the Texture Coordinate node, but the bricks did not wrap. Thanks.

$\endgroup$
3
  • 1
    $\begingroup$ Use procedural texture coordinates like Object or Generated and then use a Vector Transform node to convert between coordinate spaces, like object to world $\endgroup$ Jan 4, 2017 at 4:51
  • $\begingroup$ The problem is Object and Generated do not wrap around an object, meaning bricks only appear on one side of the "cube". The Vector transform does not seem to help this. $\endgroup$ Jan 4, 2017 at 5:41
  • $\begingroup$ You have to mask faces by their respective normals, and map the texture coordinates accordingly for each one of the facing directions with the correct UV projection $\endgroup$ Jan 4, 2017 at 14:19

4 Answers 4

17
$\begingroup$

When I read Rich Sedman's first answer, I realized that what he does with the two materials can be solved with a single material using a trick called triplanar mapping.

What is the problem here? 3D procedural textures can be made size-independent using Object coordinates, but the brick texture is only a 2D procedural texture, so it does not wrap around the mesh.

What is triplanar mapping? A 2D texture is projected along the X, Y, and Z axes, and then we blend among these based on the angle of the currect face. It is used mostly for things like terrains, rocks, tree trunks but can be also used here (assuming that the faces are either in the XZ or in the YZ planes, so that we don't get blending artifacts). Cycles does not have built-in triplanar mapping support, but one can construct it from nodes, an example is here: http://www.blendswap.com/blends/view/78446

The following is a simplified version of the blendswap material, because in this case we only need two projections (X and Y - this is strictly speaking biplanar mapping), and I also took out the mapping nodes because the scaling can be tuned in the brick texture. Note however, that the mapping nodes could be useful to reduce the discontinuity at the edges, as in Rich's answer.

The nodes:

enter image description here

The result:

enter image description here

$\endgroup$
14
$\begingroup$

One drawback of the previous two answers (both my own and lbalazscs's) is that the faces are assumed to be parallel with the X or Y axis - neither solution copes well with surfaces that are not square with the axes. This can be addressed by using vector maths to determine the texture coordinates based on the surface Normal and a reference vector. The reference vector (Orientation) determines in which plane the wrapping will take place (in our case, around the outside of the building) and this can be adjusted if necessary (eg, if the brickwork needs to be skewed).

Here is the material :

material

The Orientation vector is defined in a Combine XYZ node (named Orientation). This allow it to be easily amended if required. This vector is passed to a Cross Product node along with the Normal of the surface. The Cross Product generates a vector which is at 90 degrees to both of the input vectors. Since one of those vectors is the Normal of the surface, this means that the resultant vector is directly along the surface. Since the Orientation node is vertical (0,0,1), this generated surface vector must therefore be horizontal. Both the generated Horizontal and the (vertical) Orientation vector are passed through Normalize vector nodes to ensure they have a magnitude of '1'.

To generate the Texture Coordinate at the sample point on the surface, we use the Dot Product to combine the Object coordinate with each of the surface vectors (Horizontal and Vertical). The result of this will each be a scalar value representing the component of the coordinate in the direction of the Horizontal or Vertical vector and these are used as the X and Y texture coordinates by combining into a vector.

This produces a mapping that wraps around the mesh in a specified direction with the same scale for each surface and for each mesh (providing the Scale has been applied with CTRL-A and produces the following result (with a mesh that includes walls that are not 'square' to the X/Y axis) :

final result

As mentioned, the Orientation vector can be amended to change the orientation of the wrapping. As a demonstration, setting it to (0.2, 0.5, 0.75) can produce the following skewed brickwork :

skewed

$\endgroup$
5
  • $\begingroup$ Maybe add an object input as the orientation. Seems more intuitive to align in 3d viewport. $\endgroup$
    – Leander
    Jan 6, 2017 at 0:15
  • $\begingroup$ Cool! Although this is still not the fully generic projection along the normals: it does not work if the orientation vector is perpendicular to the face: with the default vertical orientation it cannot be used to texture the floor. $\endgroup$
    – lbalazscs
    Jan 6, 2017 at 2:56
  • $\begingroup$ Ideally the orientation would be a scalar, defining the rotation of the texture around the normal vector. But this is so far the most generic solution, great work. $\endgroup$
    – lbalazscs
    Jan 6, 2017 at 3:03
  • $\begingroup$ @Leander thanks for the suggestion. I'll look into updatig the answer for this. $\endgroup$ Jan 6, 2017 at 9:02
  • $\begingroup$ @lbalazscs Thanks :-) It's not ideal but I think the roof and floor would probably be better as a separate material - that way there's more control over the trasition betwee the two. I'm quite surprised how well this material copes with complicated meshes - tried it on a Suzanne head with surprisingly good result (I should add an image of that!). I think the biggest remaining problem is that the texture is centred on each face rather than being offset to join up with its neighbours - not such a problem for bricks I guess, but looking into generating an offset for each face for a better match. $\endgroup$ Jan 6, 2017 at 9:21
4
$\begingroup$

UV mapping is unsuitable for this as the scale is dependent on the size of the faces. There is no simple way (that I'm aware of) of determining the size of the actual face within the material to scale the texture appropriately.

The solution is to use Object coordinates - these are centered on the object origin but are the same scale for all objects - regardless of its size (provided the Scale has been applied).

However (as has been pointed out) Object coordinates do not allow the texture to be wrapped around your mesh. The solution to this is to use different materials for each orientation of faces. This way, the faces that are pointing along the X-axis can have a texture that is aligned with those faces, while those aligned along the Y-axis can have a texture that is aligned with those faces.

Add each of the materials to the mesh and, in Edit mode, select each set of faces and Assign the material to it. In this example I have created two materials - one coloured Red and the other Blue - to show how the materials have been assigned to opposite faces :

assigned materials

In my example I have two materials - one for the front and back faces and another for the side faces. If your mesh has faces at other angles then you should assign additional materials to those (eg, all faces at 45 degrees would be assigned a third material, those at, say, 30 degrees another, etc.).

Each material should then be set up identically but with a Mapping node set to orientate the texture as appropriate for that set of faces. For example, for those at the sides, the texture should be rotated 90 degrees around the X axis as shown.

material1

Adjust the Mapping of each material to align the texture on the associated set of faces. For my second material I used the following rotation :

material2

The bricks are now scaled the same, regardless of the size of the mesh/faces.

final result

You may get discontinuity of the texture at the corners (see the edge of the smaller cube) as it changes between the different materials. You can adjust the Location Mapping values for each material (and potentially add further materials to allow some faces to be adjusted without affecting others at the same orientation) to offset the texture to reduce the discontinuity to acceptable levels.

$\endgroup$
7
  • $\begingroup$ Upvoted, but I think that if you use a trick called triplanar mapping (in this case a "biplanar" would be enough), then you don't need to assign different materials to different faces. $\endgroup$
    – lbalazscs
    Jan 5, 2017 at 1:48
  • $\begingroup$ Thanks. I was thinking that perhaps there would be a way using the True Normal - but the maths gets way more complicated and I don't see how to avoid the discontinuity at the edges. I might try down that route at some point but would be very interested to see another solution. $\endgroup$ Jan 5, 2017 at 7:26
  • $\begingroup$ I added my idea as an answer. Actually it is based on a blending based on the normals, so maybe this is what you really wanted. $\endgroup$
    – lbalazscs
    Jan 5, 2017 at 15:23
  • $\begingroup$ Nice. I did have a go and came up with something similar - achieved in a slightly different way (manipulating and mixing the vectors up front) that gives similar results but also caters for faces at other angles. I'll maybe add it as another answer if it seems worthwhile. Thanks! $\endgroup$ Jan 5, 2017 at 18:01
  • $\begingroup$ Oh, I guess you are creating a custom planar projection for each face, where the projection angle is the same as the normal. Well, if you are already finished, you might just as well post it as another answer :) $\endgroup$
    – lbalazscs
    Jan 5, 2017 at 20:02
4
$\begingroup$

Ratio from comparison for UV scaling

You can get the ratio of the scaling between an object and another in cycles node editor by following the process described in this answer.

If you choose an unitary empty as object for comparison, you'll get a ratio that is equal to the size.

As you can see in the image below, scaling the object give to each shaded pixel the same variation of colur:

enter image description here

We can now use this colour (think it as a "value"), to scale the UV map of the object with the help of a MixRGB node set to Multiply.

enter image description here

enter image description here

Note: the proposed ratio algorithm isn't currently taking into account the object's rotation

$\endgroup$
3
  • $\begingroup$ Very nice solution. $\endgroup$ Jan 6, 2017 at 12:09
  • $\begingroup$ How does that work with 'Apply Scale'? Presumably it relies on the fce that the scale is different and applying scale would reset the texture scaling back to 1. $\endgroup$ Jan 6, 2017 at 12:51
  • $\begingroup$ It doesn't work at all. It's all based on the object scale, you are right. It's pro is that you can use your custom uvmap. To be really honest, this could be useful only if you are duplicating several times the same mesh and scaling it, not with different objects with different shapes, etc... but I thought It worth trow it in anyway. $\endgroup$
    – Carlo
    Jan 6, 2017 at 15:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .