1. Factorio
  2. News

Factorio News

Friday Facts #323 - Animated water

Read this post on our website

Water animation - Concept (Albert)

Since the very beginning of the project, we have focused a lot in the side of the factory, providing better designs for the machines, and expressive animations that give a sense of life and credibility in this area. We put a lot of effort also in the environmental side, adding different tile sizes, improving textures, adding doodads, cliffs, trees, decals, and constantly improving the map generation for a better feeling.

But apart from biters and the factory, nothing else moves in this Factorio planet. So the environment is nice looking but it feels somehow unreal due this lack of motion.

Today we proudly present the first experiment in this area: Animated water. This animation doesn't try to grab your attention, it's just there. Slowly moving. I personally bet that this animation, with the proper sound design, will provide the natural feeling that the planet needs.

https://cdn.factorio.com/assets/img/blog/fff-323-animated-water.mp4

Water animation - Technical Art (Ernestas)

Animation was always one of the most powerful creative tools we have. Animation is how we communicate with our audience about functionality, it creates interest and emotions people like. So let us talk about water and how the current representation might be missing something. Some of you with an eye for detail might have noticed that water in Factorio is static. It has foam, which is static. There are also some static reflections. Due to the fact that making animated water was considered polishing, we never took the time to make an actual solution.

But now we are polishing Factorio, trying to make it as beautiful as we possibly can given our constraints. I am glad to talk to you a bit about us solving animated water!

Christmas of 2018, I decided to gift myself with solving water animation in secret. Based on past conversations with Albert the goal for it was clear:
  • It had to look similar to the current water.
  • Photorealism was a no no.
  • It had to be super cheap for the GPU.

In the past I was experimenting with this cheap clouds shader. It used fractal Brownian Motion and only sampled a noise texture, instead of the usual approach of calculating Perlin noise. With a low iteration count, it was almost as cheap as drawing a sprite. So I started MonoGame (lovely framework) and implemented a tile-based world using the same technique for the shader, the only difference being I clamped noise values to simulate brighter and darker areas. For the noise I used our water sprite.

Original - Noise - Clamped

To save GPU power, water was drawn the same as tiles, one after another. The position was easy to solve also, I simply used UV coordinates to represent the game world position. With some trial and error, water was recreated with a moving effect.

https://cdn.factorio.com/assets/img/blog/fff-323-pitch.mp4

At the beginning of 2019, I pitched the prototype to the team. Sadly it was not really accepted mostly because of the movement. However, I sat down with Albert and talked and tweaked values to more appealing ones. After that, we basically forgot about it. Half a year passed and that solution was back on the table, I only had to solve reflections, foam, transparency, out of map transitions, and some other stuff.

Solving reflections, transparency and foam resulted in using a render target to save information for water shader. A render target is just a texture on which you can draw. Using three channels RGB, I am able to save three kinds of information. Red for reflections, green for transparency, and blue for foam. All drawing is additive to account for multiple tiles drawing on top of each other. This way we are able to add information not only for shore, but also for entities.

https://cdn.factorio.com/assets/img/blog/fff-323-layers.mp4

For out of map we updated our jelly feeling with waves on top. Basically we left the old graphics on the bottom and added animated water on top. For cutting/masking out water where we want, I used another shader that generated green waves in the water render target. Now some of you might ask why we did not use a waterfall. I mean it would look nice having a waterfall to this pitch-black hole of nothing. The reason is waterfall was the first thing we tried, and concluded that the jelly looks better and cleaner.

https://cdn.factorio.com/assets/img/blog/fff-323-out-of-map.mp4

Water animation - Game integration (posila)

For a long time, in order to make terrain rendering fast, we would keep an offscreen buffer with terrain that was rendered in the previous frame, and reuse it to render terrain in the current frame. If the players view didn’t change at all, we would use the offscreen buffer as is, if the player moved, we would shift the buffer accordingly, and render just the bits that were not visible before. Zooming or changing tiles in the view would invalidate the content of the offscreen buffer, and the terrain would have to be re-rendered for the entire view. But that happens only in a fraction of frames, so it’s not a big problem.

