Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mat4 multiply #8

Open
xposure opened this issue Feb 8, 2017 · 4 comments
Open

mat4 multiply #8

xposure opened this issue Feb 8, 2017 · 4 comments

Comments

@xposure
Copy link

xposure commented Feb 8, 2017

Any chance of adding mat4 multiplication for vec2/3 and returning a vec2/3?

This for example is taken for Axiom (orge3d port)...

public static vec3 operator *(mat4 matrix, vec3 vector)
{
    vec3 result = new vec3();

    float inverseW = 1.0f / (matrix.m30 * vector.x + matrix.m31 * vector.y + matrix.m32 * vector.z + matrix.m33);

    result.x = ((matrix.m00 * vector.x) + (matrix.m01 * vector.y) + (matrix.m02 * vector.z) + matrix.m03) * inverseW;
    result.y = ((matrix.m10 * vector.x) + (matrix.m11 * vector.y) + (matrix.m12 * vector.z) + matrix.m13) * inverseW;
    result.z = ((matrix.m20 * vector.x) + (matrix.m21 * vector.y) + (matrix.m22 * vector.z) + matrix.m23) * inverseW;

    return result;
}

EDIT: This is what I came up with from looking at glm code and comparing to monogame

        /// <summary>
        /// Executes a matrix-vector-multiplication.
        /// </summary>
        public static vec2 operator *(mat4 m, vec2 v) => new vec2((v.x * m.m00) + (v.y * m.m10) + m.m30, (v.x * m.m01) + (v.y * m.m11) + m.m31);

        /// <summary>
        /// Executes a matrix-vector-multiplication.
        /// </summary>
        public static vec3 operator *(mat4 m, vec3 v) => new vec3(((m.m00 * v.x + m.m10 * v.y) + (m.m20 * v.z + m.m30)), ((m.m01 * v.x + m.m11 * v.y) + (m.m21 * v.z + m.m31)), ((m.m02 * v.x + m.m12 * v.y) + (m.m22 * v.z + m.m32)));
@xposure
Copy link
Author

xposure commented Feb 8, 2017

I implemented this myself in what I would call a very hacky way, but putting it here in case anyone else is interested or is looking for a foundation to do it the right way.

Added to MatrixType.cs right before matrix-vector-multiplication

                    if (Columns == 4 && Rows == 4)
                    {
                        var cols = new int[] { 0, 1, 3 };
                        foreach (var line in "Executes a matrix-vector-multiplication.".AsComment()) yield return line;
                        yield return string.Format("public static {0} operator*({1} m, {2} v) => new {0}({3});", BaseType.Prefix + "vec" + 2, NameThat, BaseType.Prefix + "vec" + 2,
                            2.ForIndexUpTo(r => cols.ForEach(c => c < 2 ? "m.m" + c + r + " * v." + "xyzw"[c] : "m.m" + c + r).Aggregated(" + ")).CommaSeparated());

                        foreach (var line in "Executes a matrix-vector-multiplication.".AsComment()) yield return line;
                        yield return string.Format("public static {0} operator*({1} m, {2} v) => new {0}({3});", BaseType.Prefix + "vec" + 3, NameThat, BaseType.Prefix + "vec" + 3,
                            3.ForIndexUpTo(r => Columns.ForIndexUpTo(c => c < 3 ? "m.m" + c + r + " * v." + "xyzw"[c] : "m.m" + c + r).Aggregated(" + ")).CommaSeparated());
                    }

Looking at monogame, vec2 needs to skip m2X, I couldn't figure out a way to do that with ForIndexUpTo and I didn't want to modify Aggregrated to skip empty strings so I choose to add this method to Extensions.cs

        public static IEnumerable<T> ForEach<T>(this int[] n, Func<int, T> f)
        {
            for (var i = 0; i < n.Length; i++)
                yield return f(n[i]);
        }

@Philip-Trettner
Copy link
Owner

Unfortunately, it is ambiguous how to implement that.

if you have M * new vec2(x,y) it could be
A: M * new vec4(x,y,0,1) (treating the vector as a point), or
B: M * new vec4(x,y,0,0) (treating the vector as a vector).

Both are valid interpretations, so I'm a bit reluctant to decide for either for operator*.

However, we can discuss about functions that do this, e.g. Mat4.TransformPoint and Mat4.TransformVector.

@xposure
Copy link
Author

xposure commented Feb 9, 2017

That makes sense. One question, are you trying to keep this close to glm? I have other things I have changed and was wondering if its something you would want to implement.

For example I added perpendicular to 2d after // angle

            // perpendicular 2d
            if (Components == 2)
            {
                if (BaseType.IsSigned)
                {
                    yield return new Property("Perpendicular", this)
                    {
                        GetterLine = "new " + Name + "(y, -x)",
                        Comment = "Returns a perpendicular vector."
                    };
                }
                else if (BaseType.IsBool)
                {
                    yield return new Property("Perpendicular", this)
                    {
                        GetterLine = "new " + Name + "(y, !x)",
                        Comment = "Returns a perpendicular vector."
                    };
                }
            }

@Philip-Trettner
Copy link
Owner

That's a good one, I think I'll add that.

I don't want to be as close as possible to glm, it's more like the "glm spirit in C#".

That means that everything glm and GlmSharp have in common should behave similar/the same. Otherwise I'll try to extrapolate the intent of glm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants