Day 12 - 🛠️ Behind the process - Building a Material Library

Article / 15 May 2026

How I approach material libraries on AAA projects: starting pure, cataloging variants, and building effects as layers.

Most material libraries are built asset by asset. Scale that across a studio - with external partners in the mix - and after a hundred assets, nothing quite matches anything else.

I approach it differently. Everything starts from a foundation.


Starting Pure

Before anything else, I build pristine base materials - pure steel, clean copper, raw iron. No wear, no damage, no variation. Just the material at its most accurate, PBR-compliant state.

On a large project, if the baseline values are wrong - if your copper reflects at the wrong intensity or your steel sits outside the PBR range - that error compounds through every asset that inherits from it. Getting it right once means every downstream material benefits.

I also validate these directly in the engine. PBR standardizes the underlying physics, but every engine has its own roughness curve and tone mapping quirks. Testing in-engine early catches those discrepancies before they propagate.

The principle: set the foundation correctly, and consistency becomes structural.

Cataloging Variants

A pure material is only the beginning. From each base material I catalog a defined set of variants: worn, roughened, oxidized. Pure copper becomes worn copper becomes oxidized copper - the same logic across every base in the library.

The goal is a controlled vocabulary. When an artist needs a weathered version of something, the answer is already there. And because each variant is defined in relation to the base, blending between a pristine and a worn state is clean and controllable.

Library Structure & Organization

Naming conventions sound trivial until a library has three hundred entries and nobody can find anything.

In Substance Designer, I keep internal and production-ready materials in the same file but mark the base graphs as Hide in Library - so artists browsing the library never see the intermediate states. Only the final, mixed material is exposed. This prevents anyone from accidentally applying a raw "Copper_Pure" graph directly to an asset.

The folder structure follows two tiers: internal ingredients and exposed, production-ready materials.

Naming follows the convention M_[Material]_[State]_[Variant]:

  • Internal bases: [Material]_[State] → Copper_Pure, Copper_Worn, Copper_Oxidized (no prefix - not for direct use)
  • Effect nodes: FX_[Effect] → FX_Roughen, FX_Dirt
  • Final materials: M_[Material] for the clean base, M_[Material]_[State]_[Variant] for pre-authored wear states → M_Copper, M_Copper_Aged_001, M_Copper_Aged_002, M_Copper_Patina_001

The M_ prefix immediately identifies something as a production-ready material - useful when assets land in Substance Painter or get handed off to external partners. The state name describes the condition rather than the intensity, and the numbered suffix leaves room for multiple variants of the same state without renaming anything later.

The underscore prefix on _Base/ is a deliberate signal: anything in that folder is an ingredient, not a finished product. Together, these conventions ensure that neither internal artists nor external partners accidentally reach for the wrong material/textures.

Effects as Layers

Rather than baking wear or dirt into each material, I build effect nodes - modular layers that sit on top of the base. The base handles accurate, clean values. The effect handles the storytelling.

Pure copper with a roughening effect becomes a more matte, used version. The effect reads mesh data - curvature, ambient occlusion - and adjusts gloss and saturation accordingly. The same effect runs on copper, iron, or steel and produces a contextually appropriate result. Build it once, apply it everywhere.

The final surface is often a blend of several bases combined through masks, grunge maps, or mesh data. The blend logic follows directly from reference - see Day 11 - đź’ˇ Insight - Why Photo Reference Changes Everything. Basing those blend conditions on observed reference produces results that hold up under close inspection.

Performance isn't a concern here. The pure base materials are simple and fast, and compositing them is lightweight - or it can be baked out entirely into textures at the final asset stage. That said, texture resolution is worth keeping in check; more isn't always better, and going overboard adds cost without a visible return.

Real Example / Material Breakdown

Copper is a good example because its aging states are visually distinct and easy to read in render - it moves from warm, high-reflectance metal to dull brown tarnish to blue-green verdigris, with each stage clearly readable at a glance.

Every material starts factory new - Copper_Pure. Before building anything, I study photo reference to understand where the story lives - see Day 11 - đź’ˇ Insight - Why Photo Reference Changes Everything.