You may have noticed this optimization is incompatible with rendering animated tiles, so for the initial integration of Ernestas’ water effect, I had to force a full redraw every frame.

This created a performance issue, as the tile render prepare step would take up 3ms (almost 1/5 of total frame time) when zoomed out. Why does that matter?

The game’s main loop runs in 3 major stages:
  • Update - progresses the game state one tick forward.
  • Prepare render - collects the data that is needed to render the current view.
  • Render - uses this collected data to issue commands to the GPU.

While game update and render are executed in parallel, neither of them can run while prepare render does (more on this in FFF-70). So 3ms of additional prepare time means 3ms less can be spent in update before the update rate drops below 60 (and I don’t even want to mention how much time it would take in debug build, I’ll just say that I’d expect a lot of nasty looks from coworkers).

Luckily, I already had an idea how to solve this. The water animation depends only on global time, and the vertex data of water tiles doesn't change in between the frames, so instead of caching the finished terrain render in a texture, we can cache the data resulting from prepare render, which we call draw orders. To make it work, we cache draw orders per-chunk, and we only run prepare render on chunks that have just entered the player view (and weren’t in the cache already).

That pretty much solves the problem of the render prepare and has some nice side benefits. First of all, changing render scale doesn’t need to invalidate the new cache, so zooming doesn’t cause prepare render to run for all tiles in the entire view. Secondly, it creates opportunities for other future optimizations - for example, we can start caching tile draw orders that are likely to enter into the view in advance and spread this work over multiple ticks, or we can generate tile draw orders for each chunk in parallel as they are independent of each other now.

Even though the water effect is relatively cheap, some of our players play the game on really weak hardware, which already struggles with the current state of the game, so we needed to add an option to turn the effect off and essentially revert back to the old behavior. Initially I thought we would even use the old water sprites, but because we had to change the tile transition definitions, the old water would look really bad. I have decided to always render water using the new effect, but if you disable the animation, it will render frozen in time and will be cached to the offscreen buffer.

Since we were keeping the offscreen buffer logic around, we could utilize it for everyone if possible. I added a flag to cached per-chunk tile draw orders, that determines if the chunk contains a dynamic effect (and therefore needs to be rerendered each frame - if the animation is enabled) or if it can reuse pixels from the previous frame. This means when rendering chunks without any water (E.G, the middle of your factory), the new water effect will have no impact on performance.

Modding
When seeing this you might get excited about the possibilities for modding. Well, don’t just yet. The system has been setup for making it possible to define different tile effects, but at the moment it is limited to allow just 1, which is used to define the water effect. I plan to lift this restriction in the near future, but in the end you’ll be limited to only changing the properties of the effect we made. But that still might be interesting enough, due to ability to change the ‘noise texture’.

There is still no plan to support custom shader definitions before 1.0.

As always, let us know what you think on our forum.

Friday Facts #322 - New Particle system

Read this post on our website

Release plans (Klonan)

This week we released version 0.17.79, and marked it stable. Internally we have been calling this 'Stable 3', and the main feature was the new tooltips we showed in FFF-318.

There is one constraint we put on ourselves when we started this more swift feature release schedule: We want to avoid breaking mods. This is easy enough in principle, don't start renaming things, don't remove API features, etc. However as we develop further, there are certain features and improvements that we can't realistically do in a way that won't break mods, such as the new Character GUI (FFF-289) and color correction (FFF-320).

It is for this reason that we are going to accumulate some of these mod breaking changes, and release them all at once. Since it will definitely be breaking mods, we will bump the major version number, so it will be 0.18.0.

We have already internally started merging in these 0.18 features into our master branch, so we will not be doing any more 0.17 releases (unless something absolutely catastrophic is discovered).

The problem with particles (Klonan)

Particles have been in the game for as long as anyone can remember, and they are pretty simple all things considered. They are a small mostly decorative entity, that we use to add a bit of visual gratuity to the death and dying of bugs and machines.

