Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

Advanced search

1345208 Posts in 61706 Topics- by 53283 Members - Latest Member: maxnielsen

August 19, 2018, 11:50:13 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityDevLogsReturn of the Obra Dinn [GDC 2016 Demo Build]
Pages: 1 ... 39 40 [41]
Author Topic: Return of the Obra Dinn [GDC 2016 Demo Build]  (Read 555518 times)
Level 10


View Profile WWW
« Reply #800 on: November 23, 2017, 01:24:48 PM »

Brilliant, thx for sharing!

Level 4

View Profile
« Reply #801 on: November 23, 2017, 01:32:16 PM »

Great work, man! I really do appreciate the work here and I'm sure others working on lo-fi games will benefit from this.

Living and dying by Hanlon's Razor
Level 10

View Profile
« Reply #802 on: November 23, 2017, 04:24:23 PM »

Fullscreen, Round 3

Thanks everybody for all the suggestions. I tried everything, literally, and concluded that the best way to maintain the game's style and fix the fullscreen discomfort was to stabilize the swimming dither and subdue the flickering dots. I got there in the end, with a few compromises. This is the 3rd full devlog post I've written on this. For each previous version I'd get an idea or find something else to try while checking over it. At this point, don't even care.

Dithering Process

First, a quick explanation. Obra Dinn renders everything internally in 8-bit grayscale then converts the final output to 1-bit in a post-processing pass. The conversion from 8-bit to 1-bit is handled by comparing each source image's pixel to the corresponding dot in a tiling dither pattern. If the image pixel value is greater than the dither pattern dot value, the output bit is set to 1. Otherwise it's 0. The output gets reduced to 1-bit and the viewer's eye will merge the pixels back together to approximate more bits.

Thresholding a source image by a dither pattern

The two components of this process are the source image and the dither pattern. Obra Dinn uses two distinct patterns for different cases: an 8x8 bayer matrix for a smoother range of shades, and a 128x128 blue noise field for a less ordered output.

bayer / blue noise

In-engine result without wireframe lines. Bayer on the sphere, blue noise everywhere else.

Hold Still Please

The basic dithering process works great for static images and much less great for moving or animated images. When the source image changes from frame-to-frame the static dither pattern and low resolution output become a major problem. What should be solid shapes and shades now read as a wiggling mess of pixels.

Moving the sphere

These days, dithering is mostly used when the source image is either static or the output has a high resolution. The first thought when seeing this low-res swimming dither effect is not "yeah that's how dither works" but "what is this warping shaking effect and how can I turn it off."

Exhibit A. Reduced contrast for your comfort.

Try to focus on something here when it moves and behold the crinkled heart of Obra Dinn's fullscreen problems. There are ways to fix this that mostly boiling down to "this style doesn't work, change it." I went pretty far down that path, experimenting with different styles, before swinging back and wondering if maybe I shouldn't let these bullshit little pixels push me around.

Stabilizing The Dither

To give your eyes the best chance at recombining everything, dithering works best when the dither pattern dots have a 1:1 correlation with the output pixels. But, correlating only with the output means that as a scene post effect there's no connection between the geometry being rendered and the pattern that thresholds it. Each frame, moving scene elements threshold against different values. What I want instead is for the dither pattern to be "pinned" to the geometry and to appear stable as it moves with the rest of the scene.

The core of this is a mapping problem. As told by the length of this post, there's a conflict between the ideal dither pattern mapping (1:1 with the screen) and the ideal scene mapping (x:1 with the geometry) so get ready for some compromises. Most of my work was focused on mapping the input dither pattern into different spaces that better correlate the pattern with the scene geometry. Everything here is done at the pre-thresholding stage.

Texel Space

My first try was to map the dither pattern in texel space. This is equivalent to dithering the object textures during scene rendering instead of in a post-processing pass on the 8-bit output. I didn't expect this to work well but wanted to see what a perfectly scene-matched mapping looked like anyways.

Dither pattern in texel space