From there, Copper_Worn and Copper_Oxidized are cataloged as separate states in the same file, hidden from the library. Copper_Worn shifts gloss downward and pulls the albedo toward a darker, warmer brown. Copper_Oxidized introduces the characteristic blue-green shift - verdigris forming in recesses and sheltered areas first.

To build M_Copper_Aged_001, those bases are blended using:

  • A grunge map to break up the transition between clean and worn areas
  • Curvature to concentrate wear on raised geometry - edges, ridges, contact points
  • Ambient occlusion to push the oxidized state into recesses and cavities where verdigris would naturally collect

The FX_Roughen effect node sits on top, reading the same mesh data to adjust gloss locally. The result is a surface that tells a story: warmer and more reflective where it's been handled, blue-green and rough where it hasn't.

The final output is baked down to a texture set - albedo, roughness, normal - keeping runtime cost flat regardless of how complex the compositing graph is.

Copper (left to right): base → variant → oxidized → final comp

Tooling & Pipeline

My tool of choice is Substance Designer. You can build a base material, reference it in a variant, reference that in an effect node, and the whole chain updates when anything upstream changes. The maintenance overhead grows with the library, but the referencing model is what makes this approach practical at scale.

Set up the referencing system cleanly and the mixed materials carry through into Substance Painter as well - consistent values across both authoring packages without any manual syncing.

One decision worth making early is whether to keep materials live as tiling composites or commit to a baked unique texture set. Tiling materials stay flexible - parameters remain adjustable, and the referencing chain updates when anything upstream changes. A baked unique set locks the result but keeps runtime cost flat, removes library dependencies, and is the right call for hero assets where every detail is hand-authored.

A potential option: use tiling library materials for environment fill and repeating surfaces, bake unique sets for characters, props, and anything that needs to respond to LOD budgets individually.

Why This Approach Works

Reusability isn't just a workflow preference - it's a quality guarantee. When everything derives from a shared foundation, new assets automatically sit in the right range and reviews focus on storytelling, not correcting broken base values.

It takes longer to set up. On any project of meaningful scale, the return is significant.

© 2026 Stefan Groenewoud - All views are my own, not those of my employer.

Day 11 - đź’ˇ Insight - Why Photo Reference Changes Everything

Article / 14 May 2026

On why studying a real surface is the most underrated step in material creation - and why experience doesn’t make you immune to skipping it.

Most artists think they know what copper looks like. They've seen it their whole life - door handles, pipes, coins. So they open Substance Designer and start from memory. That's where it goes wrong.

You Think You Know, But You Don't

Memory doesn't retain that copper in shadow reads differently than copper in direct light. It doesn't retain that edge wear looks fundamentally different from surface wear. Or that verdigris doesn't spread uniformly - it collects in recesses, on horizontal surfaces, anywhere moisture sits. Photo reference does.

What Reference Gives You

The most valuable thing reference gives you isn't color - it's logic. When you study a real surface carefully, you stop seeing a material and start seeing a system of rules.

Where does wear concentrate? On the high points - edges, ridges, anything that gets touched or contacted. Where does oxidization start? In the recesses, the cavities, the areas that trap moisture and see less air. Where does dirt settle? The lowest geometry, the sheltered horizontal surfaces.

These aren’t arbitrary decisions made by an artist; they’re physical laws. Reference shows you what those laws produce in practice, and once you see them, you can't unsee them.


How to Study a Surface

Not all reference is equally useful. A quick image search gives you an impression. What you need is detail - close-up shots, multiple lighting conditions, ideally studio photography with controlled light.

When studying a surface I look for:

  • Transition zones - where does clean end and worn begin? Is it a sharp edge or a gradual fade?
  • Edge behavior - are worn edges brighter (polished from contact) or darker (oxidized from exposure)?
  • Surface texture variation - a single material rarely has uniform roughness across its entire surface
  • Texture frequency - is it mostly macro variation or high frequencies driving the overall feel? This affects color, roughness, and normals - and how those elements play off each other.
  • Color under different lighting - metals shift hue significantly between shadow and direct light; getting this wrong is what makes a material look like a texture rather than a surface

Into the Build

