Status
SteamPeaks
ChartsSalesUpcomingPatchesEventsCalculator
New on SteamEvery app, DLC and depot the minute Steam creates itAppsEvery app on Steam, newest change firstPackagesSubs and bundles, and what each containsDepotsDepots, manifests and install sizesTagsSteam's user tags and the games under themDevelopers & publishersCompanies and their cataloguesTechnologiesEngines, SDKs and anti-cheat found in the filesChange historyEvery PICS changelist as it lands
SignalsNineteen readings of the whole catalogueCompareAny games side by sideRecordsAll-time peaks and the days they were setReportsWeekly and monthly write-upsAlerts & newsroomWatch a game, get told when it movesSteam statusIs Steam up, right nowWeb API explorerTry the endpoints in the browser
EventsSteam's own events and the sales calendarCalculatorWhat a Steam account is worth, and its pile of shame
/
Sign in
/
SteamPeaks
The ultimate resource for Steam data.
ExploreChartsSalesSales and festsUpcomingPatchesEventsRecordsTrendingSignals
DatabaseAppsPackagesDepotsTagsDevelopersTechnologiesChange history
ToolsCalculatorCompareSearchAlertsSteam statusAPI
SiteMethodologyFAQDiscordSupportSign in via Steam
Not affiliated with Valve or Steam. Game names and artwork belong to their owners. All times UTC.
PrivacyCookiesFair useStatus
InfinicityEventsProcedural Object Placement with Variable-Radius Poisson Disk Sampling and noise
Community

Procedural Object Placement with Variable-Radius Poisson Disk Sampling and noise

Infinicity · published 26 Dec 2025, 15:54 UTC

All eventsPlayers around this dateRead on Steam

When generating large procedural worlds, placing objects believably is harder than it looks.

Trees shouldn’t overlap. Rocks shouldn’t clump unnaturally. Buildings need breathing room. And ideally, all of this should be controllable, performant, and compatible with procedural generation.

A few years ago, while working on procedural world generation for my game, I ran into exactly this problem i.e. placing objects of varying sizes, driven by noise, with zero overlap.

This post is a write-up of how I approached that problem, what didn’t work, and the solution I ended up shipping.


The Problem

At a high level, I wanted to:

  • Place objects procedurally across a 2D surface

  • Allow each object to have a different radius

  • Guarantee no overlap

  • Retain a natural, non-grid-like distribution

  • Be able to bias density using noise or gameplay logic

Classic Poisson disk sampling gives you a nice "even but random" distribution but it assumes a fixed minimum distance between points. That assumption breaks down immediately when object sizes vary.


Why Standard Poisson Disk Sampling Falls Short

Traditional Poisson disk sampling works by enforcing a single global minimum distance between samples. That’s great if every object is the same size.

But once you introduce variable radii:

  • A small object can sit comfortably near another small object

  • A large object needs more space

  • The minimum distance is no longer constant

You can try to cheat by inflating everything to the maximum radius but that leads to:

  • wasted space

  • overly sparse distributions

  • loss of detail where small objects should be dense

In short: the distance constraint needs to be local, not global.


Idea: The Radius Is the Constraint

Instead of thinking in terms of "points with a minimum distance" I reframed the problem as:

Each object has a radius, and no two objects' influence circles may overlap.

That seems obvious in hindsight, but it changes how you structure the algorithm.

Instead of asking:

"Is this point at least D away from others?"

You ask:

"Does this object’s radius overlap with any existing object’s radius?"

That means overlap tests become:

distance(p1, p2) >= r1 + r2

Once you accept that, the rest of the system can be built around it.


Adding Noise-Driven Density

Uniform distributions are fine but procedural worlds benefit from variation.

To control where objects want to appear, I introduced procedural noise as a placement bias, not as a hard rule.

The workflow became:

  1. Sample a candidate position

  2. Use noise to decide:

    • whether something should exist here

    • what size it should be

  3. Attempt to place the object

  4. Reject it if it overlaps anything already placed

This approach has a few nice properties:

  • Designers can control density using noise parameters

  • The same system works for trees, rocks, structures, etc.

  • Rejection sampling naturally enforces spacing


Making It Fast Enough

Naively checking every new object against every existing object doesn’t scale.

To keep this practical, I used spatial partitioning (a simple grid) to reduce overlap checks to nearby cells only. Each placed object is inserted into the grid cells it overlaps, and new candidates only test against objects in those cells.

This keeps placement costs roughly constant, even as object count grows.

The result is a system that:

  • scales well

  • is deterministic when needed

  • works in real time or during world generation


Results in Practice

This sampler ended up being flexible enough to use across multiple contexts:

  • natural object scattering

  • terrain decoration

  • gameplay-relevant structures

Because object size, noise bias, and placement constraints are all decoupled, it’s easy to tune without rewriting the algorithm.

I eventually cleaned up the implementation and published it here:

https://github.com/bensanmorris/poisson_disk_sampler

A couple of videos of it in action are here:

And here:


Final Thoughts

Procedural generation lives in the space between theory and messy reality. Algorithms rarely work out-of-the-box once real constraints enter the picture.

This wasn’t about inventing a new sampling technique it was about adapting a known idea to solve a real production problem.

If you’re working on procedural placement and have ever fought with clumping, overlaps, or over-uniform distributions, I hope this gives you a useful angle of attack.

More from Infinicity

Other announcements

All events
Community17 Dec 2025Turning Real Footage into Game Animations (and Why I Open-Sourced the Tool)One of the challenges I’ve been thinking about a lot while working on Infinicity is animation. I wanted characters that feel hand-animated and expressive but without relying on huge animation budgets or locking myself into a very rigid art style. I also wanted a workflow that lets me iterate quickly i.e. change timing, style, or scale without redoing everything from scratch. That led me down an…Community13 Dec 2025Player moddable terrain feature addedI’ve added a new feature that lets players tweak the mountain noise layers in real-time. Previously, the terrain was generated using layers of noise with fixed frequency and amplitude. Now players can adjust these parameters to shape the mountains exactly how they like whether that’s jagged peaks, rolling hills, or something in between. This gives a lot more expressive freedom while exploring o…Community9 Dec 2025Dev Blog: Tile cachingTile Caching = 159x Faster City Streaming Today I want to share a technical update rather than a visual one but it’s a huge boost for performance. My game uses procedural city tiles. Generating a full city tile costs around 1 millisecond . When the player is flying fast over the world, dozens of tiles may need to be created quickly, and that can become a bottleneck even when each tile is loaded…