Polygon-Drawer

With “LineSegs” there is a simple way to draw lines but i found none for Polygons so i made a very simple class for that.

License is BSD.

from panda3d.core import Triangulator,GeomVertexFormat,GeomVertexData,Geom,GeomVertexWriter,GeomTriangles,GeomNode

class Polygon(object):
    def __init__(self,vertices=[]):
        self.vertices=list(tuple(v) for v in vertices)
    def addVertex(self,x,y):
        self.vertices.append((x,y))
    def makeNode(self,pointmap=(lambda x,y: (x,y,0))):
        vt=tuple(self.vertices)
        t=Triangulator()
        fmt=GeomVertexFormat.getV3()
        vdata = GeomVertexData('name', fmt, Geom.UHStatic)
        vertex = GeomVertexWriter(vdata, 'vertex')
        for x,y in vt:
            t.addPolygonVertex(t.addVertex(x,y))
            vertex.addData3f(pointmap(x,y))
        t.triangulate()
        prim = GeomTriangles(Geom.UHStatic)
        for n in xrange(t.getNumTriangles()):
            prim.addVertices(t.getTriangleV0(n),t.getTriangleV1(n),t.getTriangleV2(n))
        prim.closePrimitive()
        geom = Geom(vdata)
        geom.addPrimitive(prim) 
        node = GeomNode('gnode')
        node.addGeom(geom)
        return node

#simple demonstration

poly=Polygon([(0,0),(0,1),(1,1),(1,0)])

import direct.directbase.DirectStart

nodePath = render.attachNewNode(poly.makeNode())

run()

I found this older convenience function that builds a triangulated polygon from the given perimeter. I tried this and it works … thanks! But I have a materials (color/transparency) problem. I’ve done similar things before with Geom() and got material properties and transparency to work, but I was attaching the node to the 3d render layer.

Now I would like to attach the node to the aspect2d layer. And no matter what I’ve tried, the polygon is drawn fully opaque and all white. I can’t seem to get the setMaterial() call to do anything.

I am drawing other stuff on my 2d layer with colors and transparencies, but for those things I’m using CardMaker() and LineSegs()

It’s always possible I’m doing something dumb, but is there something different about Geom() GeomTriangles() GeomVertexWriter() et al. that makes it ignore material properties when attached to aspect2d?

I’ve been bashing my head on this all afternoon … so just to summarize, the geometry is created and drawn where I want it, but setMaterial() seems to be ignored?

(I tweaked the python function because xrange() → range() in python3)

Here’s my code snippet:

    bgMat = Material()
    bgMat.setAmbient((0.1, 0.1, 0.1, 0.2)) # black + alpha
    bgMat.setDiffuse((0.1, 0.1, 0.1, 0.2)) # black + alpha
    poly = Polygon2d([(0.1, 0.0), (0.1, 0.5), (0.3, 0.5), (0.3, 0.2), (0.1, 0.0)])
    poly_node = aspect2d.attachNewNode(poly.makeNode())
    poly_node.setMaterial(bgMat)
    poly_node.setTransparency(TransparencyAttrib.MAlpha)

Any hints? What am I missing?

Thanks in advance!

Curt.

The answer is simple, the aspect2d node uses an orthographic lens, accordingly, the material will not be calculated gravely. In addition, I assume that the lighting is turned off at this node as unnecessary.

1 Like

Ok, thanks for the quick clarification. So if I wanted to draw a simple filled polygon (convex) using this polygon generator and put it into the aspect2d layer, is there a better way to define the color/alpha? Do I need to define the color vector at each vertex when I am doing the GeomVertexWriter loop?

I could go draw a texture and put it on a card and that would probably work too, but I was hoping to build something up procedurally so it could scale better … and I kinda like doing things procedurally in code vs. hand crafting things in a drawing editor.

(This will never be a complex polygon … maybe < 10 vertices total, so I guess I don’t need to worry about the optimal way, just need to find a way … and hopefully something that is fairly clean and direct.)

Thanks!

I think you just need to light up the aspect2d node, use any light source except ambient.

I would like to note the following, the aspect2d node, according to the idea of the developers, is intended for the interface. To implement your node for other purposes, use this template.

