Why Vectors Matter: A Little Mathematics Behind Solar Energy Analysis

Hello again!

We talked about the Solar Energy analysis in the previous post, which was a nice way of introducing a useful tool that allows us to estimate how much solar energy reaches the rooftops of our buildings. This type of information is a very useful one, with real-world implications, such as being able to determine which areas of a roof are the ideal candidates for placing solar panels.

Today though, I want to put the usefulness of that tool aside and focus on something else that is dear to me – especifically, I want to focus on the logic that enables that tool to work, and on the mathematical principles that power it.

The reason why? Well, many! But the main one is giving back to the community, and exemplifying the usefulness of otherwise abstract mathematical concepts. We’ve all been young and wondered why the hell something was worth studying, and I feel like a practical example such as this one can help in that regard. It would have made things even more compelling to me back in the day if my maths teacher had told me: hey Brais, you’ll need to use this if you want to work in video games and real time apps*!

(*The real time apps is something that would have made no difference to me, he had me hooked with video games really!).

So, today I’d like to talk about some of the mathematics that make this kind of functionality possible. More specifically, we’re going to look at vectors: how we can use them to understand the world around us, and why they are so useful when working with 3D environments.

With that our of the way, let’s get our hands dirty and look at a real-world example of how a little bit of mathematics can help us solve a surprisingly interesting problem.

1. Understanding our rooftops: vectors and surface normals

Let’s start by imagining that we want to calculate how much sunlight reaches the roof of a building. Before we can do anything meaningful, we need to know where that roof is and, perhaps more importantly, which way its surfaces are facing.

This is where vectors come into play. If you’ve ever worked with a 3D application, you’re probably familiar with the idea of representing positions and directions using three components: X, Y and Z. We can use these to describe the location of any point in our virtual city, as well as the direction in which a particular surface is facing.

For our Solar Energy tool, this second piece of information is particularly important. Consider a building with a pitched roof: even though both sides belong to the same building, their orientations are different, meaning that they won’t necessarily receive the same amount of sunlight throughout the day.

To describe those orientations, we use surface normals, which are simply vectors perpendicular to a surface.

Aerial view of a cityscape featuring numerous tall buildings, highlighting two skyscrapers with arrows pointing to their upper sections.
Above, arrows pointing in different directors – a very technical representation of vectors

And this brings us to one of those mathematical concepts that you might remember from school or university: the cross product, also known as the vector product.

Remember how the cross product of two vectors produces a third vector perpendicular to both? Nope, right?Well, regardless of our bad memory, that’s exactly the kind of operation that makes working with 3D geometry possible!

And to exemplify that, here is a bit of maths. Imagine that we have three points belonging to a triangular surface: A, B and C. By subtracting their positions, we can obtain two vectors along that surface:

AB = B − A

AC = C − A

Their cross product gives us a vector perpendicular to the surface:

N = AB × AC

We can then normalize that vector to obtain a unit normal, which has a length of 1. The order of the cross product determines which side of the surface the normal points towards, so that matters too.

In practice, Unreal Engine already provides ways of retrieving surface normals directly from geometry, which is what we use in our Solar Energy tool. Nevertheless, understanding how those normals are obtained is extremely valuable, particularly when working with procedural geometry, custom meshes or more advanced geometric calculations.

And that’s our first practical application of vector mathematics: using vectors to describe the orientation of surfaces in a three-dimensional environment.

2. The dot product: understanding how sunlight reaches a surface

Now that we know which way our roof is facing, we need to determine how that orientation relates to the position of the Sun.

Fortunately, the Sun’s position in the sky can be calculated using information such as our geographical location, the date and the time of day. Once we have that information, we can represent the direction towards the Sun using another vector.

(Actually, calculating the location of the sun isn’t exactly easy, but let’s leave that one for another post!).

This leaves us with two directions: the normal of our roof, which we’ll call N, and the direction towards the Sun, which we’ll call S. What we want to know is how closely these two vectors are aligned, because that affects how much direct solar radiation reaches the surface.

