Jump to content

1000-postings-barrier-break


photo

Recommended Posts

You have to earn it, so post another 450 useful forum answers and than it's your turn ! Right now keep your fingers off of my feature wish :-)

Link to comment

Hahaha, most probably not a bad idea to go for gold with current euro crisis....but no, I would select a UNIGINE feature you would also be very, very happy to have it at Sydac...for sure :-) let's see what will happen, maybe UNIGINE crew is generous

Link to comment

interesting, but not the thing I was thinking of :-) As I was always interested in really unlimited worlds my wish would have been related to true node-file world streaming which we have already discussed many times here on the form during the last two years...but based on the missing UNIGINE crew reaction I think I have to drop my hope...

Link to comment

Ulf, you have definitely earned the feature request. Could you please summarize it here (because there was a lot of discussions before, we need to understand you current view)?

Link to comment

Ulf, just a bit of delayed reaction. We agreed all together - and at once - that if it's in our power, we do that. I can just second Denis here: it would be a well-deserved reward for your tremendous support for newcomers and useful insights for Unigine veterans :)

Link to comment

This sounds great, thank you very much, so here we go with my most-favorit UNIGINE feature wish: true background world node file streaming for unlimited virtual worlds required in simulation and serious gaming.

 

Use cases both include very large geographic world dimensions with world sizes of several 100-1000 km x km (e.g. flight simulation with streaming cell sizes of e.g 10x10+ km), but also smaller, but extremly dense environments (e.g. highly-detailed urban city environments like in BF3 with streaming cell sizes maybe in the range of 100 - 1000m depending on asset types e.g. environment, buildings, interior furnitures etc.).

 

NodeSector as a first step allows background streaming of texture/mesh/mask resources for node hierachies 'below' individual NodeSector nodes, but nevertheless the node structure itself will always have to be loaded on startup and also be kept in memory. This both takes time and limits total virtual world complexity in practice. The solution would be the ability to partition the complete world node structure into multiple world zones/tiles with node sub-hierachies stored in individual node files which can be loaded/unloaded in the background during runtime.

 

Such a capability really would push UNIGINE engine to the next-level and also far apart from so many other engines out there. Any chance for turning this dream into short-term reallity ?

Link to comment

BTW here are some more specific backgrounds/details/thoughts on large world streaming scenarios which I had written down in another posting. Some aspects are for sure still too unspecific, but nevertheless maybe useful for illustrating the general requirements from a user perspective. I am sure, frustum will find a much more elegant technical solution

 

 

1. Use cases, database sizes and structure

 

1.1 ground warfare simulations

 

Typical database sizes are between 50x50km and 100x100 km. Databases are typically organized as 1x1km to 3x3km regular tiles. Details are spread uniformly in the database. Typical viewing distance 8km.

 

1.2 naval simulations

 

Typical database sizes are between 80x80km and 300x300km. Databases are typically organized as 5x5km to 10x10km low resolution base terrain mesh tiles with high detail ground structures (buildings, constructions, trees) organized as 1x1 to 3x3km overlay tiles along navigable coastlines, rivers or habour areas. Typical viewing distance 30km for low resolution terrain meshes and 5-8km for high detail ground structures.

 

1.3 flight simulations

 

Typical database sizes are between 200x200 and 1000x1000km. Databases are typically organized as 10x10km regulare tiles with high-detail ground insets (e.g. airports, training areas e.g shooting ranges). Terrain meshes with multiple LOD surfaces/textures. Typical viewing distances 30km.

 

 

In general for all use cases there is some kind of regular gridded world base tile structure covering the complete database and multiple localized, more fine-grained gridded or irregular placed world detail tiles overlay structures.

 

 

2. Scene content

 

Scene content mainly consists of

 

2.1 ground surface meshes

 

Individual ObjectMesh instances per zone/tile each with individual diffuse, detail material mask and additional ground type mask (e.g for type specific dust particles and step sound selection) per zone/tile

 

2.2 vast forest areas

 

Individual ObjectForest instances per zone/tile but shared tree resources for whole database. See https://developer.un...__fromsearch__1 for details

 

2.3 ground clutter

 

Individual ObjectGrass/WorldClutter instances for multiple grass, corn fields, rock layers each with individual mask images per zone/tile

 

2.4 roads, streets

 

Individual ObjectMesh instances per zone/tile as overlay on base ground surface mesh. Generic materials (100+) can be shared for whole database

 

2.5 urban building and constructions

 

Individual NodeReferences per zone/tile to a pool of 200-300 building templates for whole database.

 

