Im making a minecraft type world in panda3d and noticed that rendering the world is extremely slow because it renders all the blocks in a direction instead of the only visible ones. Im trying to get around this but panda3d's attributes are really confusing. How can i achieve rendering only visible blocks?
Code :
from math import pi, sin, cos
from direct.showbase.ShowBase import ShowBase
from panda3d.core import loadPrcFile
from panda3d.core import DirectionalLight, AmbientLight
from panda3d.core import TransparencyAttrib
from panda3d.core import WindowProperties
from panda3d.core import CollisionTraverser, CollisionNode, CollisionBox, CollisionRay, CollisionHandlerQueue
from direct.gui.OnscreenImage import OnscreenImage
from panda3d.core import Camera
loadPrcFile('settings.prc')
def degToRad(degrees):
return degrees * (pi /180)
class Game(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.blocks = {
"grass" :loader.loadModel('grass-block.glb'),
"stone" :loader.loadModel('stone-block.glb'),
"sand" :loader.loadModel('sand-block.glb'),
"dirt" :loader.loadModel('dirt-block.glb'),
}
self.cameraSwingActivated = True
md = self.win.getPointer(0)
self.last_mouse_X = md.getX()
self.last_mouse_Y = md.getY()
props = WindowProperties()
props.setCursorHidden(True)
props.setMouseMode(WindowProperties.M_relative)
base.win.requestProperties(props)
self.camera.setTwoSided(True)
self.setup_lights()
self.generate_terrain()
self.setup_camera()
self.setup_background()
# self.captureMouse()
self.setupControls()
taskMgr.add(self.update, 'update')
base.setFrameRateMeter(True)
def setupControls(self):
self.key_map = {
'forward' : False,
'back' : False,
'left' : False,
'right' : False,
'jump' : False,
'sprint' : False
}
# self.accept('escape', self.releaseMouse)
self.accept('mouse1', self.captureMouse)
self.accept('w', self.change_val, ['forward', True])
self.accept('w-up', self.change_val, ['forward', False])
self.accept('s', self.change_val, ['back', True])
self.accept('s-up', self.change_val, ['back', False])
self.accept('a', self.change_val, ['left', True])
self.accept('a-up', self.change_val, ['left', False])
self.accept('d', self.change_val, ['right', True])
self.accept('d-up', self.change_val, ['right', False])
self.accept('space', self.change_val, ['jump', True])
self.accept('space-up', self.change_val, ['jump', False])
self.accept('lshift', self.change_val, ['sprint', True])
self.accept('lshift-up', self.change_val, ['sprint', False])
def change_val(self, key, val):
self.key_map[key] = val
def generate_terrain(self):
for z in range(10):
for y in range(20):
for x in range(20):
new_block_node = render.attachNewNode("new_block_placeholder")
new_block_node.setPos((x*2 - 20, y * 2 - 20, -z * 2))
if z == 0 :
self.blocks['grass'].instanceTo(new_block_node)
else:
if z < 4:
self.blocks['dirt'].instanceTo(new_block_node)
else:
self.blocks['stone'].instanceTo(new_block_node)
def setup_lights(self):
main_light = DirectionalLight('main_light')
main_light_node_path = render.attachNewNode(main_light)
main_light_node_path.setHpr((30,-60,0))
render.setLight(main_light_node_path)
ambient_light = AmbientLight('amb_light')
ambient_light.setColor((0.4,0.4,0.4,1))
ambient_light_np = render.attachNewNode(ambient_light)
render.set_light(ambient_light_np)
def setup_camera(self):
self.disable_mouse()
self.camera.setPos((0, 0, 3))
base.camLens.setFov(120)
crosshairs = OnscreenImage(image = 'ladhs.png', pos = (0,0,0), scale = (0.05))
crosshairs.setTransparency(TransparencyAttrib.MAlpha)
def setup_background(self):
skybox = loader.loadModel('skybox/skybox.egg')
skybox.setScale(500)
skybox.setBin('background', 1)
skybox.setDepthWrite(0)
skybox.setLightOff()
skybox.reparentTo(render)
def captureMouse(self):
self.cameraSwingActivated = True
md = self.win.getPointer(0)
self.last_mouse_X = md.getX()
self.last_mouse_Y = md.getY()
properties = WindowProperties()
properties.setCursorHidden(True)
properties.setMouseMode(WindowProperties.M_relative)
# properties.setMousePos(self.win.getProperties().getXSize() // 2, self.win.getProperties().getYSize() // 2) # Set mouse position to center of the screen
self.win.requestProperties(properties)
def releaseMouse(self):
self.cameraSwingActivated = False
properties = WindowProperties()
properties.setCursorHidden(False)
properties.setMouseMode(WindowProperties.M_absolute)
self.win.requestProperties(properties)
def isNodeVisible(self, node):
temp_camera_node = Camera("temp_camera")
temp_camera = render.attachNewNode(temp_camera_node)
temp_camera.setPos(self.camera.getPos())
temp_camera.setHpr(self.camera.getHpr())
temp_camera_node.setLens(camera.node().getLens())
if temp_camera_node.isInView(node.node().getBounds(), temp_camera):
# Node is visible
return True
return False
def update(self, task):
self.cameraSwingActivated = True
dt = globalClock.getDt()
# move camera
if self.cameraSwingActivated:
md = self.win.getPointer(0)
mouse_X = md.getX()
mouse_Y = md.getY()
mouse_changeX = mouse_X - self.last_mouse_X
mouse_changeY = mouse_Y - self.last_mouse_Y
self.cameraSwingFactor = 50
currentH = self.camera.getH()
currentP = self.camera.getP()
self.camera.setHpr(
currentH - mouse_changeX * dt * self.cameraSwingFactor,
min(90, max(-90, currentP - mouse_changeY * dt * self.cameraSwingFactor)),
0
)
self.last_mouse_X = mouse_X
self.last_mouse_Y = mouse_Y
# Move player
playerMoveSpeed = 10
x_movement = 0
y_movement = 0
z_movement = 0
if self.key_map['forward']:
x_movement -= dt * playerMoveSpeed * sin(degToRad(self.camera.getH()))
y_movement += dt * playerMoveSpeed * cos(degToRad(self.camera.getH()))
if self.key_map['back']:
x_movement += dt * playerMoveSpeed * sin(degToRad(self.camera.getH()))
y_movement -= dt * playerMoveSpeed * cos(degToRad(self.camera.getH()))
if self.key_map['left']:
x_movement -= dt * playerMoveSpeed * cos(degToRad(self.camera.getH()))
y_movement -= dt * playerMoveSpeed * sin(degToRad(self.camera.getH()))
if self.key_map['right']:
x_movement += dt * playerMoveSpeed * cos(degToRad(self.camera.getH()))
y_movement += dt * playerMoveSpeed * sin(degToRad(self.camera.getH()))
if self.key_map['jump']:
z_movement += dt * playerMoveSpeed
if self.key_map['sprint']:
z_movement -= dt * playerMoveSpeed
self.camera.setPos(
self.camera.getX() + x_movement,
self.camera.getY() + y_movement,
self.camera.getZ() + z_movement,
)
# Render only visible nodes
vis_nodes = []
for node in render.findAllMatches("**/+GeomNode"):
if self.isNodeVisible(node):
visible_nodes.append()
render.clear()
for node in vis_nodes:
node.reparentTo(render)
return task.cont
game = Game()
game.run()
prc file:
model-cache-dir
show-frame-rate-meter
*you will also need 4 models for the blocks and a skybox file (or you can comment the code)