Hello Guest

Author Topic: Our per-object Motion Blur solution: use it if you want!  (Read 15793 times)

TekuStudios

  • 2D Toolkit
  • Full Member
  • *
  • Posts: 177
    • View Profile
    • Teku Studios
Our per-object Motion Blur solution: use it if you want!
« on: June 18, 2013, 10:30:07 am »
So, we've been working on an object-independent motion blur for sprites. We've reached a somehow useful solution, so we are posting it here for you guys, in case that someone needs something similar. It only works with the next 2DToolkit 2.2.

First, the Motion Blur script (component of the object to be blurred):
Code: [Select]
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class MotionBlurHandler : MonoBehaviour
{
        //Will it be a blur over the object, or a trail behind it?
        public bool front = true;
        //How much speed does the object need before blurring?
public float startSpeed = 0.005f;
        //How much time does it take for each 'copy' to fade?
public float copyFadeTime = 0.1f;
//The sprite object that will be duplicated (could be changed to 'tk2dSprite')
public GameObject trailMotionSpriteObject;
        //The script handles this
public Material fadeMaterial;
        //How many copies does the trail create?
public float maxCopies = 5.0f;
        //How many offset between copies?
public float offsetCopies = 0.01f;
        //How much time does it take to each copy to spawn?
public float timeBetweenCopies = 0.02f;
        //The alpha of the first copy
public float initAlpha = 0.5f;
        //The amount of alpha substracted between copies
public float alphaOffset = 0.15f;

private tk2dSprite _mySprite;
private float _timer;
private bool _createNow;
private int _currentCopies;
private int _currentLayer;
private Vector3 _currentOffset;
private float _currentAlpha = 1.0f;
private List<GameObject> _copyList;

void Start()
{
_copyList = new List<GameObject>();
_currentOffset = Vector3.zero;
_currentAlpha = initAlpha;
_mySprite = GetComponent<tk2dSprite>() as tk2dSprite;
}

void Update()
{
if(_timer <= timeBetweenCopies)
{
_createNow = false;
_timer += Time.deltaTime;
}
else
{
_createNow = true;
_timer = 0.0f;
}

if(Mathf.Abs (Vector3.Magnitude(rigidbody.velocity)) > startSpeed )
{
if(_currentCopies < maxCopies)
{
if(_createNow)
{
Vector3 tmpVelocity = rigidbody.velocity;
tmpVelocity.y = 0.0f;
_currentOffset += (Vector3.Normalize(tmpVelocity) * offsetCopies);
_currentAlpha -=  alphaOffset;
Vector3 tmp = Vector3.zero;
tmp.x = transform.localPosition.x-_currentOffset.x;
tmp.y = transform.localPosition.y-_currentOffset.y;
tmp.z = transform.localPosition.z-_currentOffset.z;

GameObject go = Instantiate(trailMotionSpriteObject,transform.localPosition-_currentOffset, transform.rotation) as GameObject;

_copyList.Add(go);
++_currentCopies;
if(front)
++_currentLayer;
else
--_currentLayer;

FadeInTime fit = go.AddComponent("FadeInTime") as FadeInTime;
(go.GetComponent<tk2dSprite>() as tk2dSprite).RenderLayer = _currentLayer;

go.renderer.material = renderer.material;
fit.SetInitAlpha(_currentAlpha, this);
go.transform.parent = gameObject.transform;
}
}
}
else
{
if(_currentCopies != 0)
{
(_copyList[_currentCopies-1].GetComponent<FadeInTime>() as FadeInTime).StartFading(copyFadeTime);
_copyList.RemoveAt(_currentCopies-1);
--_currentCopies;

if(_currentCopies == 0)
{
_currentOffset = Vector3.zero;
_currentAlpha = initAlpha;
_currentLayer = 0;
}
}
}
}

And the other one. This is a script that the previous one adds at runtime to each copy:
Code: [Select]
using UnityEngine;
using System.Collections;

public class FadeInTime : MonoBehaviour
{
public float fadeTime = 0.5f;
public Transform followPosition;
private bool _ready = false;

public tk2dSprite mySprite;
private float _timePassed = 0.0f;
private float _initAlpha;
private MotionBlurHandler _motionHandler;

void Start ()
{
//mySprite = gameObject.GetComponent<tk2dAnimatedSprite>() as tk2dAnimatedSprite;
mySprite = gameObject.GetComponent<tk2dSprite>() as tk2dSprite;
}

void Update ()
{
if(_ready)
{
_timePassed += Time.deltaTime;

if(_timePassed < fadeTime)
{
Color myColor = new Color();
myColor.r = mySprite.color.r;
myColor.g = mySprite.color.g;
myColor.b = mySprite.color.b;
myColor.a = Mathf.Lerp (_initAlpha,0.0f,_timePassed/fadeTime);
mySprite.color = myColor;

//Movement
// delayed follower
/*float distance = Vector3.Distance(transform.position, followPosition.position);

if(distance>0)
{
Vector3 nextPosition = Vector3.Lerp (transform.position, followPosition.position, _timePassed/fadeTime);
transform.position = nextPosition;
}*/
}
else
{
Destroy (gameObject);
}
}
}

public void StartFading(float fTime)
{
fadeTime = fTime;
_ready = true;
}

public void SetInitAlpha(float initAlpha,MotionBlurHandler mh )
{
_initAlpha = initAlpha;
_motionHandler = mh;
//mySprite = gameObject.GetComponent<tk2dAnimatedSprite>() as tk2dAnimatedSprite;
mySprite = gameObject.GetComponent<tk2dSprite>() as tk2dSprite;
Color myColor = new Color();
myColor.r = mySprite.color.r;
myColor.g = mySprite.color.g;
myColor.b = mySprite.color.b;
myColor.a = _initAlpha;
mySprite.color = myColor;

//MeshRenderer m = gameObject. GetComponent<MeshRenderer>() as MeshRenderer;
//renderer.sharedMaterial = mat;
}
}

What this system does is fairly simple: the first script instantiates copies of the original sprite with a very tiny offset, and gives them a certain amount of alpha. This creates an illusion of blurriness over the gameobject, and it only works when it is moving. The second script just handles some fading effect for the copies.

Hope you guys find it useful! :)
« Last Edit: September 01, 2013, 10:53:09 am by TekuStudios »
We are an Indie videogame developer located in Teruel, Spain. A small 6-people team which is currently working on the upcoming 'Candle'.

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #1 on: June 18, 2013, 10:45:31 am »
Thanks for sharing :)

