Clara & Pong chapter 4 is done

page 72!

A major milestone: chapter four of my comic “Clara & Pong” is done – 72 pages into the storyline. If you can read German, please head over to clarapong.com to check it out!

Before moving on to drawing the final chapter, I thought it might be interesting to share some details about my process. Since this is – especially for a relative beginner like me – a massive project, with around 100 pages, running already for more than two years – it’s pretty important to me to have a smooth workflow.

Story pipeline

It all starts with the script in text form. The major lesson I learned: Know where you’re going! I did have the major story points in mind from the beginning, and that helped me tremendously in keeping the story together. Mind you, I didn’t have all details fleshed out before starting to draw, but I could always be certain I wouldn’t draw myself into a corner.

I guess the “Right Way” to do this would have been:

  • write the script
  • draw the storyboard
  • layout the pages
  • render the pages

In my case, it turned out to work best incrementally, in overlapping “pipeline stages” with three tracks:

  • detailed script, chapter by chapter
  • storyboard, scene by scene, feeding from finished script parts
  • layout, page by page, feeding from finished storyboard panels

So, I finished the script first, the storyboard later (just a few weeks ago), and by now am conveniently pulling off panels from the storyboard, assembling pages (obviously, I’ll make corrections and put in new ideas all the time, but so far I never had to go back and change major parts of the story).

The storyboard

might look messy to you, but really provides great overview

The only non-digital part of the pipeline 🙂 I draw my storyboard on big sheets of paper, in a 6×6 grid. The drawings are just barely enough to show what’s happening in each panel, so I get the sequence down. (The picture only shows chapters 3 to 5 – before, I didn’t have a consistent approach.)

Layout & scribbles

Picking panels from the storyboard sheet, I assemble the layout for the next page. Usually I try to end each page with a transition into the next page – a smaller or larger cliffhanger, if you will. For layout and scribbling, I use my iPad Pro, moving stuff around and drawing in layers until I’m happy enough to move on to inking. Important: Make sure there’s enough space for the text!

Inking & text

layer setup

Next, I transfer the scribble to the PC (a Mac, in my case), where I import it into ClipStudio Paint, as a background image layer. My template already has two vector layers for foreground and background lines. Dividing the page up into panels gives me separate folders for each panel. The image on the left shows the layer setup of the finished page.

I love drawing in vectors, because it allows for easy corrections of shapes. When I’m done, I usually go over all the lines and adjust line weights to keep them consistent across the page.

After adding text and drawing the balloons around it, I move on to coloring the page.

Coloring

Comic palette

Here, I usually work on just one foreground and one background color layer for the whole page. I select all the frame folders, and choose “combine”, which results in a new folder masking out all the frame border areas of the page. I place my two color layers in that folder.

My coloring style is very simple, so I typically can just fill areas with flat colors. I restrict myself to a fixed color palette – which I did carefully extend over the first few chapters, but has now become very stable. Most importantly, it contains bright and dark values in warm and cool grays, plus the essential colors for my characters. A palette like this is really helpful for keeping things consistent and efficient.

… and done

Upload the page to the my website, announce it on FB, and that’s it, really. It’s all working pretty smooth and painless by now, so I can keep my pace of doing one page a week. With the completed storyboard, I now know how many pages are lying ahead, so projections show it’s quite possible to finish by the end of the year. Yay!

Site move (again)

So, I moved my existing Joomla website over to wordpress. Which hopefully makes things easier to maintain for me in the future. Will be posting new content RSN!

Pocket Observatory at Make Munich

Pocket Observatory at Make Munich! Slipped in at the very last minute, and probably had the tiniest desk in the hall. But the response was great, I am still totally overwhelmed by the positive response and all the enthusiasm. A huge THANK YOU to everyone who came over to check out the app on Gear VR! Nice people, great conversations, useful feedback, and even more ideas for future development. After two days working the desk non-stop (together with my wonderful GF) I feel a little spent but very inspired 🙂

Pocket Observatory released for Gear VR

On 3/16, Pocket Observatory has been released to the Oculus App Store for Gear VR! It has taken a lot longer than expected, but in the end, the additional iterations and feedback have improved the product tremendously. Of course, this is only version 1 – there are tons of additions on my list already, and I am open to suggestions 🙂