Once you’ve studied the reference, the blend logic writes itself. You know which material states you need. You know which mesh data drives each transition - curvature for edge wear, ambient occlusion for trapped oxidization, a grunge map to break up anything that would otherwise look too uniform.

Without reference, those decisions are guesses. With it, they’re observations.

That’s the shift. It moves material creation from decoration to description.

© 2026 Stefan Groenewoud - All views are my own, not those of my employer.

Day 10 - ⚡️ Quick - Heat Oxidation on Metal

Article / 13 May 2026

The color of heated metal isn't arbitrary - it follows physics. Here's the logic behind it and why it matters for material work.

Note: This started out as a 'quick' post but I went down the rabbit-hole trying to be as accurate and precise with my findings.

The Science

When steel is heated, a chemical reaction occurs between iron and oxygen, forming a thin oxide layer on the surface. The thickness of that layer - determined by temperature and how long the metal is exposed to heat - dictates the resulting color. Thicker layer, different color. It follows the same thin-film interference principle behind iridescence on soap bubbles or beetle shells.

The key insight for material artists: because temperature controls the layer thickness, the color progression is always consistent. Hotter areas produce predictable colors, cooler areas produce others. The gradient isn't artistic - it's physical.

The Color Gradient

Scientifically rigorous resources on heat coloring are sparse, but this reference by Jeffrey H. Dean is the strongest visual breakdown I could find. It's grounded in an artistic practice where craftspeople control temperature precisely to achieve a target color - which means the color-to-temperature relationship is treated seriously, even if the context is craft rather than physics.

The color range follows a consistent progression - pale yellow → straw → gold → brown → purple → blue → grey - with each step corresponding to a thicker oxide layer and higher temperature. The gradient always runs from the hottest point outward. That directionality is the rule to encode in your material.

⚠️ This progression is specific to steel. Aluminum, copper, and gold each produce different color ranges under heat - the underlying physics is the same, but the output colors differ.

That color shift also has consequences for how the surface reflects light.


Effect on Reflectance/Specular

The oxide layer affects reflectance in a way that's worth understanding clearly: based on my research, it behaves like a thin-film coating, producing the color shift through interference rather than by changing the underlying material. The surface remains metallic - the oxide layer doesn't convert it to a dielectric. Metalness stays at 1. The change is in the albedo and a subtle shift in the specular response as the layer thickens.

Color & Temperature Reference

Consolidated from Machinery's Handbook (5th–20th editions), the ASM Heat Treater's Guide, Evans (1925), and Bhadeshia's Cambridge notes.

Replicating in Substance Designer

The gradient logic translates cleanly into a Substance node or filter. The interesting part is that you can drive it with physically based temperature values directly - expose a temperature parameter, map it to the color gradient, and let that control the output.

For the spatial variation, the inverse of a thickness map generated of your asset, works well as the input. Thinner areas of the mesh heat faster and reach higher temperatures first - which means they sit further along the color progression. Feed that into the gradient and the directionality takes care of itself. The same rule that applies in the real world applies in the node graph: thickness controls temperature, temperature controls color.

I normalized the color range so it could be easily remapped to a gradient. By using the aforementioned inverse of the thickness map, I can dynamically control the positioning. Wrapping this in a custom node would add more controls - a min/max remap of the input mask, for example - but the core logic holds as is.

© 2026 Stefan Groenewoud - All views are my own, not those of my employer.

Day 9 - 🔬 Deep Dive - Depth Prepass Diagram

Article / 12 May 2026

What Actually Happens in a Depth Prepass

A depth prepass runs your geometry twice - but the second pass costs almost nothing. Here's why that trade-off is worth it.

A depth prepass (or Z-prepass) is a two-pass technique. In the first pass, you render your opaque meshes using a vertex shader only - no pixel shader, no render target bound - purely to write depth values into the depth buffer.

In the second pass, when you render the scene for real, the GPU uses that pre-populated depth buffer to discard any fragment that isn't the closest visible surface before the pixel shader ever runs. That guarantee of zero overdraw is the whole point.

The diagram below shows both passes and how they connect.

For comparison, here is the standard pipeline without a Z-prepass:

Without a pre-populated depth buffer, every fragment that survives rasterization goes straight to the pixel shader - regardless of whether it's actually visible. In a dense scene this leads to overdraw: the same pixel being shaded multiple times, with only the final result kept.