The .RenderLayer property on the sprite isn't available just yet.
It will be soon though, either in 2.1 or 2.2.

TekuStudios

  • 2D Toolkit
  • Full Member
  • *
  • Posts: 177
    • View Profile
    • Teku Studios
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #2 on: June 18, 2013, 10:46:09 am »
Ups. Do you want us to remove it for now?
We are an Indie videogame developer located in Teruel, Spain. A small 6-people team which is currently working on the upcoming 'Candle'.

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #3 on: June 18, 2013, 11:00:43 am »
Nah its fine. If anyone else needs the patch they can have it :)

TekuStudios

  • 2D Toolkit
  • Full Member
  • *
  • Posts: 177
    • View Profile
    • Teku Studios
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #4 on: June 18, 2013, 02:42:25 pm »
Of course, Unikron, if you wish to use or modify these scripts for further iterations of 2DT, feel free to do it :)
We are an Indie videogame developer located in Teruel, Spain. A small 6-people team which is currently working on the upcoming 'Candle'.

napalm44

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #5 on: August 31, 2013, 11:00:18 pm »
Would this work with 2.1 if I simply removed the renderlayer reference?

If so, could you explain how to set this up in more detail? I have tried and am getting no speed blur, just a bunch of clones on top of each other.

Thanks

TekuStudios

  • 2D Toolkit
  • Full Member
  • *
  • Posts: 177
    • View Profile
    • Teku Studios
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #6 on: August 31, 2013, 11:37:47 pm »
It needs the Render Layer property to work correctly, I'm afraid. However, the nex release of 2DT (2.2) is almost here and comes with a final version of that feature.
We are an Indie videogame developer located in Teruel, Spain. A small 6-people team which is currently working on the upcoming 'Candle'.

napalm44

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #7 on: September 01, 2013, 02:22:38 am »
Alright, I just updated to beta 1 2.2, solely so I could use this script :)

Here is what I have done to set it up:

1. Attach the MotionBlurHandler to my player (I want to blur him).
2. Create a prefab of my player sprite with ONLY the stuff necessary to make him a proper sprite (no rigidbody or colliders).
3. Assign that prefab to the property on the MotionBlurHandler script.

WHen I run, this is what I see:

It looks like it is trying to display the entire spritesheet that the clone uses, and each of the clones stays directly overtop of the player (no visible offset). Note: all properties on the motionblurhandler are set to default.

