Pass 1 renders eight plasma sheets into an atlas with linear depth in alpha; pass 2 marches the refracted ray to each sheet and absorbs it by real path length, so near and far layers separate under pointer parallax. Plasma cycle repeats exactly every 30 s; - / = change speed.
47 lines
2.1 KiB
Python
47 lines
2.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Render regression checks. Requires Firefox and Pillow; the page itself needs neither."""
|
|
import subprocess
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
from PIL import Image, ImageChops, ImageStat
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
|
|
|
|
class IceRenderTest(unittest.TestCase):
|
|
def test_loop_mouse_and_visible_plasma(self):
|
|
subprocess.run(['python3', str(HERE / 'build_plasma.py')], check=True)
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
root = Path(directory)
|
|
profile = root / 'profile'
|
|
profile.mkdir()
|
|
|
|
def render(name, parameters):
|
|
output = root / (name + '.png')
|
|
url = (HERE / 'ice_plasma.html').as_uri() + '#shot&' + parameters
|
|
subprocess.run(['firefox', '--headless', '--new-instance', '--profile', str(profile),
|
|
'--window-size=320,240', '--screenshot=' + str(output), url],
|
|
check=True, timeout=120, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
# Exclude the on-screen instructions.
|
|
with Image.open(output) as image:
|
|
return image.convert('RGB').crop((0, 0, 320, 180))
|
|
|
|
start = render('start', 't=0&mx=0.5&my=0.5')
|
|
loop = render('loop', 't=30&mx=0.5&my=0.5')
|
|
moved = render('moved', 't=0&mx=0.9&my=0.5')
|
|
halfway = render('halfway', 't=15&mx=0.5&my=0.5')
|
|
difference = lambda a, b: sum(ImageStat.Stat(ImageChops.difference(a, b)).mean) / 3
|
|
self.assertLess(difference(start, loop), 1.0)
|
|
self.assertGreater(difference(start, moved), 3.0)
|
|
self.assertGreater(difference(start, halfway), 3.0)
|
|
self.assertGreater(ImageStat.Stat(start).stddev[2], 10.0)
|
|
luminance = start.convert('L').histogram()
|
|
pixels = sum(luminance)
|
|
self.assertLess(sum(luminance[:20]) / pixels, 0.10) # No vast black voids.
|
|
self.assertGreater(sum(luminance[:35]) / pixels, 0.08) # The depth stays dark.
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|