Hey All,
I’m a newcomer to panda3d, but I’m loving it so far. I’m learning my way through it by slowly recreating (and piecing together tutorials/code snippets) into one of my all-time favorite games, Minecraft. So far I can procedurally generate a giant chunk of blocks. My goal is to be able to render this fairly fast, and also get a decent frame-rate while tumbling around it, assuming I’ll eventually have many more chunks in the scene. I heard that a great way to improve frame rate performance is to reduce the # of meshes in the scene by using the Rigid Body Combiner’s collect() function. This definitely helps in-game performance, but that call seems extremely costly, and it’s taking upwards of 2 minutes to collect all the meshes. Is there anything I can change about my code to make collect run faster? Or, maybe some other method to achieve similar results?
Below is my code for reference:
from panda3d.core import Geom, GeomTriangles, GeomVertexWriter
from panda3d.core import GeomVertexFormat, GeomVertexData
from panda3d.core import Texture, GeomNode
from direct.showbase.ShowBase import ShowBase
from panda3d.core import RigidBodyCombiner, NodePath
from panda3d.core import Texture
import sys, copy
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.setFrameRateMeter(True)
self.accept( "escape" , sys.exit)
c = Chunk()
for x in range(Chunk.MAX_CHUNK_X):
for y in range(Chunk.MAX_CHUNK_Y):
for z in range(Chunk.MAX_CHUNK_Z):
c.setElement(x, y, z, 1)
c.generate()
def makeSquare(x1,y1,z1, x2,y2,z2):
format=GeomVertexFormat.getV3t2()
vdata=GeomVertexData('square', format, Geom.UHStatic)
vertex=GeomVertexWriter(vdata, 'vertex')
texcoord=GeomVertexWriter(vdata, 'texcoord')
if x1!=x2:
vertex.addData3f(x1, y1, z1)
vertex.addData3f(x2, y1, z1)
vertex.addData3f(x2, y2, z2)
vertex.addData3f(x1, y2, z2)
else:
vertex.addData3f(x1, y1, z1)
vertex.addData3f(x2, y2, z1)
vertex.addData3f(x2, y2, z2)
vertex.addData3f(x1, y1, z2)
texcoord.addData2f(0.0, 1.0)
texcoord.addData2f(0.0, 0.0)
texcoord.addData2f(1.0, 0.0)
texcoord.addData2f(1.0, 1.0)
tri1=GeomTriangles(Geom.UHStatic)
tri2=GeomTriangles(Geom.UHStatic)
tri1.addVertex(0)
tri1.addVertex(1)
tri1.addVertex(3)
tri2.addConsecutiveVertices(1,3)
tri1.closePrimitive()
tri2.closePrimitive()
square=Geom(vdata)
square.addPrimitive(tri1)
square.addPrimitive(tri2)
return square
class Chunk:
MAX_CHUNK_X = 16
MAX_CHUNK_Y = 16
MAX_CHUNK_Z = 256
INITIAL_CHUNK_DATA = bytearray(MAX_CHUNK_X*MAX_CHUNK_Y*MAX_CHUNK_Z)
def __init__(self):
self.data = copy.copy(Chunk.INITIAL_CHUNK_DATA)
self.rbc = RigidBodyCombiner('rbc')
self.rbcnp = NodePath(self.rbc)
self.rbcnp.reparentTo(render)
def setElement(self, x, y, z, element):
self.data[x + y*Chunk.MAX_CHUNK_X + z*Chunk.MAX_CHUNK_X*Chunk.MAX_CHUNK_Y] = element
def getElement(self, x, y, z):
if x < 0 or y < 0 or z < 0 \
or x >= Chunk.MAX_CHUNK_X or y >= Chunk.MAX_CHUNK_Y or z >= Chunk.MAX_CHUNK_Z:
return 0 # Dummy air voxel data, change once we
# have cross-chunk access
return self.data[x + y*Chunk.MAX_CHUNK_X + z*Chunk.MAX_CHUNK_X*Chunk.MAX_CHUNK_Y]
def generate(self):
self.node = GeomNode('chunk')
self.nodePath = self.rbcnp.attachNewNode(self.node)
for x in range(Chunk.MAX_CHUNK_X):
for y in range(Chunk.MAX_CHUNK_Y):
for z in range(Chunk.MAX_CHUNK_Z):
squares = []
if self.getElement(x-1, y, z) == 0:
squares.append(makeSquare(x,y+1,z, x,y,z+1))
if self.getElement(x, y-1, z) == 0:
squares.append(makeSquare(x,y,z, x+1,y,z+1))
if self.getElement(x, y, z-1) == 0:
squares.append(makeSquare(x+1,y,z, x,y+1,z))
if self.getElement(x+1, y, z) == 0:
squares.append(makeSquare(x+1,y,z, x+1,y+1,z+1))
if self.getElement(x, y+1, z) == 0:
squares.append(makeSquare(x+1,y+1,z, x,y+1,z+1))
if self.getElement(x, y, z+1) == 0:
squares.append(makeSquare(x,y,z+1, x+1,y+1,z+1))
if len(squares) > 0:
blockNode = GeomNode('block')
for sq in squares:
blockNode.addGeom(sq)
blockNodePath = self.nodePath.attachNewNode(blockNode)
#tex = loader.loadTexture('assets/grass.png')
#blockNodePath.setTexture(tex, 1)
self.rbc.collect()
app = MyApp()
app.run()