240 lines
9.3 KiB
Python
240 lines
9.3 KiB
Python
#!/usr/bin/env python
|
|
|
|
from panda3d.core import *
|
|
import sys
|
|
import os
|
|
|
|
from direct.showbase.ShowBase import ShowBase
|
|
from direct.interval.IntervalGlobal import *
|
|
from direct.gui.DirectGui import OnscreenText
|
|
from direct.showbase.DirectObject import DirectObject
|
|
from direct.actor import Actor
|
|
from random import *
|
|
|
|
# Function to put instructions on the screen.
|
|
def addInstructions(pos, msg):
|
|
return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=.05,
|
|
shadow=(0, 0, 0, 1), parent=base.a2dTopLeft,
|
|
pos=(0.08, -pos - 0.04), align=TextNode.ALeft)
|
|
|
|
# Function to put title on the screen.
|
|
def addTitle(text):
|
|
return OnscreenText(text=text, style=1, fg=(1, 1, 1, 1), scale=.07,
|
|
parent=base.a2dBottomRight, align=TextNode.ARight,
|
|
pos=(-0.1, 0.09), shadow=(0, 0, 0, 1))
|
|
|
|
|
|
class World(DirectObject):
|
|
|
|
def __init__(self):
|
|
# Preliminary capabilities check.
|
|
|
|
if not base.win.getGsg().getSupportsBasicShaders():
|
|
self.t = addTitle(
|
|
"Shadow Demo: Video driver reports that shaders are not supported.")
|
|
return
|
|
if not base.win.getGsg().getSupportsDepthTexture():
|
|
self.t = addTitle(
|
|
"Shadow Demo: Video driver reports that depth textures are not supported.")
|
|
return
|
|
|
|
# creating the offscreen buffer.
|
|
|
|
winprops = WindowProperties(size=(512, 512))
|
|
props = FrameBufferProperties()
|
|
props.setRgbColor(1)
|
|
props.setAlphaBits(1)
|
|
props.setDepthBits(1)
|
|
LBuffer = base.graphicsEngine.makeOutput(
|
|
base.pipe, "offscreen buffer", -2,
|
|
props, winprops,
|
|
GraphicsPipe.BFRefuseWindow,
|
|
base.win.getGsg(), base.win)
|
|
self.buffer = LBuffer
|
|
|
|
if not LBuffer:
|
|
self.t = addTitle(
|
|
"Shadow Demo: Video driver cannot create an offscreen buffer.")
|
|
return
|
|
|
|
Ldepthmap = Texture()
|
|
LBuffer.addRenderTexture(Ldepthmap, GraphicsOutput.RTMBindOrCopy,
|
|
GraphicsOutput.RTPDepthStencil)
|
|
if base.win.getGsg().getSupportsShadowFilter():
|
|
Ldepthmap.setMinfilter(Texture.FTShadow)
|
|
Ldepthmap.setMagfilter(Texture.FTShadow)
|
|
|
|
# Adding a color texture is totally unnecessary, but it helps with
|
|
# debugging.
|
|
Lcolormap = Texture()
|
|
LBuffer.addRenderTexture(Lcolormap, GraphicsOutput.RTMBindOrCopy,
|
|
GraphicsOutput.RTPColor)
|
|
|
|
self.inst_p = addInstructions(0.06, 'P : stop/start the Panda Rotation')
|
|
self.inst_w = addInstructions(0.12, 'W : stop/start the Walk Cycle')
|
|
self.inst_t = addInstructions(0.18, 'T : stop/start the Teapot')
|
|
self.inst_l = addInstructions(0.24, 'L : move light source far or close')
|
|
self.inst_v = addInstructions(0.30, 'V : View the Depth-Texture results')
|
|
self.inst_u = addInstructions(0.36, 'U : toggle updating the shadow map')
|
|
self.inst_x = addInstructions(0.42, 'Left/Right Arrow : switch camera angles')
|
|
self.inst_a = addInstructions(0.48, 'Something about A/Z and push bias')
|
|
|
|
base.setBackgroundColor(0, 0, 0.2, 1)
|
|
|
|
base.camLens.setNearFar(1.0, 10000)
|
|
base.camLens.setFov(75)
|
|
base.disableMouse()
|
|
|
|
# Load the scene.
|
|
|
|
floorTex = loader.loadTexture('maps/envir-ground.jpg')
|
|
cm = CardMaker('')
|
|
cm.setFrame(-2, 2, -2, 2)
|
|
floor = render.attachNewNode(PandaNode("floor"))
|
|
for y in range(12):
|
|
for x in range(12):
|
|
nn = floor.attachNewNode(cm.generate())
|
|
nn.setP(-90)
|
|
nn.setPos((x - 6) * 4, (y - 6) * 4, 0)
|
|
floor.setTexture(floorTex)
|
|
floor.flattenStrong()
|
|
|
|
self.pandaAxis = render.attachNewNode('panda axis')
|
|
self.pandaModel = Actor.Actor('panda-model', {'walk': 'panda-walk4'})
|
|
self.pandaModel.reparentTo(self.pandaAxis)
|
|
self.pandaModel.setPos(9, 0, 0)
|
|
self.pandaModel.setShaderInput("scale", (0.01, 0.01, 0.01, 1.0))
|
|
self.pandaWalk = self.pandaModel.actorInterval('walk', playRate=1.8)
|
|
self.pandaWalk.loop()
|
|
self.pandaMovement = self.pandaAxis.hprInterval(
|
|
20.0, LPoint3(-360, 0, 0), startHpr=LPoint3(0, 0, 0))
|
|
self.pandaMovement.loop()
|
|
|
|
self.teapot = loader.loadModel('teapot')
|
|
self.teapot.reparentTo(render)
|
|
self.teapot.setPos(0, -20, 10)
|
|
self.teapot.setShaderInput("texDisable", (1, 1, 1, 1))
|
|
self.teapotMovement = self.teapot.hprInterval(50, LPoint3(0, 360, 360))
|
|
self.teapotMovement.loop()
|
|
|
|
self.accept('escape', sys.exit)
|
|
|
|
self.accept("arrow_left", self.incrementCameraPosition, [-1])
|
|
self.accept("arrow_right", self.incrementCameraPosition, [1])
|
|
self.accept("p", self.toggleInterval, [self.pandaMovement])
|
|
self.accept("t", self.toggleInterval, [self.teapotMovement])
|
|
self.accept("w", self.toggleInterval, [self.pandaWalk])
|
|
self.accept("v", base.bufferViewer.toggleEnable)
|
|
self.accept("u", self.toggleUpdateShadowMap)
|
|
self.accept("l", self.incrementLightPosition, [1])
|
|
self.accept("o", base.oobe)
|
|
self.accept('a', self.adjustPushBias, [1.1])
|
|
self.accept('z', self.adjustPushBias, [0.9])
|
|
|
|
self.LCam = base.makeCamera(LBuffer)
|
|
self.LCam.node().setScene(render)
|
|
self.LCam.node().getLens().setFov(40)
|
|
self.LCam.node().getLens().setNearFar(10, 100)
|
|
|
|
# default values
|
|
self.pushBias = 0.04
|
|
self.ambient = 0.2
|
|
self.cameraSelection = 0
|
|
self.lightSelection = 0
|
|
|
|
# setting up shader
|
|
render.setShaderInput('light', self.LCam)
|
|
render.setShaderInput('Ldepthmap', Ldepthmap)
|
|
render.setShaderInput('ambient', (self.ambient, 0, 0, 1.0))
|
|
render.setShaderInput('texDisable', (0, 0, 0, 0))
|
|
render.setShaderInput('scale', (1, 1, 1, 1))
|
|
|
|
# Put a shader on the Light camera.
|
|
lci = NodePath(PandaNode("Light Camera Initializer"))
|
|
lci.setShader(loader.loadShader('caster.sha'))
|
|
self.LCam.node().setInitialState(lci.getState())
|
|
|
|
# Put a shader on the Main camera.
|
|
# Some video cards have special hardware for shadow maps.
|
|
# If the card has that, use it. If not, use a different
|
|
# shader that does not require hardware support.
|
|
|
|
mci = NodePath(PandaNode("Main Camera Initializer"))
|
|
if base.win.getGsg().getSupportsShadowFilter():
|
|
mci.setShader(loader.loadShader('shadow.sha'))
|
|
else:
|
|
mci.setShader(loader.loadShader('shadow-nosupport.sha'))
|
|
base.cam.node().setInitialState(mci.getState())
|
|
|
|
self.incrementCameraPosition(0)
|
|
self.incrementLightPosition(0)
|
|
self.adjustPushBias(1.0)
|
|
|
|
def toggleInterval(self, ival):
|
|
if ival.isPlaying():
|
|
ival.pause()
|
|
else:
|
|
ival.resume()
|
|
|
|
def toggleUpdateShadowMap(self):
|
|
self.buffer.active = not self.buffer.active
|
|
|
|
def incrementCameraPosition(self, n):
|
|
self.cameraSelection = (self.cameraSelection + n) % 6
|
|
if (self.cameraSelection == 0):
|
|
base.cam.reparentTo(render)
|
|
base.cam.setPos(30, -45, 26)
|
|
base.cam.lookAt(0, 0, 0)
|
|
self.LCam.node().hideFrustum()
|
|
if (self.cameraSelection == 1):
|
|
base.cam.reparentTo(self.pandaModel)
|
|
base.cam.setPos(7, -3, 9)
|
|
base.cam.lookAt(0, 0, 0)
|
|
self.LCam.node().hideFrustum()
|
|
if (self.cameraSelection == 2):
|
|
base.cam.reparentTo(self.pandaModel)
|
|
base.cam.setPos(-7, -3, 9)
|
|
base.cam.lookAt(0, 0, 0)
|
|
self.LCam.node().hideFrustum()
|
|
if (self.cameraSelection == 3):
|
|
base.cam.reparentTo(render)
|
|
base.cam.setPos(7, -23, 12)
|
|
base.cam.lookAt(self.teapot)
|
|
self.LCam.node().hideFrustum()
|
|
if (self.cameraSelection == 4):
|
|
base.cam.reparentTo(render)
|
|
base.cam.setPos(-7, -23, 12)
|
|
base.cam.lookAt(self.teapot)
|
|
self.LCam.node().hideFrustum()
|
|
if (self.cameraSelection == 5):
|
|
base.cam.reparentTo(render)
|
|
base.cam.setPos(1000, 0, 195)
|
|
base.cam.lookAt(0, 0, 0)
|
|
self.LCam.node().showFrustum()
|
|
|
|
def incrementLightPosition(self, n):
|
|
self.lightSelection = (self.lightSelection + n) % 2
|
|
if (self.lightSelection == 0):
|
|
self.LCam.setPos(0, -40, 25)
|
|
self.LCam.lookAt(0, -10, 0)
|
|
self.LCam.node().getLens().setNearFar(10, 100)
|
|
if (self.lightSelection == 1):
|
|
self.LCam.setPos(0, -600, 200)
|
|
self.LCam.lookAt(0, -10, 0)
|
|
self.LCam.node().getLens().setNearFar(10, 1000)
|
|
|
|
def shaderSupported(self):
|
|
return base.win.getGsg().getSupportsBasicShaders() and \
|
|
base.win.getGsg().getSupportsDepthTexture() and \
|
|
base.win.getGsg().getSupportsShadowFilter()
|
|
|
|
def adjustPushBias(self, inc):
|
|
self.pushBias *= inc
|
|
self.inst_a.setText(
|
|
'A/Z: Increase/Decrease the Push-Bias [%F]' % self.pushBias)
|
|
render.setShaderInput('push', self.pushBias)
|
|
|
|
if __name__ == '__main__':
|
|
base = ShowBase()
|
|
w = World()
|
|
base.run()
|