keenanwoodall / Deform

A fully-featured deformer system for Unity that lets you stack effects to animate models in real-time

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error in DeformerUtils.cs/GetMeshToAxisSpace()

albertozafra7 opened this issue · comments

Good morning,
I am currently testing the Deform library for a project and I might have found an error in the GetMeshToAxisSpace() method found in Deform\Code\Runtime\Mesh\Utility\DeformerUtils.cs. The details of the error can be found below in the following sections.
However, keep in mind that I have not determined if its correction would affect negatively any of the default deformers available in the library, in my case it solves the relative distance computation between the deformer and deformable. Nevertheless, it may destroy the rest of the deformers found in the library.

Error Description

More concretely the error is within the calculation of the transformation matrix, as we are aiming to get the transformation matrix that converts the points located in the mesh space to the axis space (that we are going to name mesh_T_axis), it would be necessary to first convert from the local space of the mesh to the world space using its relative transformation matrix (named as mesh_T_world), and later transform the point from the world space to the axis space using another transformation matrix (named as world_T_axis), resulting in the following operation: mesh_T_axis = mesh_T_world * world_T_axis

Nonetheless, what is programmed within the previously mentioned function is represented by the following operation: mesh_T_axis = _world_T_axis * mesh_T_world with the code contained within the method:

/// <summary>
/// Returns a matrix that transform a mesh from local space to a space relative to the axis transform.
/// </summary>
public static Matrix4x4 GetMeshToAxisSpace (Transform axis, Transform mesh)
{
return axis.worldToLocalMatrix * mesh.localToWorldMatrix;
}

Furthermore, I believe that the scale of the axis object is not being used within the current transformation matrix computation, because, despite inverting the multiplication matrix, the results are not the desired ones. Hence, the transformation matrix computation problem can be solved as follows:

/// <summary>
/// Returns a matrix that transform a mesh from local space to a space relative to the axis transform.
/// </summary>
public static Matrix4x4 GetMeshToAxisSpace (Transform axis, Transform mesh)
{
return Matrix4x4.TRS(mesh.position, mesh.rotation, mesh.lossyScale).inverse* Matrix4x4.TRS(axis.position, axis.rotation, axis.lossyScale);
}

How did I found the error and how to reproduce it

As I am currently implementing a custom deformer that behaves similarly to the MagnerDeformer, I was trying to apply a deformation to the vertices that are under a distance threshold to a specific axis. Hence, by debugging the relative distances between the objects I found out that the computed distance is not the real distance. The custom deformer script and the sample scene are both attached to the report.
DeformError.zip

On the other hand, some screenshots of the reproduced problem can be found below::
Incorrect Behaviour
Incorrect_Behaviour
Desired Behaviour
Correct_Behaviour

The scale should be a part of the transformation matrices used in GetMeshToAxisSpace() since they're 4x4 matrices. To confirm this I made a quick test deformer that sets the color of any vertices within 1 unit of the deformer to red and it appears to be correctly affected by scale.

Unity_gC6YE57Z0C

using UnityEngine;
using Deform;
using Unity.Jobs;
using Unity.Collections;
using Unity.Mathematics;

[Deformer(Category = Category.Normal, Name = "Vertex Color Sphere", Type = typeof(VertexColorSphereDeformer))]
public class VertexColorSphereDeformer : Deformer
{
    public Color color = Color.red;

    public override DataFlags DataFlags => DataFlags.Colors;

    void OnDrawGizmosSelected() {
        Gizmos.matrix = transform.localToWorldMatrix;
        Gizmos.DrawWireSphere(Vector3.zero, 1f);
    }

    public override JobHandle Process(MeshData data, JobHandle dependency = default)
    {
        return new VertexColorSphereJob {
            color = new float4(color.r, color.g, color.b, color.a),
            transform = DeformerUtils.GetMeshToAxisSpace(transform, data.Target.GetTransform()),
            positions = data.DynamicNative.VertexBuffer,
            colors = data.DynamicNative.ColorBuffer
        }.Schedule(data.Length, DEFAULT_BATCH_COUNT, dependency);
    }

    public struct VertexColorSphereJob : IJobParallelFor
    {
        public float4 color;
        public float4x4 transform;
        [ReadOnly]
        public NativeArray<float3> positions;
        public NativeArray<float4> colors;
        public void Execute(int index)
        {
            var point = math.mul(transform, new float4(positions[index], 1f)).xyz;

            if (math.length(point) < 1) 
            {
                colors[index] = color;
            }
        }
    }
}

Using lossy scale would not quite be the same since the scale is lossy and doesn't correctly represent the scale in some situations.

Does that seem right or am I misunderstanding the issue?

Good Afternoon,
You are right, I was talking about the computation of the transformation matrix contained within the DeformerUtils.GetMeshToAxisSpace() method, which I thought was incorrect due to the order of the matrix multiplication, that is programmed as:

mesh_T_axis = world_T_axis * mesh_T_world

Instead of :

mesh_T_axis = mesh_T_world * world_T_axis

Nevertheless, after testing the deformer that you sent me I found out that it was my fault, as I was computing incorrectly the distance between the deformer and the deformable. Hence, the aforementioned (DeformerUtils.GetMeshToAxisSpace()) method works perfectly.

Thank you very much for your help,
Alberto