World Structure
Despite what I said previously about not posting about world structure, I decided to go ahead and do it anyways. That being said:
What is a world structure?
Do I mean the layout of the world; the data structures the engine uses to render the scene, run physics, know what sounds to play, and what entities to maintain; or something else? Well, it's kind of all of the above. It almost feels nebulous and hard to pin down, and stuff like resource management and "loading areas" (think the elevators in the Metroid games) add complexity to how it should all be organized. That is, at least until I start thinking about what I want the game I'm designing to actually be like. So, maybe that's the question I should be thinking about more.I know I'm making an engine, but what game do I want to make?
Well, here are some things I know:- It's going to be a 2D Metroidvania with a very large, interconnected world and multiple possible paths through the main story.
- Model transformations need to occur on the CPU (not the GPU) so other engine features can exploit them post-transformation.
- It will have multiple independent background and foreground layers--all with parallax relative to the "main" layer.
- Background and foreground layers will also have entities and physics to bring them to life.
- All lights will have both ambient (non-physical) values and cast dynamic shadows--even between layers.
- There will be other environmental and lighting effects, such as fog, precipitation, and high dynamic range.
Of course, there are probably thousands of things I could list here--all on varying levels of detail. My reasoning for mentioning the items on this list are their relationships to the world structure. Let's just work our way down this list.
It's going to be a 2D Metroidvania with a very large, interconnected world and multiple possible paths through the main story.
Right off the bat, I know the world will need to split into different larger areas, perhaps even with names (like "Brinstar" and "Norfair" in Metroid). The data structures should be conducive to a load area approach or seamless/dynamic loading approach; this means that they should at least keep track of entities within them for live engine bookkeeping. For lack of better words, let's call these larger areas zones.What are the contents of a zone? Thinking back to Super Metroid again, I would say the main thing is "screens"--or the areas that doors separate. I think background and foreground layers are also an obvious component--especially when thinking about outdoor and large cavernous areas. I don't personally like "screen" as my noun though. It's kind of a misnomer about the implied behavior as some of them go beyond one literal "screen" (as in, the display/monitor)--sometimes multiple times so. To pay homage to my level design upbringing, I'll call these things sectors.
This is making sense so far. Zones are made of layers (background and foreground) and sectors. This means layers are "shared" across sectors. I think this adds up: for example, a background layer containing a mountain range should "parallax" across all sectors in the zone. Another background layer in front of the first one can act as depth-wise boundaries/windows occluding or revealing the mountain range. The mountain range background layer can have live weather, passive entities running through scripted sequences (such as birds flying around), trees that respond to random wind patterns, etc. The layer in front of the mountain range layer can occlude (hide) it in certain parts, simply by having content in them.
Model transformations need to occur on the CPU (not the GPU) so other engine features can exploit them post-transformation.
Probably the main motivator here is that I'm a functional newbie with OpenGL and shader programming. I'm sure it's possible to divert all of the post-model-transformation functionality to shaders, but that's thinking on a level I'm not at for Integral v1.0. Some examples of post-model-transformation functionalities:
- Animations actually conform to world geometry. Think of your foot slanting down when walking down a hill and how that affects your gait and stride. I want the actors in Integral to have altered gait and stride in such circumstances as well.
- Lighting is influenced by dynamic geometry beyond rendering shadows. Light and shadow volumes must both affect high dynamic range conditions and render properties of environmental effects.
- Finalization effects such as fur and foliage need feedback from the actively-transformed models and physics system to know when to spawn further particle effects--such as fur flying when attacked.
What does this mean in practicality? It's simple actually: Models must preserve a default state and maintain an active state for their geometry. (I will talk about the model structures more in-depth in a later post.)
It will have multiple independent background and foreground layers--all with parallax relative to the "main" layer.
This one isn't too bad. All zones have an ordered list (or just a list) of background and foreground layers. Every layer has a set of understood render properties applied to every renderable item in them--including parallax.
Parallax, simply put, is the ratio of translation relative to the camera. For example, a parallax of 0.9 means that for every 10 units the camera moves to the right, the objects with that parallax appear to "move left" 9 units. The standard parallax is 1.0. Parallax values of less than 1.0 make objects appear further away, and parallax values of greater than 1.0 make objects appear closer.
Background and foreground layers will also have entities and physics to bring them to life.
An entity is anything that has game logic executed every frame. I borrowed this terminology from the Quake and Half-Life games. A synonym is actor.
So, background and foreground layers will have these as well as the "main" layer (which isn't actually technically a layer). This allows the layers to appear more dynamic ("come to life") as per the rules and hooks established by the engine.
Without special triggers, entities also won't be able to interact with each other across layers. This reduces special logic needed to keep scripted sequences running as intended--i.e. so entities from different layers don't accidentally interact with each other.
In addition to entities, layers will also have static world models (also known as brushes) for the scenery. I'm contemplating introducing the concept of detail brushes that don't execute special logic per frame yet still have world and player interactions. Applications of these would be foliage and other things that have limited, pseudo-scripted interactions such as "play sound abc.wav and run physics on certain sub-models when an entity touches it". My hesitation, at least right now, is that it could muddy the kernel of the engine and end up being frustrating when actually designing content.
All lights will have both ambient (non-physical) values and cast dynamic shadows--even between layers.
More importantly for the world structure: There will be high dynamic range (HDR) functionality, and lighting will influence it. How this will work example is actually a little unclear to me still, but I know that the engine will need to keep track of "dark" areas versus "bright" areas. I'm no light expert, but empirically I know that being outside on a bright day and then going inside--even to the best- or most naturally-lit of rooms--everything appears darker, tinted, and kind of "lower quality" while my eyes adjust. And on the flip side--going from inside to outside on a bright day--everything appears saturated until my eyes adjust.
Thinking about these scenarios and how to emulate them: sectors need rooms. Actually, every sector will have at least one (parent) room and arbitrarily-deep nested (children) rooms. Additionally though, rooms will need different models and render properties for when the player is inside or outside of them (or exterior and interior models). Think of this example: you're walking along a (side-scrolling, Metroidvania) street and approach a house. It should be possible to render that house differently when outside of it versus inside of it for what I feel are obvious creative reasons. The entirety of the house would be one (child) room, and the rooms inside the house would be further-nested rooms.
The exterior versus interior concept also has implications for the next point.
There will be other environmental and lighting effects, such as fog, precipitation, and high dynamic range.
In a sense, this point kind of ties together previous points. In short, the world structures at their core need to facilitate these features through game mechanic enrichment. The renderer needs to know when and where to render environmental effects like fog and precipitation; since it will know how to render zones, sectors, and rooms anyways, it can use these structures (primarily rooms in this case) to make these types of decisions. An example of this is a zone where it always rains, but that rain doesn't appear in or interact with the interior of rooms.
Conclusion
Having well-established world structures has really helped lay out how the renderer works. As a matter of fact, my Hello World Triangle (seen in last week's post) is built on a mesh used by a model that's placed in the background layer of a zone added to the world. The model references a previously-setup shader by name, as there's a global shader manager that makes it possible to have multiple renderers--all with different WebGL canvases (also more on this in a later post).
No comments:
Post a Comment