test_depth_buffer.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. from panda3d import core
  2. import pytest
  3. @pytest.fixture(scope='module', params=[32, 24, 16])
  4. def depth_region(request, graphics_pipe):
  5. """Creates and returns a DisplayRegion with a depth buffer."""
  6. engine = core.GraphicsEngine()
  7. engine.set_threading_model("")
  8. host_fbprops = core.FrameBufferProperties()
  9. host_fbprops.force_hardware = True
  10. host = engine.make_output(
  11. graphics_pipe,
  12. 'host',
  13. 0,
  14. host_fbprops,
  15. core.WindowProperties.size(32, 32),
  16. core.GraphicsPipe.BF_refuse_window,
  17. )
  18. engine.open_windows()
  19. if host is None:
  20. pytest.skip("GraphicsPipe cannot make offscreen buffers")
  21. fbprops = core.FrameBufferProperties()
  22. fbprops.force_hardware = True
  23. fbprops.depth_bits = request.param
  24. if fbprops.depth_bits >= 32:
  25. fbprops.float_depth = True
  26. buffer = engine.make_output(
  27. graphics_pipe,
  28. 'buffer',
  29. 0,
  30. fbprops,
  31. core.WindowProperties.size(32, 32),
  32. core.GraphicsPipe.BF_refuse_window,
  33. host.gsg,
  34. host
  35. )
  36. engine.open_windows()
  37. if buffer is None:
  38. pytest.skip("Cannot make depth buffer")
  39. if buffer.get_fb_properties().depth_bits != request.param:
  40. pytest.skip("Could not make buffer with desired bit count")
  41. yield buffer.make_display_region()
  42. if buffer is not None:
  43. engine.remove_window(buffer)
  44. def render_depth_pixel(region, distance, near, far, clear=None, write=True):
  45. """Renders a fragment at the specified distance using the specified render
  46. settings, and returns the resulting depth value."""
  47. # Set up the scene with a blank card rendering at specified distance.
  48. scene = core.NodePath("root")
  49. scene.set_attrib(core.DepthTestAttrib.make(core.RenderAttrib.M_always))
  50. scene.set_depth_write(write)
  51. camera = scene.attach_new_node(core.Camera("camera"))
  52. camera.node().get_lens(0).set_near_far(near, far)
  53. camera.node().set_cull_bounds(core.OmniBoundingVolume())
  54. if distance is not None:
  55. cm = core.CardMaker("card")
  56. cm.set_frame(-1, 1, -1, 1)
  57. card = scene.attach_new_node(cm.generate())
  58. card.set_pos(0, distance, 0)
  59. card.set_scale(60)
  60. region.active = True
  61. region.camera = camera
  62. if clear is not None:
  63. region.set_clear_depth_active(True)
  64. region.set_clear_depth(clear)
  65. depth_texture = core.Texture("depth")
  66. region.window.add_render_texture(depth_texture,
  67. core.GraphicsOutput.RTM_copy_ram,
  68. core.GraphicsOutput.RTP_depth)
  69. region.window.engine.render_frame()
  70. region.window.clear_render_textures()
  71. depth_texture.write("test2.png")
  72. col = core.LColor()
  73. depth_texture.peek().lookup(col, 0.5, 0.5)
  74. return col[0]
  75. def test_depth_clear(depth_region):
  76. assert 1.0 == render_depth_pixel(depth_region, None, near=1, far=10, clear=1.0)
  77. assert 0.0 == render_depth_pixel(depth_region, None, near=1, far=10, clear=0.0)
  78. def test_depth_write(depth_region):
  79. assert 1.0 == render_depth_pixel(depth_region, 5.0, near=1, far=10, clear=1.0, write=False)
  80. assert 0.99 > render_depth_pixel(depth_region, 5.0, near=1, far=10, clear=1.0, write=True)
  81. def test_depth_far_inf(depth_region):
  82. inf = float("inf")
  83. assert 0.99 > render_depth_pixel(depth_region, 10.0, near=1, far=inf, clear=1.0)
  84. def test_depth_near_inf(depth_region):
  85. inf = float("inf")
  86. assert 0.01 < render_depth_pixel(depth_region, 10.0, near=inf, far=1, clear=0.0)
  87. def test_depth_clipping(depth_region):
  88. # Get the actual depth resulting from the clear value.
  89. clr = render_depth_pixel(depth_region, None, near=1, far=10, clear=0.5)
  90. # We try rendering something at various distances to make sure that the
  91. # resulting depth value matches our expectations.
  92. # Too close; read clear value.
  93. assert clr == render_depth_pixel(depth_region, 0.999, near=1, far=10, clear=0.5)
  94. # Too far; read clear value.
  95. assert clr == render_depth_pixel(depth_region, 10.01, near=1, far=10, clear=0.5)
  96. # Just close enough; read a value close to 0.0.
  97. assert 0.01 > render_depth_pixel(depth_region, 1.001, near=1, far=10, clear=0.5)
  98. # Just far enough; read 1.0.
  99. assert 0.99 < render_depth_pixel(depth_region, 9.999, near=1, far=10, clear=0.5)
  100. def test_inverted_depth_clipping(depth_region):
  101. # Get the actual depth resulting from the clear value.
  102. clr = render_depth_pixel(depth_region, None, near=1, far=10, clear=0.5)
  103. # Too close; read clear value.
  104. assert clr == render_depth_pixel(depth_region, 0.999, near=10, far=1, clear=0.5)
  105. # Too far; read clear value.
  106. assert clr == render_depth_pixel(depth_region, 10.01, near=10, far=1, clear=0.5)
  107. # Just close enough; read a value close to 1.0.
  108. assert 0.99 < render_depth_pixel(depth_region, 1.001, near=10, far=1, clear=0.5)
  109. # Just far enough; read a value close to 0.0.
  110. assert 0.01 > render_depth_pixel(depth_region, 9.999, near=10, far=1, clear=0.5)