0

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)

RaptoRR
  • 59
  • 10

0 Answers0