Ok well, expectations solidly met. The objects are all mapped differently so their pattern scales don't match. Those could be unified. The real problem is the aliasing. Any resampling from one space to another like this will result in aliasing, and dither patterns can't be easily mipped or filtered like traditional textures. Still, to carry it through:

Applied to the moving scene

This isn't a total loss - the pattern is nicely pinned to geometry. The aliasing produces its own swimming effect and unifying or scaling the mappings won't help with that. Texels change size with distance from the camera so there will always be dither pattern pixels that alias badly when resampled to the screen.

Motion Warping

If I want the dither pattern to track the moving geometry beneath it, why not just warp the pattern using the change in position of each rendered pixel in the scene? Indeed why not. This is a bit like a motion blur, where each pixel tracks its movement from the previous frame. In this case, I update the dither texture to keep its pattern moving with the scene. If a scene pixel was not represented in the previous frame, the dither pattern is reloaded there. This technique is made much simpler by the game's static-ness - I only need to worry about the movement of the camera, not individual objects.

Warping the dither pattern to maintain frame-to-frame coherence with the scene

This was a pretty quick & dirty try but a few things are clear. First, it kinda works. Second, a dither pattern needs a neighborhood - it can't be individual pixels. If you consider each pixel individually, as this method does, then you'll get breaks and discontinuities in the pattern which are obvious. I shifted the camera in this test scene to highlight those on the chest here. Viewing the warped dither pattern itself makes this a little easier to see.

Thresholding solid gray with the warping dither pattern

These discontinuities are down to the differing pixel depths and thresholds that I chose. I reasoned an elaborate fix based on tracking regions, averaging their depth and shifting all dither pattern dots in that region by the same amount. A discontinuity along a region boundary could be hidden by sharp lighting changes or a wireframe line. This would've been enabled by the game's existing setup of colored regions for the wireframe generation. When I sat down to implement all that, the depth term dropped out of the first equation I came up with and gave me a much simpler alternative:

Screen-mapping With Offset

When putting together the equations for the warping dither, a very simple transform fell out:
DitherOffset = ScreenSize * CameraRotation / CameraFov

Shifting the screen-mapped dither pattern based on camera rotation

Basically, this expresses that I want the screen-mapped dither pattern to shift by exactly one screen when the camera rotates through one field of view. That maintains a 1:1 mapping with the screen while also considering a simplified transform of the scene geometry in view. This really only matches the movement at the center of the screen but bless this fucked up world because it's nearly good enough.

Offsetting the dither pattern to track one screen per camera fov rotation

Note how the dithered pixels on the chair appear to mostly move with the geometry. Likewise for the sphere. Planes more perpendicular to the view don't match very well; the floor is still a mess.

So while not being perfect, simply shifting the screen-mapped dither keeps the overall pattern and scene movement close enough that the eyes can better track them together. I was pretty happy with this. While cleaning up the code and committing everything, maybe writing a devlog post or two, the idea of a perfectly-pinned dither kept nagging at me:

World Space - Cube Mapping

The experiments so far suggest that any correlation between the dither pattern and scene geometry would have to ignore depth information from the scene. What this means practically is that the dither can be pinned to the geometry during camera rotation but not during camera translation. This isn't such a bad thing for Obra Dinn considering the slow pace of the game and the observational role of the player. You're normally walking around, stopping, and looking at things. When walking, so many things are changing onscreen that the swimming dither isn't as obvious.

With that in mind, my next attempt was mapping the dither pattern to the geometry indirectly by pre-rendering it onto the sides of a cube centered around the camera. The cube translates with the camera but stays oriented to the world. In the mix: little bit of screen, little bit of scene.

Dither pattern mapped to a cube centered around the camera

Camera's view looking up into a corner. Mapping scaled up for clarity.

The cube's mapping works well when looking directly into the sides, and not so well when aimed into a corner. Still, the dither pattern stays perfectly fixed in 3D space as the camera rotates. Even rough, the result is promising.

Thresholding scene with the cube-mapped dither pattern

Now we're talking. Being a post-processing pass makes this more general than texel-space mapping, which is good. The problem is now down to the particular cube mapping. An ideal mapping would have one texel on the cube always resolve to exactly one pixel on the screen, regardless of the camera rotation. That's not possible with a cube...

