Efficient geometry

hello,

I’ve been interested in Panda3D for a few years now and finally got the motivation to dive in.
I know this isn’t what Panda is intended for, but I’m trying to do some low level geometry operations. The code pasted below:

  • defines a set of planes
  • finds the lines of intersections of these planes
  • finds the points of intersections of the generated lines with the original planes
  • draws a box from these points

There are a few things I want to improve:

  • How do I draw finite and infinite planes in 3D space? Currently I’m forming the box faces by drawing triangles from each vertex, which is awkward. Is there a 3D equivalent class to the 2D CardMaker?
  • How do I set the camera view position? I tried setPos(-100, -100, -100) with lookAt(0, 0, 0) but I still start within the box which only has dimension 10.

Here is the code:

import math
import direct.directbase.DirectStart
from pandac.PandaModules import *


def boxPlanes(minX=-2, minY=-1, maxX=2, maxY=1, minZ=-1, maxZ=1):
    """
    Create the planes to form a 3D box
    """
    point1 = Point3(minX, minY, minZ)
    point2 = Point3(minX, minY, maxZ)
    point3 = Point3(minX, maxY, minZ)
    point4 = Point3(minX, maxY, maxZ)
    point5 = Point3(maxX, minY, minZ)
    point6 = Point3(maxX, minY, maxZ)
    point7 = Point3(maxX, maxY, minZ)
    point8 = Point3(maxX, maxY, maxZ)
    
    plane1 = Plane(point1, point2, point5)
    plane2 = Plane(point3, point4, point7)
    plane3 = Plane(point1, point3, point5)
    plane4 = Plane(point5, point7, point6)
    plane5 = Plane(point2, point4, point6)
    plane6 = Plane(point1, point2, point3)
    
    return [plane1, plane2, plane3, plane4, plane5, plane6]


def planeLines(planes):
    """ 
    Extract the line intersections from the planes
    """
    lines = []
    for i, p1 in enumerate(planes):
        for j, p2 in enumerate(planes):
            c = Point3()
            X = Vec3()
            if p1.intersectsPlane(c, X, p2):
                lines.append((X, c))
    return lines
                
    
def drawLines(lines, lineThickness=1, min=-10, max=10):
    """
    Render line vectors
    """ 
    ls = LineSegs()
    ls.setThickness(1)    
    ls.setColor(1.0, 1.0, 1.0, 0.1)
    for X, c in lines:
        ls.moveTo(X*(-10) + c)
        ls.drawTo(X*10 + c)
    NodePath(ls.create()).reparentTo(render)


def planePoints(planes, lines):
    """
    Extract points of intersection between planes
    """
    intersectionPoints = []
    for plane in planes:
        for X, c in lines:
            point = Point3()
            if plane.intersectsLine(point, Point3(X + c), Point3(X*2 + c)):
                if point not in intersectionPoints:
                    intersectionPoints.append(point)                    
    return intersectionPoints
    
    
def drawContainer(planes, points, color=(0.5, 0.5, 0.5, 0.5)):
    """
    Draw the container defined by the points on the plane
    """
    format = GeomVertexFormat.getV3cp()
    vdata = GeomVertexData("box", format, Geom.UHStatic)
    gvwV = GeomVertexWriter(vdata, 'vertex')
    gvwC = GeomVertexWriter(vdata, 'color')
        
    # need to draw points on plane, so group by plane by looking for zero distance points 
    count = 0
    for plane in planes:
        planePoints = [] 
        for point in points:
            if plane.distToPlane(point) == 0:
                # point on plane
                planePoints.append(point)
        for ps in permutations3(planePoints):
            for p in ps:
                gvwV.addData3f(p.getX(), p.getY(), p.getZ())
                gvwC.addData4f(color[0], color[1], color[2], color[3])
                count += 1
    # can only draw triangle primitives, so draw every combination of points to cover surface
    geom = Geom(vdata)
    for i in range(count):
        if i % 3 == 0:
            if i > 0: 
                tris.closePrimitive()
                geom.addPrimitive(tris)
            tris = GeomTriangles(Geom.UHStatic)
        tris.addVertex(i)
                    
    node = GeomNode("box")
    node.addGeom(geom)
    NodePath(node).reparentTo(render)


def permutations3(l):
    """
    Create length 3 permutations of the list for drawing triangles
    """ 
    newL = []
    maxL = len(l)
    for i in range(-maxL, maxL):
        for j in range(i+1, maxL):
            for k in range(j+1, maxL):
                newL.append((l[i], l[j], l[k]))
    return newL


planes = boxPlanes()
lines = planeLines(planes)
drawLines(lines)
points = planePoints(planes, lines)
drawContainer(planes, points)

# shift so looking at origin from y axis - doesn't seem to work??
base.camera.setPos(-100, -100, -100)
base.camera.lookAt(0, 0, 0)

run()

thanks for your time!
Richard

It’s rather difficult to draw an infinite plane and have it look like anything other than a completely white screen. Since it’s infinite, you know–it always completely fills the screen.

A quad, on the other hand, is pretty easy to draw. You can use the CardMaker and rotate it to the right orientation, or you can draw it by hand using two triangles. Both seem about equally easy/difficult to me.

I’m guessing you need to call base.disableMouse(). Otherwise your setPos() operation is overridden by the trackball.

David

hi drwr, thanks for your answers!

Assuming it’s opaque, but I could get some nice effects with transparent planes.
Currently I’m trying to use transparent finite planes and adjusting their coordinates in the view plane so they appear infinite.

ah OK. Do you think a more high level class be useful here? I’ve seen a few related threads to this problem.

I also saw this technique in the examples, but unfortunately I want to use the mouse to view the geometry. Surely there is a way to change the initial view. Or do I need to move my rendering in front of the initial view?

Another question: in my code I play round with intersections of points, lines, and planes. Is there a way to do intersections of 3D objects? Ideally I would want to know whether objects intersect and the geometry of the intersecting region. I’ve had a look at BoundingVolume and the subclasses of CollisionSolid but haven’t worked it out yet.

thanks for your help,
Richard

This should fix you camera positioning problem:

from pandac.PandaModules import Mat4
def setMouseEnabledPos( position, rotation ):
  # set a default camera position
  camera.setPos(position)
  camera.lookAt(render)
  camera.setHpr(camera, rotation)
  cameraMat=Mat4(camera.getMat())
  cameraMat.invertInPlace()
  base.mouseInterfaceNode.setMat(cameraMat)

More high level than the CardMaker? Well, you can always load a card model from an egg file.

The BoundingVolume classes will tell you if two shapes might be intersecting, but can’t reliably tell you that they are. The CollisionSolid classes can definitively tell you whether two shapes are intersecting, but will report only a single point of intersection, not the geometry of the intersecting region. You’ll have to implement your own intersection algorithms, or find an existing library that does it for you, in order to get this information.

David