Pass 1 is intentionally fast and cheap. Using a position-only vertex buffer reduces memory bandwidth. With no pixel shader and no render target, more draw calls can share the same vertex shader and render state - which improves batching and reduces per-draw call CPU overhead.

The optional tessellation and geometry stages (Hull, Tessellator, Domain, Geometry Shader) are part of the full rendering pipeline but are seldom used in typical video-game rendering. There are exceptions, like Ocean or Snow rendering where you would use Tessellation.

Early-Z is the payoff. Because the depth buffer is already populated from Pass 1, the GPU can reject occluded fragments before they reach the pixel shader. In a dense scene - foliage, interiors, overlapping geometry - this can save a significant amount of pixel shader work that would otherwise run on pixels you'd never see.

This also unlocks several downstream techniques: SSAO can be kicked off early using the depth buffer, hierarchical-Z occlusion culling becomes possible, and screen-space shadows and screen-space reflections can raymarch against depth before the main pass completes.

This is my interpretation based on what I've read in books and online - things do change as technology evolves.

© 2026 Stefan Groenewoud - All views are my own, not those of my employer.

Day 8 - đź“– Learning - Week 1 reflection

Article / 11 May 2026

Week 1 Reflection - Pipelines & Industry

The first week covered the rendering pipeline fundamentals I've been meaning to write up for years. Here's what I learned from actually doing it.

What I Covered

The theme for the first block was Pipelines & Industry. Shadow proxies and occlusion culling had been on my list for a while - I knew what I wanted to say, but I'd kept putting it off. Breaking them into smaller posts made them more manageable to write, though in practice I went deeper than I'd initially planned to make sure the concepts actually came across.

The industry and career posts were a different kind of challenge. Those came from real experiences, which makes them easier in some ways and harder in others - you want to be honest without being uncharitable.

What I Cut

A few topics didn't make it into the first week. I had originally planned to demonstrate some of the Substance and shader tools I've built that have set projects up for success, and some rendering techniques with real examples. The short turnaround time was part of it, but so was the need to ask for permission from previous projects before sharing anything. I'd rather do those topics properly than rush them. If time allows, they'll show up later in the experiment.

What Writing at Pace Actually Feels Like

Consistent output requires momentum, and momentum takes a few days to build. Part of why I decided not to post on weekends is to give myself space to recharge and think about where to take things next. An extra consideration for me is that English isn't my first language, so proofreading and spell-checking adds time to every post. It's manageable, but it's worth naming.

What's Next

Block 2 moves into materials and how I approach material creation at a studio. I’d also like to revisit some of the more technical topics from this week in more depth if the interest is there. Let me know which ones you’d find useful.

© 2026 Stefan Groenewoud - All views are my own, not those of my employer.

Day 7 - ⚡️ Quick - Pixel Coverage Calculations

Article / 08 May 2026

How to measure wasted UV space, and why it matters for alpha textures.

While writing a batch optimization script, I kept running into the same pattern. An asset with an alpha channel would have everything packed into a single material to save draw calls — but in practice, we were loading a full 2048×2048px albedo and alpha texture just to use 20% of it for the actual alpha-test pixels. With shaders you can split the work: an opaque shader handles the solid parts, an alpha-tested shader handles only the cutouts. But the texture itself still needs to be addressed.

The better approach is to pack the alpha parts separately into their own texture set and material. If there's very little alpha-tested geometry on an asset, you can potentially discard those polygons entirely over distance and skip the alpha texture sample altogether. And when memory gets tight, lower mips on alpha-tested materials degrade aggressively, blurring out detail fast.

The question is: how do you measure that waste, and what do you do about it?

Pixel Coverage

Capturing the alpha pixels that cover an asset tells us the number, or percentage, of pixels that are "wasted" within the UV shells or the texture overall.

By calculating the extent of the alpha texture actually used, we can make an informed decision: should the alpha cut or alpha blend mesh parts be packed separately, rather than loading a full 2K texture for a fraction of the content?

The Trade-off

