Perfomance problems on simple scene

I’m having performance problems on my simple program in both OGL and DirectX and I can’t pinpoint the cause. I have some basic geometry: Sky, moon, models/environment from panda tutorial a sphere modeled in 3ds max, one ambient light and one point light. None of the models are specially high poly. The sky and the moon are the same as the ones in the solar-system sample program.

I’m getting 20 or less fps and the only way to get it higher is to comment most of the geometry (ie only leave the sphere and the enviroment or only leave the sky and the moon). When I comment some of the geometry I get 60fps (I’m not getting 40 fps no matter what I remove from the scene for example). Using or not using shaders doesn’t affect my fps.

This is very odd considering I get 60fps on all the sample programs that come with panda.

from panda3d.core import loadPrcFileData
#loadPrcFileData('', 'load-display pandadx9')
loadPrcFileData('', 'show-frame-rate-meter 1')

import direct.directbase.DirectStart
from direct.interval.IntervalGlobal import *
from direct.showbase import DirectObject
from direct.interval.IntervalGlobal import *
from direct.showbase.DirectObject import DirectObject
from direct.actor.Actor import Actor
from pandac.PandaModules import Material, VBase4
from panda3d.core import AmbientLight, PointLight, TextureStage, Point3, Fog, AntialiasAttrib

class World(DirectObject):
    def __init__(self):
        base.setBackgroundColor(0, 0, 0)
        base.disableMouse()

        self.loadSky()
        
        self.grass= loader.loadModel('models/environment')
        self.grass.setPos(0,0,-10)
        self.grass.setScale(0.07)
        self.grass.reparentTo(render)

        
        alight= AmbientLight('alight')
        alight.setColor(VBase4(0.2, 0.2, 0.2, 1))
        self.alight = render.attachNewNode(alight)
        render.setLight(self.alight)
        
        plight= PointLight('plight')
        plight.setColor(VBase4(1,1,1, 1))
        self.plight= self.moon.attachNewNode(plight)
        render.setLight(self.plight)
        
        self.sphere = loader.loadModel("sphere")
        self.sphere.setShaderAuto()
        self.sphere.reparentTo(render)
        self.sphere.setScale(0.1)
        self.sphere.setPos(0,-25,-9)
        spin_sphere= self.sphere.hprInterval(6, Point3(360,0,0))
        spin_sphere.loop()
        dest= Point3(self.sphere.getX(), self.sphere.getY()+5, self.sphere.getZ())
        walk_sphere = LerpPosInterval(
                            self.sphere, 
                            duration=5, 
                            pos= dest,
                            blendType= 'easeIn',
                            name= 'walk_sphere')
        walk_sphere.start()
        
        
        myFog = Fog("Fog Name")
        myFog.setColor(0.3,0.3,0.3)
        myFog.setExpDensity(0.01)
        render.setFog(myFog)
    
        
        camera.setPos(6, -45, -10)
        camera.setPosHprScale(-15.00, -20.00, -9.00, 262.87, 10.30, 0.00, 1.00, 1.00, 1.00)
        render.ls()
        render.analyze()

    def loadSky(self):
        self.sky = loader.loadModel("solar_sky_sphere")

        self.sky_tex = loader.loadTexture("stars_1k_tex.jpg")
        self.sky.setTexture(self.sky_tex, 1)
        self.sky.reparentTo(render)
        self.sky.setScale(80)

        self.moon= loader.loadModel("planet_sphere")
        self.moon_tex= loader.loadTexture("moon_1k_tex.jpg")
        ts = TextureStage('ts')
        ts.setMode(TextureStage.MAdd)
        self.moon.setTexture(ts, self.moon_tex, 1)
        self.moon.setPos(50.00, -10.00, 10.00)
        self.moon.setScale(6)
        self.moon.reparentTo(render)
        
        


w = World()

run()

The result of my render.analyze with everything on:

95 total nodes (including 0 instances); 0 LODNodes.
5 transforms; 4% of nodes have some render attribute.
82 Geoms, with 82 GeomVertexDatas and 4 GeomVertexFormats, appear on 81 GeomNodes.
2369 vertices, 2369 normals, 0 colors, 2369 texture coordinates.
GeomVertexData arrays occupy 76K memory.
GeomPrimitive arrays occupy 15K memory.
108 GeomVertexArrayDatas are redundant, wasting 1K.
64 GeomPrimitive arrays are redundant, wasting 5K.
3542 triangles:
1910 of these are on 167 tristrips (11.4371 average tris per strip).
1632 of these are independent triangles.
15 textures, estimated minimum 5728K texture memory required.

Well 95 nodes and 82 Geoms sure sounds a lot for that simple scene. Maybe some of your models (grass) has many pieces which werent joined in the modeller.

The grass is the same model as the Hello World from the manual:
http://www.panda3d.org/manual/index.php/Loading_and_Animating_the_Panda_Model

The nodes referred in the render.analyze() are panda nodes right? What are the geoms?

basically, each model you load with loadModel can have one or more geoms (geomNodes).
If you have a big level map its a good idea to not have it all as a single geom as panda will have to render it all even if a small part of it is visible.

You have around 90 nodes and 80 geoms, which is too much for such a simple scene. Around 300 geoms is the limit on most graphics cards, more than that will slow the framerate.

EDIT: I replaced the models and now I have 13 nodes and even less geoms. I never knew the environment model had 70 geoms. What the…

Thanks for your replies. I found the problem, 3ds max was to blame. I figured since I have 2 gigs of RAM and the task manager said that 3ds wasn’t using any processing cycles while on the background it wasn’t affecting my fps. But in the end it was.

My guess is that 3ds max reserves some video memory for himself and once I loaded some more textures my video memory ran out and it started swaping with the ram (I have one of those old laptop videocards that use some RAM as video memory). I think that is why I was getting 60 fps with only 2 models but once I loaded one more my fps went to 20.

Thanks again for your help :smiley:

Its still weird that environment.egg has 70 geoms…

Hi Anon,

I think I’ve entered into a similar problem, having to much geoms. ( about 500 see [low FPS: pstats reports excessive Collision:ctrav:pass1 ??) )

I’ve flattened strong the whole stuff.

What are the ways to slice down geoms, or any tricky turn around to cope with this issue?

the 300 limit is for Geoms, not nodes, such as a CollisionNode. If you have your collision node split into smaller parts, thats actually a performance optimization. Many people use the Octree script to do that.
Unless you use your visible geometry for collisions, which is a bad idea most of the time.

You could to this if you had 500 geoms:

mymodel.clearModelNodes()
mymodel.flattenStrong()

What was meant by “larger chunks” is, like i quoted,

When your camera can’t see a geom, it doesnt render it, its called “culling”. If you just flatten your whole level to 1 geom, it means everything will be rendered (sent to the GPU), even if you see only a small part of it. So if you do just that, you will get rid of the 300 geom limit of GPUs, but you will possibly reach the other limit on how much your GPU can render, so you should find a balance between the two. Group your nodes/models into groups depending on their position in the world and flatten those groups together instead. In panda terms, make an empty parent node, reparent some nodes to it and flatten the parent.
Or just do that in your 3d modeller instead…