Now I like Blender

How a friend helped me get past the weirdness of Blender

TL; DR Friends make learning Blender a lot more fun.

I’ve been working in VR for over a year now and one of the skills I’m still trying to build is 3D Modeling. When I first started learning 3D last summer the first thing I tried was Blender. I gave it a couple of days. I tried to follow some tutorials and blog posts. I ended up giving up in frustration. Blender was just too confusing! The interface was weird and the controls were insane. I couldn’t understand why anyone would design a program like this.

A Twitter friend saw my frustration and suggested Maya LT. Maya is a powerful and expensive 3D modeling package, but they have a special version called Maya LT that is suited for game asset creation. When I tried Maya I felt much more at home. The controls were easier to understand, and moving around 3D space felt more like Unreal and Unity. I did struggle with learning this though. One thing I really didn’t like about Maya was their overuse of icons. Almost the entire UI is icons, all of which look more or less the same to me. I’m sure I could get used to it over time, but when trying to learn something new I found this to be a liability.

I used Maya LT for a few months, along with Google Blocks and Verto Studio. Over time the project I was working on changed and I found myself moving away from 3D modeling for a while. I build a few small projects using ProBuilder and assets from the Unity Asset Store. Somewhere along the way I canceled my Maya LT subscription.

In March and April I built a VR Bowling game in Unity. I learned a ton from this project across a number of areas but I felt bad about my lack of 3D skills. I used ProBuilder to gray-box the app and ended up filling it with assets that I purchased. When I finished that phase of work I decided it was time to brush up on 3D modeling.

This time I decided to take another look at Blender. Why? Why go back to something so frustrating? What changed?

This time I had a friend. I met someone at a co-working space that uses Blender and he started showing me a little bit about what it could do. He helped me understand some of the weird UI and input features by giving me example of how and why to use them. Basically, he showed me just enough to get me excited about Blender, then my own obsessive tendencies kicked in. In the next seven days I read two books and completed 30 hours of video tutorials. I made around 100 blend files to test ideas and learn various concepts. I even uploaded a few things to Sketchfab.

I wrote this post because I wanted to point out just how much of an impact it was to have someone that knows a tool or platform. Working alone most of the time, it’s easy for me to spend a ton of time and effort on a new tool or project and end up failing. When I tried Blender alone I was frustrated and confused. When I had a little bit of help I was able to overcome the confusion and start to make progress.

I have a long way to go before I become a good 3D artist, but I feel like I’m on the right path now.

Some resources that have helped me learn Blender.

  • Blender: The Ultimate Guide Volume 1 This is part one of five books on Blender. This book taught me a ton about Blender features, controls, input, and navigation.

  • 3D Modeling for Beginners This book was the most helpful of anything I’ve tried so far. This is a short book but it is packed full of really useful information about 3D Modeling concepts. The examples are done using Blender but you could follow along with any 3D Modeling package.

  • Learn 3D Modelling – The Complete Blender Creator Course This is a massive Udemy course on Blender. As of writing this post I have yet to complete it. I worked through the first four sections in great detail and then started skipping around a bit.

  • Blender Guru makes awesome videos and tutorials on Blender.

  • Jayanam also makes Blender tutorials, as well as many other platforms. He does some great time-lapse video that involve building complete scenes. He also does some short videos that focus on a core feature or concept.

Blender Texture Atlas Workflow

