basic.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #!/usr/bin/env python
  2. from direct.showbase.ShowBase import ShowBase
  3. from panda3d.core import PandaNode, LightNode, TextNode
  4. from panda3d.core import Filename, NodePath
  5. from panda3d.core import PointLight, AmbientLight
  6. from panda3d.core import LightRampAttrib, AuxBitplaneAttrib
  7. from panda3d.core import CardMaker
  8. from panda3d.core import Shader, Texture
  9. from direct.task.Task import Task
  10. from direct.actor.Actor import Actor
  11. from direct.gui.OnscreenText import OnscreenText
  12. from direct.showbase.DirectObject import DirectObject
  13. from direct.showbase.BufferViewer import BufferViewer
  14. from direct.filter.CommonFilters import CommonFilters
  15. import sys
  16. import os
  17. # Function to put instructions on the screen.
  18. def addInstructions(pos, msg):
  19. return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1),
  20. parent=base.a2dTopLeft, align=TextNode.ALeft,
  21. pos=(0.08, -pos - 0.04), scale=.05)
  22. # Function to put title on the screen.
  23. def addTitle(text):
  24. return OnscreenText(text=text, style=1, pos=(-0.1, 0.09), scale=.08,
  25. parent=base.a2dBottomRight, align=TextNode.ARight,
  26. fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1))
  27. class ToonMaker(ShowBase):
  28. def __init__(self):
  29. # Initialize the ShowBase class from which we inherit, which will
  30. # create a window and set up everything we need for rendering into it.
  31. ShowBase.__init__(self)
  32. self.disableMouse()
  33. self.cam.node().getLens().setNear(10.0)
  34. self.cam.node().getLens().setFar(200.0)
  35. camera.setPos(0, -50, 0)
  36. # Check video card capabilities.
  37. if not self.win.getGsg().getSupportsBasicShaders():
  38. addTitle("Toon Shader: Video driver reports that Cg shaders are not supported.")
  39. return
  40. # Enable a 'light ramp' - this discretizes the lighting,
  41. # which is half of what makes a model look like a cartoon.
  42. # Light ramps only work if shader generation is enabled,
  43. # so we call 'setShaderAuto'.
  44. tempnode = NodePath(PandaNode("temp node"))
  45. tempnode.setAttrib(LightRampAttrib.makeSingleThreshold(0.5, 0.4))
  46. tempnode.setShaderAuto()
  47. self.cam.node().setInitialState(tempnode.getState())
  48. # Use class 'CommonFilters' to enable a cartoon inking filter.
  49. # This can fail if the video card is not powerful enough, if so,
  50. # display an error and exit.
  51. self.separation = 1 # Pixels
  52. self.filters = CommonFilters(self.win, self.cam)
  53. filterok = self.filters.setCartoonInk(separation=self.separation)
  54. if (filterok == False):
  55. addTitle(
  56. "Toon Shader: Video card not powerful enough to do image postprocessing")
  57. return
  58. # Show instructions in the corner of the window.
  59. self.title = addTitle(
  60. "Panda3D: Tutorial - Toon Shading with Normals-Based Inking")
  61. self.inst1 = addInstructions(0.06, "ESC: Quit")
  62. self.inst2 = addInstructions(0.12, "Up/Down: Increase/Decrease Line Thickness")
  63. self.inst3 = addInstructions(0.18, "V: View the render-to-texture results")
  64. # Load a dragon model and animate it.
  65. self.character = Actor()
  66. self.character.loadModel('models/nik-dragon')
  67. self.character.reparentTo(render)
  68. self.character.loadAnims({'win': 'models/nik-dragon'})
  69. self.character.loop('win')
  70. self.character.hprInterval(15, (360, 0, 0)).loop()
  71. # Create a non-attenuating point light and an ambient light.
  72. plightnode = PointLight("point light")
  73. plightnode.setAttenuation((1, 0, 0))
  74. plight = render.attachNewNode(plightnode)
  75. plight.setPos(30, -50, 0)
  76. alightnode = AmbientLight("ambient light")
  77. alightnode.setColor((0.8, 0.8, 0.8, 1))
  78. alight = render.attachNewNode(alightnode)
  79. render.setLight(alight)
  80. render.setLight(plight)
  81. # Panda contains a built-in viewer that lets you view the
  82. # results of all render-to-texture operations. This lets you
  83. # see what class CommonFilters is doing behind the scenes.
  84. self.accept("v", self.bufferViewer.toggleEnable)
  85. self.accept("V", self.bufferViewer.toggleEnable)
  86. self.bufferViewer.setPosition("llcorner")
  87. self.accept("s", self.filters.manager.resizeBuffers)
  88. # These allow you to change cartooning parameters in realtime
  89. self.accept("escape", sys.exit, [0])
  90. self.accept("arrow_up", self.increaseSeparation)
  91. self.accept("arrow_down", self.decreaseSeparation)
  92. def increaseSeparation(self):
  93. self.separation = self.separation * 1.11111111
  94. print("separation: %f" % (self.separation))
  95. self.filters.setCartoonInk(separation=self.separation)
  96. def decreaseSeparation(self):
  97. self.separation = self.separation * 0.90000000
  98. print("separation: %f" % (self.separation))
  99. self.filters.setCartoonInk(separation=self.separation)
  100. t = ToonMaker()
  101. t.run()