[SOLVED] Random crash + no error mesage

Firstly hi panda’s!
I’m having some trouble in my program, I’m attempting to procedurally create a map full of cubes but it is seemingly randomly crashing while I’m in one of my loops. I’m pretty sure it’s in this loops that the crash occurs because when I leave it out the other part of the code which creates the top of the cube surfaces works, but this loop which creates the sides of the cubes fails.

I added a print function which prints the amount of vertices in the GeomVertexData, but every time it crashes this value is different therefore the random part of the crash, and I recieve no error when running it, panda just closes.

here is some of the code, the for loop where the crash I reckon is happening in.

                Orientation = [[[-0.5, -0.5], [0.5, -0.5]], [[-0.5, 0.5], [-0.5, -0.5]], [[0.5, 0.5], [-0.5, 0.5]], [[0.5, -0.5], [0.5, 0.5]]]
                i = -1
                for Cube in CubeList:
                    i = i + 1

#The variable Cube is simply the height of a cube, cubelist is a list of the 4 neighbouring cubes heights


                    if Cube <= Height:

#Only make it's side go downwards and not up

                        Diff = Height - Cube
                        for step in range(0, Diff):
#Add the vertices with their colour
                            Vertex.addData3f(x + Orientation[i][0][0], Height - step, z + Orientation[i][0][1]); Colour.addData4f(1, 0, 0, 1)
                            Colour.addData4f(0, 1, 1, 1)

                            Vertex.addData3f(x + Orientation[i][1][0], Height - step, z + Orientation[i][1][1])
                            Colour.addData4f(0, 1, 1, 1)
                            
                            Vertex.addData3f(x + Orientation[i][1][0], Height - step - 1, z + Orientation[i][1][1])
                            Colour.addData4f(0, 1, 1, 1)
                            
                            Vertex.addData3f(x + Orientation[i][0][0], Height - step - 1, z + Orientation[i][0][1])
                            Colour.addData4f(0, 1, 1, 1)
                            
                            VLenght = int(VertexData.getNumRows())
                            print(VLenght)
                            Triangles.addVertices(VLenght - 2, VLenght - 3, VLenght - 4)
                            Triangles.closePrimitive()
                            Triangles.addVertices(VLenght - 1, VLenght - 2, VLenght - 4)
                            Triangles.closePrimitive()

I’m new to panda3d, moved over from Python-Ogre due to Panda’s better documentation. So If I’m doing something horribly wrong performance or general not recommended things wise, please say. The code is a port from the python code I used in Ogre3D with minimal changes, it worked in ogre the.

It crashes around 57596, 60670, 35582 vertices printed by print(VertexData.getNumRows())
The loop is entered 30, 30, 18, 26 times, just as random as the previous tests.

I think I added all the information I could gather now, if more info is needed please ask!

So is there a way to make Panda more verbose and give me more errors, warnings etc. and is there any limitation panda can handle when creating procedural objects?

As always, thanks for any help in advance.

Welcome!

Yes, look here.

Thanks, changed the log level through warning to spam, there doesn’t seem to be anything different in the log files when running panda3d normally (removed that section of the loop) and when it crashes. It doesn’t produce a message for when it is crashing :confused:

Got allot of spam from things that didn’t know what spam was though :stuck_out_tongue:

Hmm, I don’t see anything obviously wrong in the snippet. Can you post a small but complete example that reproduces the crash, so I can see it happen too?

Thanks!
David

Read edit below
Seeing as it kept crashing after a relatively large number of vertices has been added, I tried reducing the number of cubes it should create (down from 200200 to 5050) and I got:

I guess the root of the cause is that panda doesn’t like allot of messed up data! Still would’ve liked an error though.

So yeah, there’s definitely something wrong with my code, which should be fixable on my own.

to replicate crash:
The following code has a dependency though, noise.snoise2() in the GetHeight function available from PyPi, you can replace it with a formula though if you want (return sinx(x) auta do the trick)

