<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Cornucopia</title>
    <description>The latest articles on DEV Community by Cornucopia (@cornucopia).</description>
    <link>https://dev.to/cornucopia</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3167471%2F5291035d-9d76-446e-93e5-a1c324bf95c8.jpg</url>
      <title>DEV Community: Cornucopia</title>
      <link>https://dev.to/cornucopia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cornucopia"/>
    <language>en</language>
    <item>
      <title>2,583 Plants to 3 Draw Calls - GPU Instancing in Cornucopia</title>
      <dc:creator>Cornucopia</dc:creator>
      <pubDate>Sun, 05 Apr 2026 04:08:21 +0000</pubDate>
      <link>https://dev.to/cornucopia/2583-plants-to-3-draw-calls-gpu-instancing-in-cornucopia-381p</link>
      <guid>https://dev.to/cornucopia/2583-plants-to-3-draw-calls-gpu-instancing-in-cornucopia-381p</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtm8e4wkej084h5vqp3b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtm8e4wkej084h5vqp3b.png" alt="Cornucopia farm terrain overview showing dense vegetation" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flczpxa5ivn4wfuo2t05v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flczpxa5ivn4wfuo2t05v.png" alt="Cornucopia beach area with coral, sand, and ocean vegetation" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ygwh7xi56m2hi1qklil.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ygwh7xi56m2hi1qklil.png" alt="Cornucopia terrain close-up showing flowers growing between rocks" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Walking on my treadmill while writing this. I have ADHD so if exercise isn't the first thing I do in the morning, it's just not likely to happen, lol. I bought a cheap treadmill off Amazon and set up the hydraulic table I already use for my mouse pad when I'm sitting, raised it up to about belly button height in front of my PC with my mouse and keyboard on it. Monitors tilt up a bit so I can see them while standing. Something in the house is better for me than the gym or yoga which I tend to stop going to in a couple months after signing up, as is generally the case. I was walking 2-3 hours per day for about a week before flying to Boston to show the game at PAX East, but now I'm back at it after a couple days recovery.&lt;/p&gt;

&lt;p&gt;I showed a little bit of the new farm terrain in the last post. But here's an interesting problem and solutions to the new terrain I've never mentioned before.&lt;/p&gt;

&lt;h2&gt;
  
  
  GPU Instancing: How I Got 2,583 Plants Down to 3 Draw Calls
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqew0nxoqyypepz1prahy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqew0nxoqyypepz1prahy.png" alt="Cornucopia cliff area with vine vegetation and GPU instanced plants" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So my 3D modeler first started sending me terrain model tests back in November 2025 or earlier. He was actually a fan of the game originally. Redesigned the Cornucopia logo on his own almost two years ago just because he wanted to, after reaching out to me. Over time he's become pretty much the only active person working alongside me on the game. He has been working as a contractor for about the past 2 years on the game, and is now the most important person helping on the game. (And as of right now, the only other person other than me.) A player who loved what I was building and ended up helping build it. That kind of thing doesn't happen often.&lt;/p&gt;

&lt;p&gt;In March 2026 just prior to PAX East he sent over a complete farm terrain redevelopment after we planned and brainstormed it for many months. I wanted to implement it prior to PAX, but it just wasn't possible. The terrain is WAY WAY more detailed and interesting than before and includes a new connected oceanic zone. And every day he keeps sending more fixes and improvements as we work together. Flowers, bushes, ground cover, coral for the oceanic zones, little plants growing between rocks. Today he sent background parallax layers with pine trees and oak at different depths behind the farm. The game has temperate farmland, oceanic zones, cave environments, rocky areas, the town. All of these areas are getting filled in with environmental details that give them actual personality. Stuff that was missing before.&lt;/p&gt;

&lt;p&gt;He kept asking me in the past, "How much can I add?", and really kept trying to push the scope larger and more detailed than I thought was possible for performance.&lt;/p&gt;

&lt;p&gt;And I kept looking at the designs thinking about the GPU, FPS, and performance on Switch/consoles.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79hkbrsnw1m36naiua8e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79hkbrsnw1m36naiua8e.png" alt="Cornucopia terrain development showing environmental ground cover detail" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every separate object in a game is a request to the graphics card. Every flower, every bush, every little ground cover plant. "Draw this." "Ok now draw this." "Now this one."&lt;/p&gt;

&lt;p&gt;2,583++ of them.&lt;/p&gt;

