kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Cosmic Unicorn: Fast, numpy effect examples.
rodzic
f4b0434229
commit
6c0c45d6c8
|
@ -0,0 +1,126 @@
|
|||
import time
|
||||
import gc
|
||||
import random
|
||||
from cosmic import CosmicUnicorn
|
||||
from picographics import PicoGraphics, DISPLAY_COSMIC_UNICORN, PEN_P8
|
||||
from ulab import numpy
|
||||
|
||||
"""
|
||||
Classic fire effect.
|
||||
Play with the number of spawns, heat, damping factor and colour palette to tweak it.
|
||||
"""
|
||||
|
||||
# MAXIMUM OVERKILL
|
||||
# machine.freq(250_000_000)
|
||||
|
||||
gu = CosmicUnicorn()
|
||||
gu.set_brightness(0.5)
|
||||
graphics = PicoGraphics(DISPLAY_COSMIC_UNICORN, pen_type=PEN_P8)
|
||||
|
||||
# Number of random fire spawns
|
||||
FIRE_SPAWNS = 5
|
||||
|
||||
# Fire damping
|
||||
DAMPING_FACTOR = 0.98
|
||||
|
||||
# TURN UP THE HEEEAAT
|
||||
HEAT = 3.0
|
||||
|
||||
# Create the fire palette
|
||||
"""
|
||||
# Raging Gas Inferno
|
||||
graphics.create_pen(0, 0, 0)
|
||||
graphics.create_pen(0, 0, 0)
|
||||
graphics.create_pen(20, 20, 20)
|
||||
graphics.create_pen(50, 10, 0)
|
||||
graphics.create_pen(180, 30, 0)
|
||||
graphics.create_pen(220, 160, 0)
|
||||
graphics.create_pen(255, 255, 180)
|
||||
graphics.create_pen(255, 255, 220)
|
||||
graphics.create_pen(90, 90, 255)
|
||||
graphics.create_pen(255, 0, 255)
|
||||
"""
|
||||
# Original Colours
|
||||
graphics.create_pen(0, 0, 0)
|
||||
graphics.create_pen(20, 20, 20)
|
||||
graphics.create_pen(180, 30, 0)
|
||||
graphics.create_pen(220, 160, 0)
|
||||
graphics.create_pen(255, 255, 180)
|
||||
|
||||
PALETTE_SIZE = 5 # Should match the number of colours defined above
|
||||
|
||||
|
||||
def update():
|
||||
# Clear the bottom two rows (off screen)
|
||||
heat[height - 1][:] = 0.0
|
||||
heat[height - 2][:] = 0.0
|
||||
|
||||
# Add random fire spawns
|
||||
for c in range(FIRE_SPAWNS):
|
||||
x = random.randint(0, width - 4) + 2
|
||||
heat[height - 1][x - 1:x + 1] = HEAT / 2.0
|
||||
heat[height - 2][x - 1:x + 1] = HEAT
|
||||
|
||||
# Propagate the fire upwards
|
||||
a = numpy.roll(heat, -1, axis=0) # y + 1, x
|
||||
b = numpy.roll(heat, -2, axis=0) # y + 2, x
|
||||
c = numpy.roll(heat, -1, axis=0) # y + 1
|
||||
d = numpy.roll(c, 1, axis=1) # y + 1, x + 1
|
||||
e = numpy.roll(c, -1, axis=1) # y + 1, x - 1
|
||||
|
||||
# Average over 5 adjacent pixels and apply damping
|
||||
heat[:] += a + b + d + e
|
||||
heat[:] *= DAMPING_FACTOR / 5.0
|
||||
|
||||
|
||||
def draw():
|
||||
# Copy the fire effect to the framebuffer
|
||||
# Clips the fire to 0.0 to 1.0
|
||||
# Multiplies it by the number of palette entries (-1) to turn it into a palette index
|
||||
# Converts to uint8_t datatype to match the framebuffer
|
||||
memoryview(graphics)[:] = numpy.ndarray(numpy.clip(heat[0:32, 0:32], 0, 1) * (PALETTE_SIZE - 1), dtype=numpy.uint8).tobytes()
|
||||
gu.update(graphics)
|
||||
|
||||
|
||||
width = CosmicUnicorn.WIDTH
|
||||
height = CosmicUnicorn.HEIGHT + 4
|
||||
heat = numpy.zeros((height, width))
|
||||
|
||||
t_count = 0
|
||||
t_total = 0
|
||||
|
||||
while True:
|
||||
gc.collect()
|
||||
|
||||
if gu.is_pressed(CosmicUnicorn.SWITCH_BRIGHTNESS_UP):
|
||||
gu.adjust_brightness(+0.01)
|
||||
|
||||
if gu.is_pressed(CosmicUnicorn.SWITCH_BRIGHTNESS_DOWN):
|
||||
gu.adjust_brightness(-0.01)
|
||||
|
||||
tstart = time.ticks_ms()
|
||||
gc.collect()
|
||||
update()
|
||||
draw()
|
||||
tfinish = time.ticks_ms()
|
||||
|
||||
total = tfinish - tstart
|
||||
t_total += total
|
||||
t_count += 1
|
||||
|
||||
if t_count == 60:
|
||||
per_frame_avg = t_total / t_count
|
||||
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
|
||||
t_count = 0
|
||||
t_total = 0
|
||||
|
||||
# pause for a moment (important or the USB serial device will fail)
|
||||
# try to pace at 60fps or 30fps
|
||||
if total > 1000 / 30:
|
||||
time.sleep(0.0001)
|
||||
elif total > 1000 / 60:
|
||||
t = 1000 / 30 - total
|
||||
time.sleep(t / 1000)
|
||||
else:
|
||||
t = 1000 / 60 - total
|
||||
time.sleep(t / 1000)
|
|
@ -0,0 +1,118 @@
|
|||
import gc
|
||||
import time
|
||||
import math
|
||||
import random
|
||||
from cosmic import CosmicUnicorn
|
||||
from picographics import PicoGraphics, DISPLAY_COSMIC_UNICORN, PEN_P8
|
||||
from ulab import numpy
|
||||
|
||||
"""
|
||||
A lava lamp effect, created by blurred, moving particles.
|
||||
"""
|
||||
|
||||
# MAXIMUM OVERKILL
|
||||
# machine.freq(250_000_000)
|
||||
|
||||
gu = CosmicUnicorn()
|
||||
graphics = PicoGraphics(DISPLAY_COSMIC_UNICORN, pen_type=PEN_P8)
|
||||
gu.set_brightness(0.5)
|
||||
|
||||
width = CosmicUnicorn.WIDTH
|
||||
height = CosmicUnicorn.HEIGHT
|
||||
lava = numpy.zeros((height, width))
|
||||
|
||||
|
||||
class Blob():
|
||||
def __init__(self):
|
||||
self.x = float(random.randint(0, width - 1))
|
||||
self.y = float(random.randint(0, height - 1))
|
||||
self.r = (float(random.randint(0, 40)) / 10.0) + 5.0
|
||||
self.dx = (float(random.randint(0, 2)) / 20.0) - 0.05
|
||||
self.dy = (float(random.randint(0, 2)) / 20.0) - 0.025 # positive bias
|
||||
|
||||
def move(self):
|
||||
self.x += self.dx
|
||||
self.y += self.dy
|
||||
|
||||
if self.x < 0.0 or self.x >= float(width):
|
||||
self.x = max(0.0, self.x)
|
||||
self.x = min(float(width - 1), self.x)
|
||||
self.dx = -self.dx
|
||||
|
||||
if self.y < 0.0 or self.y >= float(height):
|
||||
self.y = max(0.0, self.y)
|
||||
self.y = min(float(width - 1), self.y)
|
||||
self.dy = -self.dy
|
||||
|
||||
|
||||
blobs = [Blob() for _ in range(10)]
|
||||
|
||||
|
||||
# Fill palette with a steep falloff from bright red to dark blue
|
||||
PAL_COLS = 9
|
||||
for x in range(PAL_COLS):
|
||||
graphics.create_pen_hsv(0.5 + math.log(x + 1, PAL_COLS + 1) / 2.0, 1.0, math.log(x + 1, PAL_COLS + 1))
|
||||
|
||||
|
||||
def update():
|
||||
# Update the blobs and draw them into the effect
|
||||
for blob in blobs:
|
||||
blob.move()
|
||||
lava[int(blob.y)][int(blob.x)] = blob.r
|
||||
|
||||
# Propogate the blobs outwards
|
||||
a = numpy.roll(lava, 1, axis=0)
|
||||
b = numpy.roll(lava, -1, axis=0)
|
||||
d = numpy.roll(lava, 1, axis=1)
|
||||
e = numpy.roll(lava, -1, axis=1)
|
||||
|
||||
# Average over 5 adjacent pixels and apply damping
|
||||
lava[:] += a + b + d + e
|
||||
lava[:] *= 0.97 / 5.0
|
||||
|
||||
|
||||
def draw():
|
||||
# Copy the lava effect to the framebuffer
|
||||
# Clips to 0.0 - 1.0
|
||||
# Multiplies by palette entries (-1) to turn it into a palette index
|
||||
# Converts to uint8_t datatype to match the framebuffer
|
||||
memoryview(graphics)[:] = numpy.ndarray(numpy.clip(lava, 0.0, 1.0) * (PAL_COLS - 1), dtype=numpy.uint8).tobytes()
|
||||
gu.update(graphics)
|
||||
|
||||
|
||||
t_count = 0
|
||||
t_total = 0
|
||||
|
||||
while True:
|
||||
if gu.is_pressed(CosmicUnicorn.SWITCH_BRIGHTNESS_UP):
|
||||
gu.adjust_brightness(+0.01)
|
||||
|
||||
if gu.is_pressed(CosmicUnicorn.SWITCH_BRIGHTNESS_DOWN):
|
||||
gu.adjust_brightness(-0.01)
|
||||
|
||||
tstart = time.ticks_ms()
|
||||
gc.collect()
|
||||
update()
|
||||
draw()
|
||||
tfinish = time.ticks_ms()
|
||||
|
||||
total = tfinish - tstart
|
||||
t_total += total
|
||||
t_count += 1
|
||||
|
||||
if t_count == 60:
|
||||
per_frame_avg = t_total / t_count
|
||||
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
|
||||
t_count = 0
|
||||
t_total = 0
|
||||
|
||||
# pause for a moment (important or the USB serial device will fail)
|
||||
# try to pace at 60fps or 30fps
|
||||
if total > 1000 / 30:
|
||||
time.sleep(0.0001)
|
||||
elif total > 1000 / 60:
|
||||
t = 1000 / 30 - total
|
||||
time.sleep(t / 1000)
|
||||
else:
|
||||
t = 1000 / 60 - total
|
||||
time.sleep(t / 1000)
|
|
@ -0,0 +1,89 @@
|
|||
import gc
|
||||
import time
|
||||
import random
|
||||
from cosmic import CosmicUnicorn
|
||||
from picographics import PicoGraphics, DISPLAY_COSMIC_UNICORN, PEN_P8
|
||||
from ulab import numpy
|
||||
|
||||
"""
|
||||
HELLO NEO.
|
||||
"""
|
||||
|
||||
# MAXIMUM OVERKILL
|
||||
# machine.freq(250_000_000)
|
||||
|
||||
gu = CosmicUnicorn()
|
||||
gu.set_brightness(1.0)
|
||||
graphics = PicoGraphics(DISPLAY_COSMIC_UNICORN, pen_type=PEN_P8)
|
||||
|
||||
|
||||
# Fill half the palette with GREEEN
|
||||
for g in range(128):
|
||||
_ = graphics.create_pen(0, g, 0)
|
||||
|
||||
# And half with bright green for white sparkles
|
||||
for g in range(128):
|
||||
_ = graphics.create_pen(128, 128 + g, 128)
|
||||
|
||||
|
||||
def update():
|
||||
trippy[:] *= 0.65
|
||||
|
||||
for _ in range(2):
|
||||
x = random.randint(0, width - 1)
|
||||
y = random.randint(0, height // 2)
|
||||
trippy[y][x] = random.randint(128, 255) / 255.0
|
||||
|
||||
# Propagate downwards
|
||||
old = numpy.ndarray(trippy) * 0.5
|
||||
trippy[:] = numpy.roll(trippy, 1, axis=0)
|
||||
trippy[:] += old
|
||||
|
||||
|
||||
def draw():
|
||||
# Copy the effect to the framebuffer
|
||||
memoryview(graphics)[:] = numpy.ndarray(numpy.clip(trippy, 0, 1) * 254, dtype=numpy.uint8).tobytes()
|
||||
gu.update(graphics)
|
||||
|
||||
|
||||
width = CosmicUnicorn.WIDTH
|
||||
height = CosmicUnicorn.HEIGHT
|
||||
trippy = numpy.zeros((height, width))
|
||||
|
||||
t_count = 0
|
||||
t_total = 0
|
||||
|
||||
|
||||
while True:
|
||||
if gu.is_pressed(CosmicUnicorn.SWITCH_BRIGHTNESS_UP):
|
||||
gu.adjust_brightness(+0.01)
|
||||
|
||||
if gu.is_pressed(CosmicUnicorn.SWITCH_BRIGHTNESS_DOWN):
|
||||
gu.adjust_brightness(-0.01)
|
||||
|
||||
tstart = time.ticks_ms()
|
||||
gc.collect()
|
||||
update()
|
||||
draw()
|
||||
tfinish = time.ticks_ms()
|
||||
|
||||
total = tfinish - tstart
|
||||
t_total += total
|
||||
t_count += 1
|
||||
|
||||
if t_count == 60:
|
||||
per_frame_avg = t_total / t_count
|
||||
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
|
||||
t_count = 0
|
||||
t_total = 0
|
||||
|
||||
# pause for a moment (important or the USB serial device will fail)
|
||||
# try to pace at 60fps or 30fps
|
||||
if total > 1000 / 30:
|
||||
time.sleep(0.0001)
|
||||
elif total > 1000 / 60:
|
||||
t = 1000 / 30 - total
|
||||
time.sleep(t / 1000)
|
||||
else:
|
||||
t = 1000 / 60 - total
|
||||
time.sleep(t / 1000)
|
|
@ -0,0 +1,131 @@
|
|||
import time
|
||||
import gc
|
||||
import random
|
||||
from cosmic import CosmicUnicorn
|
||||
from picographics import PicoGraphics, DISPLAY_COSMIC_UNICORN, PEN_P8
|
||||
from ulab import numpy
|
||||
|
||||
"""
|
||||
THIS IS FINE!
|
||||
"""
|
||||
|
||||
# MAXIMUM OVERKILL
|
||||
# machine.freq(250_000_000)
|
||||
|
||||
gu = CosmicUnicorn()
|
||||
gu.set_brightness(0.5)
|
||||
graphics = PicoGraphics(DISPLAY_COSMIC_UNICORN, pen_type=PEN_P8)
|
||||
|
||||
# Number of random fire spawns
|
||||
FIRE_SPAWNS = 5
|
||||
|
||||
# Fire damping
|
||||
DAMPING_FACTOR = 0.98
|
||||
|
||||
# TURN UP THE HEEEAAT
|
||||
HEAT = 3.0
|
||||
|
||||
# Create the fire palette
|
||||
"""
|
||||
# Raging Gas Inferno
|
||||
graphics.create_pen(0, 0, 0)
|
||||
graphics.create_pen(0, 0, 0)
|
||||
graphics.create_pen(20, 20, 20)
|
||||
graphics.create_pen(50, 10, 0)
|
||||
graphics.create_pen(180, 30, 0)
|
||||
graphics.create_pen(220, 160, 0)
|
||||
graphics.create_pen(255, 255, 180)
|
||||
graphics.create_pen(255, 255, 220)
|
||||
graphics.create_pen(90, 90, 255)
|
||||
graphics.create_pen(255, 0, 255)
|
||||
"""
|
||||
# Original Colours
|
||||
graphics.create_pen(0, 0, 0)
|
||||
graphics.create_pen(20, 20, 20)
|
||||
graphics.create_pen(180, 30, 0)
|
||||
graphics.create_pen(220, 160, 0)
|
||||
graphics.create_pen(255, 255, 180)
|
||||
|
||||
PALETTE_SIZE = 5 # Should match the number of colours defined above
|
||||
|
||||
|
||||
def update():
|
||||
# Clear the bottom two rows (off screen)
|
||||
heat[height - 1][:] = 0.0
|
||||
heat[height - 2][:] = 0.0
|
||||
|
||||
# Add random fire spawns
|
||||
for c in range(FIRE_SPAWNS):
|
||||
x = random.randint(0, width - 4) + 2
|
||||
heat[height - 1][x - 1:x + 1] = HEAT / 2.0
|
||||
heat[height - 2][x - 1:x + 1] = HEAT
|
||||
|
||||
# Propagate the fire upwards
|
||||
a = numpy.roll(heat, -1, axis=0) # y + 1, x
|
||||
b = numpy.roll(heat, -2, axis=0) # y + 2, x
|
||||
c = numpy.roll(heat, -1, axis=0) # y + 1
|
||||
d = numpy.roll(c, 1, axis=1) # y + 1, x + 1
|
||||
e = numpy.roll(c, -1, axis=1) # y + 1, x - 1
|
||||
|
||||
# Average over 5 adjacent pixels and apply damping
|
||||
heat[:] += a + b + d + e
|
||||
heat[:] *= DAMPING_FACTOR / 5.0
|
||||
|
||||
|
||||
def draw():
|
||||
# Copy the fire effect to the framebuffer
|
||||
# Clips the fire to 0.0 to 1.0
|
||||
# Multiplies it by the number of palette entries (-1) to turn it into a palette index
|
||||
# Converts to uint8_t datatype to match the framebuffer
|
||||
memoryview(graphics)[:] = numpy.ndarray(numpy.clip(heat[0:32, 0:32], 0, 1) * (PALETTE_SIZE - 1), dtype=numpy.uint8).tobytes()
|
||||
|
||||
# Draw text over the top
|
||||
graphics.set_pen(0)
|
||||
graphics.text("This", 6, 4, 1, 1)
|
||||
graphics.text("is", 11, 12, 1, 1)
|
||||
graphics.text("fine", 6, 20, 1, 1)
|
||||
gu.update(graphics)
|
||||
|
||||
|
||||
width = CosmicUnicorn.WIDTH
|
||||
height = CosmicUnicorn.HEIGHT + 4
|
||||
heat = numpy.zeros((height, width))
|
||||
|
||||
t_count = 0
|
||||
t_total = 0
|
||||
|
||||
while True:
|
||||
gc.collect()
|
||||
|
||||
if gu.is_pressed(CosmicUnicorn.SWITCH_BRIGHTNESS_UP):
|
||||
gu.adjust_brightness(+0.01)
|
||||
|
||||
if gu.is_pressed(CosmicUnicorn.SWITCH_BRIGHTNESS_DOWN):
|
||||
gu.adjust_brightness(-0.01)
|
||||
|
||||
tstart = time.ticks_ms()
|
||||
gc.collect()
|
||||
update()
|
||||
draw()
|
||||
tfinish = time.ticks_ms()
|
||||
|
||||
total = tfinish - tstart
|
||||
t_total += total
|
||||
t_count += 1
|
||||
|
||||
if t_count == 60:
|
||||
per_frame_avg = t_total / t_count
|
||||
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
|
||||
t_count = 0
|
||||
t_total = 0
|
||||
|
||||
# pause for a moment (important or the USB serial device will fail)
|
||||
# try to pace at 60fps or 30fps
|
||||
if total > 1000 / 30:
|
||||
time.sleep(0.0001)
|
||||
elif total > 1000 / 60:
|
||||
t = 1000 / 30 - total
|
||||
time.sleep(t / 1000)
|
||||
else:
|
||||
t = 1000 / 60 - total
|
||||
time.sleep(t / 1000)
|
|
@ -0,0 +1,97 @@
|
|||
import gc
|
||||
import time
|
||||
import random
|
||||
from cosmic import CosmicUnicorn
|
||||
from picographics import PicoGraphics, DISPLAY_COSMIC_UNICORN, PEN_P8
|
||||
from ulab import numpy
|
||||
|
||||
"""
|
||||
A random, trippy effect.
|
||||
Experiment with the damping, number of spawns, intensity and offset to change the effect.
|
||||
"""
|
||||
|
||||
# MAXIMUM OVERKILL
|
||||
# machine.freq(250_000_000)
|
||||
|
||||
gu = CosmicUnicorn()
|
||||
gu.set_brightness(0.5)
|
||||
graphics = PicoGraphics(DISPLAY_COSMIC_UNICORN, pen_type=PEN_P8)
|
||||
|
||||
|
||||
DAMPING_FACTOR = 0.95
|
||||
NUMBER_OF_DROPS = 5
|
||||
INTENSITY = 10
|
||||
OFFSET = 0.0 # Try 0.5
|
||||
|
||||
# Fill palette with a rainbow sweep
|
||||
PALETTE_ENTRIES = 255
|
||||
for x in range(PALETTE_ENTRIES):
|
||||
_ = graphics.create_pen_hsv(float(x) / PALETTE_ENTRIES + OFFSET, 1.0, 1.0)
|
||||
|
||||
|
||||
def update():
|
||||
trippy[:] *= DAMPING_FACTOR
|
||||
|
||||
# Spawn random drops
|
||||
for _ in range(NUMBER_OF_DROPS):
|
||||
x = random.randint(0, width - 1)
|
||||
y = random.randint(0, height - 1)
|
||||
trippy[y][x] = random.randint(0, INTENSITY)
|
||||
|
||||
a = numpy.roll(trippy, 1, axis=0)
|
||||
b = numpy.roll(trippy, -1, axis=0)
|
||||
d = numpy.roll(trippy, 1, axis=1)
|
||||
e = numpy.roll(trippy, -1, axis=1)
|
||||
|
||||
# Average over 5 adjacent pixels and apply damping
|
||||
trippy[:] += a + b + d + e
|
||||
trippy[:] /= 5.0
|
||||
|
||||
|
||||
def draw():
|
||||
# Copy the effect to the framebuffer
|
||||
memoryview(graphics)[:] = numpy.ndarray(numpy.clip(trippy, 0, 1) * (PALETTE_ENTRIES - 1), dtype=numpy.uint8).tobytes()
|
||||
gu.update(graphics)
|
||||
|
||||
|
||||
width = CosmicUnicorn.WIDTH
|
||||
height = CosmicUnicorn.HEIGHT
|
||||
trippy = numpy.zeros((height, width))
|
||||
|
||||
t_count = 0
|
||||
t_total = 0
|
||||
|
||||
|
||||
while True:
|
||||
if gu.is_pressed(CosmicUnicorn.SWITCH_BRIGHTNESS_UP):
|
||||
gu.adjust_brightness(+0.01)
|
||||
|
||||
if gu.is_pressed(CosmicUnicorn.SWITCH_BRIGHTNESS_DOWN):
|
||||
gu.adjust_brightness(-0.01)
|
||||
|
||||
tstart = time.ticks_ms()
|
||||
gc.collect()
|
||||
update()
|
||||
draw()
|
||||
tfinish = time.ticks_ms()
|
||||
|
||||
total = tfinish - tstart
|
||||
t_total += total
|
||||
t_count += 1
|
||||
|
||||
if t_count == 60:
|
||||
per_frame_avg = t_total / t_count
|
||||
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
|
||||
t_count = 0
|
||||
t_total = 0
|
||||
|
||||
# pause for a moment (important or the USB serial device will fail)
|
||||
# try to pace at 60fps or 30fps
|
||||
if total > 1000 / 30:
|
||||
time.sleep(0.0001)
|
||||
elif total > 1000 / 60:
|
||||
t = 1000 / 30 - total
|
||||
time.sleep(t / 1000)
|
||||
else:
|
||||
t = 1000 / 60 - total
|
||||
time.sleep(t / 1000)
|
Ładowanie…
Reference in New Issue