Antoshidza / NSprites-Foundation

Basic assets for working with NSprites package
MIT License
65 stars 17 forks source link

Update transform system to allow for rotations #3

Closed JeroenoBoy closed 1 year ago

JeroenoBoy commented 1 year ago
Antoshidza commented 1 year ago

Ok, thank you for that brilliant work. Will merge it after finish my refactoring branch where I've reworked authoring components to be more flexible (+ some minor bug fixes).

Antoshidza commented 1 year ago

Is it problematic to split LocalTransform2D to 3 independent components Translation / Rotation / Scale? Asking because I find solid TRS component is not very handy in case where I want to change the position of entity from EntityCommandBuffer or from ComponentLookup without erasing whole LocalTransform2D or reading it's value to save it's rotation and scale.

JeroenoBoy commented 1 year ago

Yes, that is a required component for this way of handling positions. This component gets updates via the transform system and should not be manually updated. Use LocalToWorld2D to update the positions of an entity

JeroenoBoy commented 1 year ago

In your use case I think you want seperate components for the L2W? Never really required it to have seperate components myself though

Antoshidza commented 1 year ago

Yes, that is a required component for this way of handling positions. This component gets updates via the transform system and should not be manually updated. Use LocalToWorld2D to update the positions of an entity

Can you explain me how your implementation works? Like in unity's transform we have TRS components + LocalToWorld and LocalToParent matrices. And all of this can be manually updated.

Antoshidza commented 1 year ago

I'm sorry, I was a little bit out of date with current unity's transforms implementation. I've read docs and as I understand both LocalToWorld and LocalTransform should be editable at runtime.

And it also seems like LocalTransform is a preferred way to do translation / etc when you don't know your entity place at hierarchy.

I even see methods like Rotate and Translate for LocalTransform2D, so it definitely should be editable.

However I see that unity no longer have TRS components and there is solid LocalTransform component. It is a bit conflicting with performance in my mind like when I want to read only position I also load float4 and float3 for every entity. And I guess in 95% cases we really need only position.

Antoshidza commented 1 year ago

Also as I can see despite we are in 2D space we still use 4x4 matrix passed to shader. And what is optimized is LocalTransform2D which uses float2 properties instead of float3 as well as LocalToWorldSystem which operates with this 2D version of LocalTransform.

So this is quite the same implementation as a built-in one. Is this right?

JeroenoBoy commented 1 year ago

Yes, that is correct. I just copied and pasted unity's version, then making it all 2d, then making it work with NSprites-foundation

Antoshidza commented 1 year ago

There is some kind of problem with culling process. It seems like sprite gets culled every time it is NOT fully on screen. Also I doubt 2D rectangle bounds still can fully work because now we have full 3D transform matrix.

Antoshidza commented 1 year ago

Wow it was hard! There was a bunch of problems I believe I've solved:

So Bounds2D.From now looks this and package now have Bounds2DDebugSystem which draws where bounds are.

public static Bounds2D From(in LocalToWorld2D ltw, in Scale2D size, in Pivot pivot)
{
    var rotation = MathHelper.euler(ltw.Rotation).z;
    var scale = ltw.Scale * size.value;
    var localCenter= -scale * pivot.value + scale * .5f;

    var sin = math.sin(rotation);
    var cos = math.cos(rotation);

    static float2 RotateScale2D(in float sin, in float cos, in float2 v)
    {
        var abssin = math.abs(sin);
        var abscos = math.abs(cos);
        return new float2(v.x * abscos + v.y * abssin, v.x * abssin + v.y * abscos);
    }
    static float2 RotateFloat2(in float sin, in float cos, in float2 v)
        => new(v.x * cos - v.y * sin, v.x * sin + v.y * cos);

    var adjustedScale = RotateScale2D(sin, cos, scale);
    var position = ltw.Position + RotateFloat2(sin, cos, localCenter);

    return new Bounds2D(position, adjustedScale);
}

(the round is a actual position of a sprite) image