Here’s a link to the product page in the store.

Venturing into social VR with Pocket Observatory!

The past few weeks I’ve been working away on a really exciting feature for the upcoming Gear VR version of Pocket Observatory: You will be able to invite a friend (on the Oculus platform) and start a voice chat beneath the stars! GPS coordinates are exchanged between the app instances, so players can visit each other’s GPS locations. This is currently under review, and will hopefully be up in a few weeks in the Oculus Store.

To my knowledge, this is the very first social VR astronomy app ever! I’ve been thinking about this for quite a while during initial development, but didn’t realize how easy it would be to integrate using the Oculus platform SDK. Mind you, setting up peer-to-peer networking can still be nerve-wrecking, given the unreliable nature of network communication, but still… managed to pull this off in just a few weeks. Happy!

Check out the updated page at https://pocketobservatory.com for the details. Here’s a screenshot of the chat UI: (thinking about avatars and a shared space experience, too, but that’s for later.)

Educational VR molecules

Now that I’ve gained some experience with Virtual Reality and my astronomy app, I’m thinking educational software for VR could be a worthwhile field for future projects. So I’ve started tossing ideas about, one of which involves playing with molecules in a VR environment.

Aspirin molecule

Pocket Observatory for Google Cardboard

Just finished and submitted the iPhone / Google Cardboard version of Pocket Observatory! It really paid off to use Unity – porting from Android with the Oculus SDK to iPhone with GoogleVR turned out to be really easy.

Here are the quirks I encountered, might be useful to know if you’re embarking on a similar project:

  • In Gear VR, system messages (e.g., asking for permissions) are displayed properly and can be confirmed while you’re in VR. On the iPhone, a standard system dialog pops up. To deal with location service permissions, I trigger the message from within a special startup scene, before entering VR mode in the main scene.
  • Texture compression support has to be adjusted with the platform. On the iPhone, compression defaults to PVRTC, which requires square textures. The Unity importer stretches non-square textures to make them  compressible with PVRTC. This results in awful artifacts, so I had to go over the compressions options for all of my (non-square) textures.
  • Make sure the text for camera use permission is set in the iOS player settings – in GoogleVR, there is a UI button to allow the user to switch viewers. This will activate the phone’s camera in order to scan the QR code on the viewer. Not setting the text will result in an app crash.
  • Unfortunately, the Cardboard app doesn’t run in the simulator – there is no suitable architecture of the gvr library, so the app crashes at startup. I guess it would be possible to build the library from source, but haven’t tried that yet.

Visit https://pocketobservatory.com for details regarding app features and release plans!

Pocket Observatory: Finalizing!

Yes, I have decided on a name for my upcoming Gear VR astronomy app: Tadaa – Pocket Observatory! Seems it is getting to a decent stage… it’s hard to stop adding features when new ideas pop up every five minutes, but this all has to wait for future releases. Now, it’s all about polishing and optimizing!

I found a really, really helpful guide to optimizing Gear VR apps on the Oculus developer blog: https://developer3.oculus.com/blog/squeezing-performance-out-of-your-unity-gear-vr-game/. This certainly saved me a few headaches.

Here’s a very first video impression of the app: https://youtu.be/G4tHM2v0NyY I was actually wondering how I could do a video such as this, but it turned out to be super easy: Integrate the platform menu provided with the OVR toolkit, and the function is available in the platform menu by pressing the back button 🙂

‘Simple’ property animation in Unity

Recently, I’ve spent a few hours with Unity’s new animation system, Mecanim. I wasn’t working on any complex animations, but only wanted to implement fading of a few elements in my scene. This turned out to be a real desaster. Why?

  • For simply fading a property in an out, I needed two animation clips and four states, with pretty sensitive transition setup (I wanted the fading to be interruptible, etc.)
  • The animations cannot go from the current property value to the target at a certain speed. They will always animate from start to end.
  • Adding a delay would require either to modify the animation clip or do even more complex state setup.

So, after fiddling with this for a while, I came to the conclusion that this kind of animation is better done in code (which seems to be what people in the forums think, too). I’ve set up a simple class for fading a property value, added the logic to my MonoBehaviour script, and had it working the way I wanted within 20 minutes. Go figure.