Yes, separating the alpha parts into their own texture incurs an additional draw call and a unique shader. But the trade-offs work in your favor:

  • Lower LODs — the additional cost can be stripped from any LOD below the first, where alpha complexity rarely matters
  • Reuse — a small, generic alpha map can be shared across the project with a minimal memory footprint
  • Better quality — with a dedicated map, you can often increase the resolution of just that texture, improving alpha blend quality and mipmapping without the cost of upgrading the full 2K

Example: An alpha cutout here occupies less than 15% of its texture — meaning most of what gets loaded is unused. The red outline indicates a UV shell. Within that shell, the formula above counts exactly how many pixels are actually used for alpha testing.

Ideal setup.

Formula

This function computes the UV coverage of a mesh; the fraction of texture space that is actually occupied by UV shells.

def CalculateUVCoverage(inMesh):
    areas = GetUVSurfaceAreas(inMesh)
    coverage = sum(areas)
    return coverage

A value close to 1 means the UV space is well packed. A value close to 0 means most of the texture is empty — wasted texel budget.

From there, I can go a step further and measure what fraction of those UV-covered pixels are actually doing alpha work. The key is to mask the opacity map against the UV shells first — if you use the opacity map directly, any padding or dilation bleeds outside the shells and returns a false result.

areas = GetUVSurfaceAreas(inMesh)    # 2D mask: white = UV shell, black = empty
opacity = LoadImage(inAlpha)          # opacity map: black = opaque, white = transparent
masked = areas * (1 - opacity)        # invert opacity so opaque pixels become 1, then mask to UV shells
alpha_coverage = sum(masked) / sum(areas)  # fraction of shell pixels actually used for alpha

In Practice

Is it always worth it? Maybe not for every asset. But collecting this data across a project is valuable — it reveals patterns, flags waste, and gives you something concrete to learn from going into the next project.

Run CalculateUVCoverage on any alpha-using asset during your pipeline validation pass. Flag anything below a coverage threshold (I use 30% as a starting point) and evaluate whether the alpha geometry is worth splitting into its own dedicated map. A small texture at the right resolution beats a large texture you're barely using.

New solutions are emerging for this problem too. Opacity Micromaps draw triangles based on your opacity map, reducing overdraw and simplifying ray-tracing meshes at the geometry level. It may be a while before these make their way into your engine, but it's worth keeping an eye on.

© 2026 Stefan Groenewoud — All views are my own, not those of my employer.

Day 6 - 🛠️ Behind the process - Approaching Material Creation

General / 07 May 2026

How I Approach Material Creation

How to approach material creation depends on whether it’s for personal work or a professional setting.

Personal vs. Professional

The goal shifts completely depending on context. For personal work, you’re trying to demonstrate your range and knowledge — you get to choose the subject matter, push yourself into unfamiliar territory, and show what you’re capable of. For professional work, the asset needs to serve the project first. If I’ve never worked on organic materials and want to explore them, a sci-fi corridor game is not the place to try it for the first time.

How Briefs Come In

I’ve worked from all kinds of starting points. Sometimes it’s a clear-cut piece of concept art with well-defined shapes, values, and a material breakdown already implied. Other times it’s a real-world reference that needs to be pushed toward the project’s visual language. The hardest and slowest is when the brief is open to interpretation. Multiple iterations, trying to translate someone else’s vision onto the canvas, until you land somewhere that feels right. If you can reduce ambiguity early, do it.

Starting Point: Alignment and Reference

On a professional project, my first step is always to align with the art director on their vision for the asset, prop, or environment piece. I don’t start building anything until that conversation has happened.

From there: gather a large pool of reference images. More than you think you need. Bring them to art direction and start culling: decide what stays, what goes, and what elements you’re specifically trying to hit. Reference isn’t decoration; it’s your contract with the team about what the final thing should feel like.

Art Direction

There is some unknown territory depending on whether you are the first artist on a project or joining one that already has a defined look. If you join an arena shooter that has existed for five years, you know that is the style you have to match - your job is to fit into an established system, not reinterpret it in your own way. Look-dev is mostly the time on a new project when a material artist and the art director will try to define the art style together and produce benchmark assets that set the example for the rest of production. In practice that means matching existing roughness ranges, staying within the established palette, and using the same base tiling rates as surrounding assets. The creative challenge shifts from "what should this look like" to "how do I get there within these rules."