And if you remember your vector mathematics, which we’ve said you don’t, you’ll probably already know where this is going: the dot product, or scalar product. Amazing how the brain works, information that was once there but is now completely out of reach!

If we were anñe to actually remember, we’d know that the dot product of two vectors is defined as:

A · B = |A| × |B| × cos(θ)

Where θ represents the angle between them. If both vectors are normalized, their magnitudes are equal to 1, and the expression simplifies to:

A · B = cos(θ)

This is particularly convenient because the result immediately tells us how the two directions relate to each other.

A 3D graphical representation of a cityscape with labeled vectors (V0, V1, V2, V3) illustrating directions and values overlaid on the scene.
Three surfaces receiving sunlight at different angles, showing their corresponding dot products in beautiful annotations

For example, when the vectors point in exactly the same direction, their dot product is 1. This means that sunlight is arriving perpendicular to our roof, which is the most favourable orientation for receiving direct radiation at that particular moment.

If the angle between them is 45 degrees, the result is approximately 0.707. At 90 degrees, the dot product becomes 0, and when the angle exceeds 90 degrees, it becomes negative, indicating that the Sun is behind the surface.

Let’s put some numbers into this. Imagine that we have a horizontal roof with an upward-facing normal:

N = (0, 0, 1)

And that the direction towards the Sun is represented by:

S = (0.6, 0, 0.8)

Since both vectors are normalized, we can calculate their dot product by multiplying their corresponding components and adding the results:

N · S = (0 × 0.6) + (0 × 0) + (1 × 0.8) = 0.8

That’s all we need to determine how directly sunlight strikes that particular surface. In a simplified direct-radiation model, this value can be used as a factor representing the effect of the surface’s orientation, with negative results treated as zero.

This is an excellent example of why the dot product is such a useful operation. The same principle appears in countless other applications, from lighting calculations and reflections to determining whether an object is facing another one, or whether a character is moving in a particular direction.

In other words, understanding the dot product isn’t just useful for calculating solar energy. It’s one of those mathematical tools that you’ll probably find yourself using again and again when developing 3D applications.

3. Ray tracing: when geometry gets in the way

Of course, knowing that our roof is facing the Sun doesn’t necessarily mean that sunlight is reaching it. We might have a perfectly oriented surface that happens to be standing in the shadow of a much taller neighbouring building.

This introduces another interesting problem: how do we determine whether there’s something standing between our rooftop and the Sun?

One possible solution is to use ray tracing, or more specifically, geometric line traces. The principle is straightforward: we start from a point, extend a line in a particular direction, and check whether that line intersects any geometry along the way.

In our case, we already have the information we need. We know the position of the point we’re analysing, and we have a vector pointing towards the Sun. Using those two values, we can define a line extending from our rooftop towards the sky.

Aerial view of a modern urban landscape featuring skyscrapers with one prominent building highlighted by an orange arrow.
Ah, shoot! The next door building is blocking my view!

Mathematically, the endpoint of that line can be calculated using a simple vector operation:

Q = P + S × d

Where P is our starting position, S is our normalized direction vector, and d is the distance we want to travel along that direction.

For example, if our starting point is (100, 200, 300), our direction is (1, 0, 0), and we want to travel 500 units, the endpoint becomes (600, 200, 300).

Unreal Engine provides built-in functions for performing these intersection tests, so we don’t need to implement the underlying collision-detection algorithms ourselves. However, understanding the mathematics behind the operation is still extremely useful, especially when we need to construct our own traces, interpret their results or troubleshoot unexpected behaviour.

If our line intersects another building, we know that the direct path towards the Sun is obstructed. If it doesn’t, we can consider the point unobstructed within the distance we’ve tested.

Naturally, this doesn’t mean that a shaded roof receives no solar energy whatsoever, since diffuse radiation from the sky can still reach it. But determining whether a surface has direct visibility towards the Sun is an important part of understanding its solar exposure.

And once again, we’ve used relatively simple vector mathematics to solve a practical problem in a 3D environment.