Each building is modelled as ObjectMesh in undestroyed, partially and full destroyed state with 2-3 LOD levels for each destruction state. Referenced building node files can also contain additial ObjectLights (e.g. street latern), ObjectParticles (e.g. smoke pipe), ObjectCloth (e.g. flags) and WorldExpressions (e.g. procedural animation of movable parts (e.g wind mill, flap bridges, etc)

 

 

3. General functional requirements

 

3.1 no render stalls caused by background zone streaming

 

3.2 radial streaming around world streaming reference point

 

To avoid popping artifacts on fast user direction changes radial pre-caching of tiles/zones based on user-definable zone cache/purge distances around streaming reference point should be implemented. In general cache-in distance should be larger than render distance. Purge-out distance should be larger than cach-in distance to avoid resource unloading/loading-ping-pong.

 

Most of the time streaming reference point will be player position, but for some application-specific streaming scenarios (see 3.3) explicit control about streaming reference point(s) might be required.

 

3.3 support for multiple world streaming reference points

 

Required for multiple independant viewports of a single client or server-side resource streaming for multiple connected clients.

 

3.4 customizable background processing on zone load/unload

 

This might be a critical requirement. In nearly all cases additional game worls processing has to be done on world zone loading/unloading (e.g. initialisation/destruction of corresponding game objects). This processing might require traversal of newly loaded node tree e.g. for game object properties retrieval, creation of additional game data structures etc.

 

As this processing might take sigificant time most probably it has also to be done within background resource loading thread to avoid render stalls. Most natural solution might be background invocation of user-defined WorldZone callback functions e.g. WorldZone::setLoad-/UnloadCallback().

 

 

4. Design issues

 

4.1 streaming organization

 

Most probably a new node type - e.g. WorldZone or something similar - controlling streaming/purging of attached child nodes might be useful. WorldZone node data will be stored in separate node file like WorldLayer. WorldZone definable cache-in/purge-out distances on top of aggregated child-node bounding box sizes and render distances can be used controlling streaming behavior. WorldZone states unloaded, loading, loaded, unloading. Automatic callback invocation of onLoad/UnloadCallback() for customized game data preparation.

 

Usage of both WorldZone and WorldLayer would give quite flexible spatial and logical organization possibilities for large worlds.

 

4.2 streaming order and priorities

 

There should be some priority strategy for loading resources. Resources in view should be loaded with highest priority based on distance from streaming reference point. Resources outside the view frustum should be loaded with lower priority, but still there should be a prioritization based on viewer distance and resource position relative to view frustum orientation. Resources nearer to view frustum forward direction should be loaded earlier than resources in back of the viewer.

 

Remark 31.08.12

Still a little bit unsure about best approach for streaming control. In the past I would have favoured automatic and fully transparent engine-internal streaming control of all WorldZone instances based on user-defined WorldZone node page-in/-out-distances. Nevertheless user-controlled explict streaming control via UNIGINE script for WorldZone instances comparable to NodeSector implementation might give more flexibility for customized streaming control schemes (though handling might be more complicated).

 

 

4.3 streaming data format

 

Usage of standard XML or binary format for better streaming/processing efficiency ?

 

4.4 per-frame time-budget management for resource preparation/destruction

 

How to limit per-frame resource (de-)allocation within render thread to avoid render stalls ?

 

4.5 editor handling of streamable worlds

 

How can streamable worlds be handled within editor (as only a certain part of the world will fit into memory) ? Maybe best approach might be have some user-initiated load/unload of node sub-hierarchy for individual WorldZones nodes comparable to e.g. WorldCLuster or an explicit editing mode comparable to NodeReference editing.

Link to comment

Related to large world streaming these presentations Creating Vast Game Worlds and Graphics Gems for Games from Siggraph 2012 give excellent insight into encountered problems and solutions employed in Just Cause 2.

 

Also they perfectly show other related issues to large world rendering (precision, z-fighting, culling, long-distance shadows, etc) which also have been discussed in other user postings here on the forum.

Link to comment
You think big, i like it

Well, this was more than easy to predict based on your current large world requirements and simulation use cases...actually this was also our main focus when starting to work with UNIGINE engine more than 3 years ago. Since than a lot of improvements have been incooperated into the engine (most prominent is double-precision support, which is more or less a unique feature compared to all other multi-purpose engines in the market), but a full-fledged world streaming solution is still one of the biggest missing pieces.

 

Until now we weren't able to convince UNIGINE crew that specialization on high-end large world feature support could be a very attractive business model as a lot of simulation and serious gaming companies are desperately seeking for such a commercially available game engine solution (both Rheinmetall and Sydac are examples..) and would also be willing to pay higher licencing cost than small indy-game-studios.

 

Of course we have to be fair, with the availability of so-many low-cost game engines and free availability of highest-end game engines like CryEngien3, UDK etc it is hard to find the right way for a medium-sized game engine provider to find its right market niche nowadays. But maybe the fact that a growing number of users have selected UNIGINE exactly for its large world support (latest example...) might change the UNIGINE thinking step-by-step :)