World Space - Sphere Mapping

...but I got pretty close with a sphere.

Mapping the dither pattern onto the inside of a sphere

Finding this particular spherical mapping took some time. There's no way to perfectly tile a square texture onto a sphere. It would've been possible to redefine the dither matrices in terms of a hexagon grid or something else that does tile on a sphere. Possible maybe, I didn't try. Instead, I just hacked on the square tiling until this carefully tweaked "rings" mapping of the original dither pattern gave good results.

Applied to the scene

Better than the cube. Still lots of aliasing. The spherically-mapped dot size is very similar to the screen pixel size - off just enough to cause moire patterns. I could feel the closeness, and a very simple fix for this kind of aliasing is to supersample: apply the dither thresholding at a higher resolution and downsample.

Spherically-mapped dither pattern at 2x and downsampled to 1x

Thresholding at 2x, then downsampling to 1x

This is the best I got. There are a few compromises:

    1 The dither pattern dots get larger and less effective at the edges of the screen
    2 The pattern isn't aligned up-down-left-right for most camera rotations
    3 The output is no longer 1-bit due to the final box-downsample

But the upside is pretty lofty:

    1 The dithering is perfectly pinned for all camera rotations. This feels slightly uncanny in-game.
    2 Discomfort from swimming dither is totally gone, even at fullscreen
    3 The pixellated style of the game is preserved

It's possible eliminate compromise #3 by reducing the output back to 1-bit with a simple 50% threshold. The result is still better than without supersampling (the triple comparison directly below is thresholded).

Side by side, by side

In the game's default palette


It feels a little weird to put 100 hours into something that won't be noticed by its absence. Exactly no one will think, "man this dithering is stable as shit. total magic going on here." I don't want to give people problems they didn't know they should have though so it was worth fixing.

The screenspace mapping with offset works best at 1x and the sphere mapping works best at 2x. All scene rendering is at 800x450 now (up from 640x360), which helps legibility without sacrificing the low-res style. The final game will have two display modes: 

Border-boxed, screenspace offset dither, 1-bit output

Fullscreen, sphere-mapped dither, softened output

Quoting because pagination, and I'm sure there will be some useful discussion. For starters:
I guess the non-square pixels in the final output are also an inevitable compromise? It kind of breaks the suspension of disbelief.

I just realized that this compromise may not need to be inevitable, if you apply the treshold at the original pixel resolution (instead of this 2x blow-up). Of course, that would re-introduce the aliasing on the sphere, but if you only apply "lower-res tresholding" to the non-Bayer parts you would avoid that.
Canned Turkey
Professional Otter
Level 10


View Profile WWW
« Reply #803 on: November 23, 2017, 09:45:35 PM »

Once again proving yourself as probably the most inventive developer alive. Wonderful work  Smiley

Level 1

View Profile
« Reply #804 on: November 24, 2017, 02:27:50 AM »

Amazing writeup!

Level 0

View Profile WWW
« Reply #805 on: November 24, 2017, 05:19:39 AM »

Extremely fascinating project. I remember reading about it when it started some years ago. Glad to see you're still in the saddle. (Not much more to add, just wanted to cheer you on and to follow this thread) Gentleman

As always,

as always
Level 0

View Profile
« Reply #806 on: November 29, 2017, 02:16:17 PM »

Well done with the "screen-mapping with offset" solution. It honestly looks indistinguishable from the original dithering, but is already a lot easier on the eyes.

However, the shape-mapping stuff looks wrong to me. It's still way better than what you had though, and maybe at a larger screen resolution and with a little bit of softening, it doesn't break the illusion?

View Profile
« Reply #807 on: December 02, 2017, 02:14:00 AM »


If there will be no lateral camera movement, only rotation, then you can render whole scene as spherical panorama and then show only needed part. This will guarantee that all pixels will stay in place.

View Profile
« Reply #808 on: December 03, 2017, 10:39:47 AM »