For anyone interested, here is the code. It could probably be improved in various ways, but it’s doing what I want for my project. Feel free to play with it.

ValueFader.cs:

 public struct FadeParameters
 {
   public float initialValue;
   public float maxValue;
   public float minValue;
   public float fadeInDuration;
   public float fadeOutDuration;
   public float fadeInDelay;
     // applies only when going from Idle to FadingIn
     // (not e.g. FadingOut -> FadingIn)
 }
 
 public class ValueFader
 {
   private enum FadeState
   {
     FadingIn,
     FadingOut,
     Idle
   }
 
   private float _remainingDelay;
   private float _currentValue;
   private FadeParameters _fadeParameters;
   private FadeState _currentFadeState = FadeState.Idle;
   private float _fadeInIncrement;
   private float _fadeOutIncrement;
   public float currentValue { get { return _currentValue; } }
 
   public ValueFader(FadeParameters fp)
   {
     _fadeParameters = fp;
     _fadeInIncrement =
       (_fadeParameters.maxValue - _fadeParameters.minValue)
       / _fadeParameters.fadeInDuration;
     _fadeOutIncrement =
       (_fadeParameters.maxValue - _fadeParameters.minValue)
       / _fadeParameters.fadeOutDuration;
     _currentValue = fp.initialValue;
     _remainingDelay = fp.fadeInDelay;
   }
 
   public void FadeIn()
   {
     if (_currentValue < _fadeParameters.maxValue)
     {
       _currentFadeState = FadeState.FadingIn;
     }
     else
     {
       SetIdle();
     }
   }
 
   public void FadeOut()
   {
     if (_currentValue > _fadeParameters.minValue)
     {
       _currentFadeState = FadeState.FadingOut;
     }
     else
     {
       SetIdle(); // might have been in FadingIn, during delay
     }
   }
 
   // Returns true, if currentValue was changed by this method
   public bool Update(float deltaTime)
   {
     if (_currentFadeState == FadeState.Idle)
     {
       return false;
     }
 
     bool retVal = false;
 
     if (_currentFadeState == FadeState.FadingIn)
     {
       if (_remainingDelay <= 0.0f)
       {
         _currentValue += _fadeInIncrement * deltaTime;
         if (_currentValue >= _fadeParameters.maxValue)
         {
           _currentValue = _fadeParameters.maxValue;
           _currentFadeState = FadeState.Idle;
         }
 
         retVal = true;
       }
       else
       {
         _remainingDelay -= deltaTime;
       }
     }
     else //if (_currentFadeState == FadeState.FadingOut)
     {
       _currentValue -= _fadeOutIncrement * deltaTime;
       if (_currentValue <= _fadeParameters.minValue)
       {
         _currentValue = _fadeParameters.minValue;
         SetIdle();
       }
 
       retVal = true;
     }
 
     return retVal;
   }
 
   private void SetIdle()
   {
     _currentFadeState = FadeState.Idle;
     _remainingDelay = _fadeParameters.fadeInDelay;
   }
 }
 

And here is how you would use it, from within a MonoBehavior script.

Set up the animation parameters like this, and store the ValueFader in a class member:

FadeParameters imageFP;
imageFP.fadeInDuration = 1.0f;
imageFP.fadeOutDuration = 0.7f;
imageFP.initialValue = 0.0f;
imageFP.maxValue = 0.1f;
imageFP.minValue = 0.0f;
imageFP.fadeInDelay = 1.0f;

_imageFader = new ValueFader(imageFP);  

How you control fading values in or out, depends entirely on your logic. You might want to do it based on some event:

void OnSomethingHappened()
 {
   ...
   if (startFadingIn)
   {
     _imageFader.FadeIn();
   }
   else if (startFadingOut)
   {
     _imageFader.FadeOut();
   }
 } 

You get the idea… In Update(), apply the animated value to a material color, or whatever you want to animate:

void Update()
{
  if (_imageFader.Update(Time.deltaTime))
  {
    _imageMaterial.SetColor(
      "_Color", new Color(1.0f, 1.0f, 1.0f, _imageFader.currentValue));
  }
  ...
 } 

 And that’s all 🙂