Need advice on Panda3d's performance (Answered)

Hello, I,m not asking for a solution to a problem this time, but rather advice or any tricks to speed up panda3d, my game barely runs above 20fps using the toon shader and I was wondering if I can get a bit of frames of speed up (maybe a steady 24fps).

I had read in the threads of this forum, and most recommend using less nodes, using the command “flattenStrong” and the like, I was wondering if the number of triangles can effect speed, what about many static nodes that do nothing?

I use over 100 nodes that are hidden tiles (real meshes) in a scene because of locational purposes, then I heard about “transforms” which I know nothing about, anyway I would be grateful for any advice or tips, Thank you.

I suggest calling render.analyze() which gives some statistics about the scene. This can begin to give some insight into the complexity of your scene. Also, using PStats will let us know which parts of rendering your scene are taking longer.

The number of triangles is not as important as the number of nodes. If you use a lot of separate tile nodes, this can be a problem, but mostly if they are visible. If they are generally invisible, then structuring your scene graph into a quad tree structure might help, or even just grouping together nearby tiles under a common parent node.

I do have render.analtyze() written into my debug code, but I was only using it to check for a consistent number of nodes on my cleanup code, should I post what is said on it?

Sadly the locational tiles are visible but hidden behind or under the level geometry itself so they cannot be seen (thus hidden), maybe this is the issue? I actually thought about this yesterday, if I can somehow obtain all the locations into string list then delete the nodes from render immediately at the script’s startup.

But is that possible? is it possible to remove portions the node loaded though loader? what about stash()? would stashing them effect performance? maybe I can stash() them to increase speed? Anyway thank you for your insight rdb, I will look into PStats.

Something like that should work indeed. (Although I might suggest a list of Vec3/Point3, unless you specifically want strings). Just fetch all of your location-nodes, call “getPos” on each (perhaps passing in a reference NodePath, if called for), put the result into a list, and then call “removeNode” on each to get rid of it.

Since you say that they’re laid out in a grid, I might suggest that you keep your positions in a list of lists–that is, a 2D grid.

oh, okay. the reason I want to stick with string is because the name of the node is needed for certain functions in my code, I was planning using something like this
“nodename:Vec3(100,200,300)” and using code like this below.