For instance, Biters are full of blood, so when they die, they make quite a splash. Lets try to count how many particles we spawn in a typical dying explosion.

https://cdn.factorio.com/assets/img/blog/fff-322-biter-die.mp4
In this clip, the blood particle sprite has been replaced with a debug visualisation, to make counting easier

So it's quite a few. The Biter spawned 427 particles, and the Spawner 749. Well they don't persist very long, and they're only decorative, so it's all fine right?

One key word I would like to highlight in the previous description, is that they are an entity. When kovarex and slpwnd started making Factorio, they made a robust system for managing game objects and their interactions - the entity system - and everything that has a physical representation in the game world was built on top of this system. As the game grew bigger, it became obvious, the entity system is too heavy weight for some things, and we can get better performance by creating more specialized systems. This led to removing items on belts from the entity system in 0.12, and doing the same for smoke and terrain decoratives in later versions. Despite most other games or game engines having very efficient particle systems from the early stages of development, particles in Factorio are still piggybacking off the entity system in 0.17.

This means that particles are registered on the game surface in the same generic way as everything else. This also means, that they are iterated through when doing entity searches. So what sort of engine actions do entity searches?
  • Area trigger effects - such as grenade, flamethrower stream damage, atomic bomb, poison capsule.
  • Pathfinding - To check if a path can traverse a given tile.
  • Movement collision checks - such as Characters, Units, Projectiles.
  • And many others...


As you can imagine, having thousands of extra entities to iterate through every tick, can start slowing down the simulation. The worst case these days is defending your walls with flamethrowers. In the image below, all entities are highlighted with a debug visualization.



If you lost count, this scene contains 15,689 entities

Flamethrowers vs Biters are pretty much the perfect example of the problem:
  • The biters need to check every tick when they move if they collide with anything.
  • When the flamethrower streams land, they do splash damage, which is an area trigger effect.
  • The flamethrower stream also creates the fire on the ground, which does a collision check.
  • Every 10 ticks, the Fire on the ground do damage with an area trigger effect.
  • The flamethrowers kill biters very efficiently, so a lot of particles spawn in a very short amount of time.
This combination leads to some significant slowdowns later in the game when big groups come knocking. Also, since we improved the pathfinding, the problem is even worse in the latest versions of 0.17.

So how do we solve it?
Particle Optimization - Technical (Rseding)

When Posila first talked to me about doing a re-work of how Particles function in the game I had a lot of ideas. Not all of them worked out in the end but they sounded nice:
  • They wouldn't be entities.
  • They would work like smoke does (stored in contiguous blocks of memory).
  • They wouldn't need to be updated each tick if they didn't effect the game state.


In the end I found that it wasn't worth the added complexity to make #3 work.

The process
Particles needed to not be entities. Something being an entity has a lot of memory and performance overhead that particles just didn't need. Unfortunately when I implemented artillery I made the manual-targeting marker a particle. The reasons why don't matter any more, but it meant I had to add migrations to handle that and then migrations to handle removing all of the entity particles.

I stripped out all of the extra data/logic from particles that they no longer needed - reducing the size of each particle in memory from 224 bytes to 64 bytes. As a side effect of making them not entities it also reduces the amount of information that has to be saved in the save file. However, in most cases particles don't exist long enough to end up in the save file so that didn't really matter.

I needed some place to store/work with the particles runtime as they are created, exist for some short amount of time, and go away. Most stuff in the game ends up being stored on a given chunk (a 32x32 area of the world). In the case of particles I didn't care at all about any of the other stuff on a given chunk so I didn't want to stick them there. Instead, I made a separate thing that functions very closely to chunks and called it "particle chunk". The key differences being: they only exist when there are particles to update on them and the only data they hold are particles. That meant when the game needs to go over each particle to update them, all it has to do is go over all of the "particle chunks" that exist and run update. Additionally since I had full control of these new particle chunks I can recycle them in memory as needed to avoid spending extra time allocating and de-allocating memory as particles come and go.

