Help with Matrice transformations #3643
-
Hi, I'm completely moving Sceneform to a from scratch Kotlin version fully based on Filament. I have this part to replace with an android-utils/Matrix.kt usage : public void decomposeRotation(Vector3 decomposedScale, Quaternion destRotation) {
float m00 = data[0];
float m01 = data[1];
float m02 = data[2];
float m03 = data[3];
float m10 = data[4];
float m11 = data[5];
float m12 = data[6];
float m13 = data[7];
float m20 = data[8];
float m21 = data[9];
float m22 = data[10];
float m23 = data[11];
float m30 = data[12];
float m31 = data[13];
float m32 = data[14];
float m33 = data[15];
// To extract the quaternion, we first remove the scale from the matrix. This is done in-place,
// and then after the quaternion is extracted the matrix is set back to it's original values.
// This allows us to decompose the rotation without allocating an additional matrix to hold the
// rotation matrix, which is better for performance.
decomposeRotation(decomposedScale, this);
extractQuaternion(destRotation);
data[0] = m00;
data[1] = m01;
data[2] = m02;
data[3] = m03;
data[4] = m10;
data[5] = m11;
data[6] = m12;
data[7] = m13;
data[8] = m20;
data[9] = m21;
data[10] = m22;
data[11] = m23;
data[12] = m30;
data[13] = m31;
data[14] = m32;
data[15] = m33;
}
public void decomposeRotation(Vector3 decomposedScale, Matrix destMatrix) {
// Remove x scale.
if (decomposedScale.x != 0.0f) {
for (int i = 0; i < 3; i++) {
destMatrix.data[i] = data[i] / decomposedScale.x;
}
}
destMatrix.data[3] = 0.0f;
// Remove y scale.
if (decomposedScale.y != 0.0f) {
for (int i = 4; i < 7; i++) {
destMatrix.data[i] = data[i] / decomposedScale.y;
}
}
destMatrix.data[7] = 0.0f;
// Remove z scale.
if (decomposedScale.z != 0.0f) {
for (int i = 8; i < 11; i++) {
destMatrix.data[i] = data[i] / decomposedScale.z;
}
}
destMatrix.data[11] = 0.0f;
destMatrix.data[12] = 0.0f;
destMatrix.data[13] = 0.0f;
destMatrix.data[14] = 0.0f;
destMatrix.data[15] = 1.0f;
}
public void extractQuaternion(Quaternion destQuaternion) {
float trace = data[0] + data[5] + data[10];
if (trace > 0) {
float s = (float) Math.sqrt(trace + 1.0) * 2.0f;
destQuaternion.w = 0.25f * s;
destQuaternion.x = (data[6] - data[9]) / s;
destQuaternion.y = (data[8] - data[2]) / s;
destQuaternion.z = (data[1] - data[4]) / s;
} else if ((data[0] > data[5]) && (data[0] > data[10])) {
float s = (float) Math.sqrt(1.0f + data[0] - data[5] - data[10]) * 2.0f;
destQuaternion.w = (data[6] - data[9]) / s;
destQuaternion.x = 0.25f * s;
destQuaternion.y = (data[4] + data[1]) / s;
destQuaternion.z = (data[8] + data[2]) / s;
} else if (data[5] > data[10]) {
float s = (float) Math.sqrt(1.0f + data[5] - data[0] - data[10]) * 2.0f;
destQuaternion.w = (data[8] - data[2]) / s;
destQuaternion.x = (data[4] + data[1]) / s;
destQuaternion.y = 0.25f * s;
destQuaternion.z = (data[9] + data[6]) / s;
} else {
float s = (float) Math.sqrt(1.0f + data[10] - data[0] - data[5]) * 2.0f;
destQuaternion.w = (data[1] - data[4]) / s;
destQuaternion.x = (data[8] + data[2]) / s;
destQuaternion.y = (data[9] + data[6]) / s;
destQuaternion.z = 0.25f * s;
}
destQuaternion.normalize();
} I guessed that One little more question : Do you think that the Matrix.kt usage which makes a lot of instantiations could have a strong impact on memory usage inside a frameCallback since I have to update transformation on every frame on an AR context? Thanks |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 3 replies
-
Memory usage won't be an issue. |
Beta Was this translation helpful? Give feedback.
-
Thanks. I will keep this function as it is for now since ARCore gives quaternion rotations informations. I have already moved Sceneform "hybrid" renderables to a fully Filament entities Koltin version. |
Beta Was this translation helpful? Give feedback.
-
Here is my Kotlin implementation of the Quaternion rotation using kotlin-math val Mat4.rotation4: Float4
get() {
val t = x.x + y.y + z.z
return normalize(
when {
t > 0 -> {
val s = sqrt(t + 1.0).toFloat() * 2.0f
Float4((z.y - y.z) / s, (x.z - z.x) / s, (y.x - x.y) / s, 0.25f * s)
}
x.x > y.y && x.x > z.z -> {
val s = sqrt((1.0f + x.x - y.y - z.z).toDouble()).toFloat() * 2.0f
Float4(0.25f * s, (x.y + y.x) / s, (x.z + z.x) / s, (z.y - y.z) / s)
}
y.y > z.z -> {
val s = sqrt((1.0f + y.y - x.x - z.z).toDouble()).toFloat() * 2.0f
Float4((x.y + y.x) / s, 0.25f * s, (y.z + z.y) / s, (x.z - z.x) / s)
}
else -> {
val s = sqrt((1.0f + z.z - x.x - y.y).toDouble()).toFloat() * 2.0f
Float4((y.x - x.y) / s, (x.z + z.x) / s, (y.z + z.y) / s, 0.25f * s)
}
}
)
} I didn't made the opposite functions yet since I only need AR to Filament data and not the inverse (even if maybe one day it could be possible) |
Beta Was this translation helpful? Give feedback.
-
I'm only missing those two function converted to kotlin-math. Can you help figure out the corresponding calls ? public Vector3 transformPoint(Vector3 vector) {
Preconditions.checkNotNull(vector, "Parameter \"vector\" was null.");
Vector3 result = new Vector3();
float vx = vector.x;
float vy = vector.y;
float vz = vector.z;
result.x = data[0] * vx;
result.x += data[4] * vy;
result.x += data[8] * vz;
result.x += data[12]; // *1
result.y = data[1] * vx;
result.y += data[5] * vy;
result.y += data[9] * vz;
result.y += data[13]; // *1
result.z = data[2] * vx;
result.z += data[6] * vy;
result.z += data[10] * vz;
result.z += data[14]; // *1
return result;
} and public void makeTrs(Vector3 translation, Quaternion rotation, Vector3 scale) {
float mdsqx = 1 - 2 * rotation.x * rotation.x;
float sqy = rotation.y * rotation.y;
float dsqz = 2 * rotation.z * rotation.z;
float dqxz = 2 * rotation.x * rotation.z;
float dqyw = 2 * rotation.y * rotation.w;
float dqxy = 2 * rotation.x * rotation.y;
float dqzw = 2 * rotation.z * rotation.w;
float dqxw = 2 * rotation.x * rotation.w;
float dqyz = 2 * rotation.y * rotation.z;
data[0] = (1 - 2 * sqy - dsqz) * scale.x;
data[4] = (dqxy - dqzw) * scale.y;
data[8] = (dqxz + dqyw) * scale.z;
data[1] = (dqxy + dqzw) * scale.x;
data[5] = (mdsqx - dsqz) * scale.y;
data[9] = (dqyz - dqxw) * scale.z;
data[2] = (dqxz - dqyw) * scale.x;
data[6] = (dqyz + dqxw) * scale.y;
data[10] = (mdsqx - 2 * sqy) * scale.z;
data[12] = translation.x;
data[13] = translation.y;
data[14] = translation.z;
data[15] = 1.0f;
} |
Beta Was this translation helpful? Give feedback.
-
Thanks. // Transform the center of the box.
result.center = center * worldMatrix.translation
// Transform the size of the box.
result.size = size * worldMatrix.scale
// Transform the rotation of the box.
result.rotationMatrix = rotationMatrix * rotation(worldMatrix.rotation) and fun Mat4.makeTrs(translation: Float3, rotation: Float4, scale: Float3) = this * translation(translation) * rotation4(rotation) * scale(scale) |
Beta Was this translation helpful? Give feedback.
rotation(Float3)
creates a rotation matrix, it does not decompose the rotation component of a matrix. You can perform the decomposition by callingmyMatrix.rotation
which gives you aFloat3
containing the 3 Euler angles of rotation. You can also get the scale and translation in the same way. We don't have an API to create a quaternion from a matrix but you could just copy/paste that functionextractQuaternion
. You can get the array of a matrix withtoFloatArray()
.Memory usage won't be an issue.