So, I am making a lot of progress on my minecraft terrain clone. But I’m hitting the same performance hit everyone else is. I found a couple of examples of drawing each face, then making cubes out of each face. This gave me a much needed performance boost, but it’s still too slow.
I think what I need to do is leave the primitive open while creating all the cubes, then closing it after I’ve created them all. The problem is, I’m having a difficult time conceptualizing just how to do this. So I’ll just share my working (but horribly horribly slow code):
def myNormalize(self, myVec):
myVec.normalize()
return myVec
def makeCube(self,x,y,z):
# Draw a cube with the default x,y,z plane
# being the front left bottom point
square0=self.makeSquare(x,y,z,x+1,y,z+1)
square1=self.makeSquare(x,y,z,x,y+1,z+1)
square2=self.makeSquare(x+1,y,z,x+1,y+1,z+1)
square3=self.makeSquare(x,y+1,z,x+1,y+1,z+1)
square4=self.makeSquare(x,y,z+1,x+1,y+1,z+1)
square5=self.makeSquare(x,y,z,x+1,y+1,z)
snode=GeomNode('square')
snode.addGeom(square0)
snode.addGeom(square1)
snode.addGeom(square2)
snode.addGeom(square3)
snode.addGeom(square4)
snode.addGeom(square5)
cube=render.attachNewNode(snode)
# By default, geomNodes face only one way.
cube.setTwoSided(True)
# Load up our texture and apply it to the cube...the way the UV mapping works
# All textures should be added to this file
cube.setTexture(loader.loadTexture("assets/models/glow-diffuse.png"))
glowMap = loader.loadTexture("assets/models/glow-lightmap.png")
glowTex = TextureStage('glowTex')
glowTex.setMode(TextureStage.MGlow)
cube.setTexture(glowTex, glowMap)
cube.flattenStrong()
def makeSquare(self, x1,y1,z1, x2,y2,z2):
format=GeomVertexFormat.getV3n3cpt2()
vdata=GeomVertexData('square', format, Geom.UHDynamic)
vertex=GeomVertexWriter(vdata, 'vertex')
normal=GeomVertexWriter(vdata, 'normal')
color=GeomVertexWriter(vdata, 'color')
texcoord=GeomVertexWriter(vdata, 'texcoord')
#make sure we draw the square in the right plane
if x1!=x2:
vertex.addData3f(x1, y1, z1)
vertex.addData3f(x2, y1, z1)
vertex.addData3f(x2, y2, z2)
vertex.addData3f(x1, y2, z2)
normal.addData3f(self.myNormalize(Vec3(2*x1-1, 2*y1-1, 2*z1-1)))
normal.addData3f(self.myNormalize(Vec3(2*x2-1, 2*y1-1, 2*z1-1)))
normal.addData3f(self.myNormalize(Vec3(2*x2-1, 2*y2-1, 2*z2-1)))
normal.addData3f(self.myNormalize(Vec3(2*x1-1, 2*y2-1, 2*z2-1)))
else:
vertex.addData3f(x1, y1, z1)
vertex.addData3f(x2, y2, z1)
vertex.addData3f(x2, y2, z2)
vertex.addData3f(x1, y1, z2)
normal.addData3f(self.myNormalize(Vec3(2*x1-1, 2*y1-1, 2*z1-1)))
normal.addData3f(self.myNormalize(Vec3(2*x2-1, 2*y2-1, 2*z1-1)))
normal.addData3f(self.myNormalize(Vec3(2*x2-1, 2*y2-1, 2*z2-1)))
normal.addData3f(self.myNormalize(Vec3(2*x1-1, 2*y1-1, 2*z2-1)))
texcoord.addData2f(0.0, 1.0)
texcoord.addData2f(0.0, 0.0)
texcoord.addData2f(1.0, 0.0)
texcoord.addData2f(1.0, 1.0)
# quads aren't directly supported by the Geom interface
# So we have to combine two triangles to make a square
tri1=GeomTriangles(Geom.UHDynamic)
tri2=GeomTriangles(Geom.UHDynamic)
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
def buildChunk(self, x1, x2, y1, y2, z1, z2, world,level,chunk):
for x in range (x1, x2):
self.blocks[x] = {}
for y in range (y1, y2):
self.blocks[x][y] = {}
for z in range (z1, z2):
self.blocks[x][y][z] = self.getPerVal(x,y,z,world,level,chunk)
if z == 1:
self.makeCube(x,y,z)
elif self.blocks[x][y][z] != 0:
self.makeCube(x,y,z)
def getPerVal(self,x,y,z,world,level,chunk):
self.gpv = world(level,chunk,x,y,z)
return self.gpv
My interest is in figuring out how to move:
tri1.closePrimitive()
tri2.closePrimitive()
square=Geom(vdata)
square.addPrimitive(tri1)
square.addPrimitive(tri2)
Into the portion after I’ve created my “chunk” so that each chunk is it’s own primitive. Is that possible? How might I go about doing that?
Thanks!
ZM
(the example code from the procedurally create cube was very helpful, as you can probably tell!)
Edit to add:
I think I need to create a dictionary that stores everything in it, then iterate through the dictionary to close it. But that seems to be easier said then implemented.