from direct.showbase.ShowBase import ShowBase
from panda3d.core import DirectionalLight, Material, NodePath, Camera, OrthographicLens

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        my_aspect2d = NodePath("my_aspect2d")

        scale = 2.0

        my_lens = OrthographicLens()
        my_lens.set_film_size(base.win.get_x_size()/base.win.get_y_size()*scale, scale)
        my_lens.set_near_far(-1000, 1000)

        camera = Camera("camera_orthographic")
        camera.set_lens(my_lens)

        camera_np = NodePath(camera)
        camera_np.reparent_to(my_aspect2d)

        display_region = base.cam.node().get_display_region(0)
        display_region.camera = camera_np

        material = Material("test")
        material.set_base_color((0, 1, 0, 0))

        sphere = base.loader.load_model("sphere.egg")
        sphere.reparent_to(my_aspect2d)
        sphere.set_material(material)

        light = DirectionalLight("sun")
        light_np = NodePath(light)
        light_np.set_hpr(35, -25, 0)
        light_np.reparent_to(my_aspect2d)

        my_aspect2d.set_light(light_np)

app = MyApp()
app.run()

Thanks again for the clarification and help. For my situation, I really am doing a 2d layer on top of 3d so it doesn’t make a huge amount of sense to add a light source to the 2d layer … I only want to define a color for my geometry.

So today I went back and carefully remembered how to use GeomVertexWriter properly to add color values at each vertex, and that works. My shapes are just a few vertices so this works well.

I need to do some API work to parameterize the color choice, but something like this seems to work:


   def makeNode(self,pointmap=(lambda x,y: (x,0,y))):
        c = [1, 0, 0, 0.2]
        vt=tuple(self.vertices)
        t=Triangulator()
        # fmt=GeomVertexFormat.getV3()
        fmt=GeomVertexFormat.getV3c4()
        vdata = GeomVertexData('name', fmt, Geom.UHStatic)
        vertex = GeomVertexWriter(vdata, 'vertex')
        color = GeomVertexWriter(vdata, 'color')
        for x,y in vt:
            t.addPolygonVertex(t.addVertex(x,y))
            vertex.addData3(pointmap(x,y))
            color.addData4(c[0], c[1], c[2], c[3])
        t.triangulate()
        prim = GeomTriangles(Geom.UHStatic)
        for n in range(t.getNumTriangles()):
            prim.addVertices(t.getTriangleV0(n),t.getTriangleV1(n),t.getTriangleV2(n))
        prim.closePrimitive()
        geom = Geom(vdata)
        geom.addPrimitive(prim)
        node = GeomNode('gnode')
        node.addGeom(geom)
        return node

I do need to mark the parent node as transparent to get the transparency to work:

        poly = Polygon2d([(0.1, 0.0), (0.1, 0.5), (0.3, 0.5), (0.3, 0.2), (0.1, 0.0)])
        poly_node = aspect2d.attachNewNode(poly.makeNode())
        poly_node.setTransparency(TransparencyAttrib.MAlpha)

So hopefully all is good, and life makes sense once again. :slight_smile:

Thanks!

Curt.

For what it’s worth, the light wouldn’t affect the 3D scene I believe–it would just cause the materials in the 2D elements to be rendered as expected.

(I’m inclined to just using a light in these cases, myself.)

Still, I’m glad that you found a solution that worked for you! :slight_smile:

1 Like

You applied the color to the vertices, but it has nothing to do with the materials. The material is the result of lighting, so lighting is required to display it.

However, as I wrote above, this will be incorrectly calculated for an orthographic lens, for example, there will be no correct glare.

1 Like

So going back 25 years (or more?) I thought I recalled in raw opengl you could just set a color and start drawing stuff (all that state management stuff that panda3d does automatically for us.) So I just assumed it would be easy to draw a translucent colored triangle on the aspect2d layer. But all the explanations here might make good sense and my recollection of the old days could be getting foggy … as in glFog(GL_FOG_MODE, GL_EXP2) … but it’s nice to have panda3d so we don’t have to remember/write raw opengl … I’m not complaining. :slight_smile: