Set sun position on a Nishita sky to the rotation of an empty

I was wondering if it’s possible to use an empty to control the sun position on a Nishita sky node. I’d like this so I can animate it properly and do easy testing in-world without having to edit the world material each time: Nishita gives you two values for Sun Elevation and Sun Rotation, those can’t be easily animated to simulate the sun rising and setting at a logical angle, while also not allowing inputs to be plugged into their values which seems like an oversight in the node definition.

I’d like to avoid a whole script if possible, would rather do it manually if it’s that complicated. I’m assuming my only option then are drivers, but how do I define them for the rotation and elevation fields so the sun moves at the location pointed to by an arrow empty?

You have 2 options.
1 in the properties tab - word settings under surface there is a drop down menu to control the suns nodes elevation rotation etc without having to enter the shader editor.

2 If you really want to use an empty (I think it is easier to use the first option) you can use a driver to control the suns elevation etc. Here I have done that from the properties tab, you can also do the same in the shader editor.

First right click the empties z location an select “copy as new driver”.

Then right click the suns elevation field and chose paste driver.

For it to be manageable I had to set the driver to scripted expression and divide the value by 100 (as shown in the driver editor)

You can do the same with the rotation value of the empty (you will not need to divide the rotation value)

Edit:
Edit:

I just remembered a third possibility you might like.

There is a bundled addon called “Lighting sun position that you can sync with the sky texture. It gives you a new tab in world settings with which you can enter time of day and it will place the sun accordingly. There are many setting like north offset that will rotate the sun around the screen (change the north)

2 Likes

Thank you for the help! I still prefer doing it with an empty so I went for that option. I just wasn’t sure how to map the rotation of my empty to that of the sky in each driver, turns out it was very easy: X rotation to Sun Elevation, -Z rotation to Sun Rotation. Kudos to Pavan Bhadaja for the clarification:


There is just one problem remaining: Due to how the Nishita sky node is programmed, the elevation does not warp around accordingly. You’re only allowed to use a value between -90 and 90: This means the elevation caps once the empty points upward (noon) unless you manually change the Z axis from 0 to 180. Is there a formula for the driver expressions to automatically warp the angle?

The angle of elevation has to be used in conjunction with the rotation value.

It is clamped because it describes the angle of the sun from the world centre respect to the ground plane and will always be between -90 and 90. Straight up and straight down or less. The rotation value describes a circle around the world center.

The “sun position” add-on lets you go over mid-day using the time slider.
When you play with the time slider the addon adjusts both the elevation and the rotation value.

To get the sun to do the whole day going over 12 O’clock (90º) you have to adjust both values.
There is a mathematical relationship between them (rotation and elevation.)

My maths suck so I much prefer the addon for this, also I find it very logical.
First you set the North offset to decide where north is (best to do this at sunrise or sunset), then it is a simple question of changing the time of day. This is easily animated and physically logical.

I can not imagine a logical way to do this with an empty, it would be easy to set the sun to the position where you want it for one frame by rotating x and z but you would have to work out an equation (that uses the rotation of both the empty’s z and x axis) to set the values for an animated day, as you would have to rotate the empty on both axis at once it could be a nightmare.

It would probably be easier to first set an initial sun rotation value and elevation (like the addon’s north offset) then rotate the empty on a single axis using drivers to “add” the values needed to the sun nodes rotation and elevation values. (Which is what the addon does for you with the time slider)

Math makes my head hurt and I have no idea of the correct driver settings, you may even need to add a script with “if - else”. I would probably prefer to look into the addon’s code to see how they did it! :upside_down_face:

My advise would be to use the addon as it is great :slight_smile:

2 Likes

The sun position addon definitely looks interesting and easy enough, gave it a quick overview and I like. And it’s builtin so I shouldn’t have to worry about it breaking in future Blender versions if another team stops supporting it. I may give it a go at least out of curiosity.

The empty is still tempting because it lets me control the sun using an in-world pointer or armature bone, which seems useful for a scene you want to animate freely. My plan was to parent it to another empty at a slightly tilted angle and have that parent constantly rotate, simulating a realistic ongoing daytime cycle. It looks like that addon could do this on its own though… I still want my projects to work without requiring addons however, I have to think on it.

Also I actually want to use two Nishita skies blended on top of one another: Normal one for the sun, another for the moon at a roughly opposite angle with much lower intensity. Going to have stars as well… those are super easy to do by range-mapping a Voronoi F1 / Euclidean texture accordingly. Does the sky addon make it easy to control multiple skies at once?

As for my driver based approach it feels like that should be salvageable too. It’s just that I need a more complex expression which makes the X / Z values reset / reverse based on each other’s values, so 270 turns into -90 and so on. I’m not great with complex math so I’ll wait for someone to provide an answer on this too so I know I have it handy in any case.

Managed to figure it out! Partly thanks to the answer provided by Pavan Bhadaja, followed by playing with the drivers and rotations in more depth.

The issue I was running into is that Nishita sky is programmed so the sun elevation angle doesn’t warp around: Only values between -90* and 90* are valid, meaning an empty spinning all the way around won’t work as values like 270 cap the sun. I was looking at complex driver formulas to warp / reverse the angles, yet it seems that wasn’t needed: The sun always rises and sets at an angle, thus you can define a virtual 180* cone for the sun to work in which can itself be pointed in any direction on the Z axis.

For my daytime cycle I parented the sun’s empty to a clock empty: The clock spins in one direction, you can animate the cycle by infinitely increasing its Y rotation over time, and you can give it any Z rotation to point the sun cycle at your desired location. The sun empty has a fixed rotation in the X axis to specify the sun’s height at midday (max 90*), the higher this angle the further from the horizon and higher into the sky the sun travels each cycle.

In the image below the circle is the clock and the large cone is the sun. A smaller cone represents the moon, it will use a second Nishita sky blended on top at lower intensity, which will work the same way just parented at an opposing angle from the sun on the clock.

The drivers are a bit tricky. First you simply use the X rotation of the sun empty as the Sun Elevation value, the -Z rotation as the Sun Rotation value (Z must be negative or the sun goes the other way around). You need to use world rotation for this to work, local or pose space ignore the empty when it’s being rotated by its parent. Also very importantly, you must set the mode to “Swing and Y Twist” from the default “Auto Euler”, “XYZ Euler” and other transform modes won’t work this way! Do so on both drivers and that should be it: You should have a day / night cycle you can animate from the scene via one rotation value.


I figured out how to solve the wrapping issue with the following driver expressions:

Sun Elevation: pi/2-abs(var)
Sun Rotation: pi-var

You’ll have to use “XYZ Euler” for this approach. X will ping-pong the sun if you animate it outside the -90* / +90* range so avoid doing that if possible, the Z axis can be freely animated though. Both X and Z need to be animated together to produce a cycle, rotating with an attachment won’t work any more.

It is always worth working things out (I am sometimes lazy!)

This looks good, I think it is similar to what the addon does, well done. I will have a go at it following your explanations.

This is a good point, I had not thought of. I do not think that the addon can control 2 sky systems in one scene. The moon’s rotation is very different from the sun, so yes you could use a sky texture for it but I have no idea how to make it correct. However I presume you take an artistic approach more than a “physically” correct one.

You could make a separate scene for the moon with a different world. In the “moon” scene use a point lamp as the moon object (in the addons settings “sun object”), this will sync the position of the point lamp with the nishita sun position of that scene. You could then use the position of that lamp to control the position of your moon object (or the values of the second sky texture) in the “sun” scene.
This is of course getting more complicated, so your empty could be better for this.

Edit:
It would be very interesting to see what you come up with in the end, so please post the result! :slightly_smiling_face:

Thank you! In the end, at least for the time being, I went with just scripting the whole thing using two world properties for the sun (with another two for the moon): I liked the empty but just couldn’t get it to wrap right so it felt broken and incomplete. It seems easier to just use sin / cos on #frame to make the sun move automatically. Simply use the following driver expressions, with a sun_direction around 0.5 and sun_time around 1000 for a good test… note that negative values are allowed to flip the side of sky or direction, whereas the moon is automatically reversed from the sun:

Sun Elevation: sin(pi*frame/sun_time)*abs(pi/2*sun_distance)
Sun Rotation: cos(pi*frame/sun_time)*(sun_distance*pi)-(sun_distance*pi)
Moon Elevation: cos(pi*frame/moon_time)*abs(pi/2*moon_distance)
Moon Rotation: sin(pi*frame/moon_time)*(moon_distance*pi)-(moon_distance*pi)+pi

I’m still working on my project, will post the final result a bit later including on Blendswap eventually… it will be an (almost) fully procedural and hyper-realistic landscape. And yes the moon is easy to do: Just use the same drivers as the sun in reverse direction, then use a MixRGB to Add / Screen / Lighten the moon’s Nishita sky on top of the sun’s at a low intensity (I’m using 0.01).

A little preview of my world setup I can share. The bottom nodes are the sun and moon Nishita skies, you can see the properties their drivers use at the right. The voronoi at the top is how I do the stars… muted them here since they look very noisy in the preview, only do this with a denoiser as stars are bright and sharp and a recipe for noisy speckles.

1 Like