find = [loclist.index(i) for i if “nodename” in i]
lval = loclist[int(find[0])].split(":")
node.setPos(eval(lval[1])

Anyway I wanted to say thanks Thaumaturge, I going ask weather I should just detachNode() or remove it, thanks you saved me a post.

Perhaps a dictionary would be slightly simpler, then–something like this:

#In the code in which you initially find your node-locations--that is,
# where you currently, presumably, do something like the following:
# locationList.append(nodePath.getName() + str(nodePath.getPos()))
# --you might instead do this:
self.locationList[nodePath.getName()] = nodePath.getPos()

#Later, when you want to access a location:
location = self.locationList[nodename]
node.setPos(location)
1 Like

I know nothing about dictionaries, but what you posted seems really handy if I,m understanding it correctly, so where in a list where you place the item index number, in a dictionary you can insert name and call that dictionary item by that name?

EDIT: so I tired your dictionary idea, and from the short test it seems to work, but I will post back when I wake up after I reedited the level script and blender3d file, to test it fully to see if a speed up occurs.

Stashing will improve performance, because stashed nodes will not be considered by Panda’s cull mechanism. It will be as though they aren’t even in the scene graph.

Though, I’d be interested at looking at the output of render.analyze() and render.ls() to see if anything jumps out about the way the scene is organised.

More or less–although it’s more general than that, I believe. In short, and speaking roughly:

Where a list might be said to associate a “value” (which could be just about anything) with an index, a “dictionary” associates a “value” with a “key”.

In this case, we want to associate locations (our “values”) with names (our “keys”), so our keys are strings. However, a dictionary can use just about anything as a key, I believe. If, for example, your locations were instead associated with in-game enemies, you could use those enemies as your “keys”.

okay, let me load a previous version of my game and print it out on the python console, and I’ll get back to you, I would do it on the current version, but it is being worked on right and if I load it now, it would crash.

EDIT: here rdb, I included the render.ls() command into my “monitor” function but it seemed to have done nothing, but here is what the analyze() outputted.

178 total nodes (including 0 instances); 0 LODNodes.
116 transforms; 8% of nodes have some render attribute.
119 Geoms, with 110 GeomVertexDatas and 3 GeomVertexFormats, appear on 110 GeomNodes.
33791 vertices, 33791 normals, 0 colors, 33411 texture coordinates.
GeomVertexData arrays occupy 1254K memory.
GeomPrimitive arrays occupy 96K memory.
182 GeomVertexArrayDatas are redundant, wasting 122K.
91 GeomPrimitive arrays are redundant, wasting 10K.
19441 triangles:
1200 of these are on 599 tristrips (2.00334 average tris per strip).
18241 of these are independent triangles.
9 textures, estimated minimum 37120K texture memory required.

I kind of figured with the tests I made on your idea.

Fair enough! As long as you know; dictionaries and lists can be useful tools, I find! :slight_smile:

1 Like

yes, I have learned something new, that will help in the future, much thanks, I will try your idea fully after I give rdb the information from the analyze and ls() commands, I will post back in while as I have to rework a lot of assets for the changes.

EDIT: okay, I just ran my first test with your trick Thaumaturge and this what it gave me:

89 total nodes (including 0 instances); 0 LODNodes.
27 transforms; 16% of nodes have some render attribute.
30 Geoms, with 21 GeomVertexDatas and 3 GeomVertexFormats, appear on 21 GeomNodes.
33435 vertices, 33435 normals, 0 colors, 33411 texture coordinates.
GeomVertexData arrays occupy 1246K memory.
GeomPrimitive arrays occupy 95K memory.
6 GeomVertexArrayDatas are redundant, wasting 122K.
3 GeomPrimitive arrays are redundant, wasting 10K.
19263 triangles:
1022 of these are on 510 tristrips (2.00392 average tris per strip).
18241 of these are independent triangles.
9 textures, estimated minimum 37120K texture memory required.

Not too bad, I did gain a 1.5 to 2 fps increase, thanks Thaumaturge (and you too rdb), is there anymore? I wanted another 2 fps increase to get to a steady 24fps.

1 Like

I may be mistaken, but that’s surprisingly light, given the frame-rate that you’re reporting. o_0

I really do recommend, as rdb has done, that you run PStats and see just what might be impacting your performance so.

In addition to that, what are the specs of the machine on which you’re running this?

Well it can also be the hardware I use, so I understand why it would it dip so low, I,m using a macbook air using only “Intel HD Graphics 4000 1536 MB” and 4gb of ram running at 1.7Ghz, so maybe that is the best my machine can do?

I also heard it performs better when compiled into a runtime so end users might not see this, I,m going to look into PStats now, thanks for the heads up.

EDIT: I just took a quick look at PStats and it requires networking, something I have trouble with, like if I where to include “PStatClient.connect()” into my debug code what will it do? does it send a summery of what is going to a server? can’t it just do this locally like the render.analyze()?

EDIT2: so I went ahead and inputted “PStatClient.connect()” into my code, and at first I got a error that it is not defined so I did some guesswork by importing a “PStatClient” module from the panda3d.core and when I loaded it again it did nothing.

Sort of, but perhaps not quite as you’re imagining. In short, it networks within your machine, connecting a server (running on your machine) to your application (also running on your machine).

The process looks something like this, I believe:

In your “config.prc” file, look for a line that reads “want-pstats #f”, and change “#f” to “#t”; if the line isn’t there, just add it with “#t”. (Alternatively, in your program itself use the “loadPrcFileData” function, passing in “want-pstats #t”.)

Then, open a terminal and run the command “pstats”. If the command doesn’t work just like that, search for it on you computer and try to run it from there. You should see a little window pop up with text along the lines of “Listening on port 5185”. (I don’t know whether the number varies.)

Finally, run your program. You should now see an additional window appear–the PStats window! :slight_smile:

If it doesn’t work, check that you don’t have a firewall blocking the port that PStats mentions in the window that appears after running the “pstats” command.

I tried your idea, and still nothing, I read around the forums and heard that pip install of panda3d lacks pstats, but I don’t know for sure. I,m having trouble even finding my panda3d installation folder right now.

I think that it’s currently included in the Linux version, at least–I don’t know about the Mac or Windows versions offhand, I’m afraid.

I have a procedure that might help–with the caveat that I’ve tried this under Linux, and am not in a position to speak to whether it’s valid under other operating systems. That said, try this:

In a terminal/command-prompt, type the following:

pip3 show panda3d

(If, when you installed Panda, you used the command “pip” instead of “pip3”, then use that here instead. If in doubt, just try both.)

That should print out a bunch of information–including the installation folder of your copy of Panda3D.

well it worked, and I found the panda3d directory, but I still cannot find pstats, is it in the panda3d_tools folder? because I found the pview but no pstats.

Hmm… I have it in the panda3d_tools folder, it seems. Perhaps it’s not yet included for your operating system? I’m afraid that I don’t know–one of the Panda devs might be able to comment better on that, perhaps.

If it’s not included, and there isn’t a download available (again the devs might know better than I on that), you might be able to build it from the source-code. But before you attempt that, I recommend waiting for others to give feedback!