&lt;p&gt;On a decent gaming PC, fine. But we're also developing for console and we want it running well on lower end PCs, laptops, and maybe Mac in the future. Those systems care a lot about how many separate draw requests you throw at them. It's not about how many triangles are on screen, it's about how many separate things you're asking the GPU to handle at once.&lt;/p&gt;

&lt;p&gt;And I'm looking at this beautiful scene that finally has the environmental detail the game was always missing, and I'm thinking... do I have to tell him to cut it back? Because the game can't handle it?&lt;/p&gt;

&lt;p&gt;I really didn't want to.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Breakthrough
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx85a6pw112w3kt6oo7h1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx85a6pw112w3kt6oo7h1.png" alt="Cornucopia farm area with bushes along paths and GPU instanced vegetation" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My first attempt was standard GPU instancing, where you tell the GPU "here's one mesh, draw it 500 times at different positions." Efficient. But it requires identical geometry and these plants are all unique shapes from Blender. Different flowers, different bushes, different sizes. Didn't compress enough.&lt;/p&gt;

&lt;p&gt;Then I realized something.&lt;/p&gt;

&lt;p&gt;These plants are all stuff the player can't interact with. You can't pick them up, walk into them, nothing. They're purely visual. And they share the same texture atlas.&lt;/p&gt;

&lt;p&gt;This is actually the first time we've ever added environmental greenery that's un-interactable. Pretty much everything in the game, you can interact with. So that's the reason we can instance these with the GPU. But anything that's collidable or you can interact with, like the regular props or regular weeds or trees, those need their own separate game objects with their own scripts and information on them. And I don't really think I can safely instance those because of the amount of unique information and interactability stored on each one.&lt;/p&gt;

&lt;p&gt;If nobody interacts with them and they share the same texture... why are they separate objects? What if I just take all the nearby ones and literally merge their meshes into one big mesh? Unique shapes don't matter once you bake all the vertices into world space. The GPU just sees one object. (Individually animating each of them with wind was another concern, but I get into that later in this post.)&lt;/p&gt;

&lt;p&gt;That was the moment everything changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Process
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0tru5pxl9mk8prriftg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0tru5pxl9mk8prriftg.png" alt="Cornucopia waterfall area with dense plant life and terrain detail" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first problem was trees. Your character walks around tree trunks and bumps into them, so trunks need collision. If I merged the trunks into one big mesh you'd just clip right through everything. But the leafy canopy on top? Nobody needs to walk up there. So canopies can be combined, trunks can't. Same thing for cosmetic vegetation and bushes, don't need collisions for them.&lt;/p&gt;

&lt;p&gt;I needed to separate every tree in the scene into its two parts before doing anything else. Wrote a tool in Unity that does it in one click. Canopy meshes get grouped for baking, trunk meshes stay individual but get marked static so Unity batches them behind the scenes.&lt;/p&gt;

&lt;p&gt;Then I made the actual vegetation baker. This is the tool that does the combining. You select a parent object with all the plants underneath it, click one button, and it handles everything. It splits the world into a grid where each cell is 20 units across. I chose that size specifically because it's roughly one screen width for the isometric camera. That way the GPU can skip entire cells that are offscreen instead of trying to process one giant mesh that covers the whole map. Within each cell, it merges plant meshes together up to 60,000 vertices. 16-bit index format where possible because it's faster on less powerful hardware.&lt;/p&gt;

