3D Renderer Demo

Hi all. I’m new here. I thought I would try making a 3d renderer for Arcade, and here’s what I came up with:

2020-06-02_12-03-43

Controls:

  • Joystick: Move camera
  • A: Cycle the lighting model (None, Flat, Dither)
  • B: Toggle wireframe overdraw

The renderer has an optional depth buffer, but using it causes an out-of-memory error (err 22) on my PyGamer! I’m trying to think of a clever way to solve that. The depth buffer can be disabled in engine.ts, in case you wanted to try running this on your device.

Not a surprise, but it runs really slooow on device, even with just one object in the scene. Flat shading mode speeds it up a little. Dither mode (pictured) is pretty expensive.

Still todo:

  • Improve perspective projection
  • Find a way to support depth buffer on device
  • Proper triangle/view frustum clipping
  • Add more primitive shapes
  • Make a better looking demo scene (spaceship flying through a city ala https://youtu.be/XezcZVu66QI?t=485 ?)
  • Experiment with other types of lighting
  • Find performance problems and try to improve them
  • Or maybe just call it good enough and move on to the next thing :slight_smile:

I hope you enjoy it!

11 Likes

One aspect of this experiment I found particularly interesting was having to implement sine and cosine for the fixed-point Fx8 type. I ended up using a quarter-arc lookup table (64 entries), mapping to a 256-angle unit circle. I probably should mention in a code comment that angles are not in radians OR degrees! They’re in “Fx8ians”, I guess :).

1 Like

Hmm, haven’t looked too deeply into the implementation yet but a few things I’ll point out in case you haven’t seen them :

(Also nice to meet you, I’m Joey!)

1 Like

Oh nice I will check those out, thanks. On device the renderer seems to be pixel-bound. Multiple cubes rotate at a nice clip as long as I zoom way out.

I looked at michal’s 3d raycasting demo, very cool! The screen.blitRow has obvious perf benefits. I wasn’t able to easily adopt it because my renderer doesn’t write to an off-screen image. I wonder if doing that would improve performance though. I think I will try that later.

In the meantime, I made a tweak that noticeably improved performance: instead of writing each pixel to the screen individually, I create an Image for the scan line (an n-by-1 image) and write the pixels to that. Then I drawTransparentImage to copy the scan line to the screen. Much better performance both in the simulator and on device.

michal’s 3d raycasting demo has much better input handling than my clunky solution. I will be adopting that :).

Updated the demo link above.

2 Likes

Latest code is here for anyone interested: https://github.com/eanders-ms/pxt-3d

(also, improved dithering:)
image

1 Like

This is awesome!

@eanders, while it’s fresh in your mind, do you have any product feedback on Arcade? Thoughts on how to improve the text language experience?

Overall it was a delightful experience. I was surprised at how much I could do with it. Having a debugger was very helpful. There were a few areas I think could use refinement, but overall fantastic:

  • Debugger feedback:

    • The functionality in place was sufficient for me to quickly find bugs that would have been much more difficult otherwise. I was grateful to have the debugger!
    • The thing that tripped me up most: When you switch source files in the explorer, it resets the sim. This becomes a problem when working in the debugger. When I switch to another source file, or step into a function in another source file, it restarts the debug session.
    • I would like to be able to hover on a variable to see its value.
    • Sometimes I can’t expand a member variable in the watch panel. e.g., I can’t expand this.camera.
  • Editor feedback:

    • Amazing editing experience overall.
    • It can be difficult to find the location of a syntax error. A very clear indicator shows in the explorer, but within the file I have to hunt for the tiny red squiggle. It would be great if the line itself had a clear indicator. Maybe the line number could be highlighted, something like:
      image
  • GitHub integration:

    • Top notch! Absolutely incredible!
    • I think I found an edge case: I was using a fancy variable name to represent an angle in a linear algebra routine. The variable name was let θ = . This caused a SHA hash error when Arcade tried to sync the repo.

That’s all! Excellent work!

2 Likes

Ooh great feedback @eanders ! A few of those things have already made their way into beta (https://arcade.makecode.com/beta):

  • Debugger variables now have hover text, and if you click on them it will expand and let you copy the current value
  • We’ve got a new error list that Hristo, an intern on the team, has been working on, to help find syntax errors (and locate runtime errors). I’ll note that we did recently increase the debounce time for error checking so the red squiggles / error list won’t pop up quite as fast at the moment.
  • (also if you haven’t used beta yet, you should check out the github integration there - significant changes, including automatically building a gh pages site for you with the test code e.g. https://jwunderl.github.io/pxt-fireworks/)

gif w/ both:

Also, re: not being able to see member variables in debugger – that’s fixable with a comment annotation, //% callInDebugger, like here: https://github.com/microsoft/pxt-common-packages/blob/master/libs/game/sprite.ts#L70 . The reason we need the comment annotation is because any member variable may also be a getter that mutates state, so we can’t safely call them in debug mode without potentially changing the behavior of ‘normal’ mode (I’d say they typically shouldn’t, but ¯\_(ツ)_/¯ maybe you wanna lazy load an object). Also relevant beta feature, injecting globals to show up in debugger: https://github.com/microsoft/pxt/pull/6872 && https://github.com/microsoft/pxt-microbit/pull/2852/files

1 Like

Ah yes it was an accessor that I couldn’t expand! That makes sense. I’ll try adding //% callInDebugger. Beta debug features look like really nice improvements.