Fullscreen, Round 3
Thanks everybody for all the suggestions. [...]

Thanks Lucas for all the work! Would you get some celebration time and show us a short video with the title screen and some already disclosed views within the ship? I'm very curious about seeing the new dither-like effect in more frames Well, hello there!
Level 0

View Profile
« Reply #809 on: December 21, 2017, 07:25:31 AM »

Thanks for sharing all those details about your process! I think those 100 hours will be repaid tenfold in playtime thanks to the improvement. It would be interesting to know if anyone / any game has done anything similar in the past to achieve this or if you are the first.

View Profile
« Reply #810 on: December 26, 2017, 05:53:49 AM »

Just played the demo, and I have to say it does feel magic being able to play 1bit game on a retina screen and it feels awesome, so totally worth it Smiley (try and do that with non-optimised 1bit games!) But all that apart, and god is in the details for sure, the gameplay and camera and story feels really compelling, really want to discover more about what happened to Obra Dinn. Can't wait for the next release. Thanks for sharing!
Level 1

View Profile
« Reply #811 on: April 17, 2018, 05:23:50 AM »

How's this coming dude?

Level 1

Solo Game Developer

View Profile WWW
« Reply #812 on: April 19, 2018, 04:47:10 PM »

Yes I am also very eager to know that. I have been following along with this game since the start!

← Avatar from my  Healing Process: Tokyo. 3 years in so far. Daily dev-log is here. I have advice for composers looking for work, join here, I'll tell you.

View Profile
« Reply #813 on: May 03, 2018, 05:51:00 PM »

I can't wait for this game to be released
Level 3

View Profile WWW
« Reply #814 on: May 18, 2018, 08:04:31 PM »

Hey guys. It's been a while since I've had anything worth a post here. All my work since the last post has been on boring or spoilerish production line tasks. I'm finally somewhere that I can post a status update with a few interesting notes. At the end of February, I set two deadlines: All the music completed by April 1st, all the audio completed by May 1st. I hit the music deadline and sailed briskly past the audio one.


The basic gameplay has the player walking around the ship, finding flashbacks. Each flashback starts with an audio-only playback of 10-40 seconds before you're dropped into a frozen 3D walkable scene. The 3D scenes have music but otherwise no sound. There are 49 total flashbacks. The flashbacks are grouped into 10 overall disasters that struck the ship, killing off a few crew members each time. Flashbacks are experienced generally in reverse, with exceptions.

Spreadsheet of all flashbacks, chronological, divided by disaster


My original plan for the music was to just write a bunch of tracks in different styles and assign them to the flashbacks however felt right. As the scope of the game became (dauntingly) clearer I decided that composing a theme for each disaster would help the players orient themselves better. Each disaster now has two one-minute songs: A & B. Flashbacks within a disaster are assigned A or B in a way that ensures the player will likely always alternate between the two, rarely hearing the same song twice in a row during normal play.


To keep with the general setting, all instrumentation is classical. I think in one or two cases I cheat with an electric bass or kick drum track. Mostly though it's just your standard strings, brass, woodwinds, orchestral percussion, organ, harpsichord, etc. I took a few years of piano lessons when I was a kid and played drums in a speed metal band in high school (Megadeath > Metallica). That means I suck at orchestration and have only the smallest shred of awareness about classical instrumentation. Expect to hear some cellos playing beyond their range.


Everything was composed in Logic Pro X. I started out exclusively using Sonokinetic's DaCapo orchestral samples in Kontakt but got frustrated with the slow load times and heavy CPU usage - before this project I'd always used hardware synthesizers that load instantly. DaCapo sounds good enough that I wasn't willing to give it up completely so instead I added a Roland Integra-7 hardware unit for more instant sounds, sequenced in Logic as an external instrument. There are some really nicely-articulated orchestral instruments in the Integra-7 that fit perfectly.

Because I don't like actually using a computer while making music, I went a little goofy and set up separate desk with fullscreened Logic on a low-res TV. This is as close as I could reasonably get to a hardware DAW while still having all the convenience of software.

Composing the music in Logic Pro X


