1
$\begingroup$


I attached a wave texture into a height input of a bump node, expecting to get normals corresponding to a sine surface, but instead I get normals of (0,0,1) and I can't find why.\

I checked the values by displacement as follows:

Texture factor output:
The values are as expected
enter image description here


Desired bump node output normals:
These are the normals I would like to obtained
enter image description here

Actual normals values obtained by a bump node:
Normals Z values are always 1 - Why?
enter image description here

Normals X values are always 0 (and the same for Y values) - Why?
enter image description here

$\endgroup$
3
  • 1
    $\begingroup$ Hello I'm not sure what you're trying to do here, you need to plug a Displacement node into the Displacement input $\endgroup$
    – moonboots
    Jan 14 at 22:33
  • $\begingroup$ @moonboots - I built here a graph to inspected the normal components values obtained from the bump output node. The displacement serves as "value-meter" in this context. $\endgroup$
    – audi02
    Jan 15 at 13:18
  • $\begingroup$ oh ok sorry, too complicated for me ;) $\endgroup$
    – moonboots
    Jan 15 at 15:04

3 Answers 3

1
$\begingroup$

The normals you're getting out of a bump node from a wave texture height are correct.

But, you cannot use these normals as the input to displacement.

Displacement affects your base normals, because it moves verts (with true displacement) or changes their normals (with bump) or both, and your base normals affect the activity of a bump node (notice the "normal" input.) This creates a circularity. Blender doesn't make this circularity entirely clear-- its interface suggests that displacement is only output, never input, so it's not like it's anybody's fault for missing it-- but it still exists.

Blender always calculates displacement before it calculates bump. Your noodles don't matter. It can't calculate based on a circularity, so it decides to do things this way, no matter what you tell it to do.

But, there's a really simple workaround for this. Two workarounds, actually. Either plug your wave texture output into your displacement (via displacement node), or plug them into a bump node and plug the normal output of that bump node into the normal input of your diffuse BSDF.

Would it be possible to do things otherwise? Yes. In the case of a circularity, Blender could input pre-displacement normals into the input for the bump node and calculate it from those. It does this with generated texture coords, for good or ill (leading to a lot of confusion sometimes for people who expect coords used for displacement to match coords used for albedo.) But it doesn't do that with normals.

Could you use GN to store pre-displacement normals and use them? You could store them, but Blender just won't run a bump node until after it's figured displacement. You would have to recreate the bump node functionality within GN-- probably, something just reasonably close to a bump node. It wouldn't work with adaptive subdivision though.

$\endgroup$
3
  • $\begingroup$ Is Blender always calculating displacement before bump? The bump on a plane gets distorted by the displaced geometry... also bump is visible in material preview as well, (shader-based) displacement only in rendered view. So I would have thought it is the other way round, but I admit I don't know it. $\endgroup$ Jan 15 at 13:31
  • $\begingroup$ That's lights the point!! $\endgroup$
    – audi02
    Jan 15 at 14:21
  • 1
    $\begingroup$ @GordonBrinkmann I can see how you could think of the order, as pseudo-transformations, as occuring either way. But while you can use a bump map with the normals provided by displacement, you cannot use displacement with the normals provided from a bump map. Similar thing happens, for same reason, with the use of normal texture coords for displacement (which is more irritating than bump because it prevents live triplanar displacement.) My conclusions are from experimentation, so no, there's no 100% certainty, I could have made an error-- but I don't believe that I did. $\endgroup$
    – Nathan
    Jan 15 at 15:49
1
$\begingroup$

Actually I do not know if you only want to get the normals or the displacement shown in the question. I'll go for the displacement, because this seems more what you want since you are using the Displacement socket on the Material Output.

Two things: Firstly, you don't need a Bump node for displacement, there is a dedicated Displacement node. You can also simply use the Fac output of the Wave Texture node and plug it into the Z socket of a Combine XYZ node, but the Displacement has some options that might be helpful like setting the Scale or Midlevel (the Combine XYZ node works as if Midlevel = 0 and Scale = 1). But what you need is enabling Settings > Surface > Displacement > Displacement Only (or Displacement and Bump if you want bump as well) in the Material Properties:

material > displacement

Secondly, I cannot see it in your screenshots how high the resolution of your mesh is and I suspect it is a simple plane with only four corner vertices. This is not enough if you want displacement - because for displacement you need geometry that can be displaced. Either real geometry from a subdivided mesh or using a Subdivision Surface modifier.