For a personal project you are the art director, so you will have to figure out what look you're going for. That can be building toward a specific game company you'd love to work for, or simply setting yourself a new challenge.

I've never had to fully redo a material, but there have been moments where you have to reassess whether the direction you're heading is right for the intended look. A material can look very good in isolation, but in context it becomes too distracting. It might be a great portfolio piece on its own but it's also about striking a balance that best serves the project. That's not always easy.

Splitting It Up

Before diving in, it’s worth asking: is this one material, or a combination of materials and shading effects working together to produce the result? A wall might have a base plaster material, a damage decal layer, and a wetness mask, each is a separate concern. Getting that decomposition right early saves significant rework.

The choice usually comes down to this: a layered material approach gives you flexibility at runtime; think a slick oil layer on top of an asset that needs to shift over time, or a burn effect that sits on top of everything and is controlled by a placement mask. A single material is your typical export directly from Designer or Painter, but you need to account upfront for things like shader-driven tint, detail map blending, or any other parameters that need to be controlled at the engine level. Neither is always the right answer, it depends on how the asset will be used, how often it needs to vary, and what the shader budget allows.

The Actual Process

Set your texel density first. Figure out the tiling rate and set the real-world measurements in Substance Designer or Painter before you start building. This ensures that anything derived from your height map (normals, ambient occlusion, curvature) is physically grounded and PBR-compliant, and that your material sits consistently alongside everything else in the project at the same real-world scale.

Compartmentalize reusable features. If your project has rocks appearing across multiple surfaces — cliff faces, rubble piles, ground scatter; build a rock generator node once and share it across all materials that need it. The same goes for any recurring detail: pine needles, cracks, edge wear. You get visual consistency across the project and a single point to update when something needs to change.

Settle on a naming convention early. Your materials, resources, and shared nodes need to be findable: by you six months from now, and by whoever else is working in the same library. Whatever convention you pick, document it and stick to it.


Closing Thought

What works for one person doesn’t always translate to another’s workflow, so don’t be afraid to experiment and adapt. That said, on a professional project, you often don’t have the bandwidth to rethink your process mid-stream. Build the habits in personal work, so they’re second nature when it counts.

© 2026 Stefan Groenewoud — All views are my own, not those of my employer.

Day 5 - đź’¬ Take - The optimization conversation

Article / 06 May 2026

Optimization is treated as a problem-solving activity when it should be a planning activity. By the time someone raises a performance concern, the art is already built, the habits are already formed, and fixing it is expensive.

Timing Is Everything

Game development is often a balancing act; you need R&D first to figure out the style and direction of your project. I'm not saying teams should hyper-fixate on optimization at the expense of that process; that's the complete opposite of what I'm getting at. If pipelines are too early in their development, it's genuinely hard to optimize content because the foundation isn't ready yet. Shader optimizations are a good example of this. Setting up LODs, on the other hand, makes sense early in a traditional pipeline, as that work always has to be done regardless of where you are in production.

The moment optimization gets treated as something to deal with later, the cost of dealing with it compounds.

It's Rarely a Disaster, But It's Always a Tax

Contrary to what some might expect, I don't have horror stories. During each project there were challenges developing asset pipelines while tools weren't production-ready yet, which led to learning lessons along the way. That's normal. What's less normal, and worth flagging, is when performance issues get diagnosed too bluntly. Solely watching the performance graph and waiting for it to drop can give false positives. Lowering texture resolution will improve performance, but does it actually solve the underlying problem? Are you missing LODs, uncollapsed draw calls, unoptimized collision meshes? The number going up doesn't tell you that.

What It Looks Like in Practice

Some of the more concrete challenges I encountered: not having all content run through the optimized pipeline, which meant additional manual tweaks were still needed for far-distance LOD meshes. On a cross-platform title, not setting proper LOD distances early caused issues that were expensive to revisit. Skipping the first visual LOD incorrectly. And collision meshes with too many triangles, something with a real CPU cost. There was no hard limit defined for collision triangle counts; it was largely driven by artist experience and the assumption that larger on-screen assets required more accurate colliders. That's fair, but it still came at a cost that wasn't being tracked.