4. From individual points to an entire rooftop

So far, we’ve looked at how vectors allow us to describe the orientation of a surface, determine how directly sunlight strikes it, and check whether surrounding geometry obstructs the Sun. The next step is to apply those concepts to an entire rooftop rather than a single point.

One way to approach this is to divide the area we’re interested in into a collection of sampling locations. Each of these represents a small portion of the roof, allowing us to analyse its position, orientation and exposure independently.

An aerial view of a city model displaying various buildings along a waterfront, with a user interface on the left side featuring options for solar energy analysis and building selection.
Different points on the roof we are about to analyse

This is particularly useful when working with complex buildings, where different parts of the roof might have different inclinations or be affected by shadows from nearby structures. Not that I’ve chosen such a building on the previous image, though!

By repeating our calculations across the roof, we can begin to understand how solar exposure varies spatially, rather than treating the building as a single surface with a single result.

There’s another interesting mathematical concept hiding here: sampling. Instead of analysing every possible point on a continuous surface, which would be impractical, we select a finite number of representative locations.

The number and distribution of those samples affect the detail of the resulting analysis, as well as the amount of work required to perform it. This introduces a trade-off between spatial resolution and computational cost, something that becomes increasingly important when working with large or complex 3D environments. And that’s before we even consider that the Sun doesn’t remain in the same position throughout the day!

If we want to estimate solar energy over a longer period, we need to repeat our analysis at different times, taking into account the changing position of the Sun and the corresponding effects on our rooftop. At that point, what started as a handful of relatively simple vector operations can quickly turn into a substantial computational task…

But we’ll leave that particular challenge for the next post 😀

5. Why understanding the mathematics matters

When we’re learning mathematics, it’s not always obvious how the concepts we’re studying might eventually become useful. Operations such as dot products and cross products can seem like little more than exercises involving numbers and formulas, particularly when we haven’t yet encountered a problem that requires them.

But hey, this post is all about showing the light at the end of the tunnel! These operations really are fundamental to understanding and manipulating three-dimensional environments. A cross product can help us determine the orientation of a surface. A dot product can tell us how closely two directions are aligned. And a few simple vector operations can allow us to construct geometric queries and determine how objects relate to one another. In our case, those concepts form part of the foundations of a tool that can help us understand how solar energy reaches the rooftops of buildings in a city.

Coming from an architectural and 3D modelling background, I’ve found this particularly interesting throughout my journey into development. Many of the problems I encounter today become considerably easier to approach once I recognise the mathematical principles behind them. And bridging that gap is something that I think makes learning about these topics that much more interesting… or at least worthwile!

And speaking about worthwile, this is something I’d encourage anyone starting out in programming or 3D development to keep in mind. You don’t need to know every formula by heart, and you certainly don’t need to understand every mathematical concept before you can begin building things. But becoming familiar with the fundamentals gives you a set of tools that you can return to whenever a new problem appears.

And, as an aside, it can also lead to nerding out about phylosophical things. Such as – why do we even define space in 3 dimensions? Are dimensions tied to the magnitude of the space itself? And other outrageous ideas you might find thinking about yourself as you try to make sense of why we are describing space in the way we are doing, and what other methods might be out there.

.

.

.

What’s next?

In the next part of this series, we’ll move away from the geometry itself and look at another challenge that arises when developing tools like this one: computational performance.

After all, calculating the solar exposure of a single point is relatively straightforward, but what happens when we need to repeat those calculations thousands of times, across an entire rooftop and over a period of several months?

That’s where concepts such as asynchronous execution, multithreading and parallel processing start to become particularly useful. We’ll explore what those terms mean, why they matter, and how they can help us build applications that remain responsive while performing complex calculations. I think having a concrete example is a great way to stay motivated when it comes to learning about these topics – or at least, that was the case for me! Learning about asynchronous and multithreaded execution can be a bit dry for someone who didn’t study computer engineering at uni.

Until then, I hope you are having a great week, and lots of love from over here!

See you on the next one!