Shader based rounded rectangle for ui

I created this small shader that renders rounded rectangles for ui. Some notable features are:

  • Set corner radius
  • Border, with thickness
  • Built in shadows, including soft shadows
  • Sprite support
  • Default, URP and HDRP support

It’s based on the buildin Image component so it also shares most of the features from that like masking, button tint, button sprite swap etc.

Watch the video below for a demonstration:

Download here: https://bitbucket.org/laitch/proceduraluishapes/

How to use:

  • Place the folder “ProceduralUIShapes” somewhere in you asset folder
  • Right click on the canvas in the Hierarchy and select UI -> RoundedRect
  • Make sure that the shader channels TexCoord1, -2 and -3″ are enabled on the canvas component under “Additional Shader Channels”

Experiments with async/await and Task to run multithreaded code

A couple of years ago when unity started supporting .NET 4.x we got access to newer C# features, including async/await. Today I decided to see if I could use this to easily run multithreaded code in unity.

First I would like to point out that asynchronous does not mean multithreaded. Just having an async method is more akin to having a coroutine method like we are used to in Unity. But in an async method we can start (and wait on) a task on a separate thread using something like this:

private void Start()
{
    Test();
}

private async void Test()
{
    string result = "";
    await Task.Run(() => {
        Thread.Sleep(1000);
        result = "This is some result";
    });
    Debug.Log(result);
}

With this in mind I created a static helper class where you can run any method on a separate thread and get the result sent back to the main thread via a callback action

using System;
using System.Threading.Tasks;

public static class RunOnSeparateThread
{
    public static async void Run<TResult>(Func<TResult> task, Action<TResult> onDone)
    {
        TResult result = default;
        await Task.Run(() => result = task());
        onDone?.Invoke(result);
    }

    public static async void Run<T1, TResult>(Func<T1, TResult> task, Action<TResult> onDone, T1 arg1)
    {
        TResult result = default;
        await Task.Run(() => result = task(arg1));
        onDone?.Invoke(result);
    }

    public static async void Run<T1, T2, TResult>(Func<T1, T2, TResult> task, Action<TResult> onDone, T1 arg1, T2 arg2)
    {
        TResult result = default;
        await Task.Run(() => result = task(arg1, arg2));
        onDone?.Invoke(result);
    }

    public static async void Run<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> task, Action<TResult> onDone, T1 arg1, T2 arg2, T3 arg3)
    {
        TResult result = default;
        await Task.Run(() => result = task(arg1, arg2, arg3));
        onDone?.Invoke(result);
    }
}

The class has methods for taking in a System.Func delegate, a callback method with the return value of the delegate, and then all the arguments for the delegate. It’s worth noting that System.Func can take up to 16 arguments, I only implemented overrides for up to 3 as I feel like that’s enough for proof of concept. I then created a little test script and attached to to a gameobject in the scene:

using System.Threading;
using UnityEngine;

public class Example : MonoBehaviour
{
    private void Start()
    {
        RunOnSeparateThread.Run(SlowTask, OnSlowTaskDone, 10, 1000);
    }

    private void Update()
    {
        //Illustrate that main thread is still running
        transform.Rotate(Vector3.up, Time.deltaTime * 10);
    }
    private void OnSlowTaskDone(string result)
    {
        LogWithThreadId(result);
    }

    private string SlowTask(int count, int wait)
    {
        for (int i = count; i >= 0; i--)
        {
            LogWithThreadId(i);
            Thread.Sleep(wait);
        }
        return "Result: 42";
    }

    private void LogWithThreadId(object content)
    {
        Debug.Log("ThreadId " + Thread.CurrentThread.ManagedThreadId + ":\t" + content);
    }
}

This script just starts a slow method that counts down and writes to the console, by the end the method returns a result that a callback method prints that result to the console. I also made the gameobject rotate in the Update method just to illustrate that the main thread was still running.

Everything seems to be working, but I want to point out that I have only tested this in the Editor on windows so no guarantee that this will work on all platforms

Hello world!

Hello Internet, my name is Lars Hagen. I’m a professional videogame developer. In my spare time I like to experiment with various ideas and concepts related to game development, and my tool of choice is Unity3D. I created this blog to have a central place to show my stuff. Enjoy.