Everyday Flash

Creative use of technology // A blog about 3D Flash and Actionscript by Bartek Drozdz

Modifiers in Unity3D

Ringo from FlashBookmarks asked me if there were modifiers similar to AS3Dmod in Unity. I searched for something similar some time ago, but didn't find anything interesting.

However, when I was starting C# scripting, I ported two of the modifiers from AS3Dmod - Bend and Twist. So I thought to share them with everyone. Don't expect much, it's not the full library, just two classes. If I have some free time, I'll look into how to implement stacking, since for the moment you cannot apply two modifiers to the same object (the second one won't have any effect).

To play around with them grab this package and import it into Unity. Keep in mind that the modifiers work at runtime, so you won't see any effects in the editor until you run the game. If you want to animate them, just add another script that will have a reference to the modifier instance and change it's properties at each Update() call.

If you are interested in this kind of "bricolage" with 3D geometry, I recommend to take a look at the Procedural Examples project provided by Unity. You will find there some highly interesting samples like dynamic extrudes or perlin noise. It's a great starting point to explore runtime geometry transformation.

Of course, take a look into the sources of the modifiers too! You'll see how simple it is to access the geometry at runtime and do some modifications. Basically it goes like this:

C#:
  1. MeshFilter mfilter  = GetComponent(typeof(MeshFilter)) as MeshFilter;
  2. mesh = mfilter.mesh;
  3. Vector3[] vs = mesh.vertices;
  4. int vc = vs.Length;
  5. for (int i = 0; i <vc; i++) {
  6.   // Modify your vertices here
  7. }
  8. mesh.vertices = vs;
  9. mesh.RecalculateNormals();

Things worth notice: In Unity a vertex is just an instance of Vector3 - there isn't any special class for this, as in Flash-based 3D engines.

You can see a bit of the casting-drama I need to do (lines 1-2) to get to the object holding the actual geometry information (Mesh). That's a bit annoying in C#, with JS that code would be more readable. Anyway, it's better to make that only once, in Start() and not at every Update().

To get correct lightning effects on the materials, do not forget to call mesh.RecalculateNormals() after you've modified the positions of the vertices.

If you want to modify your mesh continuously (i.e. to animate it) it's necessary to keep the original array of vertices, because the code above overwrites the original positions. Take a look at the source code in the package to see how I did it.

That's all for now, hope you enjoy it!

Categories: 3D, Actionscript 3, CSharp, Tools, Unity3d, as3dmod

comments RSS

5 Comments

  1. Nice work Bartek! Excellent to see you’ve been able to port some code from AS3 to C# for use in Unity.

  2. Nice post. For full animation control – what about animating via the animation view in stead of scripted animation? Expose relevant properties in your script and curves away!

  3. @AngryAnt Thanks for the tip! So far I didn’t have time to check the new animation editor, but this is a great idea.

    UPDATE Nov 17 2009. I checked it with the animation editor and it works great (no code changes needed) Thanks for the tip!

  4. Blenderificus

    thank you soooo very much for porting some of your modifiers to unity from flash. If you ever get the time, I truly look forward to you porting the rest over :-) thanks again!

  5. interesting…
    Actually you can combine this with Ani.Mate, a tween class for Unity.

    since my C is not very sharp, i took out some code from GUIManager, to achive the effekt. Of course you need Ani.Mate. Thats only 2 Scripts within the GuiManager Package.

    I am using that one for iPhone Development.
    so, Check it out:

    using UnityEngine;
    using System.Collections;

    [RequireComponent (typeof(MeshFilter))]
    public class Bend : MonoBehaviour {

    private Vector3[] original;
    private Mesh mesh;
    private Animator pAnimator; //Animator script component

    public float force = 3.0f;

    /*————————————-Unity Methods————————————-*/
    void Awake ()
    {

    pAnimator = (Animator) gameObject.GetComponent(typeof(Animator));

    }

    void Start() {

    MeshFilter mfilter = GetComponent(typeof(MeshFilter)) as MeshFilter;
    mesh = mfilter.mesh;
    original = mesh.vertices;
    startUnwrap();
    }

    void startUnwrap() {
    AnimateTo(1f, null, null, null, “force”, -0.5f, “easing”, Ani.AnimationEasingType.SinusoidalEasing, “direction” , Ani.EasingType.InOut);
    AnimateTo(0.5f, null, null, null, “force”, 0.3f, “easing”, Ani.AnimationEasingType.SinusoidalEasing, “direction” , Ani.EasingType.InOut);
    AnimateTo(1.5f, null, null, null, “force”, 0f, “easing”, Ani.AnimationEasingType.ElasticEasing, “direction” , Ani.EasingType.Out);

    StartAnimation(Ani.Animate.OneShot, null, null, null);

    }

    void Update() {
    if(force == 0.0f) {
    mesh.vertices = original;
    mesh.RecalculateNormals();
    return;
    }

    Vector3[] vs = mesh.vertices;
    int vc = vs.Length;

    float radius = 1 / force;

    for (int i = 0; i < vc; i++) {
    Vector3 v = copy(original[i]);

    float l = v.z;
    float d = v.x;

    float fa = (Mathf.PI / 2) + (force * l);

    float op = Mathf.Sin(fa) * (radius + d);
    float ow = Mathf.Cos(fa) * (radius + d);

    vs[i].z = -ow;
    vs[i].x = op – radius;
    }

    mesh.vertices = vs;
    mesh.RecalculateNormals();
    }

    private Vector3 copy(Vector3 orig) {
    return new Vector3(orig.x, orig.y, orig.z);
    }

    //Mode To
    public void AnimateTo (float Duration, GameObject CallbackObj, string CallbackMsg, object CallbackParams, params object[] args)
    {
    //Wrapper function
    pAnimator.AnimateTo(this, Duration, CallbackObj, CallbackMsg, CallbackParams, args);
    }

    //Mode From
    public void AnimateFrom (float Duration, GameObject CallbackObj, string CallbackMsg, object CallbackParams, params object[] args)
    {
    //Wrapper function
    pAnimator.AnimateFrom(this, Duration, CallbackObj, CallbackMsg, CallbackParams, args);
    }

    //Mode By
    public void AnimateBy (float Duration, GameObject CallbackObj, string CallbackMsg, object CallbackParams, params object[] args)
    {
    //Wrapper function
    pAnimator.AnimateBy(this, Duration, CallbackObj, CallbackMsg, CallbackParams, args);
    }

    //Start animation sequence
    public void StartAnimation (Ani.Animate AnimateMode, GameObject CallbackObj, object CallbackMsg, object CallbackParams)
    {
    //Wrapper function
    switch (AnimateMode)
    {
    case Ani.Animate.OneShot:
    pAnimator.StartAnimation(Ani.Animate.OneShot, CallbackObj, CallbackMsg, CallbackParams);
    break;
    case Ani.Animate.Loop:
    pAnimator.StartAnimation(Ani.Animate.Loop, CallbackObj, CallbackMsg, CallbackParams);
    break;
    }
    }

    //Stop animation sequence
    public void StopAnimation ()
    {
    //Wrapper function
    pAnimator.StopAnimation();
    }

    //Clear animation queue
    public void ClearAnimation ()
    {
    //Wrapper function
    pAnimator.ClearAnimation();
    }

    }

Leave a comment



  • FITC10