Right now all 20 flashback songs are composed, sequenced, and in the game. There's also a separate theme song for the title screen. Working on the music for a month, I learned a lot of things about the process so my OCD is asking me to kindly go back and mix/master/level/balance everything at some point.

Flashback Voices

The audio for each scene playback is presented like a radio play, with no visuals, and is composed of two basic parts: the recorded vocal performances from the voice actors, and the foley sound effects. All together there are 29 speaking roles in the game, from a wide range of nationalities:

  1 American, 2 Austrian, 1 Dane, 9 British English, 1 French, 1 Indian,
  3 Irish, 1 Italian, 1 Pole, 2 Russian, 1 Swede, 3 Taiwanese, 2 Chinese, 2 British Welsh

Most of the casting and recording so far has been through voices.com. They have a project management service that streamlines submitting jobs and reviewing auditions. All this works great for the more standard nationalities/accents and for a game with so many brief speaking roles I can't imagine a better way. For any non-native English roles I ask friends of the same nationality to review auditions and tell me if someone sounds authentic. Getting a good performance was important but accents also provide gameplay-critical clues so I really want native speakers. This is all complicated by the fact that most of the dialog is in English, so non-native English speakers need to perform in a language foreign to them.

Reviewing auditions on voices.com

I've also worked with a few voice actors individually outside of voices.com. The big ones being the Formosan characters, who all speak in Taiwanese Hokkien. For those I got the help of Johnson Lin from IGDA Taiwan, who hooked me up with Lee-Kuo Chen (Sunhead Games, making Carto). Lee-Kuo was a huge help in first translating all the necessary dialog into Mandarin/Taiwanese, and in finding and managing the Taiwanese voice actors.

All actors record their lines on their own equipment or using a local studio's equipment. That complicates things when putting a scene together, fixing booth quirks and matching recordings to make them sound like they're in the same scene together. When something doesn't sound right or doesn't match up, I usually just obscure the voice slightly with other sounds. Pragmatism.

Random Comments

  • The writing has a huge effect on the quality of the performances. Bad writing can't be acted well and there were characters that auditioned poorly across the board. If no-one can nail a character that usually meant the writing was unnatural and I'd go back to rewrite it and try again.
  • In contrast with a bigger studio, or just a developer that knows that they're doing, I didn't get all the scripts/roles/characters together at once and have it handled efficiently. I've been rewriting the script over the years and casting the voices in phases as I get more nailed down.
  • Pacing is hard to judge on the page. More than once I'd written a long detailed scene with lots of talking, gotten solid performances, found it too long, and cut a large amount of dialog from the final scene.
  • I struggled to use effective expletives in the script. Every single scene ends with a death and it's almost always violent; you expect to hear some cursing. Even though the dialog isn't fully period appropriate I wanted to leave out modern expressions like "fuck!", "shit!", "bullshit!", etc. I also didn't want to fall into cliched pirate or sailor speak. In the end I mostly just removed the expletives or settled for less harsh ones (to me) like "bloody", "fools!", "damn!", etc.
  • One particular actor did a fantastic job with one of the Welsh characters, except that his accent came out as standard English and not proper Welsh. I think he's actually American. Anyways, instead of trying to recast I changed the in-game character to be generic "English."


A few characters are still not cast/recorded. These are all roles that are either from non-English speaking countries (Austria, Poland, etc), or just underrepresented in the easily-accessible voice actor community (Welsh, Irish, etc). I'll cast these in a final pass after the game is fully playable from start to finish and I can build a list of all missing vocal exclamations.

Flashback Sounds

I created all the flashback sounds in Adobe Audition. It's a great non-linear multi-track audio editor with one critical weakness: no track grouping. That means multiple track lanes that all serve the same general purpose can't be grouped and collapsed to make effecting/routing easier. Still, I was able to use the basic bussing and lots of scrolling to deal with comically huge multitrack files. If I was doing this again, I'd probably give Logic Pro X a shot at full multitrack audio editing. It has most of the features of Audition with the added bonus of robust track grouping.