Here is an example showing you the resolution of a plane for a decent displacement result, the orange grid being the mesh resolution and the small black grid inbetween the additional subdivision by a Subdivision Surface modifier set to Simple and Levels = 3. On the left the Fac output of the Wave Texture is plugged into a Combine XYZ node, on the right it is plugged into the Height of a Displacement node. With Midlevel = 0 and Scale = 1, they produce the same result:

combine vs. displacement

Of course you can recreate the Midlevel and Scale option with a Combine XYZ as well: the value you enter as Midlevel first has to be subtracted from the Fac value, then you have to Multiply it with the Scale value. The order is important (at least if you want to replicate the Displacement node settings), first subtract, then multiply. Here I show it with Midlevel = 1 and Scale = 0.2:

recreating the displacement options

By the way, what you can do with the Combine XYZ node directly while you would need Texture Coordinate and Mapping nodes for the Displacement is moving the displaced mesh around horizontally by changing the X and Y values.

Alternatively, you could also use Adaptive Subdivision, which requires you to enable the Feature Set > Experimental in the Render Properties, then appears another setting further down in the Render Properties called Subdivision which allows you to set the Dicing Rate in pixels for renders and viewport, i.e. the resolution of the mesh relative in absolute pixels of the screen/image size.

Then you do not have to subdivide the plane at all, only enable Adaptive Subdivsion in the Subdivision Surface modifier. Note that these shader-based displacements are only visible in rendered view and they only work in Cycles.

adaptive subdivision

$\endgroup$
1
  • $\begingroup$ Thanks for the detailed explanation. The graph is to inspect the output values of the bump node, for checking what normal values it gives when connecting wave texture into its height input. But the normal values I obtained are (0,0,1) which is strange. $\endgroup$
    – audi02
    Jan 15 at 13:26
0
$\begingroup$

I guess there is a misconception here or a confusion between a Vector in general, the Normal of a face and what the Displacement does. I will simplify this in the explanations below, maybe not 100% accurate but you might get the idea.

A Vector in general is an $n$-tuple of elements, in Blender usually a 3-tuple holding XYZ coordinates (or a Color socket is basically a 3-tuple as well holding RGB values).

Displacement can use vectors to displace (= move) vertices in directions given by 3-tuple vectors holding X, Y and Z values moving them forwards/backwards, left/right or up/down depending on their local or otherwise submitted coordinates (for example from a different object). The main thing is: displacement moves vertices in a direction.

The Normal (and now I'm oversimplifying to later make clear why it seems your displacement setup cannot work) is the direction a face is pointing in and Blender differentiates between the frontside of a face and the backside. Now if you are looking on the frontside of a face, its normal is pointing towards you. Looking at the backside of the same face, the normal is pointing away from you. Normal values can range from -1 (pointing completely into the opposite direction of the according axis) to 1 (parallel to the according axis).

And here comes the problem: in your example, the displacement lets the geometry move from 0 to 1 on the Z axis in 3D space. This results in faces with normals where at the highest point the normal is pointing upwards (Z = 1) and at the lowest point as well. The faces inbetween have lower values on Z (but not 0 because there is no vertical face) and varying values on X.

In the image below I have split the normals in X and Y values, plugged them into a Map Range node mapping from -1/1 to 0/1 and used a Color Ramp to increase the contrast a bit. On the left you see the normals' X values and the Z values on the right. Faces pointing towards +X are bright (> 0.5), faces pointing towards -X are dark (< 0.5) on the left object, while faces on the right object that are more or less horizontal (pointing upwards) are very bright (Z value going towards 1):

view from above

Now I guess you expect these values to be converted into displacement by your setup. But the Bump node does not have a simple Vector output where the values which you can see above are the result. It converts the calculated height into normals, which can be viewed from two sides: the frontside of the face and the backside of the face. Which means, when I now change the view to the underside of the objects, the X values stay the same, but the Z values are no longer white at the maximum and minimum height - because they are pointing away from the view (I had to adjust the Color Ramp or it would have been completely black from the previous setting):

view from below

I admit I do not know why the Displacement node interprets the X values as 0 and the Z values as 1 (using a minimum? maximum? average? value), but I would strongly suspect that the Normal output simply does not supply valid data for Displacement since the values are inconsistent and depending on the view.

$\endgroup$

You must log in to answer this question.

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