Any idea what might be wrong?

TekuStudios

  • 2D Toolkit
  • Full Member
  • *
  • Posts: 177
    • View Profile
    • Teku Studios
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #8 on: September 01, 2013, 10:52:00 am »
I'm afraid that we didn't set it up for animated sprites, it is only designed for non-animated sprites (e.g. a rock falls off a cliff and you want to blur it when it is moving). The script needs to be tweaked in order to work with animations.

Also, have you added the second script to your project? The first one needs the second one.
« Last Edit: September 01, 2013, 10:54:28 am by TekuStudios »
We are an Indie videogame developer located in Teruel, Spain. A small 6-people team which is currently working on the upcoming 'Candle'.

napalm44

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #9 on: September 01, 2013, 05:28:41 pm »
The sprite that I'm using in the TrailMotionSpriteObject variable is actually not animated, and that is the only sprite that matters right? I say this because don't see any references to the sprite component of the BlurMotionHandler object, aside from class variables that are assigned to but never used.

And yes, I have the FadeInTime script in my project.

Have you successfully gotten the script to work as is? I'm wondering if the version you posted is a bit dated (just looking at some of the commented out code, and class variables that are assigned to but never used)?

TekuStudios

  • 2D Toolkit
  • Full Member
  • *
  • Posts: 177
    • View Profile
    • Teku Studios
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #10 on: September 01, 2013, 06:25:14 pm »
The sprite that I'm using in the TrailMotionSpriteObject variable is actually not animated, and that is the only sprite that matters right?
It depends on that gameObject. It shouldn't have anything besides a tk2dSprite component, otherwise the entire object duplicates and everything goes crazy. What we do is to store each sprite that is going to be duplicated in its own unique prefab. I'll explain this:

We know exactly what objects will have this faked motion blur effect, so let's say that you have a boulder that falls off a cliff and want to blur it. Then you should create an empty gameObject, attach only a tk2dSprite component and give it the exact sprite you want to appear duplicated. So then you store it as a Prefab and assign it to the script's TrailMotionSpriteObject variable through the Inspector.

This is exactly how we do it, it should work perfect if you follow those steps. However, this is just some script we coded months ago and I'm a bit out, if you still experience weird issues I'll take a deep look at it as soon as possible.
We are an Indie videogame developer located in Teruel, Spain. A small 6-people team which is currently working on the upcoming 'Candle'.

napalm44

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #11 on: September 01, 2013, 07:38:21 pm »
Yea, that is what I am doing as well:

1. I have one gameobject that I want to blur. It has a rigidbody, collider, sprite, and sprite animator attached to it. I attach the BlurMotionHandler to the object to it and leave settings as default.
2. I have a prefab of a similar sprite has the following components attached: http://i536.photobucket.com/albums/ff328/reeda1283/ScreenShot2013-09-01at110917AM.png. This is the prefab that s assigned to to the TrailMotionSPriteObject property of the gameobject mentioned in #1

I have even created a brand new simple scene to test this and it doesnt seem to work. The scene contains only a camera, a cube with a collider (which functions as the ground), and a gameobject with a sprite, rigidbody, collider and BlurHandler component attached. The gameobject bounces up and down repeatedly, and although I can see (in the heirarchy) the clones being created as children of the main gameobject, they are not visible at all.

ps Why does the script include this line: tmpVelocity.y = 0.0f; ? Doesn't that mean we will only ever blur along the x-axis?

TekuStudios

  • 2D Toolkit
  • Full Member
  • *
  • Posts: 177
    • View Profile
    • Teku Studios
Re: Our per-object Motion Blur solution: use it if you want!
« Reply #12 on: September 01, 2013, 08:23:39 pm »
You can change the y velocity if you want. We only wanted to blur some things when x != 0. This is not an asset or something like that, just some script we decided to share, so there are some things that we just commented for our purposes.

I think I've located the issue. Please try this: setup a non-animated sprite (not a character, just some static object or item with a single image for sprite), and try to blur it. We didn't code this to blur animated sprites, so I'm afraid that your atlas (which contains all your character frames) is duplicating in full. Try to do this with a single object, I think it will work then.

If you want this to work with characters that have multiple frames, I don't think it will work, unfortunately. But feel free to change whatever you want to accomodate the scripts to your project.
We are an Indie videogame developer located in Teruel, Spain. A small 6-people team which is currently working on the upcoming 'Candle'.