from direct.directnotify.DirectNotify import DirectNotify
from direct.showbase.ShowBase import ShowBase
from panda3d.core import GeomVertexFormat, GeomVertexData, Geom, \
    GeomVertexWriter, GeomTriangles, GeomNode, MultiplexStream, Notify, Filename
import noise

class Terrain:

    def GetHeight(self, x, z):
        Base = noise.snoise2(x / 40.0, z / 40.0, 4, 0.60)
        Height = int(Base * 30)
        return Height

    def BaseGen(self, start=(0, 0), end=(100, 100)):
        'returns a cuboid map representing the raw data used for making a map'
        
        #Prepare the vertex data to be written
        Format = GeomVertexFormat.getV3c4()
        VertexData = GeomVertexData('Base', Format, Geom.UHStatic)
        Vertex = GeomVertexWriter(VertexData, 'vertex')
        Colour = GeomVertexWriter(VertexData, 'color')
        Triangles = GeomTriangles(Geom.UHStatic)
        
        #Loop through
        for x in range(start[0], end[0]):
            for z in range(start[1], end[1]):
                
                #Get the neighbouring cubes and i's own height'
                BackC = self.GetHeight(x, z - 1)
                FrontC = self.GetHeight(x, z + 1)
                LSideC = self.GetHeight(x - 1, z)
                RSideC = self.GetHeight(x + 1, z)
                CubeList = [BackC, LSideC, FrontC, RSideC]
                
                Height = self.GetHeight(x, z)
                
                #create the top surface of the cube
                Vertex.addData3f(x - 0.5, z - 0.5, Height); Colour.addData4f(1, 0, 0, 1)
                Vertex.addData3f(x - 0.5, z + 0.5, Height); Colour.addData4f(0, 1, 0, 1)
                Vertex.addData3f(x + 0.5, z + 0.5, Height); Colour.addData4f(0, 0, 1, 1)
                Vertex.addData3f(x + 0.5, z - 0.5, Height); Colour.addData4f(1, 1, 0, 1)
                #template: Vertex.addData3f(); Colour.addData4f()
                
                #Create the triangles
                VLenght = int(VertexData.getNumRows())
                Triangles.addVertices(VLenght - 2, VLenght - 3, VLenght - 4)
                Triangles.closePrimitive()
                Triangles.addVertices(VLenght - 1, VLenght - 2, VLenght - 4)
                Triangles.closePrimitive()
                #Now we are going to create the sides
                #Orientation of the sides for simpler code
                Orientation = [[[-0.5, -0.5], [0.5, -0.5]], [[-0.5, 0.5], [-0.5, -0.5]], [[0.5, 0.5], [-0.5, 0.5]], [[0.5, -0.5], [0.5, 0.5]]]
                i = -1
                for Cube in CubeList:
                    i = i + 1
                    if Cube <= Height:
                        Diff = Height - Cube
                        for step in range(0, Diff):
                            Vertex.addData3f(x + Orientation[i][0][0], Height - step, z + Orientation[i][0][1]); Colour.addData4f(1, 0, 0, 1)
                            Colour.addData4f(0, 1, 1, 1)

                            Vertex.addData3f(x + Orientation[i][1][0], Height - step, z + Orientation[i][1][1])
                            Colour.addData4f(0, 1, 1, 1)
                            
                            Vertex.addData3f(x + Orientation[i][1][0], Height - step - 1, z + Orientation[i][1][1])
                            Colour.addData4f(0, 1, 1, 1)
                            
                            Vertex.addData3f(x + Orientation[i][0][0], Height - step - 1, z + Orientation[i][0][1])
                            Colour.addData4f(0, 1, 1, 1)
                            
                            VLenght = VertexData.getNumRows()
                            #print(VLenght)
                            Triangles.addVertices(VLenght - 2, VLenght - 3, VLenght - 4)
                            Triangles.closePrimitive()
                            Triangles.addVertices(VLenght - 1, VLenght - 2, VLenght - 4)
                            Triangles.closePrimitive()
                #print(Height)
            #print(x)
        #Finally create the finished scene
        geom = Geom(VertexData)
        geom.addPrimitive(Triangles)
        node = GeomNode('gnode')
        node.addGeom(geom)
        print(start, end)
        return node

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        node = Terrain().BaseGen()
        nodePath = self.render.attachNewNode(node)

