Trouble with MeshDrawer2d

I’m trying to draw a 2D grid that can have arbitrary squares filled in (eventually this will be drawn to a texture and projected onto terrain, but I’m just trying to get it to draw to the screen now.) The grid is working fine (using the LineSegs class) but I’m not able to get any of the filling squares to display. The code I’m using for this is below:

        filledSquares = [
            (2, 2, Vec4(0, 255, 0, 255)),
            (2, 3, Vec4(0, 0, 255, 255)),
            (2, 4, Vec4(255, 0, 0, 255))
        ]
        
        meshDrawer = MeshDrawer2D()
        meshDrawer.setBudget(1000)
        
        meshDrawer.begin()
        
        for square in filledSquares:
            square = filledSquares[0]
            meshDrawer.rectangle(square[0] * squareSize, square[1] * squareSize, squareSize, squareSize, 0, 0, 0, 0, square[2])
        
        meshDrawer.end()
        
        squareNode = meshDrawer.getRoot()
        
        squareNode.reparentTo(render)

I’ve played around a bit with MeshDrawer2D. I think .rectangle() is slightly broken. If you call squareNode.setTwoSided(True), it should show up. The constructor method just writes the rectangle the wrong way around.

Also, I’m not sure if you’ve noticed but this line

            square = filledSquares[0]

will mean you’ll write the first square 3 times.

And colours tend to be on the scale 0.0 - 1.0 in pand3d, not 0 - 255.

Edit: further playing around revealed .rectangle still doesn’t work in some cases. I had much better behaviour from .rectangleRaw, but it still needed setTwoSided(True) and still breaks sometimes. So yeah, I’d just not use MeshDrawer2D.

The filledSquares[0] was a leftover bit of code from when I tried to remove the loop and just draw the first square to see if that might have been the problem. Looks like I forgot to take it out.

Unfortunately, setting the node to two-sided didn’t change anything. I also tried adding the other options listed in the MeshDrawer maunal page (with the exception of the texture map) but I’m still not getting anything to display. My current code is as follows:

        filledSquares = [
            (2, 2, Vec4(0, 1, 0, 1)),
            (2, 3, Vec4(0, 0, 1, 1)),
            (2, 4, Vec4(1, 0, 0, 1))
        ]
        
        meshDrawer = MeshDrawer2D()
        meshDrawer.setBudget(1000)
        
        meshDrawer.begin()
        
        for square in filledSquares:
            meshDrawer.rectangle(square[0] * squareSize, square[1] * squareSize, squareSize, squareSize, 0, 0, 0, 0, square[2])
        
        meshDrawer.end()
        
        squareNode = meshDrawer.getRoot()
        squareNode.setDepthWrite(False)
        squareNode.setTransparency(True)
        squareNode.setTwoSided(True)
        squareNode.setBin("fixed",0)
        squareNode.setLightOff(True)
        
        squareNode.reparentTo(render)

I’ve got… something kind of working. But if I try to refactor it from this, it stops working altogether. Even doing simple things like passing what to reparent root to and doing it in the init makes it fail.

So basically what I’m saying is I have no idea. If you can get this to work reliably I’d love to know.

class Test():
    def __init__(self):

        filledSquares = [
            (2, 2, Vec4(0, 1, 0, 1)),
            (1, 3, Vec4(0, 0, 1, 1)),
            (2, 4, Vec4(1, 0, 0, 1))
        ]
        
        meshdrawer = MeshDrawer2D()
        meshdrawer.setBudget(1000)
        
        meshdrawer.begin()

        squaresize = 1.0

        uv = Vec2(0,0)
        for x,y,colour in filledSquares:
            meshdrawer.rectangleRaw(x,y,squaresize,squaresize,0,0,0,0,colour)                    

        meshdrawer.end()

        root = meshdrawer.getRoot()
        root.setTwoSided(True)
        #root.setLightOff()
        self.root = root
        
    def getGeometry(self):
        return self.root

...

        test= Test()
        geom = test.getGeometry()
        geom.reparentTo(target nodepath)

Can I see the whole file you’re using for the test?


from direct.showbase.ShowBase import ShowBase
from panda3d.core import *

s = ShowBase()

squaresize = 1.0

class Test():
    def __init__(self,parent):       
        self.meshdrawer = MeshDrawer2D()
        self.meshdrawer.setBudget(1000)

        self.root = self.meshdrawer.getRoot()
        self.root.setTwoSided(True)
        self.root.reparentTo(parent)

    def make(self,squares):
        self.meshdrawer.begin()
        for x,y,colour in squares:
            self.meshdrawer.rectangleRaw(x,y,squaresize,squaresize,0,0,0,0,colour)                   
        self.meshdrawer.end()
        self.root = self.meshdrawer.getRoot()
        self.root.setTwoSided(True)
       

filledSquares = [
    (0, 0, Vec4(0.5, 1, 0.5, 1)),
    (2, 2, Vec4(0, 1, 0, 1)),
    (1, 3, Vec4(0, 0, 1, 1)),
    (2, 4, Vec4(1, 0, 0, 1))
]

test= Test(render)
test.make(filledSquares)

new = [(0, 0, Vec4(0.5, 1, 0.5, 1)),
       (1, 0, Vec4(0, 1, 0, 1)),]
test.make(new)

base.cam.setY(-20)

s.run()

Edit: I managed to find a refactoring that doesn’t randomly stop working. This should work for what you want. You instance Test with the nodepath you want it to appear under, and you call make() on it to give it what to make. Calling make() again will override the geometry with the new one

It seems like the location of the “reparentTo” call makes the difference. When I moved that outside of the class in my file it started to work. I’d prefer not to have to do that, though, since it could cause some serious problems in keeping my code organized as it get bigger. I’ll see if there are any other ways to make it work.

EDIT: Just noticed your edit. It seems a bit better, but it still restricts me annoyingly. I’ll see if there’s any other way of drawing squares that I could use.

I was able to get the squares drawn by ditching MeshDrawer2d and instead fell back on GeomVertexData, GeomPrimitive, etc. A bit more work than I expected, but once I get the code properly refactored I shouldn’t have to touch it again.

I’d say that either the documentation or the actual code for MeshDrawer2d is in need of some serious revision. It could be a very useful tool, but it just doesn’t work in its present condition. Luckily, Panda3D had some other, albeit more complicated tools to fall back on.

The problem is associated with the MeshDrawer2D. Keep the MeshDrawer2D out of any function i.e. in the global scope and it will work fine.