&lt;p&gt;I also wrote a one-click optimizer on top of that. Turns off shadow casting on all vegetation (shadows are expensive on weaker hardware and honestly you don't notice them on small plants), marks everything for static batching, and gives me a report of the estimated draw calls so I can see exactly where we're at.&lt;/p&gt;

&lt;p&gt;We ran actual density tests too. I imported a test file literally called GrassDensityCapacityTest to see how much we could push before the frame rate died. Turns out the system handles way more than we expected. That was a really good moment. The 3D modeler has also been sending me all kinds of tests throughout the months of this farm terrain remake. Like how far the player can jump, how high they jump, platforming elements, sand wetness tests, all kinds of stuff. It's actually hard to remember it all, but it's been a lot. And that's really helped him with the process of how to model all this stuff in Blender. It's been a lot. It's hard to remember it all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Wind
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjdzjh0ymnfesbk88r32n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjdzjh0ymnfesbk88r32n.png" alt="Cornucopia rocky terrain with ground cover plants" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the part I'm most happy about and honestly surprised it works properly with the GPU instancing thanks to a custom shader and script.&lt;/p&gt;

&lt;p&gt;When every plant was its own object, each one swayed in the wind on its own. Easy. But once you combine thousands of them into a few big meshes, they're all the same object now. How do you make individual plants inside one combined mesh still move independently?&lt;/p&gt;

&lt;p&gt;Before combining, I go through each plant and "paint" its vertices with a sway weight. The bottom of the plant, the part in the ground, gets painted with 0. That means don't move, you're anchored. The top gets painted with 1. Full sway. Everything in between is a smooth gradient. So the stems barely move, the middle moves a bit, and the tips of the leaves and petals move the most. Just like a real plant in the wind.&lt;/p&gt;

&lt;p&gt;Then I wrote a shader that reads those painted values and pushes the vertices around. I use two overlapping sine waves at slightly different frequencies. That layering is what makes it feel gusty and organic instead of everything going perfectly back and forth in sync. Some plants lean left while the one right next to it leans right. Some are mid-sway while others are catching up.&lt;/p&gt;

&lt;p&gt;The shader I wrote ended up handling all of these details automatically once it's all baked and the wind settings are on. And you can actually set the wind values for each batch, so the behavior of the tree foliage animates differently than the separately batched random vegetation like flowers and weeds and decorative stuff.&lt;/p&gt;

&lt;p&gt;And I thought carefully about what should and shouldn't sway. Coral sitting on rocks? Stays still. Ground cover flat against terrain? Static. I made separate NoWind material variants for those. Small detail but when everything sways including stuff that shouldn't, the whole scene looks wrong.&lt;/p&gt;

&lt;p&gt;The tree canopies have a different feel from ground plants too. More of a slow, subtle breathing kind of movement. Softer than the obvious swaying of flowers and bushes. Different vegetation, different personality.&lt;/p&gt;

&lt;p&gt;For any devs reading: the shader handles all three rendering modes (baked combined mesh, standalone tree with wind component, plain mesh) without any if/else branching. GPUs are slow at branching, so I use step() and lerp() to blend between modes with pure math. Same code path for everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjolf4lqpej3hdlowa3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjolf4lqpej3hdlowa3e.png" alt="Cornucopia GPU instancing before and after comparison" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I ran the baker and watched the draw call counter go from 2,583 to 3.&lt;/p&gt;

&lt;p&gt;2,583 draw calls became 3. A 99.88% reduction.&lt;/p&gt;

&lt;p&gt;This was pretty surprising, and I was very happy seeing this work properly.&lt;/p&gt;

&lt;p&gt;99% reduction. The farm used to be just the interactive props sitting on kind of a bare surface. Now there are flowers growing between every rock, bushes along every path, ground cover everywhere. And when you're walking through it all and everything is swaying around you in the wind, each plant moving a little differently... that's a handful of draw calls doing the work of thousands. You'd never know. All of the existing stuff that you can interact with works the same. It's just all of this decorative environmental stuff that really brings the world to life is what's GPU instanced.&lt;/p&gt;

&lt;p&gt;Haven't tested on console yet specifically. Numbers look really promising though.&lt;/p&gt;

&lt;p&gt;And the most important thing: my modeler can add as much environmental vegetation as he wants now. I don't have to be the person saying "cut it back" when it looks this good. A fan of the game who ended up being the person making it beautiful, and now there's not much holding him back in terms of creating this terrain. That's a good feeling.&lt;/p&gt;

&lt;p&gt;I should note that there's a lot of things specific to the game that are constraints due to the non-rotating nature of the camera view. It's sort of a Paper Mario style where you can zoom in and out but it's fixed to one direction. We don't want any of the design to have higher elements in the foreground that block the camera view when you're in the lower angle perspective. So that was also a key design decision when remaking the terrain, and it took a little while to totally convey it all to the modeler over the months. Trial and error of tests.&lt;/p&gt;




&lt;h2&gt;
  
  
  Technical Deep Dive (For Devs Who Want To Do This)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyatzhwd9bhxe5xb3iav7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyatzhwd9bhxe5xb3iav7.png" alt="Cornucopia environmental vegetation wind animation" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to implement something similar, here's how the key pieces actually work. Skip this if you're not into code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Baking Pipeline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Vegetation Baker is a Unity EditorWindow. Takes a parent GameObject, collects every child that has a MeshFilter, and runs through three stages.&lt;/p&gt;

&lt;p&gt;First, wind color baking. For each unique shared mesh, it clones the mesh and writes vertex colors. Finds the local Y bounds of the plant (min to max), normalizes every vertex Y into a 0-to-1 range. That goes into the red channel. Green channel gets set to 0 as a "this has been baked" marker. Unbaked meshes have G=1 (the default white), so the shader can tell the difference. Caches these baked meshes so identical plants reuse the same version instead of cloning every time.&lt;/p&gt;

&lt;p&gt;Second, spatial chunking. Groups all the CombineInstance data by grid cell. Each cell is CELL_SIZE units (I use 20, matching the isometric camera viewport width). Within each cell, builds sub-chunks that respect a max vertex count of 60,000. Grid coordinates are just floor(position / cellSize). Simple but effective.&lt;/p&gt;

&lt;p&gt;Third, combining. For each chunk, creates a new Mesh, picks index format based on vertex count (16-bit when under 65K, 32-bit otherwise), calls Unity's CombineMeshes() with mergeSubMeshes and useMatrices both true so the world-space transforms get baked in. Recalculates bounds. Saves everything as a VegetationData ScriptableObject with the combined meshes stored as sub-assets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Wind Shader&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Surface shader with a custom vertex function. The branchless mode detection looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;float isBaked = step(v.color.g, 0.49);      // 1 if baked vertex colors
float hasMeshWind = step(0.001, windData.x); // 1 if MeshWind component active
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These two values drive everything through nested lerps. For baked meshes, the sway comes from vertex color R (squared for a nice ease-in curve at the base). For MeshWind meshes, from world Y within the sway range. For plain meshes, from local vertex Y.&lt;/p&gt;

&lt;p&gt;The displacement uses world position for phase so nearby plants share similar timing but aren't identical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;float phase = (worldPos.x + worldPos.z + _Time.y * speed) * freq;
float sinVal = sin(phase) + sin(phase * 1.3 + _Time.y * 0.7) * 0.3;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second sine at 1.3x frequency with a time offset creates the gusty feel. Displacement goes into X and a smaller amount into Z for diagonal sway. Transforms back to object space before applying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At Runtime&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The VegetationRenderer just calls Graphics.DrawMesh() for each combined mesh every frame. No GameObjects, no transforms, just raw draw calls. The instancing fallback path is still there using DrawMeshInstanced() with manual frustum culling, but the combined path is what we actually use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'd Do Differently&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If I started fresh, I'd probably look into compute shader indirect instancing. More flexibility for LOD and dynamic spawning. But for a project where the vegetation is placed by a modeler and doesn't change at runtime, the baking approach is simpler and it works really well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7y33hv58kat4r38qwyz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7y33hv58kat4r38qwyz.png" alt="Cornucopia Unity editor showing vegetation baker tool" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;There's a reason I needed all of this working before anything else. Can the new area connect to the farm without a loading screen? I didn't think it was possible before this. The modeler was really insistent that we have the lower new area seamlessly connected to the farm, and I was thinking the whole time that it's probably not gonna be a good idea because it's gonna lower the FPS too much and we should just have a loading screen in between and have it as a separate area. But I haven't tested incredibly thoroughly on low end hardware, so I can't say definitively if we're still gonna run into any issues. But right now it looks amazing. And his dream of having so many details did appear to come true due to how I've optimized all this stuff, and really becoming aware of GPU instancing and writing these custom scripts and shaders. So the future of these terrain remakes is looking really exciting!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9p10bkf59o0b37b79j0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9p10bkf59o0b37b79j0.png" alt="Cornucopia draw call counter showing 2583 to 3 reduction" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-david&lt;/p&gt;




&lt;p&gt;Wishlist on Steam: &lt;a href="https://store.steampowered.com/app/1681600/Cornucopia/" rel="noopener noreferrer"&gt;https://store.steampowered.com/app/1681600/Cornucopia/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>indiegame</category>
      <category>unity3d</category>
      <category>devlog</category>
    </item>
    <item>
      <title>I Took My Unity Game to PAX East 2025 — Here’s What I Learned</title>
      <dc:creator>Cornucopia</dc:creator>
      <pubDate>Thu, 15 May 2025 17:21:24 +0000</pubDate>
      <link>https://dev.to/cornucopia/i-took-my-unity-game-to-pax-east-2025-heres-what-i-learned-1a81</link>
      <guid>https://dev.to/cornucopia/i-took-my-unity-game-to-pax-east-2025-heres-what-i-learned-1a81</guid>
      <description>&lt;p&gt;After 8 years building my 2.5D farming RPG Cornucopia in Unity, I finally brought it to PAX East 2025.&lt;/p&gt;

&lt;p&gt;This was my second PAX (I showed at West in 2024), but my first time with a proper booth setup. I had four demo stations, banners, business cards, a 65" TV playing the trailer, and free Cornucopia tattoos.&lt;/p&gt;

&lt;p&gt;Here’s a breakdown of what worked, what didn’t, and what I’d do differently if you’re ever planning to bring your Unity game to an event like this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup &amp;amp; Tech&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Save files matter. I created files that dropped players straight into active gameplay—tools in hand, crops growing, pets following. No menus, no tutorials. Just play. This removed friction and let people get a real feel instantly. Still, kids constantly saved over them.&lt;/p&gt;

&lt;p&gt;Visibility is everything. I made the mistake of blocking part of my booth with a standee. Once I moved it and adjusted the screens for better sightlines, foot traffic improved fast.&lt;/p&gt;

&lt;p&gt;Decks helped. I ran 2 laptops and 2 Steam Decks. The Decks got a surprising amount of attention. One was docked below the TV, the other was in a side area with its own stand. People naturally picked them up and jumped in. They also ran the game well—60fps, no overheating—though one had stiff top bumpers.&lt;/p&gt;

&lt;p&gt;Audio + video draw people. I looped a gameplay trailer on a big screen and played the soundtrack through a Bluetooth speaker. Once I started charging the speaker overnight, it worked great. It gave the booth energy.&lt;/p&gt;

&lt;p&gt;Bring backups. Duct tape, chargers, cables, Velcro ties, adapters. Just do it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observing Players&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Watching real people play my game taught me more than any analytic report ever could. I saw:&lt;/p&gt;

&lt;p&gt;Where they paused&lt;/p&gt;

&lt;p&gt;What they ignored&lt;/p&gt;

&lt;p&gt;Where they got confused&lt;/p&gt;

&lt;p&gt;What made them laugh&lt;/p&gt;

&lt;p&gt;I identified a major controller bug just by watching people interact with one mechanic. I’m fixing it now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Booth Presence&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I didn’t pitch the game. I didn’t chase people. I just stood calmly and made eye contact. When someone looked interested, I’d offer help or ask simple questions:&lt;/p&gt;

&lt;p&gt;“What kind of games do you usually play?”&lt;/p&gt;

&lt;p&gt;“Are you from Boston?”&lt;/p&gt;

&lt;p&gt;That’s what started real conversations. Being calm and grounded helped more than any pitch could.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feedback and Comparison&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A lot of people compared Cornucopia to Stardew Valley, Harvest Moon, or Paper Mario. I didn’t argue. I just listened. It gave me insight into how people framed the game.&lt;/p&gt;

&lt;p&gt;Next time I’ll put up a short sign listing some of the features that make Cornucopia unique—just as a quiet guide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Streamers &amp;amp; Devs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I gave out a few Steam keys and did a few casual interviews. Some streamers recognized the game from months ago and told me their favorite memories. That felt good.&lt;/p&gt;

&lt;p&gt;Next time I’ll come with printed key cards and a better way to track who I gave them to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;General Tips&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Write things down. Your brain is toast by Day 2.&lt;/p&gt;

&lt;p&gt;Bring food and water. I used Costco protein packs and bottled water under the table.&lt;/p&gt;

&lt;p&gt;Comfortable shoes and clean clothes. It sounds obvious, but it matters.&lt;/p&gt;

&lt;p&gt;Get there early. Traffic was rough.&lt;/p&gt;

&lt;p&gt;Bring more cards than you think you’ll need. I ran out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PAX East reminded me that players are real people. You see their reactions. You hear their laughter. You watch their confusion and joy in real time.&lt;/p&gt;

&lt;p&gt;That does something to you.&lt;/p&gt;

&lt;p&gt;It made the game feel real again—not just something I’ve been chipping away at alone. It was one of the best things I’ve done in a long time.&lt;/p&gt;

&lt;p&gt;If you’re building something and ever get the chance to show it in person, I highly recommend it.&lt;/p&gt;

&lt;p&gt;Thanks to everyone who came by.&lt;/p&gt;

&lt;p&gt;— David&lt;/p&gt;

</description>
      <category>postmortem</category>
      <category>devlog</category>
      <category>gameexpo</category>
      <category>pax</category>
    </item>
  </channel>
</rss>