I just learned a basic texture atlas workflow for Blender.

  1. Import a texture atlas. I made a simple one with 6 colors in Photoshop.
  2. UV Unwrap the model (I used smart unwrap for no other reason than that it sounded cool.
  3. Select all face and add the texture atlas in the UV editor. I’m not sure what any of these controls are called, I just used them for the first time today.
  4. Select each model or group of faces. For example I wanted to make the lamp shade yellow, so I selected all faces on the lamp shade. Then, in the UV window select all of the faces (I used box select) and scale them down to a size where they will fit in one of the color boxes. Then move them to the desired color box. Repeat for each model or group of faces.

I plan on using this workflow as I create some low poly assets for various projects I’m working on.

Special thanks to Cherylynn Lima for teaching this in a video. Watch it here: https://www.youtube.com/watch?v=bP_1XfpEy80

Unity Coroutines – A note to self

As I’ve been working on the Radical Bowling project I’ve found myself using coroutines quite a bit. It seems like every time I have to look up the syntax, so I thought I would write a few quick examples to reference.

Example: Defer by time

In this example I can defer some behavior for the specified time. In this case I destroy the game object.

IEnumerator DestroySelf(float time)
    {
        yield return new WaitForSeconds(time);
        GameObject.Destroy(this.gameObject);
    }

Example: Lerp a value over time

In this example I Lerp the volume of an audio source from it’s starting volume to 0.0f over time.

IEnumerator FadeMusic(float time)
    {
        var audioSource = GetComponent();
        float volume = audioSource.volume;
        float currentTime = 0.0f;

        do
        {
            var newVolume = Mathf.Lerp(volume, 0.0f, currentTime / time);
            audioSource.volume = newVolume;
            currentTime += Time.deltaTime;
            yield return null;
        }
        while (currentTime <= time);
        audioSource.Stop();
    }

There are a lot of other ways that coroutines can be used but these are the two methods I've been using the most. Don't forget to call coroutines with the StartCoroutine() method.

Update: 4/18/2018

It's important to call Coroutines correctly. In my bowling game I created a bug when I made the DestroySelf() function public and called it from another class. Calling a coroutine from another class is supported and often a good idea, but in this case I had code elsewhere on my object that would destroy the game object before the coroutine could execute. Basically it went something like this:

- Step 1: Player throws ball
- Step 2: Ball triggers collider and calls coroutine with 2 second delay
- Step 3: Most of the time the ball rolls off the lane and is destroyed but another method

The issue was Step 2. I added this late last week to try to remove balls that didn't have enough remaining force to actually roll of the lane. I fixed this today by making a public function in the BallController class. I call this from my other class and it is responsible for starting the coroutine. Maybe not the most elegant solution, but this is a demo project after all.


    public void DestroySelf(float time)
    {
        StartCoroutine(_DestroySelf(time));
    }

    private IEnumerator _DestroySelf(float time)
    {
        yield return new WaitForSeconds(time);
        GameObject.Destroy(this.gameObject);
    }

Update: 4/21/2018

This morning I ran into an instance when I needed to cancel a running coroutine. After checking the docs this is what I came up with. A variable named coroutine keeps track of the running instance. I can pass this to StopCoroutine to... stop the coroutine.


    private IEnumerator coroutine;

    public void DestroySelf(float time)
    {
        coroutine = _DestroySelf(time);
        StartCoroutine(coroutine);
    }

    public void AbortDestroySelf()
    {
        if(coroutine != null)
        {
            StopCoroutine(coroutine);
            coroutine = null;
        }
    }

    private IEnumerator _DestroySelf(float time)
    {
        yield return new WaitForSeconds(time);
        GameObject.Destroy(this.gameObject);
    }

VR Hermits: Wine rack of todo list items

This week Dave educates Joe on the Unity Profiler using the Update method as an example. VR Hermits went to a VR MeetUp, tried Leap Motion, and made some new friends. Joe gives a short update on the VR Bowling game. He also talks about his plans for the next project.

Full episode

Radical Bowling – Scripting Dynamic Friction

TL, DR; This is how I add dynamic friction to the bowling ball over time.

When I first started working on this project I was doing some reading on bowling lanes. It turns out that they lanes have oil on them. The exact placement and pattern of the oil depends on the alley, lane, and event but that is not important to my game. This oil pattern is what causes the bowling ball to do that weird (and awesome) sliding thing, where the ball seems to roll backwards in some cases. I wanted to simulate this in my game so I tried a few things.

The first thing that I tried was just making the ball slippery. I make a physics material for the ball and set the dynamic friction to zero. The result was a really unnatural effect that looked more like the ball was being dragged down the lane. Not what I’m going for.

Next I added a physics material to the lane as well. With both the lane and ball having zero dynamic friction I had a really slippery ball. In fact, at this point I could bowl strikes without the ball ever starting to roll. It would just slide all the way down the lane.

Then I had what I thought was a great idea. I would use two colliders. In Unity, physics materials are a property of a collider, so I thought that adding two colliders would give me the effect I wanted. This approach did work but it had a some drawbacks. For one, all balls stopped sliding at the exact same distance down the lane. It looked OK at first but after bowling a few frames people would start to notice. Another drawback was that using two colliders started to interfere with other scripts and logic throughout the game. For example, I’m using OnCollisionStay to change the volume and pitch of the ball rolling sound and leaving the first collider would terminate the rolling sound.

I was thinking aloud about this problem on VR Hermits when I started to wonder if I could actually change the physics material at runtime. Yes, yes I can. Below is the solution that I came up with today. It’s not perfect and I’m sure I’ll need to make adjustments over time, but this is far better than anything I’ve tried so far. Basically I just made a coroutine that will adjust the friction over time. First I add a bunch of friction all at once and then I Lerp the rest on with the time remaining.


using UnityEngine;

public class BallController : MonoBehaviour {

    public float frictionDelay = 0.8f;
    public float frictionTarget = 0.4f;
    private PhysicMaterial pm;

    private void Awake()
    {
        pm = GetComponent().material;
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "Floor")
        {
            StartCoroutine(AdjustFriction(frictionDelay));
        }

    }

    IEnumerator AdjustFriction(float time)
    {
        // Start by waiting half of the delay time
        yield return new WaitForSeconds(time / 2);

        // We are going to SLAM on some friction using a number between zero anbd half of the target friction
        pm.dynamicFriction = Random.Range( 0.0f, frictionTarget / 2);


        // Then we are going to Lerp our way to the target friction with the time left
        float currentTime = 0.0f;
        do
        {

            pm.dynamicFriction = Mathf.Lerp(pm.dynamicFriction, frictionTarget, currentTime / (time / 2));
            Debug.Log(pm.dynamicFriction.ToString());
            currentTime += Time.deltaTime;
            yield return null;

        }
        while (pm.dynamicFriction < frictionTarget);
    }

}
1 2 3 4 5