+2 votes

Hello,

I try to check power of Godot and how well is it for my purposes.
I need "render to texture" many 2D objects and then draw that textures in 3D space.
So I made test script to create 4 materials based on 4 Viewport textures. In every viewport I put AnimatedSprite. Then I use that 4 materials (yes, just 4) to draw thousands of meshes.
But I can draw well only 2-3 thousands of meshes without dropping fps. For me it's very strange. Engine should support at least 2-3 hundreds of materials and more than 10000 objects I guess.

Could somebody comment this ?
Actually I need about 500 dynamic materials in scene and 3000-4000 objects, using that materials.

Here is the script:

extends Spatial

var title = "Game: "
var meshes = []

# Called when the node enters the scene tree for the first time.
func _ready():
    var materials : Array = []
    # create several materials
    for i in range(1,5): # 1 - 4
        var newVPort : Viewport = createVieport()
        add_child(newVPort)
        var asprite : AnimatedSprite
        match i:
            1:
                asprite = createAnimatedSprite(["res://anim/anim_1_1.png", "res://anim/anim_1_2.png", "res://anim/anim_1_3.png"])
            2:
                asprite = createAnimatedSprite(["res://anim/anim_2_1.png", "res://anim/anim_2_2.png", "res://anim/anim_2_3.png", "res://anim/anim_2_4.png", "res://anim/anim_2_5.png", "res://anim/anim_2_6.png", "res://anim/anim_2_7.png", "res://anim/anim_2_8.png", "res://anim/anim_2_9.png", "res://anim/anim_2_10.png", "res://anim/anim_2_11.png", "res://anim/anim_2_12.png", "res://anim/anim_2_13.png", "res://anim/anim_2_14.png"])
            3:
                asprite = createAnimatedSprite(["res://anim/anim_3_1.png", "res://anim/anim_3_2.png", "res://anim/anim_3_3.png", "res://anim/anim_3_4.png"])
            4:
                asprite = createAnimatedSprite(["res://anim/anim_4_1.png", "res://anim/anim_4_2.png", "res://anim/anim_4_3.png", "res://anim/anim_4_4.png"])
        asprite.centered = false;
        newVPort.add_child(asprite)
        var tex = newVPort.get_texture()
        var mat = createMaterial(tex)
        materials.append(mat)

    for i in range(1, 2000):
        var mesh : MeshInstance = createMesh()
        mesh.material_override = materials[randi() % materials.size()]
        add_child(mesh)
        var newPos = Vector3(-2.0 + randf()*4, -randf(), -2.0 + randf()*4)
        mesh.translate(newPos)

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
    OS.set_window_title(title + " | fps: " + str(Engine.get_frames_per_second()))
    #print(Performance.get_monitor(Performance.TIME_FPS))
    #print(Performance.get_monitor(Performance.TIME_PROCESS))
    pass

func createVieport():
    var vport:Viewport = Viewport.new()
    vport.size.x = 64
    vport.size.y = 64
    vport.usage = Viewport.USAGE_2D
    vport.disable_3d = true
    vport.hdr = false
    vport.render_target_v_flip = true
    return vport

func createMaterial(texParam:Texture):
    var mat:SpatialMaterial = SpatialMaterial.new()
    mat.albedo_color = Color.white
    mat.albedo_texture = texParam
    return mat

func createMesh():
    var pmesh = PlaneMesh.new()
    pmesh.size = Vector2(0.5, 0.5)
    var mesh:MeshInstance = MeshInstance.new()
    mesh.mesh = pmesh
    mesh.rotate(Vector3(1, 0, 0), PI/2)
    return mesh

func createAnimatedSprite(imgArr:Array):
    var frames:SpriteFrames = SpriteFrames.new()
    frames.add_animation("default")
    frames.set_animation_loop("default", true)
    var w = 0
    var h = 0
    for fname in imgArr:
        var res:Texture = load(fname) #StreamTexture
        if res != null:
            frames.add_frame("default", res, -1)
            if w == 0:
                w = res.get_width()
            if h == 0:
                h = res.get_height()
    var sprite:AnimatedSprite = AnimatedSprite.new()
    var scale = min(64.0/w, 64.0/h)
    sprite.scale = Vector2(scale, scale)
    sprite.frames = frames
    sprite.animation = "default"
    sprite.play("default")
    return sprite
in Engine by (16 points)

Did you try out using a Multimesh instead? It seems to be the right thing for your use case:
https://docs.godotengine.org/en/3.1/classes/class_multimesh.html?highlight=multimesh

Also:
I encountered some performance issues (while loading adding/removing nodes) in Godot 2.15 when many nodes where flat as children under one node. At that time I cicumvented that by grouping the nodes under multiple sub-nodes. But I have no idea it that problem still exists in Godot 3.1

Thank you for reply.
Actually Multimesh is not what I need, because I should have almost every mesh with unique material. I would say more clear - every mesh should have multiple surfaces and every surface should have unique material.

So, today tested grouping with subnodes - nothing changed.
Also made 6 surface cubes (with SurfaceTool) and assign different dynamic materials to different surfaces. Result is even worse :(

I wonder is it possible to find bottleneck in Godot pipeline ?

Were you able to get around this issue? I am currently trying to create multiple viewports as textures, and when I use add_child in my main scene, it freezes for 1-2 seconds...

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.