SEED - Watching entities: Difference between revisions

From The DarkMod Wiki
Jump to navigationJump to search
Tels (talk | contribs)
add
 
 
(9 intermediate revisions by 3 users not shown)
Line 1: Line 1:
== Intoduction ==
== Introduction ==
 
There are two reasons why you want a [[SEED]] entitiy to "watch" over entities that you created inside the [[DarkRadiant|editor]], namely the SEED can:
 
# '''cull entities''' that are too far away from the player. That means it removes the entity entirely, not merely hiding it as the engine does. This allows you to overcome the [[entity limit]] and also saves memory when not all entities are always present
# '''combine entities''' that are close together and share the same rendermodel. In this case the combined rendermodel isssues only one drawcall ( [[Drawcalls]] ) instead of multiple. This can improve rendering performance dramatically.
 
== Culling of entities ==
 
Culling of entities is entirely automatic and should always be safe to use. The SEED will know when it should not cull entities, and when it needs to respawn them. If you ever need to disable entity culling, you can do so by setting [[SEED - Spawnargs#cull_range|'''cull_range''']] to 0.
 
== Combining entities ==


Suppose you build a highly-detailed scene in DR and you want to improve the performance of the scene. There are three different kind of ways (apart from worldspawn and any moveables/lights etc) you can use to add visible things to such a scene:
Suppose you build a highly-detailed scene in DR and you want to improve the performance of the scene. There are three different kind of ways (apart from worldspawn and any moveables/lights etc) you can use to add visible things to such a scene:


# static entities with an entity def (f.i. [b]atdm:statue_aphrodite[/b]). This is basically a func_static with a model spawnarg pointing to a model in a file (.LWO, or .ASE). You'd use "Create entity" in DR to create such a thing.
# static entities with an entity def (f.i. '''atdm:statue_aphrodite'''). This is basically a func_static with a model spawnarg pointing to a model in a file (.LWO, or .ASE). You'd use "Create entity" in DR to create such a thing.
# static models (f.i. [b]models/darkmod/decorative/wall/longbanner_ragged.lwo[/b]). This is also basically a func_static with a model spawnarg pointing to a model in a file (.LWO, or .ASE), except that the spawnclass is "func_static" for all of them. You'd use "Create model" in DR to create such a thing.
# static models (f.i. '''models/darkmod/decorative/wall/longbanner_ragged.lwo'''). This is also basically a func_static with a model spawnarg pointing to a model in a file (.LWO, or .ASE), except that the spawnclass is "func_static" for all of them. You'd use "Create model" in DR to create such a thing.
# func_statics based on brushes or patches. You'd use "Create func_static" in DR to create such a thing.
# func_statics based on brushes or patches. You'd use "Create func_static" in DR to create such a thing.


There are fundamental differences betwen the first two cases and the third case:
There are fundamental differences betwen the first two cases and the third case:


In both the first cases you have an entity, and a model in a file. This means, it is always possible (inside the engine) to load the model data by just given the file. Also, the engine will only ever keep one copy of the model data around (sharing it).
In both the first cases you have an entity, and a model in a file. This means, it is always possible (inside the engine) to load the model data by just giving the file. Also, the engine will only ever keep one copy of the model data around (sharing it).


In the third way, you have the "model data" stored in the map file. Not only is it not possible to reload that data (as there is no model file name), but also all the data is duplicated if you duplicate such a func_static in DR.
In the third way, you have the "model data" stored in the map file. Not only is it not possible to reload that data (as there is no model file name), but also all the data is duplicated if you duplicate such a func_static in DR.




=== Why ''can'' combining entities ''improve'' performance? ===
=== Why ''can'' it ''improve'' performance? ===


* One important feature of the idTech4 engine is that if it has to render multiple things for multiple light passes, then it uses one drawcall per light per "what it renders". This means if you have two tables based on map geometry (brush or patch), then it is better to combine these two func_statics into one, as it will reduce the [[drawcalls]].
* One important feature of the idTech4 engine is that if it has to render multiple things for multiple light passes, then it uses one drawcall per light per "what it renders". This means if you have two tables based on map geometry (brush or patch), then it is better to combine these two func_statics into one, as it will reduce the [[drawcalls]].




=== Why ''can'' combining entities ''degrade'' performance? ===
=== Why ''can'' it ''degrade'' performance? ===


*If the two things you combined cross a visportal afterwards, then they will be visible in both areas. That can lead to the situation where the entity is no longer culled, instead it is always fully drawn becaue the engine can't know that only half of it is visible.
*If the two things you combined cross a visportal afterwards, then they will be visible in both areas. That can lead to the situation where the entity is no longer culled, instead it is always fully drawn becaue the engine can't know that only half of it is visible.
*If each part of the entity is hit by one light, then the combined entity is hit by two lights, and thus both parts are drawn twice, where formerly only one part was draw once for one light, and the other for the other light.
*If each part of the entity is hit by one light, then the combined entity is hit by two lights, and thus both parts are drawn twice, where formerly only one part was draw once for one light, and the other for the other light.
*If the combined entity covers an huge area, the engine will often thing things are inside that entity space, even tho they are "between" the parts. This can lead to poor performance in case of stims or collision detection. For static entities (even solid ones) this is usually no concern.
*If the combined entity covers an huge area, the engine will often think things are inside that entity space, even though they are "between" the parts. This can lead to poor performance in case of stims or collision detection. For static entities (even solid ones) this is usually no concern.




== When should you combine entities: ==
=== When should you combine entities? ===


* When all parts are hit by the same light(s) (or none)
* When all parts are hit by the same light(s) (or none)
* AND all parts are in the same visportaled area
* AND all parts are in the same visportaled area
* AND all parts are reasonable close together (a few 1000 doom units)
* AND all parts are reasonably close together (a few 1000 doom units)




== How to combine entities ==
=== How to ===




== func_statics base on map geometry ==
==== func_statics based on map geometry ====


For the third way this indeed works: Select first func_static, "Revert to worldspawn", do the same for the second, then select both, and use "Convert to func_static". Et voila, one merged entity which will improve performance.
For the third way this indeed works: Select first func_static, "Revert to worldspawn", do the same for the second, then select both, and use "Convert to func_static". Et voila, one merged entity which will improve performance.


== Entities with a model ==
You do not need the SEED to do this.
 
 
==== Entities with a model ====


For the first two ways there is, however, no way you can combine them in DR. The only recourse you have is by taking a modelling program (like '''Blender''') and then combine the entities in it and create a new model. This is not only time consuming but also cumbersome.
For the first two ways there is, however, no way you can combine them in DR. The only recourse you have is by taking a modelling program (like '''Blender''') and then combine the entities in it and create a new model. This is not only time consuming but also cumbersome.
Line 46: Line 60:
And here is where the SEED entity comes into play.  
And here is where the SEED entity comes into play.  


For our example, we create 6 banners on a wall. 5 use the same model (ragged banner, 3 with one skin, 2 with another skin) and 1 uses a different model (big banner). Here is how it looks in the editor:
If you have either set [[#combine|'''combine''']] to '''1''' on the SEED, or set [[#seed_combine|'''seed_combine''']] to '''1''' on the target, then the SEED will combine all multiple models of the same name into one multi-model entity. To prevent it, set '''seed_combine''' to 0 on the target entity.
 
For our example, we create 6 banners on a wall. 5 use the same model (ragged banner, 3 with one skin, 2 with another skin) and 1 uses a different model (big banner). Then we target one of the banners from the SEED and set:
 
"seed_watch_brethren" "1"
 
on it. Here is how it looks in the editor:


[[Image:SEED Watch.jpg|600px|Inside DR]]
[[Image:SEED Watch.jpg|600px|Inside DR]]
Line 56: Line 76:
You can see that afterwards there are only two entities instead of 5 (ignore the missing banner far-away, I did make the screenshot before adding it to the map).
You can see that afterwards there are only two entities instead of 5 (ignore the missing banner far-away, I did make the screenshot before adding it to the map).


{{editing}}
The other "seed_*" spawnargs (like '''seed_floor''', '''seed_spacing''' etc.) are ignored on the target entity. The only relevant spawnargs are '''lod_*''' and '''hide_distance''' - these cause the LOD system to kick in. Also, do not forget to put a '''hide_distance''' on the target entity, or the SEED would never cull the entities it watches.
 
{{seed}}

Latest revision as of 00:53, 22 June 2011

Introduction

There are two reasons why you want a SEED entitiy to "watch" over entities that you created inside the editor, namely the SEED can:

  1. cull entities that are too far away from the player. That means it removes the entity entirely, not merely hiding it as the engine does. This allows you to overcome the entity limit and also saves memory when not all entities are always present
  2. combine entities that are close together and share the same rendermodel. In this case the combined rendermodel isssues only one drawcall ( Drawcalls ) instead of multiple. This can improve rendering performance dramatically.

Culling of entities

Culling of entities is entirely automatic and should always be safe to use. The SEED will know when it should not cull entities, and when it needs to respawn them. If you ever need to disable entity culling, you can do so by setting cull_range to 0.

Combining entities

Suppose you build a highly-detailed scene in DR and you want to improve the performance of the scene. There are three different kind of ways (apart from worldspawn and any moveables/lights etc) you can use to add visible things to such a scene:

  1. static entities with an entity def (f.i. atdm:statue_aphrodite). This is basically a func_static with a model spawnarg pointing to a model in a file (.LWO, or .ASE). You'd use "Create entity" in DR to create such a thing.
  2. static models (f.i. models/darkmod/decorative/wall/longbanner_ragged.lwo). This is also basically a func_static with a model spawnarg pointing to a model in a file (.LWO, or .ASE), except that the spawnclass is "func_static" for all of them. You'd use "Create model" in DR to create such a thing.
  3. func_statics based on brushes or patches. You'd use "Create func_static" in DR to create such a thing.

There are fundamental differences betwen the first two cases and the third case:

In both the first cases you have an entity, and a model in a file. This means, it is always possible (inside the engine) to load the model data by just giving the file. Also, the engine will only ever keep one copy of the model data around (sharing it).

In the third way, you have the "model data" stored in the map file. Not only is it not possible to reload that data (as there is no model file name), but also all the data is duplicated if you duplicate such a func_static in DR.


Why can it improve performance?

  • One important feature of the idTech4 engine is that if it has to render multiple things for multiple light passes, then it uses one drawcall per light per "what it renders". This means if you have two tables based on map geometry (brush or patch), then it is better to combine these two func_statics into one, as it will reduce the drawcalls.


Why can it degrade performance?

  • If the two things you combined cross a visportal afterwards, then they will be visible in both areas. That can lead to the situation where the entity is no longer culled, instead it is always fully drawn becaue the engine can't know that only half of it is visible.
  • If each part of the entity is hit by one light, then the combined entity is hit by two lights, and thus both parts are drawn twice, where formerly only one part was draw once for one light, and the other for the other light.
  • If the combined entity covers an huge area, the engine will often think things are inside that entity space, even though they are "between" the parts. This can lead to poor performance in case of stims or collision detection. For static entities (even solid ones) this is usually no concern.


When should you combine entities?

  • When all parts are hit by the same light(s) (or none)
  • AND all parts are in the same visportaled area
  • AND all parts are reasonably close together (a few 1000 doom units)


How to

func_statics based on map geometry

For the third way this indeed works: Select first func_static, "Revert to worldspawn", do the same for the second, then select both, and use "Convert to func_static". Et voila, one merged entity which will improve performance.

You do not need the SEED to do this.


Entities with a model

For the first two ways there is, however, no way you can combine them in DR. The only recourse you have is by taking a modelling program (like Blender) and then combine the entities in it and create a new model. This is not only time consuming but also cumbersome.

And here is where the SEED entity comes into play.

If you have either set combine to 1 on the SEED, or set seed_combine to 1 on the target, then the SEED will combine all multiple models of the same name into one multi-model entity. To prevent it, set seed_combine to 0 on the target entity.

For our example, we create 6 banners on a wall. 5 use the same model (ragged banner, 3 with one skin, 2 with another skin) and 1 uses a different model (big banner). Then we target one of the banners from the SEED and set:

"seed_watch_brethren" "1"

on it. Here is how it looks in the editor:

Inside DR

And here is how it looks in the game, before (without SEED) and after (with SEED combining models):

Before After

You can see that afterwards there are only two entities instead of 5 (ignore the missing banner far-away, I did make the screenshot before adding it to the map).

The other "seed_*" spawnargs (like seed_floor, seed_spacing etc.) are ignored on the target entity. The only relevant spawnargs are lod_* and hide_distance - these cause the LOD system to kick in. Also, do not forget to put a hide_distance on the target entity, or the SEED would never cull the entities it watches.