mirror of
				https://github.com/panda3d/panda3d.git
				synced 2025-11-03 20:13:57 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			160 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python
 | 
						|
 | 
						|
"""
 | 
						|
Author: Josh Enes
 | 
						|
Last Updated: 2015-03-13
 | 
						|
 | 
						|
This is a demo of Panda's occluder-culling system. It demonstrates loading
 | 
						|
occluder from an EGG file and adding them to a CullTraverser.
 | 
						|
"""
 | 
						|
 | 
						|
# Load PRC data
 | 
						|
from panda3d.core import loadPrcFileData
 | 
						|
loadPrcFileData('', 'window-title Occluder Demo')
 | 
						|
loadPrcFileData('', 'sync-video false')
 | 
						|
loadPrcFileData('', 'show-frame-rate-meter true')
 | 
						|
loadPrcFileData('', 'texture-minfilter linear-mipmap-linear')
 | 
						|
#loadPrcFileData('', 'fake-view-frustum-cull true') # show culled nodes in red
 | 
						|
 | 
						|
# Import needed modules
 | 
						|
import random
 | 
						|
from direct.showbase.ShowBase import ShowBase
 | 
						|
from direct.gui.OnscreenText import OnscreenText
 | 
						|
from panda3d.core import PerspectiveLens, TextNode, \
 | 
						|
TexGenAttrib, TextureStage, TransparencyAttrib, LPoint3, Texture
 | 
						|
 | 
						|
 | 
						|
def add_instructions(pos, msg):
 | 
						|
    """Function to put instructions on the screen."""
 | 
						|
    return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1),
 | 
						|
                        parent=base.a2dTopLeft, align=TextNode.ALeft,
 | 
						|
                        pos=(0.08, -pos - 0.04), scale=.05)
 | 
						|
 | 
						|
def add_title(text):
 | 
						|
    """Function to put title on the screen."""
 | 
						|
    return OnscreenText(text=text, style=1, pos=(-0.1, 0.09), scale=.08,
 | 
						|
                        parent=base.a2dBottomRight, align=TextNode.ARight,
 | 
						|
                        fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1))
 | 
						|
 | 
						|
 | 
						|
