test_color_buffer.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. from panda3d import core
  2. import pytest
  3. TEST_COLOR = core.LColor(1, 127/255.0, 0, 127/255.0)
  4. TEST_COLOR_SCALE = core.LVecBase4(0.5, 0.5, 0.5, 0.5)
  5. TEST_SCALED_COLOR = core.LColor(TEST_COLOR)
  6. TEST_SCALED_COLOR.componentwise_mult(TEST_COLOR_SCALE)
  7. FUZZ = 0.02
  8. @pytest.fixture(scope='session', params=[False, True], ids=["shader:off", "shader:auto"])
  9. def shader_attrib(request):
  10. """Returns two ShaderAttribs: one with auto shader, one without."""
  11. if request.param:
  12. return core.ShaderAttrib.make_default().set_shader_auto(True)
  13. else:
  14. return core.ShaderAttrib.make_off()
  15. @pytest.fixture(scope='session', params=["mat:off", "mat:empty", "mat:amb", "mat:diff", "mat:both"])
  16. def material_attrib(request):
  17. """Returns two MaterialAttribs: one with material, one without. It
  18. shouldn't really matter what we set them to, since the tests in here do
  19. not use lighting, and therefore the material should be ignored."""
  20. if request.param == "mat:off":
  21. return core.MaterialAttrib.make_off()
  22. elif request.param == "mat:empty":
  23. return core.MaterialAttrib.make(core.Material())
  24. elif request.param == "mat:amb":
  25. mat = core.Material()
  26. mat.ambient = (0.1, 1, 0.5, 1)
  27. return core.MaterialAttrib.make(mat)
  28. elif request.param == "mat:diff":
  29. mat = core.Material()
  30. mat.diffuse = (0.1, 1, 0.5, 1)
  31. return core.MaterialAttrib.make(mat)
  32. elif request.param == "mat:both":
  33. mat = core.Material()
  34. mat.diffuse = (0.1, 1, 0.5, 1)
  35. mat.ambient = (0.1, 1, 0.5, 1)
  36. return core.MaterialAttrib.make(mat)
  37. @pytest.fixture(scope='session')
  38. def light_attrib():
  39. light = core.AmbientLight('amb')
  40. light.color = (1, 1, 1, 1)
  41. light_attrib = core.LightAttrib.make()
  42. light_attrib = light_attrib.add_on_light(core.NodePath(light))
  43. return light_attrib
  44. @pytest.fixture(scope='module', params=[False, True], ids=["srgb:off", "srgb:on"])
  45. def color_region(request, graphics_pipe):
  46. """Creates and returns a DisplayRegion with a depth buffer."""
  47. engine = core.GraphicsEngine()
  48. engine.set_threading_model("")
  49. # Vulkan needs no host window.
  50. if graphics_pipe.get_interface_name() != "Vulkan":
  51. host_fbprops = core.FrameBufferProperties()
  52. host_fbprops.force_hardware = True
  53. host = engine.make_output(
  54. graphics_pipe,
  55. 'host',
  56. 0,
  57. host_fbprops,
  58. core.WindowProperties.size(32, 32),
  59. core.GraphicsPipe.BF_refuse_window,
  60. )
  61. engine.open_windows()
  62. if host is None:
  63. pytest.skip("GraphicsPipe cannot make offscreen buffers")
  64. host_gsg = host.gsg
  65. else:
  66. host = None
  67. host_gsg = None
  68. fbprops = core.FrameBufferProperties()
  69. fbprops.force_hardware = True
  70. fbprops.set_rgba_bits(8, 8, 8, 8)
  71. fbprops.srgb_color = request.param
  72. buffer = engine.make_output(
  73. graphics_pipe,
  74. 'buffer',
  75. 0,
  76. fbprops,
  77. core.WindowProperties.size(32, 32),
  78. core.GraphicsPipe.BF_refuse_window,
  79. host_gsg,
  80. host
  81. )
  82. engine.open_windows()
  83. if buffer is None:
  84. pytest.skip("Cannot make color buffer")
  85. if fbprops.srgb_color != buffer.get_fb_properties().srgb_color:
  86. pytest.skip("Cannot make buffer with required srgb_color setting")
  87. buffer.set_clear_color_active(True)
  88. buffer.set_clear_color((0, 0, 0, 1))
  89. yield buffer.make_display_region()
  90. if buffer is not None:
  91. engine.remove_window(buffer)
  92. def render_color_pixel(region, state, vertex_color=None):
  93. """Renders a fragment using the specified render settings, and returns the
  94. resulting color value."""
  95. # Skip auto-shader tests if we don't support Cg shaders.
  96. if not region.window.gsg.supports_basic_shaders:
  97. sattr = state.get_attrib(core.ShaderAttrib)
  98. if sattr and sattr.auto_shader():
  99. pytest.skip("Cannot test auto-shader without Cg shader support")
  100. # Set up the scene with a blank card rendering at specified distance.
  101. scene = core.NodePath("root")
  102. scene.set_attrib(core.DepthTestAttrib.make(core.RenderAttrib.M_always))
  103. camera = scene.attach_new_node(core.Camera("camera"))
  104. camera.node().get_lens(0).set_near_far(1, 3)
  105. camera.node().set_cull_bounds(core.OmniBoundingVolume())
  106. if vertex_color is not None:
  107. format = core.GeomVertexFormat.get_v3cp()
  108. else:
  109. format = core.GeomVertexFormat.get_v3()
  110. vdata = core.GeomVertexData("card", format, core.Geom.UH_static)
  111. vdata.unclean_set_num_rows(4)
  112. vertex = core.GeomVertexWriter(vdata, "vertex")
  113. vertex.set_data3(core.Vec3.rfu(-1, 0, 1))
  114. vertex.set_data3(core.Vec3.rfu(-1, 0, -1))
  115. vertex.set_data3(core.Vec3.rfu(1, 0, 1))
  116. vertex.set_data3(core.Vec3.rfu(1, 0, -1))
  117. if vertex_color is not None:
  118. color = core.GeomVertexWriter(vdata, "color")
  119. color.set_data4(vertex_color)
  120. color.set_data4(vertex_color)
  121. color.set_data4(vertex_color)
  122. color.set_data4(vertex_color)
  123. strip = core.GeomTristrips(core.Geom.UH_static)
  124. strip.set_shade_model(core.Geom.SM_uniform)
  125. strip.add_next_vertices(4)
  126. strip.close_primitive()
  127. geom = core.Geom(vdata)
  128. geom.add_primitive(strip)
  129. gnode = core.GeomNode("card")
  130. gnode.add_geom(geom, state)
  131. card = scene.attach_new_node(gnode)
  132. card.set_pos(0, 2, 0)
  133. card.set_scale(60)
  134. region.active = True
  135. region.camera = camera
  136. color_texture = core.Texture("color")
  137. region.window.add_render_texture(color_texture,
  138. core.GraphicsOutput.RTM_copy_ram,
  139. core.GraphicsOutput.RTP_color)
  140. region.window.engine.render_frame()
  141. region.window.clear_render_textures()
  142. col = core.LColor()
  143. color_texture.peek().lookup(col, 0.5, 0.5)
  144. return col
  145. def test_color_write_mask(color_region):
  146. state = core.RenderState.make(
  147. core.ColorWriteAttrib.make(core.ColorWriteAttrib.C_green),
  148. )
  149. result = render_color_pixel(color_region, state)
  150. assert result == (0, 1, 0, 1)
  151. def test_color_empty(color_region, shader_attrib, material_attrib):
  152. state = core.RenderState.make(
  153. shader_attrib,
  154. material_attrib,
  155. )
  156. result = render_color_pixel(color_region, state)
  157. assert result == (1, 1, 1, 1)
  158. def test_color_off(color_region, shader_attrib, material_attrib):
  159. state = core.RenderState.make(
  160. core.ColorAttrib.make_off(),
  161. shader_attrib,
  162. material_attrib,
  163. )
  164. result = render_color_pixel(color_region, state)
  165. assert result == (1, 1, 1, 1)
  166. def test_color_flat(color_region, shader_attrib, material_attrib):
  167. state = core.RenderState.make(
  168. core.ColorAttrib.make_flat(TEST_COLOR),
  169. shader_attrib,
  170. material_attrib,
  171. )
  172. result = render_color_pixel(color_region, state)
  173. assert result.almost_equal(TEST_COLOR, FUZZ)
  174. def test_color_vertex(color_region, shader_attrib, material_attrib):
  175. state = core.RenderState.make(
  176. core.ColorAttrib.make_vertex(),
  177. shader_attrib,
  178. material_attrib,
  179. )
  180. result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
  181. assert result.almost_equal(TEST_COLOR, FUZZ)
  182. def test_color_empty_vertex(color_region, shader_attrib, material_attrib):
  183. state = core.RenderState.make(
  184. shader_attrib,
  185. material_attrib,
  186. )
  187. result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
  188. assert result.almost_equal(TEST_COLOR, FUZZ)
  189. def test_color_off_vertex(color_region, shader_attrib, material_attrib):
  190. state = core.RenderState.make(
  191. core.ColorAttrib.make_off(),
  192. shader_attrib,
  193. material_attrib,
  194. )
  195. result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
  196. assert result == (1, 1, 1, 1)
  197. def test_scaled_color_empty(color_region, shader_attrib, material_attrib):
  198. state = core.RenderState.make(
  199. shader_attrib,
  200. material_attrib,
  201. )
  202. result = render_color_pixel(color_region, state)
  203. assert result == (1, 1, 1, 1)
  204. def test_scaled_color_off(color_region, shader_attrib, material_attrib):
  205. state = core.RenderState.make(
  206. core.ColorAttrib.make_off(),
  207. shader_attrib,
  208. material_attrib,
  209. )
  210. result = render_color_pixel(color_region, state)
  211. assert result == (1, 1, 1, 1)
  212. def test_scaled_color_flat(color_region, shader_attrib, material_attrib):
  213. state = core.RenderState.make(
  214. core.ColorAttrib.make_flat(TEST_COLOR),
  215. core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
  216. shader_attrib,
  217. material_attrib,
  218. )
  219. result = render_color_pixel(color_region, state)
  220. assert result.almost_equal(TEST_SCALED_COLOR, FUZZ)
  221. def test_scaled_color_vertex(color_region, shader_attrib, material_attrib):
  222. state = core.RenderState.make(
  223. core.ColorAttrib.make_vertex(),
  224. core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
  225. shader_attrib,
  226. material_attrib,
  227. )
  228. result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
  229. assert result.almost_equal(TEST_SCALED_COLOR, FUZZ)
  230. def test_scaled_color_empty_vertex(color_region, shader_attrib, material_attrib):
  231. state = core.RenderState.make(
  232. core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
  233. shader_attrib,
  234. material_attrib,
  235. )
  236. result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
  237. assert result.almost_equal(TEST_SCALED_COLOR, FUZZ)
  238. def test_scaled_color_off_vertex(color_region, shader_attrib, material_attrib):
  239. state = core.RenderState.make(
  240. core.ColorAttrib.make_off(),
  241. core.ColorScaleAttrib.make(TEST_COLOR_SCALE),
  242. shader_attrib,
  243. material_attrib,
  244. )
  245. result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR)
  246. assert result.almost_equal(TEST_COLOR_SCALE, FUZZ)
  247. def test_color_transparency(color_region, shader_attrib, light_attrib):
  248. mat = core.Material()
  249. mat.diffuse = (1, 1, 1, 0.75)
  250. material_attrib = core.MaterialAttrib.make(mat)
  251. state = core.RenderState.make(
  252. core.TransparencyAttrib.make(core.TransparencyAttrib.M_alpha),
  253. light_attrib,
  254. shader_attrib,
  255. material_attrib,
  256. )
  257. result = render_color_pixel(color_region, state)
  258. assert result.x == pytest.approx(0.75, 0.1)
  259. def test_color_transparency_flat(color_region, shader_attrib, light_attrib):
  260. mat = core.Material()
  261. mat.diffuse = (1, 1, 1, 0.75)
  262. material_attrib = core.MaterialAttrib.make(mat)
  263. state = core.RenderState.make(
  264. core.TransparencyAttrib.make(core.TransparencyAttrib.M_alpha),
  265. core.ColorAttrib.make_flat(TEST_COLOR),
  266. light_attrib,
  267. shader_attrib,
  268. material_attrib,
  269. )
  270. result = render_color_pixel(color_region, state)
  271. assert result.x == pytest.approx(0.75, 0.1)
  272. def test_color_transparency_vertex(color_region, shader_attrib, light_attrib):
  273. mat = core.Material()
  274. mat.diffuse = (1, 1, 1, 0.75)
  275. material_attrib = core.MaterialAttrib.make(mat)
  276. state = core.RenderState.make(
  277. core.TransparencyAttrib.make(core.TransparencyAttrib.M_alpha),
  278. core.ColorAttrib.make_vertex(),
  279. light_attrib,
  280. shader_attrib,
  281. material_attrib,
  282. )
  283. result = render_color_pixel(color_region, state, vertex_color=(1, 1, 1, 0.5))
  284. assert result.x == pytest.approx(0.75, 0.1)
  285. def test_color_transparency_no_light(color_region, shader_attrib):
  286. mat = core.Material()
  287. mat.diffuse = (1, 1, 1, 0.75)
  288. material_attrib = core.MaterialAttrib.make(mat)
  289. state = core.RenderState.make(
  290. core.TransparencyAttrib.make(core.TransparencyAttrib.M_alpha),
  291. shader_attrib,
  292. material_attrib,
  293. )
  294. result = render_color_pixel(color_region, state)
  295. assert result.x == pytest.approx(1.0, 0.1)