From 8dbec584fc43e61bd7285358084d43685ab31297 Mon Sep 17 00:00:00 2001 From: httpdigest Date: Sun, 23 Jul 2023 18:25:32 +0200 Subject: [PATCH] Optimize Vector4d matrix multiply methods taking into account matrix properties (#337) - mul() now takes into account identity, translation and affine - new method mulTranslation() when assuming translation - new method mulGeneric() when not assuming (and also not testing for) properties - mulProject() now takes into account identity, translation and affine - new method mulProjectTranslation() when assuming translation - new method mulProjectAffine() when assuming affine - new method mulProjectGeneric() when not assuming (and also not testing for) properties --- src/main/java/org/joml/Vector4d.java | 126 ++++++++++++++-- src/main/java/org/joml/Vector4dc.java | 199 +++++++++++++++++++++++++- 2 files changed, 308 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/joml/Vector4d.java b/src/main/java/org/joml/Vector4d.java index 50833e13..ab0be3a5 100644 --- a/src/main/java/org/joml/Vector4d.java +++ b/src/main/java/org/joml/Vector4d.java @@ -1091,13 +1091,15 @@ public Vector4d mul(Vector4fc v, Vector4d dest) { * @return this */ public Vector4d mul(Matrix4dc mat) { - if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0) - return mulAffine(mat, this); - return mulGeneric(mat, this); + return mul(mat, this); } - public Vector4d mul(Matrix4dc mat, Vector4d dest) { - if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0) + int prop = mat.properties(); + if ((prop & Matrix4dc.PROPERTY_IDENTITY) != 0) + return dest.set(this); + if ((prop & Matrix4dc.PROPERTY_TRANSLATION) != 0) + return mulTranslation(mat, dest); + if ((prop & Matrix4dc.PROPERTY_AFFINE) != 0) return mulAffine(mat, dest); return mulGeneric(mat, dest); } @@ -1122,6 +1124,23 @@ public Vector4d mulTranspose(Matrix4dc mat, Vector4d dest) { return mulGenericTranspose(mat, dest); } + public Vector4d mulTranslation(Matrix4dc mat, Vector4d dest) { + double x = this.x, y = this.y, z = this.z, w = this.w; + dest.x = Math.fma(mat.m30(), w, x); + dest.y = Math.fma(mat.m31(), w, y); + dest.z = Math.fma(mat.m32(), w, z); + dest.w = w; + return dest; + } + public Vector4d mulTranslation(Matrix4fc mat, Vector4d dest) { + double x = this.x, y = this.y, z = this.z, w = this.w; + dest.x = Math.fma(mat.m30(), w, x); + dest.y = Math.fma(mat.m31(), w, y); + dest.z = Math.fma(mat.m32(), w, z); + dest.w = w; + return dest; + } + public Vector4d mulAffine(Matrix4dc mat, Vector4d dest) { double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))); double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))); @@ -1133,7 +1152,19 @@ public Vector4d mulAffine(Matrix4dc mat, Vector4d dest) { return dest; } - private Vector4d mulGeneric(Matrix4dc mat, Vector4d dest) { + /** + * Multiply the given matrix mat with this vector. + *

+ * This method does not make any assumptions or optimizations about the properties of the specified matrix. + * + * @param mat + * the matrix whose transpose to multiply the vector with + * @return this + */ + public Vector4d mulGeneric(Matrix4dc mat) { + return mulGeneric(mat, this); + } + public Vector4d mulGeneric(Matrix4dc mat, Vector4d dest) { double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))); double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))); double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))); @@ -1216,17 +1247,19 @@ public Vector4d mul(Matrix4x3fc mat, Vector4d dest) { * @return this */ public Vector4d mul(Matrix4fc mat) { - if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0) - return mulAffine(mat, this); - return mulGeneric(mat, this); + return mul(mat, this); } - public Vector4d mul(Matrix4fc mat, Vector4d dest) { - if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0) + int prop = mat.properties(); + if ((prop & Matrix4fc.PROPERTY_IDENTITY) != 0) + return dest.set(this); + if ((prop & Matrix4fc.PROPERTY_TRANSLATION) != 0) + return mulTranslation(mat, dest); + if ((prop & Matrix4fc.PROPERTY_AFFINE) != 0) return mulAffine(mat, dest); return mulGeneric(mat, dest); } - private Vector4d mulAffine(Matrix4fc mat, Vector4d dest) { + public Vector4d mulAffine(Matrix4fc mat, Vector4d dest) { double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))); double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))); double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))); @@ -1236,7 +1269,7 @@ private Vector4d mulAffine(Matrix4fc mat, Vector4d dest) { dest.w = w; return dest; } - private Vector4d mulGeneric(Matrix4fc mat, Vector4d dest) { + public Vector4d mulGeneric(Matrix4fc mat, Vector4d dest) { double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))); double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))); double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))); @@ -1248,7 +1281,7 @@ private Vector4d mulGeneric(Matrix4fc mat, Vector4d dest) { return dest; } - public Vector4d mulProject(Matrix4dc mat, Vector4d dest) { + public Vector4d mulProjectGeneric(Matrix4dc mat, Vector4d dest) { double invW = 1.0 / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w))); double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW; double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW; @@ -1260,6 +1293,50 @@ public Vector4d mulProject(Matrix4dc mat, Vector4d dest) { return dest; } + public Vector4d mulProjectTranslation(Matrix4dc mat, Vector4d dest) { + double invW = 1.0 / w; + double rx = Math.fma(mat.m00(), x, mat.m30() * w) * invW; + double ry = Math.fma(mat.m11(), y, mat.m31() * w) * invW; + double rz = Math.fma(mat.m22(), z, mat.m32() * w) * invW; + dest.x = rx; + dest.y = ry; + dest.z = rz; + dest.w = 1.0; + return dest; + } + public Vector3d mulProjectTranslation(Matrix4dc mat, Vector3d dest) { + double invW = 1.0 / w; + double rx = Math.fma(mat.m00(), x, mat.m30() * w) * invW; + double ry = Math.fma(mat.m11(), y, mat.m31() * w) * invW; + double rz = Math.fma(mat.m22(), z, mat.m32() * w) * invW; + dest.x = rx; + dest.y = ry; + dest.z = rz; + return dest; + } + + public Vector4d mulProjectAffine(Matrix4dc mat, Vector4d dest) { + double invW = 1.0 / w; + double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW; + double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW; + double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))) * invW; + dest.x = rx; + dest.y = ry; + dest.z = rz; + dest.w = 1.0; + return dest; + } + public Vector3d mulProjectAffine(Matrix4dc mat, Vector3d dest) { + double invW = 1.0 / w; + double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW; + double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW; + double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))) * invW; + dest.x = rx; + dest.y = ry; + dest.z = rz; + return dest; + } + /** * Multiply the given matrix mat with this vector, perform perspective division. * @@ -1270,8 +1347,29 @@ public Vector4d mulProject(Matrix4dc mat, Vector4d dest) { public Vector4d mulProject(Matrix4dc mat) { return mulProject(mat, this); } + public Vector4d mulProject(Matrix4dc mat, Vector4d dest) { + int prop = mat.properties(); + if ((prop & Matrix4dc.PROPERTY_IDENTITY) != 0) + return dest.set(this); + if ((prop & Matrix4dc.PROPERTY_TRANSLATION) != 0) + return mulProjectTranslation(mat, dest); + if ((prop & Matrix4dc.PROPERTY_AFFINE) != 0) + return mulProjectAffine(mat, dest); + return mulProjectGeneric(mat, dest); + } + public Vector3d mulProject(Matrix4dc mat, Vector3d dest) { + int prop = mat.properties(); + if ((prop & Matrix4dc.PROPERTY_IDENTITY) != 0) + return dest.set(this); + if ((prop & Matrix4dc.PROPERTY_TRANSLATION) != 0) + return mulProjectTranslation(mat, dest); + if ((prop & Matrix4dc.PROPERTY_AFFINE) != 0) + return mulProjectAffine(mat, dest); + return mulProjectGeneric(mat, dest); + } + public Vector3d mulProjectGeneric(Matrix4dc mat, Vector3d dest) { double invW = 1.0 / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w))); double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW; double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW; diff --git a/src/main/java/org/joml/Vector4dc.java b/src/main/java/org/joml/Vector4dc.java index 4c6dd601..349f0382 100644 --- a/src/main/java/org/joml/Vector4dc.java +++ b/src/main/java/org/joml/Vector4dc.java @@ -407,10 +407,45 @@ public interface Vector4dc { */ Vector4d mul(Matrix4fc mat, Vector4d dest); + /** + * Multiply the given matrix mat with this vector and store the result in dest. + *

+ * This method does not make any assumptions or optimizations about the properties of the specified matrix. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * + * @param mat + * the matrix whose transpose to multiply the vector with + * @param dest + * the destination vector to hold the result + * @return dest + */ + Vector4d mulGeneric(Matrix4dc mat, Vector4d dest); + + /** + * Multiply the given matrix mat with this vector and store the result in dest. + *

+ * This method does not make any assumptions or optimizations about the properties of the specified matrix. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * + * @param mat + * the matrix whose transpose to multiply the vector with + * @param dest + * the destination vector to hold the result + * @return dest + */ + Vector4d mulGeneric(Matrix4fc mat, Vector4d dest); + /** * Multiply the transpose of the given matrix mat with this vector and store the result in * dest. - * + *

+ * Note that this method performs the operation M^T * this, where M is the provided matrix + * and thus interprets this as a column vector. + * * @param mat * the matrix whose transpose to multiply the vector with * @param dest @@ -420,9 +455,48 @@ public interface Vector4dc { Vector4d mulTranspose(Matrix4dc mat, Vector4d dest); /** - * Multiply the given affine matrix mat with this Vector4d and store the result in + * Multiply the given matrix mat, which is assumed to only contain translation, with this vector + * and store the result in dest. + *

+ * This method only works if the given matrix _only_ represents a translation. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * + * @param mat + * the affine matrix to multiply the vector with + * @param dest + * the destination vector to hold the result + * @return dest + */ + Vector4d mulTranslation(Matrix4dc mat, Vector4d dest); + + /** + * Multiply the given matrix mat, which is assumed to only contain translation, with this vector + * and store the result in dest. + *

+ * This method only works if the given matrix _only_ represents a translation. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * + * @param mat + * the affine matrix to multiply the vector with + * @param dest + * the destination vector to hold the result + * @return dest + */ + Vector4d mulTranslation(Matrix4fc mat, Vector4d dest); + + /** + * Multiply the given affine matrix mat with this vector and store the result in * dest. - * + *

+ * This method only works if the given matrix _only_ represents an affine transformation. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * * @param mat * the affine matrix to multiply the vector with * @param dest @@ -431,6 +505,23 @@ public interface Vector4dc { */ Vector4d mulAffine(Matrix4dc mat, Vector4d dest); + /** + * Multiply the given affine matrix mat with this vector and store the result in + * dest. + *

+ * This method only works if the given matrix _only_ represents an affine transformation. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * + * @param mat + * the affine matrix to multiply the vector with + * @param dest + * the destination vector to hold the result + * @return dest + */ + Vector4d mulAffine(Matrix4fc mat, Vector4d dest); + /** * Multiply the transpose of the given affine matrix mat with this vector and store the result in * dest. @@ -478,6 +569,108 @@ public interface Vector4dc { */ Vector3d mulProject(Matrix4dc mat, Vector3d dest); + /** + * Multiply the given matrix mat with this vector, perform perspective division + * and store the (x, y, z) result in dest. + *

+ * This method does not make any assumptions or optimizations about the properties of the specified matrix. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * + * @param mat + * the matrix to multiply this vector by + * @param dest + * will hold the result + * @return dest + */ + Vector3d mulProjectGeneric(Matrix4dc mat, Vector3d dest); + + /** + * Multiply the given matrix mat with this vector, perform perspective division + * and store the result in dest. + *

+ * This method does not make any assumptions or optimizations about the properties of the specified matrix. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * + * @param mat + * the matrix to multiply this vector by + * @param dest + * will hold the result + * @return dest + */ + Vector4d mulProjectGeneric(Matrix4dc mat, Vector4d dest); + + /** + * Multiply the given matrix mat, which is assumed to only contain translation, with this vector, + * perform perspective division and store the (x, y, z) result in dest. + *

+ * This method only works if the given matrix _only_ represents a translation. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * + * @param mat + * the matrix to multiply this vector by + * @param dest + * will hold the result + * @return dest + */ + Vector3d mulProjectTranslation(Matrix4dc mat, Vector3d dest); + + /** + * Multiply the given matrix mat, which is assumed to only contain translation, + * with this vector, perform perspective division and store the result in dest. + *

+ * This method does not make any assumptions or optimizations about the properties of the specified matrix. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * + * @param mat + * the matrix to multiply this vector by + * @param dest + * will hold the result + * @return dest + */ + Vector4d mulProjectTranslation(Matrix4dc mat, Vector4d dest); + + /** + * Multiply the given affine matrix mat, with this vector, + * perform perspective division and store the (x, y, z) result in dest. + *

+ * This method only works if the given matrix _only_ represents an affine transformation. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * + * @param mat + * the matrix to multiply this vector by + * @param dest + * will hold the result + * @return dest + */ + Vector3d mulProjectAffine(Matrix4dc mat, Vector3d dest); + + /** + * Multiply the given affine matrix mat, with this vector, + * perform perspective division and store the result in dest. + *

+ * This method only works if the given matrix _only_ represents an affine transformation. + *

+ * Note that this method performs the operation M * this, where M is the provided matrix + * and thus interprets this as a column vector. + * + * @param mat + * the matrix to multiply this vector by + * @param dest + * will hold the result + * @return dest + */ + Vector4d mulProjectAffine(Matrix4dc mat, Vector4d dest); + /** * Add the component-wise multiplication of this * a to b * and store the result in dest.