Scene audio composed in Audition. There's 48 more like this.

The difficulty of putting together each scene is based on how conventional it is. A bunch of dudes talking or fighting is easy. The dialog is recorded and video-gamey action sound effects are abundant. The really hard scenes are the ones with complex actions, usually involving unconventional sounds that are much harder to source. I've recorded just a few basic sounds on my own. 99% of the effects I'm using are from existing sound libraries. The main ones:

My main go-to for sound effects. I've spent hundreds of $$$ here. Good search, tons of providers, widest overall selection. On the downside, preview clips are slow to play, quality is wildly variant, pricing is a little high ("Fart #95", 1 second, $6) buying sounds requires a comparatively long checkout/download process (even after buying credits), and all previews are overlaid with "POND FIVE!" watermarks, which gets mindbendingly annoying.

Fewer providers but faster search, fast previews without watermarks, overall higher quality, much faster purchase/download process (one click after buying credits). I usually searched here first.

A wide selection of complete sound effect libraries. Probably the highest quality but a fairly limited selection overall. Designers tend to focus on the standard sounds and even if you find something useful/unusual in a library you'll end up buying hundreds of unnecessary sounds along with it. There's no way to preview everything in a library - even the perfectly-tagged sound may not be what you're expecting. Also, library makers have an unfortunate habit of padding their sfx numbers. 11,000 sounds of crashing waves, all basically identical. I only purchased libraries when I had no other choice, and even so ended up spending 90% of the money on things I couldn't use.


All 49 scenes have their first-pass audio complete. Some have missing voices which need to be added. Like with the music, I'll also need to go back and rebalance/remix all the scenes to fit together well.


Throughout the years of working on this project, I've really enjoyed bouncing around between engineering and creative tasks. Enjoyed maybe a little too much. More than once I'd move forward on something, put it aside to work on something else, and return to the earlier task having completely forgotten the tools/pipeline/systems/everything.

For these last two months I decided the best way to get this shit done was to focus on one thing at a time. One month of music only, one month of audio only. That ended up being a big efficiency win - I was way more productive in each case. I don't think this would've worked that well earlier, before the game was totally nailed down. But still I regret not setting aside more ultra-focus time sooner.

Level 0

View Profile
« Reply #815 on: May 20, 2018, 07:59:07 AM »

(Megadeath > Metallica).

That's the only thing I didn't enjoy about the post. Amazing effort as always, I'm really looking forward to playing it!
Level 0

View Profile
« Reply #816 on: June 26, 2018, 08:29:31 AM »

Great stuff! I really enjoy the peak behind the curtain; that spreadsheet reminds of me of many of my (non-game-related) projects. Smiley Is this really four years in the making now? Homestretch!
Level 0

View Profile
« Reply #817 on: July 15, 2018, 11:53:55 AM »

Am really enjoying the insights into problem solving both technical (like the dithering stuff) and with life prioritization (month on each focus)!
Level 1

View Profile WWW
« Reply #818 on: July 16, 2018, 09:06:40 AM »

As always, your amazing ability to conjugate the artistic and technical parts of the gaming dev is tremendously inspiring.
Both sides of the process are very creative. Now we learn that you apply the same insane amount of skills to sound and music too. Just, wow.

Two questions, if I may:

(1) the dithering tuning seems to focus on camera rotations. Any reason for that? Clearly camera does a lot a translations too, especially forward, which would seem do defy many of the mechanisms you devised (cube and sphere maps). About that, translations will also probably include many extra-low velocity cases (when the WASD movement comes to a smooth stop), which, it seems, can be expected to be particularly problematic to be hammered into looking right. Am I wrong?

(2) general question, not sure it is decent to ask this but: not only the amount of inventive and skill is insane, but so is the amount of plain dedication infused in your games. How does this balance out? From the... economic sustainability point of view. Exactly because your dev log is so powerfully inspirational, I wonder if you could comment on this, in general.


Warballs! · spherical fierceness · 1P · free · arena fighter · challenging
Pages: 1 ... 39 40 [41]
Jump to:  

Theme orange-lt created by panic