Fugue Devlog 7: Environmental Effects and Objects

04.18.2021

A tree

With the dialogue system in decent shape, I'm moving onto exterior environments. There's a lot to figure out here: environmental effects like wind, fire, smoke, rain, and snow; terrain design; rocks; vegetation including grass, bushes, and trees; skyboxes; and water (which I'm categorizing into "still" water, like those in ponds and pools, and "active" water, like that of the sea). In general creating "natural" effects and objects is way harder than human-made interiors and objects!

Several of the effects (rain, snow, fire, smoke) can be implemented as particle systems. I played around with Godot's Particles node and am pretty happy with the results. Here are a couple demos showing falling leaves and petals:

Falling leaves using a particle system

Falling petals using a particle system

The only thing that doesn't seem possible is the leaves rotating along the x/z axes. It's not a huge deal since these are more of mood-setting elements and there'll be plenty else on the screen to focus on.

Many of the remaining effects are usually implemented with shaders: wind in grass and trees (this tree wind shader works pretty well), the grass itself, and water. I don't have much experience with shaders so I spent some time learning more about them and playing around with them. I haven't yet managed to finish anything substantial yet but will keep exploring there.

In terms of skyboxes, those seem not too difficult to implement in Blender: basically you build your skybox and then export it as a panoramic image into Godot.

Terrain, rocks, water, and vegetation are a lot harder. For terrain and water there are fortunately some Godot plugins available that make it much easier. For terrain, there's Zylann's HTerrain plugin for heightmap-based terrains. This works well for outdoor natural environments and it supports some things out of the box, like painting grass textures and basic wind for grass. Unfortunately the heightmap-based approach doesn't work for things like caves and overhangs, so it's not a panacea.

For caves and overhangs there's Zylann's VoxelTerrain plugin for voxel-based terrains. It's not as mature as HTerrain (lacks a few of its key features, like LOD and grass painting) and it requires compilation into Godot (i.e. not just an addon you can drop in), so I'm not sure if this is exactly what I want to use.

Alternatively, I could create the terrains in Blender using the sculpting and texture painting tools there and import them into Godot. Caves aren't too difficult in Blender (you can use a cube and some displace modifiers to create the right rocky walls as a starting point) so maybe this is the way to go.

For rivers there's Arnklit's Waterways. I wonder if I can stretch it to work for other bodies of water. In any case I may need something different for still bodies of water, like those in grottos:

A grotto

For trees, there were two plugins for Blender I looked at: tree-gen and modular-tree. I also looked at hand-making trees based on "How to Create a Low Poly Tree in 1 Minute" (a similar technique, mainly using Blender's particle system for leaves/small branches, came up in a few other videos). The generated tree-gen mesh has almost 1.3 million vertices which is way too many. In comparison the basic tree generated by modular-tree has about 21k vertices1 and the handmade low-poly tree has only 6.6k vertices. That might still be too many—I don't yet have an intuition of what number I should aim for, I just know that fewer vertices are better in my case. The low-poly one also better matches the look of the game so far (low-poly, photo-realistic textures, and dithering, which in this case is just an artifact of Blender).

tree-gen example

modular-tree example

Low poly example based on "How to Create a Low Poly Tree in 1 Minute"

I wrote a Blender addon that generates the base of the tree (trunk and branches, but without the leaves) in a manner similar to that low-poly tutorial. You still need to manually set up the vertices and particle system for the leaves, but I may expand the script to do some of that automatically. It was a struggle to get the script working properly (my linear algebra is really rusty and the Blender Python documentation, at least for the bmesh parts, is really lacking), and it's not nearly as powerful as tree-gen or modular-tree, but it does what I need and in the style suitable for the game.

Here's the tree with this basic wind shader:

Tree with wind

With trees and other vegetation, as well as rocks, you need not only to create the tree meshes, but also distribute them. This post details the use of a particle system to distribute vegetation throughout a terrain, but Zylann has yet another (!) plugin, Scatter3d, that lets you paint scene instances (e.g. meshes) in Godot. For wind, Godot has a tutorial for a wind shader.

For rocks, Blender has an add-on to generate rocks, which as far as I can tell is based around feeding noise into a displacement modifier (this is the basic approach for creating caves in Blender as well). I've also seen rocks generated with a particle shader, which probably makes more sense if you have a desert landscape that needs tons of small rocks scattered about. If I've learned anything while researching how to approach these natural elements, it's that a rock is not a rock, and water is not water, and so on...there are rocks that are big, for up-close use, or medium-sized ones for foreground elements, or tiny ones for a sprawling landscape; water in a calm pool is not the same as water running through a river which is not the same as water that's crashing against a beach.

A tricky thing with natural elements is the right amount of realism. There's of course a lot of effort spent on figuring out ways to most accurately simulate natural environments and effects, and realism usually comes with a big cost to performance. I'm not trying to make natural environments that approach reality but that are interesting and convincing enough. Whenever I come across a video or post detailing how to make a tree or a water shader or what not, I always have to figure out the context. Is these for rendering in a 3d short film? Is this for a triple-A video game where players are assumed to have the latest graphics cards? Is this a demo of how realistic you can get an effect but way too computationally demanding for practical use?

For example, I found this beautiful Breath of the Wild style grass created using a shader. It's a bit resource intensive and, as wonderful as it looks, it's just not the vibe Fugue's going for.

Next I need to pull these pieces together and try building a couple natural environments—probably a forest clearing and a grotto to start.


  1. It was a little tricky to set up modular-tree. One note is to checkout the blender_28 branch if you're using Blender 2.8 or above. The other is that there's a bug when adding a twig node. What worked for me is to first add a twig node and "execute" the node, creating a mesh called tree, then rename the mesh to twig (or whatever else). Then set up the tree nodes: a trunk node into a branch node, then a "tree parameters" node separately. Check create_leafs, then click the eyedropper for the leaf parameter and select your twig mesh in the scene hierarchy. Then click execute tree


Log: 4/16/2021

04.16.2021
log

This week: post-growth bicycle manufacturing, a Daoist "Cultivation Simulator" (!!), and the end of development (and growth?).

Material challenges of bicycle manufacturing in a post-growth world, Philippe Gauthier

An exercise in thinking through how exactly bikes—an industrial product that is probably essential in most visions of a sustainable/degrowth—would be produced in such a post-growth world. It's an interesting thought exercise in that bicycles are close to an ideal technology, but complicated in important ways. They are mechanically straightforward with relatively few parts, especially compared to many of the other devices, but are still composed of technically-complex materials. They are relatively easy to repair and long-lasting, so production doesn't need to be non-stop—achieving bicycle "saturation" among a population is possible (if you consider the existing stock of bicycles, we might have already achieved saturation)—but maintenance still requires products like chain grease, bike pumps, and tools. There's relatively little variance among bicycles: aside from differences for bodies like frame sizes and seat shapes and maybe some alterations for different environments like types of tires, bicycles are more similar than they are different.

A lot of questions come up when thinking through this. Nowadays bicycles vary tremendously in price range, with cheap ones made of bad steel and extraordinary expensive ones made of more exotic materials like carbon fiber. What materials provide the best trade-offs for price, energy intensity, resource requirements, production complexity, and so on? What scale of production makes the most sense (maybe regional factories)? Will there be regional variances in bicycle production because of resource availability (maybe wood instead of steel or aluminum)? How is waste like popped inner tubes handled? Do we have specialist bicycle manufacturers or are is their production more on-demand at generalist facilities?

I would love to read more deep dives like this!

The End of Development , Tim Barker

Are we coming to the end of growth? Degrowth feels less like the active pursuit of ending growth and more like stopping the desperate attempts to squeeze out one last drop and managing the damage that happens when it does end on its own. But if growth will end on its own, how do we know when it has? How can we tell if we aren't just in a "slump" on the road to yet further gains? A reasonable place to look for signs of the end of growth are in developing countries, who, as the label implies, should theoretically have the most room to grow.

Conventional wisdom says that development in the economic sense happens through manufacturing, but the power of manufacturing to grow economies has waned:

Rodrik’s observation is that deindustrialization has been happening across the Global South as well, where industrial employment has already peaked and begun to decline. This is “premature” in the sense that the peaks are coming at a lower level (measured in share of employment and output or the level of national income) than they did in the now-rich countries that industrialized earlier. At the height of the golden age of capitalism in 1973, Japan, Germany, and the UK had roughly 40 to 50 percent of their populations working in manufacturing. In Brazil, by contrast, the peak, reached in 1986, was 23 percent; for Nigeria, in 1991, it was just 13 percent.

Service-led growth was put forward as an alternative development path, but growth driven by services pales in comparison because productivity in services does not grow at the same rate that they do in manufacturing and they seem incapable of employing as many people:

Rwanda, which averaged over 8 percent annual economic growth from 1995 to 2015, has also been offered as an example of service-led growth. A major component of the country’s “service exports” is tourism, which is said to have grown over 20 percent per year between 2002 and 2012. As with India, even proponents of the service strategy give reason for skepticism. In this case, “The main driver of tourism, gorilla trekking, is reaching full capacity,” economists Ggombe Kasim Munyegera and Richard S. Newfarmer wrote in 2018, “and the country needs to develop additional attractions to keep the sector growing.” Even if these attractions materialize, which one hopes they will, it is important to remember we are talking about growth from a very low baseline. In terms of purchasing power–adjusted GDP per capita, Rwanda ranks 166th in the world. There is no evidence here of a way for poor countries to become middle-income countries.

Manufacturing demand is limited; eventually you reach a kind of saturation unless demand is stimulated/constructed in some way (I'm reminded of Aaron Benavav's Automation and the Future of Work):

Unlike in the United States, investment in China is not held back by the requirement that it produce private profits. But even unencumbered by this requirement, Chinese officials find they have run out of outlets for public investment: “We have plenty of bridges and roads already,” an official from Sichuan Development, a state-owned enterprise, told the Financial Times in 2019. Over the last decade, Chinese manufacturing has also declined as a share of employment and value added.

The end of the piece talks about "just-in-case" production (in contrast to "just-in-time") where overcapacity becomes a virtue, i.e. a buffer against catastrophes like a pandemic, and a turn towards domestic production for domestic needs rather than export-led growth. I've seen more talk of domestic manufacturing as a national security issue in the US amid the supply chain scares of COVID-19; but in the context of developing countries such an inward turn is more about serving the population's needs (which I guess is a national security issue from the perspective of some people). But my understanding is that the debts that many of these countries hold basically require them to pursue export-oriented development as part of those agreements and out of necessity to pay back those debts? And domestic production will be undercut by cheap imports, so such capacities will struggle to develop. This part reminds me of Ha-Joon Chang's great series, "Economics for People" and his book Kicking Away the Ladder where he discusses how critical protectionist policies were in the early development of the rich countries.

I wonder, when does growth != accumulation? That is, is growth always just the rearrangement of wealth or wealth-potential, and how much of the growth of the rich nations is just the capturing of the wealth of the rest of the world? Poorer countries can't really replicate that.

Amazing Cultivation Simulator

Amazing Cultivation Simulator

I find a lot of interesting stuff while searching for images, and this time I found Amazing Cultivation Simulator, a Rimworld/Dwarf Fortress-like game but set in a world of Chinese mythology.

It's really overwhelming. Way more like Dwarf Fortress in terms of complexity than Rimworld. It actually might be more complicated than Dwarf Fortress. I only played very briefly—I don't know when I'll have a chunk of time to dive more deeply into the game, but it looks like there are tons of different subsystems and subgames that could take weeks to fully digest. They all look interesting though, like the feng shui mechanic. But these games walk a fine line between a engaging story generator and a meticulous management nightmare.

Amazing Cultivation Simulator

Amazing Cultivation Simulator

It's listed as only Windows, but runs decently on Linux through Proton.



Fugue Devlog 6: More Dialogue System!

04.15.2021

A few pain points came up after working with the dialogue system and editor more. The schema of having the text (what's being said) and varying choices and outcomes on the same level didn't make much sense, since the vast majority of dialogue is simple linear exchanges. Having the possibility of choices and outcomes attached to every utterance made the editor graph really unwieldy. This led to a few changes:

  • Because the type of an event can be inferred from who the speaker is, i.e. a "thought" is anything where the speaker is "self", and otherwise it's a "verse", the event types can be dropped.
  • I renamed "events" to "verses", because the term "event" is confusing in the context of dialogue.
  • Verses no longer have one piece of text attached to them but can encompass multiple "lines". Each "line" of a verse has at minimum some text and its speaker, but it can also have a timeouts and/or a delay, or emit a signal to trigger other parts of the game.
    • These are specified by a bit of syntax at the beginning of the line's text. E.g. !foo;t5;d8|This is the text means this line will: emit a signal called "foo", have a 5 second timeout, and a 8 second delay.

These changes meant the dialogue editor could be streamlined:

More streamlined script schema

Another small quality-of-life improvement is a button on each outcome to add a new verse already connected to that outcome. Before I'd have to add the new verse, then drag it next to the outcome so I could connect the cable.

The other update to the dialogue system is a better dialogue box layout system, to minimize overlapping dialogue boxes:

Demo of the dialogue box layout system

This was tricky to figure out. The primary constraint is that you can't reposition dialogue boxes so much that it's unclear who the associated speaker is. The safest axis of movement is along the x-axis, so the very simple approach is to just go from left to right and move boxes either left or right if there are overlaps. Of course there are many situations where this won't help, but I don't think the game will have much more than a few simultaneous speakers at once. The other simplification is that this layout adjustment is applied only to "clear" dialogue boxes; that is those within range that you can clearly "hear" the speakers. Anything out of range will be drawn below these if there's overlap.

I also implemented a custom rich text effect based on this tutorial. It seems like a powerful system:

Custom text effect


Fugue Devlog 5: Dialogue System Implementation

04.13.2021

I'm chipping away at implementing the dialogue system. It's daunting; sometimes it feels like trying to build a house all at once. Once you start to sort out what the foundation is, what part depends on what other part, etc, a build order starts to become clear and the whole implementation becomes more manageable. If you can sort that out on paper and think through most if not all of the possible issues, implementation is really straightforward.

Some of the key features like choice selection, tracking dialogue states (e.g. remembering how many times you've interacted with that speaker), and speaker tracking are demoed below:

Demo of choice selection and tracking dialogue state

I discussed an ambient dialogue system in a previous post and made some headway on implementing it. The off-screen dialogue box handling needs more work (really janky atm), but I have the dialogue box "blurring" (which fuzzes dialogue boxes as you get further from then, to mimic those voices becoming harder to hear) more or less working.

I had to compromise a bit though. I originally envisioned a gaussian blur effect, where at sufficient distances the dialogue boxes were basically smeared into nothingness. But blurring individual UI element is really complicated. It looked like the only approach was to setup separate viewports for each dialogue box, render those to textures, and then apply a blur shader to those textures. Way too complicated.

Here's the current implementation of dialogue "blurring". As the player gets further from the speakers, the dialogue boxes scale down and become transparent. It needs some tweaking, e.g. the transparency change looks awkward as a linear function, maybe should be using squared distance to feel more organic. But I think this works well as a general approach. This also means that distant dialogue takes up less screen space, so there'll be less clutter.

Demo of dialogue "blurring"

Here's the handling of off-screen/ambient dialogue. I ended overcomplicating it, spending too much time trying to implement this unnecessarily complicated version, then found that the simpler approach worked better anyways (just clamping off-screen dialogue boxes to screen space). There was some weirdness that needed fixing—basically, off-screen objects in perspective cameras are positioned counterintuitively, so the y-positioning of the dialogue boxes can look unexpected. The most noticeable case is when off-screen dialogue boxes are positioned at the top the screen for things that are behind the camera. It feels more "natural" to have those at the bottom of the screen; so there's a small snippet that ensures that's the case.

Demo of off-screen/ambient dialogue

The other feature, which is also a bit janky right now, is interrupting ongoing NPC dialogue. Discussions where the player isn't involved, i.e. among a group of only NPCs, advance automatically. If the player enters the vicinity of any of the NPCs involved in that discussion, and the player can speak with at least one of those NPCs, they will pause their discussion and address the player. If the player leaves the vicinity, they resume their discussion from wherever they left off.

There's a lot to tweak here, like timing around the discussion pausing and resuming, checking for race conditions (always a possibility when timers are involved), and figuring out how best to handle the lead-in/lead-out snippets (here: "Do you need something?" when the player interrupts and "What was I saying..." when the discussion resumes).

Demo of interrupting an NPC dialogue

Aside from cleaning up the implementations of these features, I'm mostly finished with this first pass at the dialogue system. Still many things to figure out about how dialogue is best triggered and how it should be associated with entities and so on. No doubt things will need fixing and I'll want to do things the system doesn't support as-is. And the tools will also change; I'm already finding pain points with the dialogue editor that need improving.

The next step is to start reviewing all of my notes for the game's world and story and start putting together a more concrete draft/design document. That'll help me figure out what other key mechanic systems are required.


Fugue Devlog 4: Dialogue System Improvements

04.09.2021

Not a lot of coding today, but a lot more work on the dialogue system. Sketching the manager render sequence out, figuring out the speaker tracking, dialog box placement, etc.

Sketch of the ambient dialogue system

Dialogue system notes

More dialogue system notes

I've tried to think through all possible cases but surely some have been overlooked. I just hope that none are serious enough to require a complete restructuring. There are so many cases to consider, but a few that are trickier include:

  • Should multiple on-screen decisions be allowed? If so, how do players select between decisions? Right now I'm thinking that only one decision be allowed, but don't know of a robust way of enforcing that constraint in the dialogue editor validator.
  • Should time stop/player movement be locked while in dialogue? I like the idea of being able to move around, break off from conversations, etc. Makes it feel more lively. But it adds in complications of pausing and resuming dialogue. And fixing the player in place while in a conversation feels like a reasonably "real" constraint to have.
    • That being said, pausing and resuming is necessary for ambient conversations. For example, two people having a conversation, then pausing to address the player when they get close enough (e.g. "Can I help you?"), and resuming their conversation once the player leaves their vicinity. This is part of a broader question of whether or not the ambient dialogue system should be distinct from the "player" dialogue system. Ideally they are one and the same, and the player's involvement is a special case (e.g. time stops/player movement stops only if an active script includes the player as a speaker; dialogue always auto-advances/times out if the player isn't involved, etc).
  • How should dialogue progression be handled? There are a lot of potentially conflicting cases here. In general there are three ways a statement can advance: the player hits the next dialogue input, the player selects a choice (if the statement is a decision), or the statement times out (if it has a timeout specified). This is straightforward if there's one statement on-screen. But if there are multiple, as with simultaneous dialogue, then what? If some statements have timeouts and some don't, does pressing the next dialogue input advance them all? Or do they wait for the timeouts to finish? There isn't really a clear answer here. I may just have to pick something and be ready to change it as the rest of the game develops.

This last point is kind of the case with the dialogue system more broadly. I won't really know how well any of this works until I implement it and start working through test cases.

I did get a very basic version of the speaker tracking implemented, was pretty straightforward to do in Godot. Basically I calculate the full bounding box ("AABB") of a spatial node and use that to determine its center x coordinate and maximum y coordinate. Then unproject that point to the camera/screen space. It will get more complicated with multiple speakers and potentially overlapping dialogue boxes, though I think I have a decent solution to that in the sketches above.

Basic speaker tracking

Blender scripting

I also learned a bit of Blender scripting (which uses Python). Most people I know who do a lot of 3d modeling use Rhino/Grasshopper, and I've seen a lot of really amazing work done with scripting in that tool. It looks like Blender is just as capable, which is cool.

I made a big button for quickly exporting the current file to my Godot model folder. Normally I have to go to the export dialogue, navigate to the appropriate folder, then save. Navigating through folders is slow...it's a small thing but smoothes out the workflow a lot.

Big quick export button in Blender

I'm also really impressed by the environment Blender provides for scripting. It has a console for trying things out and logs every interaction you have with the UI so that you can easily figure out what functions do what. There are also several templates provided that make it easy to quick prototype an idea.

Blender scripting environment

<< >>