Archive 17/01/2023.

Managing large scenes

gabdab

I am setting up a large forest scene .
Are node clone or clonecomponent viable strategies for like :
main:
Instantiate a minimum number of base models in main ,with static models.

update:
Search in a larger group of nodes for those (without component, just pos rot scale) inside a sphere centered on player , with the help of kd trees .

Clone base models component (static model) for sphere contained nodes .

Remove component for nodes outside sphere .

?

rasteron

Providing your scene models with LODs will definitely help with larger scenes like forest. Managing Draw Distances is also a must have. Having multiple zones is good but this will depend on your setup. I remember in Torque3D, the tree system have a lowest LOD set to billboard (autogenerated) which is kinda handy so with Urho3D, a script object that will handle it will be enough.

gabdab

Is it possible to instanciate node’s component (as in Blender -linked duplicates-) instead of cloning ?
Is it frame safe to draw many transparent images on all platforms (Android) ?
Also , cloning/removing approximatively 100 (static model) components on update would be aggressive on memory usage ?

cadaver

The update scheme you describe should be perfectly possible at least on desktop machines. For mobiles I don’t make promises, you’ll have to test. One StaticModel component + its node shouldn’t take more than about 0,5 KB of memory. Urho doesn’t support “linked” duplicate components at runtime, but the per-instance attributes are fairly lightweight (model reference, material reference, flags/variables like cast shadows and viewmask). If you want to optimize, doing things like SetModel() and SetMaterial() manually to the new component is probably faster than using the Clone() function, which goes through the generic attribute mechanism.

Another way is to instantiate and remove rectangular world “tiles” as the player moves around, though this can create some framerate hitching.

Heavy use of transparent images can be a blend/fillrate killer on mobiles, so again, you’ll need to test what is too much for your target hardware.

rasteron

Hey Lasse, since we’re in this subject, it’s already supported and I just remember to ask, how do you toggle hardware instancing on/off to compare performance results?

cadaver

Renderer::SetDynamicInstancing(true/false) or renderer.dynamicInstancing

Note: GLES2 does not support instancing.

rasteron

[quote=“cadaver”]Renderer::SetDynamicInstancing(true/false) or renderer.dynamicInstancing

Note: GLES2 does not support instancing.[/quote]

great! thanks :slight_smile:

gabdab

…what would it be the quickest route to avoid duplication of loaded models on memory ,from the engine point of view ?
To be clear :
If I load a scene with 100 nodes (component - static model - ‘man.mdl’) , how many times is man.mdl read and how many copies of it are kept in memory ?

cadaver

Once. This is managed by ResourceCache. After the model is initially loaded (first SetModel() call by the first object) the subsequent SetModel() calls will just query the model from the resource cache and this will be rather fast.

What I meant with “linking not supported” is that component attributes (like model and material references, cast shadows flag etc.) cannot be referenced from a “source” component, but rather each object contains its own unique copies of these.

gabdab

from a few tests I would say that this is the best option .
Cloning and removing static model’s components from the scene at runtime is too heavy on frames per second …
All new mobiles comes with at least 1 gb ram , I guess this would be enough to handle large scenes …

sabotage3d

Don’t want to hijack the thread but I am currently merging all the instances together for mobile to reduce the draw calls is that a good strategy ? For example I have a lot of trees and rocks scattered on terrain. I am merging the rocks, trees and terrain each separately into single mdl.

gabdab

If I understood correctly , it is better to leave models separated .
If you merge them they collectively get drawn even if some are out of camera frustum .
Alternatively some get drawn some not , and you save memory .

gabdab

How do you retrieve a list of nodes that are currently inside frustum ?
FrustumOctreeQuery ,how do you invoke it exactly ?
It would speed up operations on nearby nodes …
I managed to use a kd tree for operations on nodes in a radius from the player , but it is redundant with the engine octree somehow .

gabdab

Working like a charm, thanks :

[code]//init:
PODVector<Drawable*> tempDrawables ;
Urho3D::Octree* octree_;
octree_ = globals::instance()->scene->GetComponent();

//update:
const Frustum& frustum = globals::instance()->camera->GetFrustum();
FrustumOctreeQuery octreeQuery(tempDrawables, frustum,DRAWABLE_GEOMETRY);
octree_->GetDrawables(octreeQuery);
for (unsigned i = 0; i < tempDrawables.Size(); ++i)
{
// if (tempDrawables[i]->IsInView() )
std::cout<<"d "<<tempDrawables[i]->GetNode()->GetName().CString()<<std::endl;
}[/code]

cadaver

You can also access a viewport’s View object and get the geometries (View::GetGeometries()) that were visible last frame, that avoids wasting time on double queries.

codingmonkey

for mobile to reduce the draw calls is that a good strategy

also you may try to use clip planes with two scenes.
near scene to camera is detail scene and far scene is lowpoly scene with lowpoly trees and grass…
you render only half each of them, then merging these parts with post process shader to one frame

TikariSakari

Something that I’ve noticed, that might cause quite a high performance for mobile is the water shader in Urho. On my low performance android phone the shader itself, although I might use it wrongly, can use more than 10-15ms per frame. This is basically just setting plane and adding the water-material on it.

cadaver

You probably should make your own lightweight water shader; the one that comes with Urho3D has been made and tested on desktops. It doesn’t look especially heavy, but it calculates UVs in the pixel shader (= dependent texture reads) which is performance hell on mobiles.

rasteron

Found a water shader for mobile, apparently it is a Unity Shader/Asset but it looks complete…

nevzatarman.com/2014/10/10/unity-water-shaders/

Github Repo:
github.com/paganini24/UnityWaterShadersTest

public domain license.

gabdab
SharedPtr<Viewport> viewport(new Viewport(context_,scene_,cameraNode_->GetComponent<Camera>()));

tempDrawables = viewport->GetView()->GetGeometries ();[/code]
Gives me 
[code] /home/gabriele/Programmi/Urho3D-1.4/Project_1.7_USP/main.cpp:198:36: error: invalid use of incomplete type ?class Urho3D::View?
   tempDrawables=viewport->GetView()->GetGeometries ();
                                    ^
In file included from /home/gabriele/Programmi/Urho3D-1.4/Project_1.7_USP/URHO3D/include/Urho3D/Graphics/Renderer.h:25:0,
                 from /home/gabriele/Programmi/Urho3D-1.4/Project_1.7_USP/main.cpp:29:
/home/gabriele/Programmi/Urho3D-1.4/Project_1.7_USP/URHO3D/include/Urho3D/Graphics/../Graphics/Batch.h:44:7: note: forward declaration of class Urho3D::View?
 class View;
thebluefish

[code]
SharedPtr viewport(new Viewport(context_,scene_,cameraNode_->GetComponent()));

tempDrawables = viewport->GetView()->GetGeometries ();[/code]
Gives me

error: invalid use of incomplete type ?class Urho3D::View? tempDrawables=globals::instance()->viewport->GetView()->GetGeometries (); [/quote]

#include <Urho3D/Graphics/View.h>
gabdab

Perfect,thanks :smiley:

[code] View* v = globals::instance()->viewport->GetView();
tempDrawables=v->GetGeometries ();

//const Frustum& frustum1 = globals::instance()->camera->GetFrustum();
//FrustumOctreeQuery octreeQuery(tempDrawables, frustum1,DRAWABLE_GEOMETRY);
//octree_->GetDrawables(octreeQuery);
for (unsigned i = 0; i < tempDrawables.Size(); ++i)
{
//if (tempDrawables[i]->IsInView() )
std::cout<<"d "<<tempDrawables[i]->GetNode()->GetName().CString()<<std::endl;
}[/code]