class Game(ShowBase):
 | 
						|
    """Sets up the game, camera, controls, and loads models."""
 | 
						|
    def __init__(self):
 | 
						|
        ShowBase.__init__(self)
 | 
						|
        self.xray_mode = False
 | 
						|
        self.show_model_bounds = False
 | 
						|
 | 
						|
        # Display instructions
 | 
						|
        add_title("Panda3D Tutorial: Occluder Culling")
 | 
						|
        add_instructions(0.06, "[Esc]: Quit")
 | 
						|
        add_instructions(0.12, "[W]: Move Forward")
 | 
						|
        add_instructions(0.18, "[A]: Move Left")
 | 
						|
        add_instructions(0.24, "[S]: Move Right")
 | 
						|
        add_instructions(0.30, "[D]: Move Back")
 | 
						|
        add_instructions(0.36, "Arrow Keys: Look Around")
 | 
						|
        add_instructions(0.42, "[F]: Toggle Wireframe")
 | 
						|
        add_instructions(0.48, "[X]: Toggle X-Ray Mode")
 | 
						|
        add_instructions(0.54, "[B]: Toggle Bounding Volumes")
 | 
						|
 | 
						|
        # Setup controls
 | 
						|
        self.keys = {}
 | 
						|
        for key in ['arrow_left', 'arrow_right', 'arrow_up', 'arrow_down',
 | 
						|
                    'a', 'd', 'w', 's']:
 | 
						|
            self.keys[key] = 0
 | 
						|
            self.accept(key, self.push_key, [key, 1])
 | 
						|
            self.accept('shift-%s' % key, self.push_key, [key, 1])
 | 
						|
            self.accept('%s-up' % key, self.push_key, [key, 0])
 | 
						|
        self.accept('f', self.toggleWireframe)
 | 
						|
        self.accept('x', self.toggle_xray_mode)
 | 
						|
        self.accept('b', self.toggle_model_bounds)
 | 
						|
        self.accept('escape', __import__('sys').exit, [0])
 | 
						|
        self.disableMouse()
 | 
						|
 | 
						|
        # Setup camera
 | 
						|
        self.lens = PerspectiveLens()
 | 
						|
        self.lens.setFov(60)
 | 
						|
        self.lens.setNear(0.01)
 | 
						|
        self.lens.setFar(1000.0)
 | 
						|
        self.cam.node().setLens(self.lens)
 | 
						|
        self.camera.setPos(-9, -0.5, 1)
 | 
						|
        self.heading = -95.0
 | 
						|
        self.pitch = 0.0
 | 
						|
 | 
						|
        # Load level geometry
 | 
						|
        self.level_model = self.loader.loadModel('models/level')
 | 
						|
        self.level_model.reparentTo(self.render)
 | 
						|
        self.level_model.setTexGen(TextureStage.getDefault(),
 | 
						|
                                   TexGenAttrib.MWorldPosition)
 | 
						|
        self.level_model.setTexProjector(TextureStage.getDefault(),
 | 
						|
                                         self.render, self.level_model)
 | 
						|
        self.level_model.setTexScale(TextureStage.getDefault(), 4)
 | 
						|
        tex = self.loader.load3DTexture('models/tex_#.png')
 | 
						|
        self.level_model.setTexture(tex)
 | 
						|
 | 
						|
        # Load occluders
 | 
						|
        occluder_model = self.loader.loadModel('models/occluders')
 | 
						|
        occluder_nodepaths = occluder_model.findAllMatches('**/+OccluderNode')
 | 
						|
        for occluder_nodepath in occluder_nodepaths:
 | 
						|
            self.render.setOccluder(occluder_nodepath)
 | 
						|
            occluder_nodepath.node().setDoubleSided(True)
 | 
						|
 | 
						|
        # Randomly spawn some models to test the occluders
 | 
						|
        self.models = []
 | 
						|
        box_model = self.loader.loadModel('box')
 | 
						|
 | 
						|
        for dummy in range(0, 500):
 | 
						|
            pos = LPoint3((random.random() - 0.5) * 9,
 | 
						|
                         (random.random() - 0.5) * 9,
 | 
						|
                         random.random() * 8)
 | 
						|
            box = box_model.copy_to(self.render)
 | 
						|
            box.setScale(random.random() * 0.2 + 0.1)
 | 
						|
            box.setPos(pos)
 | 
						|
            box.setHpr(random.random() * 360,
 | 
						|
                         random.random() * 360,
 | 
						|
                         random.random() * 360)
 | 
						|
            box.reparentTo(self.render)
 | 
						|
            self.models.append(box)
 | 
						|
 | 
						|
        self.taskMgr.add(self.update, 'main loop')
 | 
						|
 | 
						|
    def push_key(self, key, value):
 | 
						|
        """Stores a value associated with a key."""
 | 
						|
        self.keys[key] = value
 | 
						|
 | 
						|
    def update(self, task):
 | 
						|
        """Updates the camera based on the keyboard input."""
 | 
						|
        delta = globalClock.getDt()
 | 
						|
        move_x = delta * 3 * -self.keys['a'] + delta * 3 * self.keys['d']
 | 
						|
        move_z = delta * 3 * self.keys['s'] + delta * 3 * -self.keys['w']
 | 
						|
        self.camera.setPos(self.camera, move_x, -move_z, 0)
 | 
						|
        self.heading += (delta * 90 * self.keys['arrow_left'] +
 | 
						|
                         delta * 90 * -self.keys['arrow_right'])
 | 
						|
        self.pitch += (delta * 90 * self.keys['arrow_up'] +
 | 
						|
                       delta * 90 * -self.keys['arrow_down'])
 | 
						|
        self.camera.setHpr(self.heading, self.pitch, 0)
 | 
						|
        return task.cont
 | 
						|
 | 
						|
    def toggle_xray_mode(self):
 | 
						|
        """Toggle X-ray mode on and off. This is useful for seeing the
 | 
						|
        effectiveness of the occluder culling."""
 | 
						|
        self.xray_mode = not self.xray_mode
 | 
						|
        if self.xray_mode:
 | 
						|
            self.level_model.setColorScale((1, 1, 1, 0.5))
 | 
						|
            self.level_model.setTransparency(TransparencyAttrib.MDual)
 | 
						|
        else:
 | 
						|
            self.level_model.setColorScaleOff()
 | 
						|
            self.level_model.setTransparency(TransparencyAttrib.MNone)
 | 
						|
 | 
						|
    def toggle_model_bounds(self):
 | 
						|
        """Toggle bounding volumes on and off on the models."""
 | 
						|
        self.show_model_bounds = not self.show_model_bounds
 | 
						|
        if self.show_model_bounds:
 | 
						|
            for model in self.models:
 | 
						|
                model.showBounds()
 | 
						|
        else:
 | 
						|
            for model in self.models:
 | 
						|
                model.hideBounds()
 | 
						|
 | 
						|
game = Game()
 | 
						|
game.run()
 |