app = MyApp()
app.run()

commenting the entire

for Cube in CubeList

loop should remove the problem.
(Read remove, not solve)

[edit]
Ok, semi fixed now, just out of view in my IDE but clearly visible here is that there was one too many

Colour.addData4f(0, 1, 1, 1)

in the loop. It now creates a mesh! And as far as I can see it doesn’t crash anymore!
Thanks for making me post the code and see my fault, I wouldn’t have seen it when looking in my IDE :smiley:

It’s… It’s beautiful! :’-)

Well, I found the fundamental problem. It’s these lines:

                        for step in range(0, Diff):
                            Vertex.addData3f(x + Orientation[i][0][0], Height - step, z + Orientation[i][0][1]); Colour.addData4f(1, 0, 0, 1)
                            Colour.addData4f(0, 1, 1, 1)

Note that you are calling Colour.addData4f() twice here, presumably due to a cut/paste error. But this means you end up calling Colour.addData4f() five times for each four calls to Vertex.addData3f(), and the discrepancy eventually results in the array getting out of sync and reallocating itself in strange ways, leading to a crash.

It shouldn’t cause a crash when you do this; I’ll see if I can put in a more robust detection.

David

Also note that if you pre-reserve the size of the vertex buffer with an early call to VertexData.setNumRows(), assuming you know how many rows you will eventually add (and you do know that, in this case), then you are likely to gain a substantial performance boost. :slight_smile:

David

Hmm… I know how many top ‘blocks’ I’ll be adding (eg. 2002004 to get the num of vertices, but I don’t know before hand how many of the side vertices will be added.

For example if I add 2 cubes, one with a height of 4 and another of 1, I know that, I know from the 2 cubes part that I’ll have 8 vertices. But then with the height differences I have beforehand go through every cube and look for cubes around it that is lower than itself, get the difference in height and multiply that by 4.

If I have this correct I loop through it all to get the number of vertices I want to add and then loop through it all again to actually add the vertices. This seems very inefficient.

[edit] or actually, if you mean add the positions of the vertices I want to a list, then get the lenght of that list, setnumrow and then loop through the list to add the vertices.

Will do a quick benchmark later on and see if it is faster that way.

Here’s the results:

The vanilla version: filling the rows as it get’s the data.
((0, 0), (200, 200))
(‘Creating vert positions’, 2.557218074798584)
(‘Number of vertices’, 255172)
The version creating the vertex data first, adding them to a list as it get’s the data. then using the lenght of the list to set setnumrows()
((0, 0), (200, 200))
(‘Creating vert positions’, 10.624695062637329)
(‘Adding the data (n/a?)’, 7.272252082824707)
(‘Number of vertices’, 255172)
Same as above except it doesn’t do setnumrows().
((0, 0), (200, 200))
(‘Creating vert positions’, 10.570744037628174)
(‘Adding the data (n/a?)’, 7.8965179920196533)
(‘Number of vertices’, 255172)
Added more test for the timings to see where it spends most of the time with the above version:
((0, 0), (200, 200))
(‘Creating vert positions’, 11.727519035339355)
(‘Adding the data (n/a?)’, 8.039654016494751)
(‘for the vertices’, 2.8171689510345459)
(‘for the colours’, 2.6951239109039307)
(‘for the triangles’, 2.5177340507507324)
(‘Number of vertices’, 255172

So yeah, the added overhead of using lists is actually very high.
The overhead of looping over the lists to add the data definitely way more than the benefit of using setnumrows().

Hey performance tuning is actually fun :smiley:

Hmm, how about that! Very nice job with the analysis. :slight_smile:

David