keenanwoodall / Deform

A fully-featured deformer system for Unity that lets you stack effects to animate models in real-time
MIT License
3.29k stars 225 forks source link

How to move an object Transform (no mesh) ? #23

Closed nathanvogel closed 5 years ago

nathanvogel commented 5 years ago

Hi, I would like to transform the position + rotation of a GameObject (a camera) along with the deformation of a mesh. Is there a way to do that?

Thank you for this ++ asset!

keenanwoodall commented 5 years ago

I'm not sure if I know exactly what you're trying to do, but if you want an effect to follow the camera perfectly you could just make the deformer object a child of the camera. Feel free to explain your goal further if I'm misunderstanding :+1:

nathanvogel commented 5 years ago

Sorry I'll try to be clearer 👍 I want to do something like this: example-bend

black = before red = after deform

The line is the deformed mesh and the camera is another independant object.

keenanwoodall commented 5 years ago

I gotcha. So the camera needs to be deformed as if it's a vertice on the mesh. There isn't currently a way to do this with deform, but I'll look into parenting objects to vertices as I think that's a useful feature. When I get the time I'll try and make a hacky temporary script you can use in the meantime.

nathanvogel commented 5 years ago

Awesome! Thanks for the help :)

keenanwoodall commented 5 years ago

@nathanvogel Sorry for the delay. I threw together a quick and dirty script (emphasis on dirty). It's not super easy to use but, just drop it on an object, give it a reference to a Deformable component, and increase the triangle index property until the triangle you want is selected. (sorry I know that's lame) The object will be pinned to that triangle. Do note: I didn't add control for changing rotation/position offsets. They shouldn't be hard to add, but I figured it'd be easier to attach an empty object to the triangle and then add the camera as a child. Then you can change the offsets via the scene transform handles rather than fiddling with offsets in the inspector.

I needed to expose the mesh data to be able to access the triangles (without copying the vertex array every frame). Those changes are currently only on the develop branch but will probably make their way into the next release. You can apply the changes to your installation of Deform manually or work off of the linked commit.

Here's the script:

using UnityEngine;
using Deform;

[ExecuteAlways]
public class AttachToTriangle : MonoBehaviour
{
    public struct Triangle
    {
        public Vector3 a, b, c;

        public void Multiply(Matrix4x4 m)
        {
            a = m.MultiplyPoint3x4(a);
            b = m.MultiplyPoint3x4(b);
            c = m.MultiplyPoint3x4(c);
        }

        public Vector3 GetPosition() => (a + b + c) / 3f;
        public Quaternion GetRotation() => Quaternion.LookRotation((c - b).normalized, (b - a).normalized);
    }

    public Deformable target;
    public int triangleIndex;
#if UNITY_EDITOR
    [SerializeField] private bool drawTriangle = true;
#endif
    private void Update()
    {
        if (target == null) 
            return;

        var data = target.GetDynamicManagedMeshData();
        if (data == null) 
           return;

        triangleIndex = Mathf.Clamp(triangleIndex, 0, data.Triangles.Length / 3);

        var triangle = GetTriangle(data, triangleIndex);

        triangle.Multiply(target.transform.localToWorldMatrix);
#if UNITY_EDITOR
        if (drawTriangle)
            DrawTriangle(triangle);
#endif

        var newPosition = triangle.GetPosition();
        var newRotation = triangle.GetRotation();

        transform.SetPositionAndRotation(newPosition, newRotation);
    }

    public Triangle GetTriangle(ManagedMeshData data, int triangleIndex)
    {
        var vertexIndex = triangleIndex * 3;
        var triangles = data.Triangles;
        var vertices = data.Vertices;
        return new Triangle
        {
            a = vertices[triangles[vertexIndex + 0]],
            b = vertices[triangles[vertexIndex + 1]],
            c = vertices[triangles[vertexIndex + 2]]
        };
    }

    private void DrawTriangle(Triangle triangle)
    {
        Debug.DrawLine(triangle.a, triangle.b);
        Debug.DrawLine(triangle.b, triangle.c);
        Debug.DrawLine(triangle.c, triangle.a);
    }
}

2019-10-26_12-45-59

nathanvogel commented 5 years ago

Super cool! Thanks a lot, I really appreciate and I'll try it this week :)

nathanvogel commented 4 years ago

Hey! I'm working on another part of the project these days, but I tried your script and just wanted to give you some feedback:

Thanks again!

keenanwoodall commented 4 years ago

That's great to hear! 👍