0

I recently got BBC-Micro:bit, and it has a small 5x5 led "display".

I want to make code that draws smooth moving dots without staircase effect, but I'm struggling to make it vertically and horizontally smooth when moving.

This is what I have, it only smooths dot vertically:

while (true) {
    basic.clearScreen()
    plotAA(input.acceleration(Dimension.X), input.acceleration(Dimension.Y),
        255, 255)
    basic.pause(15)
}

function plotAA(_x: number, _y: number, _brightness: number, _scale: number) {

    /* 
    * Draw a dot without "staircase effect"/aliasing.
    * _x           : from 0 to 4 but in _scale scale
    * _y           : from 0 to 4 but in _scale scale
    * _brightness  : led brightness
    * 
    * Half of _scale is a number of [0,0] pixel center
    */

    // Keep in mind that numbers are 32 bit signed integers!

    let px = (_x + _scale) % _scale * 2 // subpixel x position
    let py = (_y + _scale) % _scale * 2 // subpixel y position

    // It should be _x / _scale, but to fix a bug I use this...
    let rx = (_x + _scale) / _scale - 1 // real x position (ceil)
    let ry = (_y + _scale) / _scale - 1 // real y position (ceil)

    led.plotBrightness(rx, ry, ((_scale - py) + /* Add something here? */0) * _brightness / _scale)
    led.plotBrightness(rx + 1, ry, ((_scale - py)) * _brightness / _scale)
    led.plotBrightness(rx, ry + 1, (py) * _brightness / _scale)
    led.plotBrightness(rx + 1, ry + 1, (py) * _brightness / _scale)
}

To test this code, use https://makecode.microbit.org/ (select JavaScript on the top).

How to make it move smoothly vertically and horizontally at the same time?

Community
  • 1
  • 1
Algirdas Butkus
  • 98
  • 1
  • 10
  • what about subpixel precision ... by bleeding the brightness to all pixels touching the dot by the percentage of cover ... But that is doable only if you can set individual brightness for each pixel separately (for example by PWM or something) .... so the question is how is your display connected – Spektre Jan 24 '18 at 16:55
  • @Spektre I think I can calculate distance between 4 led's. Depending on their distance I can set the brightness of them. I think it's the most accurate way to do it. – Algirdas Butkus Jan 24 '18 at 17:09
  • it is exact opposite of bilinear interpolation .... you can use/tweak `|dot_position-pixel_center|` as the brightness ratio. Still 5x5 is very small resolution so do not expect miracles from it ... – Spektre Jan 24 '18 at 17:13
  • I don't expect that it will work perfectly, I expect it just to be a bit smoother, it should be good enough. – Algirdas Butkus Jan 24 '18 at 17:28

1 Answers1

2

I think I can calculate distance between 4 led's and the selected point. Depending on their distance I can set the brightness of led's. It's the most accurate way to do it that I know.

EDIT: Solved.

// numbers are 32bit signed integers!

while (true) {
    basic.pause(30)
    basic.clearScreen()
    plotAA(input.acceleration(Dimension.X) + 255 * 2, input.acceleration(Dimension.Y) + 255 * 2, 255, 255)
    //plotAAY(255 * 2, input.acceleration(Dimension.Y) + 255 * 2, 255, 255)
    //plotAAX(input.acceleration(Dimension.X) + 255 * 2, 255 * 2, 255, 255)
}

function plotAAX(_x: number, _y: number, _brightness: number, _scale: number) {
    let vertical = false;

    /* 
    * Draw a dot without "staircase effect"/aliasing.
    * _x           : from 0 to 4 but in _scale scale
    * _y           : from 0 to 4 but in _scale scale
    * _brightness  : led brightness
    * 
    * Half of _scale is a number of pixel center
    */

    let px = (_x + _scale) % _scale * 2 // subpixel x position

    let rx = (_x + _scale) / _scale - 1 // real x position (ceil)
    let ry = (_y + _scale) / _scale - 1 // real y position (ceil)

    led.plotBrightness(rx, ry, (_scale - px) * _brightness / _scale)
    led.plotBrightness(rx + 1, ry, px * _brightness / _scale)
}

function plotAAY(_x: number, _y: number, _brightness: number, _scale: number) {
    /* 
    * Draw a dot without "staircase effect"/aliasing.
    * _x           : from 0 to 4 but in _scale scale
    * _y           : from 0 to 4 but in _scale scale
    * _brightness  : led brightness
    * 
    * Half of _scale is a number of pixel center
    */

    let py = (_y + _scale) % _scale * 2 // subpixel y position

    let rx = (_x + _scale) / _scale - 1 // real x position (ceil)
    let ry = (_y + _scale) / _scale - 1 // real y position (ceil)

    led.plotBrightness(rx, ry, (_scale - py) * _brightness / _scale)
    led.plotBrightness(rx, ry + 1, py * _brightness / _scale)
}

function plotAA(_x: number, _y: number, _brightness: number, _scale: number) {

    /* 
    * Draw a dot without "staircase effect"/aliasing.
    * _x           : from 0 to 4 but in _scale scale
    * _y           : from 0 to 4 but in _scale scale
    * _brightness  : led brightness
    * 
    * Half of _scale is a number of pixel center
    */

    let px = (_x + _scale) % _scale // subpixel x position
    let py = (_y + _scale) % _scale // subpixel y position
    // -(half of scale) to (half of scale)

    let rx = (_x + _scale) / _scale - 1 // real x position (ceil)
    let ry = (_y + _scale) / _scale - 1 // real y position (ceil)

    led.plotBrightness(rx, ry, Math.max(_scale - distance(0, 0, px, py), 0) * _brightness / _scale)
    led.plotBrightness(rx, ry + 1, Math.max(_scale - distance(0, _scale, px, py), 0) * _brightness / _scale)
    led.plotBrightness(rx + 1, ry, Math.max(_scale - distance(_scale, 0, px, py), 0) * _brightness / _scale)
    led.plotBrightness(rx + 1, ry + 1, Math.max(_scale - distance(_scale, _scale, px, py), 0) * _brightness / _scale)
}

function distance(_1x: number, _1y: number, _2x: number, _2y: number) {
    _1x -= _2x
    _1y -= _2y
    return Math.sqrt(_1x * _1x + _1y * _1y)
}

I'll tweak it a little bit later on.

Algirdas Butkus
  • 98
  • 1
  • 10
  • Added gamma correction that was found in https://learn.adafruit.com/led-tricks-gamma-correction/the-quick-fix, working pretty well! – Algirdas Butkus Jan 24 '18 at 18:25
  • I think there are better ways to do it, but I don't think that I'll need to draw so many dots in one frame that it would become laggy. This isn't the best solution, but it works nicely! One dot approximately draws in 1ms, so I can have 41 dots and have led's update 24 times per second(24 FPS), that's good enough. – Algirdas Butkus Jan 25 '18 at 13:38