As we all know and see, many house models in Knights Province are still in various stages of sketch phase. They are approaching a sort of right proportions, silhouette and overall structure. From a distance, they read correctly (although if you ask me, I’d probably scale them down by ~10%, but that’s a topic for another day). But up close, a lot of surfaces are still just flat-shaded placeholder materials. This is especially noticeable on wooden elements – planks and beams, which make up a significant portion of most buildings. This is especially noticeable during a new house building process (at least for the houses that have their geometry correctly assigned to progress steps, but that’s another topic for yet another day).
Which brings us to the next point – why automate it? The game uses classic UV mapping techniques for their simplicity. So, texturing wooden planks manually is not difficult at all. In fact, it is one of the easier tasks. Individually each plank and beam are quite simple: unwrap along the length, align with the grain direction and edges, adjust scaling a bit, ensure edges align with texture, repeat the same for endgrain. Rinse and repeat 500 times for every house and you get the scope of the problem xD. Yes, it is extremely repetitive (and boring). Also, every time something gets changed, UVs need to be adjusted to avoid stretchy textures and broken mappings. And repetition is exactly the kind of work that should be automated.

The goal here is fairly pragmatic – reduce manual work, keep visual consistency, allow faster iterations for sketch models and generally have things looking nicer. This is particularly useful at the current stage, where many houses are still evolving in their shape and proportions. Investing time into manual UV work at this stage would be a largely wasted effort. If the texturing basics could be generated automatically, manual work can be reserved for more interesting and characteristic house elements.
With that in mind, let’s try the naive approach first. Lets just map everything to sort of wood texture and see if it looks any better:

Well .. it certainly brought some improvements, but booking up close it is terrible xD. Maybe cube mapping or triplanar mapping? Well, that would not work, since beams and planks are rarely axis aligned.
Let’s do it seriously then. We should start from the top – What is a “plank”? A “plank” can be approximated as an elongated box-like shape with one dominant axis (length) and two minor axes for width and thickness. It will also have two ends. Some planks could be curved slightly, but overall topology should be quite consistent – 2 ends and 4 sides that are mostly perpendicular to each other.
So the initial algorithm was to detect box-like shapes, determine their main axis, map them on to UV and apply a wood texture. This worked well for as long as the geometry behaved exactly like that. Which it often doesn’t. However, this was an important step and proof of concept – with some texturing even the sketchiest models (pun intended) started to look much better.

For the majority of the real models, the assumptions started breaking down. Much too many of the planks are not boxes in the strict topology sense:
* not all planks are 6-sided, far from it
* some have back-facing sides missing
* some are subdivided along the length and are bent or irregular
* some are bent almost 180 degrees from start to end
* some are just a fusion of many elements
At this point, the problem stops being “UV mapping” and becomes geometry interpretation, which is significantly less trivial.
To make better sense of all these issues, I switched to a very simple yet effective debugging method. Instead of applying textures and checking them for failures, I’ve detected each problem as early as possible and assigned a distinctive bright color to it. Note how many planks have “failed” for various reasons, only a few met the “simple box” rules.

This immediately reveals how the algorithm segments geometry, where topology is incorrect and which parts are not detected at all. It also makes it obvious when a single plank is split into multiple parts or multiple planks are merged into one, or surface problems like polygons facing a wrong direction. This step was surprisingly helpful. Without it, it would be very difficult to reason about failures just from final textures.
Off to refining the approach! After several iterations, the process became more structured and resilient. Roughly, it now works like this:
* having most of the wood geometry modelled using quads simplifies the algorithm by a lot (since the engine supports multi-vertex polygons since that helps with better normal shading)
* identifying desired surfaces based on naming (names like AUTOTEXTUREWOOD_xxx)
* grouping connected geometry into “islands of connected polygons”
* converting “islands” into plank candidates using geometric heuristics (quads only, polygon topology, edge neighboring rules)
* reconstructing missing sides and covering holes
* determining dominant axis for each plank candidate
* reordering polygon strips to go uniformly end-to-end
* mapping plank sides UVs aligned to corresponding axis
* mapping planks ends using their normals for alignment

You know things get serious when code comments take up more space than code itself and include some ASCII-art:

The key part here is not UV generation itself, but correctly identifying what a “plank” actually is and what every plank should be. Once that is done, the rest is quite trivial. With the current implementation, around ~90% of planks are autotextured correctly. Which is already enough to significantly reduce manual work and improve the overall looks.
There are still several categories that do not behave well.

Some shapes are effectively multiple planks combined into a single mesh (see that window on the roof). There is no reliable way of splitting them automatically without introducing errors. These are better handled manually.
Other problematic cases are planks with triangle polygons in them (lower horizontal beam on the tower). Those are easier to fix in the model, by redoing them using only quads.
In some cases planks are too bent and/or slanted (towers roof). They can still be “salvaged” if plank-detection rules are slightly relaxed. After all, maybe it is better to texture something suboptimally than to not texture it at all. This is a balance.
You can also notice that the grain direction is slightly off between beam sections. At the moment, each polygon gets mapped without inter-plank continuity. This is something to fix later on. There are also some wrong stretching on diagonal planks – also easy to fix in the coming days.
End grain (planks ends) is a separate problem. It requires a different texture and proper alignment with plank direction. Right now it is handled in a simplified way, which is not always visually correct.
Currently, if the plank can not be textured it will be just skipped and retain the flat color.
Autotexturing runs during house models loading. Measured cost is approximately ~30 ms per house. Given that it replaces a large amount of manual work and that it runs only once per load this is well within acceptable limits. Of course there is still room for optimization, but it is not a priority, given that estimate texturing for 30 houses will be under 1 second.
One important aspect is that this system is fully automatic. Any house model that uses specific surface names will be automatically textured. As soon as geometry is in place and has a special surface name, it already looks “good enough”.
One extra detail is that we can also tint the planks using vertex colors for nicer looks. This is also automated with texture color being compensated with vertex colors to match the desired surface color set for the surface in the model:

Beyond wood, the same approach can be applied to other materials. Plaster is a good candidate – it has large continuous surfaces with similar need for fast iteration. The main challenge there will be avoiding visible tiling seams. Since plaster is uniform in every direction, it will be much simpler than wood elements.
Overall, procedural autotexturing for planks and beams turned out to be much less trivial than expected. The code size now approaches 66kb and will still grow with the fixes. The core idea is quite simple. The complexity comes from real-world geometry, which rarely follows ideal assumptions. Even so, the current results are already useful, most planks are handled automatically, visual quality is consistently good and manual workload is reduced significantly. As more houses are added or updated, they will benefit from the system automatically, without additional effort.
In the coming days I will work through more houses, assigning materials and fixing bad topologies. I still haven’t decided if this feature should be in Alpha 13.2 or go towards Alpha 14. What is your opinion, what other low-hanging fruits are there to make the game look and play better?
























