コード例 #1
0
def makeQuad(renderVP, collisionVP, bl=None, tr=None, br=None, tl=None):
    """Return a tuple of EggPolygons (renderQuad,collisionQuad): renderable and
  collision geometry for a 4-vertex polygon.

  Keyword arguments:
  renderVP -- EggVertexPool to which vertices will be added for the
        renderable quad
  collisionVP -- EggVertexPool to which vertices will be added for the
           collidable quad
  bl -- bottom-left vertex of quad (Point3D). Default (-10,-10,0)
  tr -- top-right vertex of quad (Point3D). Default (10,10,0)
  br -- bottom-right vertex of quad (Point3D)
  tl -- top-left vertex of quad (Point3D)
  If either of br or tl is None then sensible defaults will be computed
  according to the values of bl and tr.

  """
    if bl is None: bl = P.Point3D(-10, -10, 0)
    if tr is None: tr = P.Point3D(10, 10, 0)
    if br is None:
        l = tr.getX() - bl.getX()
        br = bl + P.Vec3D(l, 0, 0)
    if tl is None:
        w = tr.getY() - bl.getY()
        tl = bl + P.Vec3D(0, w, 0)
    renderQuad = P.EggPolygon()
    collisionQuad = P.EggPolygon()
    for corner in [bl, br, tr, tl]:
        vertex = P.EggVertex()
        vertex.setPos(corner)
        collisionVertex = P.EggVertex()
        collisionVertex.setPos(corner)
        renderQuad.addVertex(renderVP.addVertex(vertex))
        collisionQuad.addVertex(collisionVP.addVertex(collisionVertex))

    # A bug in Panda3D means that auto-triangulation of concave polygons
    # fails for some combinations of vertices (the polygon is not properly
    # transformed into triangles) creating gaps in a model where polygons are
    # missing. We can check for this failure by calling
    # EggPolygon.triangulateInto() and checking its return value. If False is
    # returned we reverse the vertex order of the polygon (so it now faces
    # downward instead of up) and reverse the backface flag so the downside
    # (which is now facing up) is rendered instead of the upside (which is now
    # facing down). The result looks more or less the same as if the polygon
    # had triangulated correctly in the first place (except the shading will be
    # different). Thanks to ynjh_jo for this workaround.
    egn = P.EggGroupNode(
    )  # triangulateInto() stores the resulting polygons in
    # an EggGroupNode, which we discard, we only care
    # about the True or False return value
    if not renderQuad.triangulateInto(egn, 0):
        # Triangulation failed, fix it.
        renderQuad.reverseVertexOrdering()
        renderQuad.setBfaceFlag(1)
        collisionQuad.reverseVertexOrdering()
        collisionQuad.setBfaceFlag(1)

    renderQuad.recomputePolygonNormal()  # Use faceted not smoothed lighting
    return renderQuad, collisionQuad
コード例 #2
0
def makeTerrainFromHeightMap(heightmap):
    """Return a tuple of NodePaths (renderNodePath,collisionNodePath) to
  renderable and collision geometry for a chainable terrain model built from
  the given heightmap.

  collisionNodePath is parented to renderNodePath. renderNodePath is not
  parented to anything by this function.

  Every 3x3 group of quads in the collision geometry is collected under a
  PandaNode for efficient collision detection. This could be improved on by
  building both the renderable and collision geometry as octrees.

  Keyword arguments:
  heightmap -- a 2D list of height values.

  """
    size = len(heightmap)
    renderNodePath = P.NodePath('')
    renderEggData = P.EggData()
    renderVertexPool = P.EggVertexPool('')
    collisionNodePath = renderNodePath.attachNewNode('')
    # Supply the EggGroup & EggVertexPool for the first node.
    collisionVertexPool = P.EggVertexPool('')
    collisionEggGroup = P.EggGroup('')
    collisionEggGroup.addObjectType('barrier')
    # We group every (numQuadGrid x numQuadGrid) quads under 1 collision node.
    numQuadGrid = 3
    # The modulo of (size-2)/numQuadGrid marks when the quads must be grouped
    # into 1 geom.
    edgeMod = (size - 2) % numQuadGrid
    for i in range(0, len(heightmap) - 1, numQuadGrid):
        # Limit nextIrange to avoid it from jump over the edge.
        nextIrange = min(numQuadGrid, len(heightmap) - 1 - i)
        for j in range(0, len(heightmap) - 1):
            for nextI in range(0, nextIrange):
                bl = P.Point3D(i + nextI, j, heightmap[i + nextI][j])
                tr = P.Point3D(i + nextI + 1, j + 1,
                               heightmap[i + nextI + 1][j + 1])
                br = P.Point3D(i + nextI + 1, j, heightmap[i + nextI + 1][j])
                tl = P.Point3D(i + nextI, j + 1, heightmap[i + nextI][j + 1])
                # Construct polygons (quads) with makeQuads.
                renderQuad, collisionQuad = makeQuad(renderVertexPool,
                                                     collisionVertexPool, bl,
                                                     tr, br, tl)
                renderEggData.addChild(renderQuad)
                collisionEggGroup.addChild(collisionQuad)
                if j % numQuadGrid == edgeMod and nextI == nextIrange - 1:
                    # Group the previous (numQuadGrid x numQuadGrid) quads under
                    # collision node.
                    collisionEggData = P.EggData()
                    collisionEggData.addChild(collisionEggGroup)
                    pandaNode = P.loadEggData(collisionEggData)
                    nodePath = collisionNodePath.attachNewNode(
                        pandaNode.getChild(0).getChild(0))
                    # Uncomment the next line to see the collision geom.
                    #nodePath.show()
                    # Supply the EggGroup & EggVertexPool for the next node.
                    collisionEggGroup = P.EggGroup('')
                    collisionEggGroup.addObjectType('barrier')
                    collisionVertexPool = P.EggVertexPool('')
    pandaNode = P.loadEggData(renderEggData)
    renderNodePath.attachNewNode(pandaNode)
    return renderNodePath, collisionNodePath