In my experience, most developers had a reasonable instinct around texture resolution — keeping maps at 2K, with 4K as a real exception reserved for cinematics, characters, or full-screen assets. That baseline consistency helped. The problems surfaced, on a different project, where consistency broke down across asset types: environment art with twice the texel density of characters, or assets with triple the average triangle count. The more content is authored without addressing this, the harder it becomes to course-correct later.

Conclusion

Performance matters, but it shouldn't hinder the creative process, and sometimes it does, driven by the loudest voices in the studio. Hyper-fixating on performance for performance's sake is not the way a team should approach it. It's a collaborative and iterative process that has to involve art direction, leads, and producers, so that everyone understands the constraints of the pipeline — and how scalable, or not scalable, it actually is.

This is as much a leadership problem as it is a technical one. The conversation doesn't need to be a blocker; it needs to be on the agenda.

© 2026 Stefan Groenewoud — All views are my own, not those of my employer.

Day 4 - đź’¬ Take - Navigating the Creative Industry

General / 05 May 2026

Navigating the Creative Industry – My Experiences

The games industry is small. People talk. And yet, somehow, the recruitment process remains one of the least transparent parts of a career in this field.

This isn’t a guide on how to write a CV or ace an interview. It’s a collection of real experiences — things that actually happened, shared because I wish someone had told me this earlier. Whether you’re a newcomer or a seasoned professional looking for a change, I hope this saves you some time, frustration, and unnecessary self-doubt.

Studio Experiences

Studio A: Silence After Interest

A recruiter at a major triple-A studio reached out, the conversations went well, and then: nothing. I sent two or three follow-up emails. No response. Not even a “we’ve gone a different direction.”

It wasn’t just frustrating. It was unprofessional. In an industry this small, a recruiter is the face of the studio. Silence communicates more than they probably intend.

Takeaway: If a studio goes quiet after expressing interest, follow up once clearly, then move on. Their silence is information. And if you end up there later, you’ll remember how they treated candidates.

Studio B: The NDA Pressure

After multiple calls with another triple-A studio, they kept pushing for work samples I couldn’t share. The project hadn’t been announced. The work was under NDA; I told them this repeatedly. Their response: ”We could have a quick call so you can just briefly show it.”

Think about that. A company looking to hire trustworthy people, actively trying to get someone to breach a legal agreement. I’m certain they wouldn’t appreciate it if their own staff did the same.

Takeaway: A studio that pressures you to violate an NDA is showing you exactly how they operate. Walk away cleanly and without guilt.

Studio C: The Visa Oversight

Two interviews in. Good conversations. Then I had to chase the recruiter for a status update, only to find out they’d run into complications hiring me because of the visa process. Something they could have identified in the very first call.

Weeks of my time, and theirs, wasted on something that should have been a 5-minute check at the start.

Takeaway: Early in any process, ask directly: ”Are there any relocation, work authorisation, or visa constraints that could affect this role?” It protects everyone’s time. If a studio doesn’t have that answer upfront, that tells you something too.

Studio D: The Low-Ball Offer

A studio in a major European city extended an offer that barely covered basic living costs, let alone healthcare, in one of the most expensive cities in the world. I was more junior at the time, but the number was still disconnected from the reality of actually living there.

Takeaway: Always research cost of living against the offered salary before getting emotionally invested. Tools like Numbeo exist. Use them. Knowing your number going in puts you in a much stronger position and prevents the gut-punch of an offer that insults the city you’d be moving to.

Recruiter Experiences

Recruiter A: The Mentor Mirage

About ten or twelve years ago, I came across someone offering paid “mentor sessions” for newcomers to the industry. The pitch: guaranteed connections, 10+ years of recruitment experience, interview prep, resume polish, introductions to major studios.

When it came time to deliver on those introductions, they vanished.

It cost people money and, more importantly, time and trust during a vulnerable moment in their careers. To this day, I haven't seen this person deliver on the introductions they promised, and I haven't seen them working at any major studio since. In hindsight, there was probably more to the story than I knew at the time.

Takeaway: Vet anyone offering mentorship or career connections with the same rigour you’d apply to a job offer. Ask for specific examples. Ask who they’ve placed and where. Legitimate mentors welcome those questions.

Recruiter B: “It’s a Done Deal”

For a role at one of the largest studios in the US, the recruiter was enthusiastic to the point of being unprofessional. Phrases like ”it’s a done deal” and ”they’re lucky to have you in the process.” I went through the interviews. The team was great. Then I found out the job description didn’t actually match the role that was being filled.

Not only unprofessional; it’s a waste of the hiring team’s time and the candidate’s.

Takeaway: Treat recruiter enthusiasm as a yellow flag, not a green one. Ask direct, specific questions about the role’s responsibilities, team size, and reporting structure before investing in multiple interview rounds.

What I’ve Learned Overall

The recruitment process in games asks a lot of you: your time, your portfolio, your emotional energy. Not every studio or recruiter treats that investment with the respect it deserves.

A few things that have helped me:

  • Communicate your constraints early. Visa status, location, availability, salary expectations: raise these in the first conversation. It’s not impolite, it’s efficient.
  • Set your boundaries. It's okay to say no, or to step away from a process if something feels off.
  • Your NDA is not negotiable. Any studio worth working for will understand this immediately.
  • A recruiter’s enthusiasm is not an offer. Verify everything in writing.
  • Research the studio independently. Glassdoor, LinkedIn, people in your network who’ve worked there. The small industry works both ways; information travels.
  • Silence after engagement is an answer. Don’t chase indefinitely. One clear follow-up, then redirect your energy.

The industry is small. Your reputation matters, and so does theirs. Don’t be afraid to hold studios and recruiters to the same standard they hold you.

© 2026 Stefan Groenewoud — All views are my own, not those of my employer.

Day 3 - 🔬 Deep dive - Occluder Meshes

Article / 04 May 2026

Occluder Meshes

A companion to Shadow Proxies — another manual mesh optimization technique that helps the engine discard work it doesn't need to do.

Purpose

As shaders become more complex and heavier, optimization becomes more important. If a shader doesn't write to the depth pass, it won't contribute to the pre-pass that culls unnecessary pixels further down the pipeline.

Systems like backface culling (which discards triangles facing away from the camera) or occlusion culling middleware like Umbra handle some of this automatically, but they don't take care of the pixel shader cost for geometry that's technically "in view" but hidden behind something else.

By creating a custom occluder mesh that writes to the depth buffer, you're helping the Z-prepass cull pixels that are definitely not visible from a given angle. The key constraint: all triangles of the occluder mesh must stay within the bounds of the visual mesh. If the occluder extends beyond the visual geometry, it will incorrectly kill pixel shader information behind it, causing rendering artifacts where visible pixels get culled.

Maximum draw distance is also worth considering. If an occluder mesh is too aggressive at large distances, it can cause issues due to reduced vertex precision over distance; depth buffers become less precise at far ranges because of how depth is distributed non-linearly (more precision near the camera, less far away). An overly tight occluder at distance can start incorrectly culling pixels that should be visible.

Rule of thumb: I tend to target walls or props that cover most of a character's body, or roughly 10–15% of the screen, at least for third-person games. Anything smaller and the occluder drawcall costs more than it saves.

Engine Support

Unreal Engine does support custom occluder meshes. In UE4 and UE5, you can enable Software Occlusion Culling and mark specific simplified meshes as occluders. UE5 also handles much of this automatically through Nanite's software rasterizer for opaque geometry, but for non-Nanite assets and translucent materials, custom occluders remain relevant.

Note: not all engines support this level of per-asset control. Some proprietary engines expose it explicitly, others handle occlusion at a higher level with less artist input.

When It Helps

  • Large opaque props that block a meaningful portion of the screen.
  • Interior walls, pillars, architectural elements in dense scenes.
  • Non-Nanite assets in a UE5 pipeline.

When It Doesn't

  • Small props: the occluder drawcall will cost more than it saves.
  • Translucent or alpha-blended geometry: these don't write to depth and can't act as occluders.
  • Nanite-enabled opaque geometry in UE5: Nanite handles this automatically.

© 2026 Stefan Groenewoud — All views are my own, not those of my employer.