Bending light in Cycles
In today’s tutorial we’ll break the laws of physics, and prove we can abuse nodes to make Cycles do anything we want
I posted about this effect on Twitter some time ago as a “useless experiment”. People were interested in it, so I’ve gone back to look deeper into it. The trick is fairly simple: make an object look like it’s being lit from the opposite side using only a Cycles material.
As you can see, there’s only one light in the scene, a Sun lamp. You can actually make the light come from any direction, since it’s controlled by a normal node.
I’m using the vector math node to push the normals around. To do that I grabbed the normals coming out of the Geometry node and the output of the Normal node. The Separate XYZ section helps push the coords in the right place and smooth a the shading a little more.
Here’s the noodle for Suzanne’s material (the others have the default material).
So, how does it work?
It’s a little hard to say since you can’t see what normals look like inside Cycles. My guess is that normals are being pushed inside the mesh. The normals of the faces close to the light become near opposite to it, while the farther faces point closer to the light source.
Normals are vectors (think of them as lines) perpendicular to faces and vertices. Normals are used for a number of things, one of which is to calculate how lighting hits and illuminates a mesh. As far as I know only face normals are available in the Geometry node, so those are the ones that concern us.
The diffuse component of a mesh’s lighting is calculated according to Lambert’s Cosine Law . To calculate how much a point in the mesh is illuminated by a ray of light, we multiply the amount of light in the ray by the cosine of the angle between the normal and the ray.
A ray of light coming at a 90º angle to the normal results in a cosine of 1. That face would receive all the light from the ray, becoming very bright.
Angles between 0º and 90º result in cosines between 0-1. Less light is applied the closer to zero, it looks like the light enery is “spread” through the mesh.
Ray lights coming at 0º result in a cosine of zero. Since the light amount is multiplied it, this angle produces no light.
Obtuse angles (between 90º-180º) produce negative cosines which gets clamped to zero, also producing no light at all.
So how does this explain the bending light effect? If the normals close to the light point away from it, the angle they produce becomes obtuse. As we’ve seen that means they receive zero light. On the other hand, normals farther away start pointing towards the light producing acute angles and cosines in the range 0-1. That means they receive light. You could think of it as light passing through the object, rather than bending around it.
Note that Lambert’s Cosine Law uses the term “directly proportional”. I haven’t looked at Cycles’ code, so I don’t really know if it’s directly multipling or using a different formula.
I’m not much of a math guy myself, but if you’re interested in learning more about this you can start with the 8th Chapter of the OpenGL tutorial and Scratchapixel.
Smoothing it up
Of course once you start mucking around with normals like this, you also kill smooth shading (since face normals are interpolated from vertex normals).
To fix that we need two things:
First, work with a highly subdivided mesh. If you’re using the subsurf modifier, you need to apply it. Otherwise the geometry node will use the unsubdivided mesh data.
Use a tweaked normal as a color input to give them a smoother appereance. I used a normal node to shift them to the correct position and a multiply node to bump the brigthness.
Bonus! Try some textures with it
While playing around with this idea, I also found some interesting effects when mixing normals and textures.
One of them is Plasma-ish noise! I’ve wanted to make plasma like effects in Blender for a while, they look so demoscene.
To make this happen I took the object’s coordinates, substracted from with a noise texture then added to the result with another noise texture. The noises have different scales so they create sorts of ridges and islands in the coordinates. Finally I substracted a value to offset the coordinates (which I can animate) and fed it into the final noise texture.
The other effect is a reptilian-ish skin using the magic texture. This is double cool because it’s honestly the first good use I’ve found for that node.
The effect is generated from normals so you can use the color socket for more details or a different texture. You can tweak it too by moving around the normal node orb.
Stay foolish, stay hungry…
I think the most interesting part of all this tricks isn’t the actual effects (which you’ll rarely use), but how far you can go with nodes. Always keep in mind that if something can’t be done in an obvious way, it can surely be hacked together with nodes. So, keep an open mind! Spend some quality time trying stupid combinations and studying how the engine works.