Link to comment
  • 1 year later...

Ok, yesterday's party on new and true background node file streaming is over, let's see what we really got (as far as I understand it  :) )

 

  • interpreter is thread save now + Async class can execute user functions in a separate thread

    This opens up whole new possibilities as this means TRUE parallel script execution (instead of thread/yield/wait cooperative 'threading' in the main thread). This should allow to run longer script operations (e.g. writing some data to an external file) without risk of render stalls and in a straight forward single function code sequence instead of some chunked fashion via yield to not exceed frame time budget. 

    Looking into the Async class source code it looks like only a single script function/operation will be executed by the single Async thread in parallel to the main thread, but anyway: cool !
     
  • Asynchron game object initialization on node file loading / deinitialization on unloading

    As described in 3.4 above this is most of the time required except you only load pure static scene geometry. Often this includes analysing the newly loaded node tree structure (e.g. by looking for for certain node properties) and building a correspondig game object structure (e.g. switches/transforms tree for easy control of lights/windows/doors in a loaded house model node file).

    As such processsing can take longer time once again Async class threaded function execution seems to be the right approach for doing this after engine.world.loadAsynNode() / before node_delete() call on nodes to unload.

    An elegant alternative might be usage of a WorldExpression within the node file itself and doing initialization/deinitialization within WorldExpression __constructor__/__destructor__ though there might be some problem, not sure (see post below) 
     
  • Asynchron material/property libraries loading / deinitialization on unloading

    Material- and PropertyManager are thead-safe now for supporting threaded background node file loading. While the loading aspect is fully transparent, there seems to be NO automatic unloading, so this has to be done manually.

    If you have some user-defined e.g. WorldStreamer class controlling world zone loading/unloading this is no big issue, but when using out-of-the-box WorldLayer class unloading of material/property libraries will not happen automatically and will stay in memory ! This might be an issue and has to be kept in mind.

    Therefore best approach might be to avoid additional material/property libraries in streamable WorldLayer node files completely and instead included global material/propertiey liebraries only within the overall world file. Maybe UNIGINE can give some more tips and tricks on best streaming world organization.
     

In summary the new streaming solution is really great ! And once again frustum found the most elegant way to include such a BIG internal change without external effects on existing projects, perfect !

Link to comment

As described in the previous post it might be a nice idea to use WorldExpression placed within node file to asyncronously execute initialization/deinitialization code for the whole node file on background loading/unloading within __constructor__/__destructor__.

 

Most 'natural' approach would be to place the WorldExpression node as top-level node and then use getNumChilds()/getChild(index) for tree traversal, but there might be an issue during WorldExpression __constructor__ invocation as child nodes might not be loaded and initialized yet ?!?

int WorldExpression::loadWorld(const Xml *xml) {		// size	if(xml->isChild("size")) xml->getChild("size")->getFloatArrayData(size,3);	setSize(size);		// source	if(xml->isChild("expression")) setExpression(xml->getChild("expression")->getData());		return Node::loadWorld(xml);}
The __constructor__ will be called during setExpression() call, but node data and all child nodes - as far as I understand it - will be initialized afterwards in Node::loadWorld(), so it wouldn't be possible to get access to any child node within the constructor. Not sure but maybe simple reordering would solve this issue (if existing) ?
int WorldExpression::loadWorld(const Xml *xml) {		int return = Node::loadWorld(xml);	// size	if(xml->isChild("size")) xml->getChild("size")->getFloatArrayData(size,3);	setSize(size);		// source	if(xml->isChild("expression")) setExpression(xml->getChild("expression")->getData());         return ret;	}WorldScript
BTW: Might be a good idea to rename WorldExpression to WorldScript , as in the meantime it is much more powerfull (const/destr, variable passing, etc) than in its initial days.
Link to comment

I am sorry, but I have another issue on world streaming: right now more or less everything is streamed except skinned animations (which might also consume large amounts of memory when it comes to realistic/complex character animation) ! 

 

Simple idea would be to include animation references e.g. by adding a  list of required animation files directly to ObjectMeshSkinned, so these animations could also be loaded asynchronously in the background on node file loading ? Something like

<node id="56491540" type="ObjectMeshSkinned">
   .....
   <animations>
       <animation name="anim1">filepath1</animiation>
       <animation name="anim2">filepath2</animiation>
   </animations>
</node>

Of course system should cache animations shared by multiple ObjecMeshSkinned instances and keep them in memory as long as at least one instance is referencing a specific animation, but this shouldn't be a too big thing to implement (most probably somewhere in WorldManager class I would guess).

 

Having such a list of attached animations per ObjectMeshSkinned would also allow much better testing within UNIGINE editor ! Right now only one animation can be manually specifed and played.

 

@UNIGINE: would this make sense ?

Link to comment
×
×
  • Create New...