The end result is a nice performance boost, reduced memory usage, and simplification of the logic around how particles work. A simple unscientific test we performed was nuking the same biter base in the old system and the new system, and recording what the max update tick time was.



The circular ring of entities around the edge are the 'Atomic bomb wave' projectiles.

Old system:
  • Max Entity update = 7ms.
  • Entity count (Excluding projectiles) = 7769


New system:
  • Max Entity update = 2.4ms.
  • Max Particle update = 1.7ms
  • Entity count (Excluding projectiles) = 786


This is not very scientific or highly controlled, but just to give an idea of the scale of the improvement. A 10x reduction in the number of created entities, and about a 40% reduction in max update time. Having the new optimized particle system also means the GFX team can go a bit more crazy with particle effects in the future...

As always, let us know what you think on our forum.

Version 0.17.79 released

Bugfixes


  • Fixed that the infinity pipe mode could sometimes reset when changing other infinity pipe settings. more
  • Fixed that electric energy interfaces didn't consume power correctly. more
  • Fixed market GUI not showing price in the tooltips of modifiers. more
  • Fixed market GUI showing empty price property in the tooltips when no price is set.
  • Fixed lights render quality slider in graphics settings missing tooltip. more


You can get experimental releases by selecting the 'experimental' beta branch under Factorio's properties in Steam.

Factorio version 0.17.78

Bugfixes


  • Fixed a desync related to biter pathfinding. more

Friday Facts #321 - Countdown

Read this post on our website.

1.0 date (kovarex)

Hello,
we feel that the Factorio development is taking way too long. The approach "It is done when it is done" was serving us well to deliver a high quality product, but if we continued this way, we would be doing it basically forever. A lot of us don't have any problem working on Factorio for some more time, but the main problem is, that we would like to introduce new features and content instead of just polishing parts that are already present in the game. We also considered, that the game is quite polished now, and if we just pushed the button to release 1.0, it wouldn't be a catastrophe. From our perspective, a lot of things wouldn't be finished, but from the perspective of a new player, the things we are working on now are mainly nitpicks.

With this in mind, we decided to just specify a 1.0 release date publicly, so we have to stick with it. We will just focus on the most important aspects as we approach the date, and we just do whatever we have time to do. Once the 1.0 happens, we can have some rest and after that, we can finally focus on the content and features again.

The date is 25th September 2020.

Version 1.0 does not mean that development on the game will end, or that Factorio is 100% finished. When we have a better idea of what we will be working on after the 1.0 release, we will let you know.

GDS 2019 (Klonan)
Game Developers Session 2019 is happening in a few weeks, Friday 29th and Saturday 30th of November. This year, like last, we are silver sponsors of the event, so you will see our banners around the venue if you attend.

This year we are happy to have two of our team doing talks at the conference:
  • Albert - "Developing the Visual Style of Factorio".
  • Vaclav - "Technical Side of Creating Factorio Graphics".
You can read a bit more about our talks and others on the speakers page.

Other than our two speakers, a lot of the team will be attending the conference, so if you see anybody sporting a Factorio t-shirt, it could be one of us (don't be afraid to come talk to us).

We also took the opportunity to do some updates to our cover art.



The Factorio team must grow (Klonan)

We have been on a bit of a hiring spree lately, trying to fill gaps in the team where we can identify them. We are happy to say, we have continued our team growth, with two new additions to the team.

Ian is a sound designer from the UK, who has moved to Prague quite recently. He will be working with us full-time here in the office, and with the help of Rseding for engine features, will be developing the soundscape of the game as we narrow in on the 1.0 release.

Next up is Allaizn. You might remember a few of our team mentioned him in past Friday Facts, and he is infamous for his experiments with cars on belts. He has had source access to the game for a long time, and in the past has made some good contributions through the program, so he has been able to get up to speed with us very quickly. For now he is reinforcing Posila in the Graphics backend department.

For some more details on our new colleagues and the rest of the team, we have short bios for everyone on our Team page.

As always, let us know what you think on our forum.