Skip to content

Commit

Permalink
Fixed Mat3f.createRotationMatrix() method to correctly handle the
Browse files Browse the repository at this point in the history
singularity on the positive Y-Axis

Also added a commented out Pixar version of a orthonormal axis generation
technique - see the createRotationMatrix() method for details.
  • Loading branch information
alansley committed Jul 17, 2020
1 parent 863cb06 commit 1481c38
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 25 deletions.
4 changes: 4 additions & 0 deletions Changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
1.3.8 (2020/07/17)
- Fixed the Mat3f.createRotationMatrix() method to correctly handle the singularity on the positive Y-axis (thanks, meaten!)
- Also added a (commented out) Pixar version which works, but generates slightly different orthogonal 3x3 matrices (see method for details)

1.3.7 (2020/04/02)
- Updated documentation to discuss potential Mac demo crash & potential mitigation steps
- Updated documentation display of project file structure
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ To use the library in your own Maven project, declare the following dependencies
<dependency>
<groupId>au.edu.federation.caliko</groupId>
<artifactId>caliko</artifactId>
<<<<<<< HEAD
<version>1.3.8</version>
=======
<version>1.3.6</version>
>>>>>>> 863cb069101035f61613b7983f504991d9a0d876
</dependency>
```

Expand All @@ -51,7 +55,11 @@ To use the library in your own Maven project, declare the following dependencies
<dependency>
<groupId>au.edu.federation.caliko.visualisation</groupId>
<artifactId>caliko-visualisation</artifactId>
<<<<<<< HEAD
<version>1.3.8</version>
=======
<version>1.3.6</version>
>>>>>>> 863cb069101035f61613b7983f504991d9a0d876
</dependency>
```

Expand Down
2 changes: 1 addition & 1 deletion caliko-demo/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<parent>
<groupId>au.edu.federation.caliko</groupId>
<artifactId>caliko-aggregate</artifactId>
<version>1.3.7</version>
<version>1.3.8</version>
</parent>

<licenses>
Expand Down
2 changes: 1 addition & 1 deletion caliko-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<parent>
<groupId>au.edu.federation.caliko</groupId>
<artifactId>caliko-aggregate</artifactId>
<version>1.3.7</version>
<version>1.3.8</version>
</parent>

<artifactId>caliko-distribution</artifactId>
Expand Down
Binary file modified caliko-distribution/src/site/docs/caliko-user-guide.docx
Binary file not shown.
Binary file modified caliko-distribution/src/site/docs/caliko-user-guide.pdf
Binary file not shown.
2 changes: 1 addition & 1 deletion caliko-visualisation/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<parent>
<groupId>au.edu.federation.caliko</groupId>
<artifactId>caliko-aggregate</artifactId>
<version>1.3.7</version>
<version>1.3.8</version>
</parent>

<licenses>
Expand Down
2 changes: 1 addition & 1 deletion caliko/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<parent>
<groupId>au.edu.federation.caliko</groupId>
<artifactId>caliko-aggregate</artifactId>
<version>1.3.7</version>
<version>1.3.8</version>
</parent>

<licenses>
Expand Down
98 changes: 81 additions & 17 deletions caliko/src/main/java/au/edu/federation/utils/Mat3f.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public void setIdentity()
* Create a rotation matrix from a given direction.
* <p>
* The reference direction is aligned to the Z-Axis, and the X-Axis is generated via the
* genPerpendicularVectorQuuck() method. The Y-Axis is then the cross-product of those two axes.
* genPerpendicularVectorQuick() method. The Y-Axis is then the cross-product of those two axes.
* <p>
* This method uses the <a href="https://gist.github.com/roxlu/3082114">Frisvad technique</a> for generating perpendicular axes.
*
Expand All @@ -136,8 +136,71 @@ public void setIdentity()
return new Mat3f(xAxis, yAxis, zAxis);
}*/

/**
* Create a rotation matrix from a given direction.
* <p>
* The reference direction is aligned to the Z-Axis. Note: The singularity is on the positive Y-Axis.
* <p>
* This method uses the <a href="https://gist.github.com/roxlu/3082114">Frisvad technique</a> for generating perpendicular axes.
*
* @param referenceDirection The vector to use as the Z-Axis
* @return The created rotation matrix.
*
* @see Vec3f#genPerpendicularVectorQuick(Vec3f)
*/
public static Mat3f createRotationMatrix(Vec3f referenceDirection)
{
/*** You may want to try this - but the generated rotation matrix will be a little different (see below):
Note: There is no difference in solve distance between these, performance varies slightly - see test details on build (i.e. "mvn package")
--- Rotation matrix creation (Meaten fix) --- --- Rotation matrix creation (Pixar) ---
Rotation matrix generated from plusX:
X Axis: 0.000, 0.000, 1.000 X Axis: 0.000, -0.000, -1.000
Y Axis: 0.000, 1.000, 0.000 Y Axis: -0.000, 1.000, -0.000
Z Axis: 1.000, 0.000, 0.000 Z Axis: 1.000, 0.000, 0.000
Rotation matrix generated from plusY:
X Axis: 1.000, 0.000, 0.000 X Axis: 1.000, -0.000, -0.000
Y Axis: 0.000, 0.000, 1.000 Y Axis: -0.000, 0.000, -1.000
Z Axis: 0.000, 1.000, 0.000 Z Axis: 0.000, 1.000, 0.000
Rotation matrix generated from plusZ:
X Axis: -1.000, 0.000, 0.000 X Axis: 1.000, -0.000, -0.000
Y Axis: 0.000, 1.000, -0.000 Y Axis: -0.000, 1.000, -0.000
Z Axis: 0.000, 0.000, 1.000 Z Axis: 0.000, 0.000, 1.000
Rotation matrix generated from minusX:
X Axis: 0.000, 0.000, -1.000 X Axis: 0.000, 0.000, 1.000
Y Axis: 0.000, 1.000, 0.000 Y Axis: 0.000, 1.000, -0.000
Z Axis: -1.000, 0.000, 0.000 Z Axis: -1.000, 0.000, 0.000
Rotation matrix generated from minusY:
X Axis: 1.000, 0.000, 0.000 1.000, 0.000, -0.000
Y Axis: 0.000, 0.000, -1.000 Y Axis: 0.000, 0.000, 1.000
Z Axis: 0.000, -1.000, 0.000 Z Axis: 0.000, -1.000, 0.000
Rotation matrix generated from minusZ:
X Axis: 1.000, -0.000, 0.000 X Axis: 1.000, -0.000, 0.000
Y Axis: 0.000, 1.000, 0.000 Y Axis: 0.000, -1.000, -0.000
Z Axis: 0.000, 0.000, -1.000 Z Axis: 0.000, 0.000, -1.000
// Create an orthonormal basis using Pixar's method.
// Source: https://graphics.pixar.com/library/OrthonormalB/paper.pdf
float sign = Math.copySign(1.0f, referenceDirection.z);
float a = -1.0f / (sign + referenceDirection.z);
float b = referenceDirection.x * referenceDirection.y * a;
Vec3f xAxis = new Vec3f(1.0f + sign * referenceDirection.x * referenceDirection.x * a, sign * b, -sign * referenceDirection.x);
Vec3f yAxis = new Vec3f(b, sign + referenceDirection.y * referenceDirection.y * a, -referenceDirection.y);
Mat3f rotMat = new Mat3f();
rotMat.setZBasis( referenceDirection );
rotMat.setXBasis( xAxis.normalised() );
rotMat.setYBasis( yAxis.normalised() );
return rotMat;
***/

/*** OLD VERSION 1.3.4 and earlier
Vec3f xAxis;
Vec3f yAxis;
Expand All @@ -160,27 +223,28 @@ public static Mat3f createRotationMatrix(Vec3f referenceDirection)
return new Mat3f(xAxis, yAxis, zAxis);
***/

/*** NEW VERSION - 1.3.5 onwards ***/
/*** NEW VERSION - 1.3.8 onwards ***/

Mat3f rotMat = new Mat3f();

// Bone direction is bang on the Y-axis singularity? Give it a tiny nudge because you can't cross product two identical vectors.
if (referenceDirection.y == 1.0f) {
referenceDirection.y -= 0.0001f;
referenceDirection.normalise();

// Singularity fix provided by meaten - see: https://github.com/FedUni/caliko/issues/19
if (Math.abs(referenceDirection.y) > 0.9999f)
{
rotMat.setZBasis(referenceDirection);
rotMat.setXBasis( new Vec3f(1.0f, 0.0f, 0.0f));
rotMat.setYBasis( Vec3f.crossProduct( rotMat.getXBasis(), rotMat.getZBasis()).normalised());
}
else
{
rotMat.setZBasis( referenceDirection );
rotMat.setXBasis( Vec3f.crossProduct( referenceDirection, new Vec3f(0.0f, 1.0f, 0.0f) ).normalised() );
rotMat.setYBasis( Vec3f.crossProduct( rotMat.getXBasis(), rotMat.getZBasis() ).normalised() );
}

rotMat.setZBasis( referenceDirection );
rotMat.setXBasis( Vec3f.crossProduct( referenceDirection, new Vec3f(0.0f, 1.0f, 0.0f) ).normalised() );
rotMat.setYBasis( Vec3f.crossProduct( rotMat.getXBasis(), rotMat.getZBasis() ).normalised() );

return rotMat;

}

// THIS IS WAAAAAY BETTER THAN THE COMMENTED OUT ABOVE - BUT I THINK REFERENCE ANGLES **MUST** BE HONOURED IN THE
// FORWARD PASS OR WE END UP WITH JUMPY BULLSHIT RESULTS (SEE LOCAL HINGE WITH REFERENCE CONSTRAINTS)
//
// PERHAPS genPerpendicularVectorQuick SHOULD USE THE SAME TECHNIQUE TO KEEP EVERYTHING IN ORDER??


/**
* Return whether this matrix consists of three orthogonal axes or not to within a cross-product of 0.01f.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import au.edu.federation.utils.SerializationUtil;
import au.edu.federation.utils.Utils;
import au.edu.federation.utils.Vec3f;
import au.edu.federation.utils.Mat3f;

public class ApplicationPerfTest
{
Expand All @@ -35,10 +36,46 @@ public class ApplicationPerfTest
@Test
public void runTests() throws IOException, Exception
{
System.out.println("---------- Caliko CPU Performance Analysis ----------");
System.out.println("---------- Caliko Performance Analysis ----------");

writer = new PrintWriter(folder.newFile("caliko-performance-test.txt"), "UTF-8");

System.out.println("\n--- Rotation matrix creation ---\n");
writer.println("\n--- Rotation matrix creation ---\n");

Mat3f m;

Vec3f plusX = new Vec3f(1.0f, 0.0f, 0.0f);
Vec3f plusY = new Vec3f(0.0f, 1.0f, 0.0f);
Vec3f plusZ = new Vec3f(0.0f, 0.0f, 1.0f);

Vec3f minusX = new Vec3f(-1.0f, 0.0f, 0.0f);
Vec3f minusY = new Vec3f( 0.0f, -1.0f, 0.0f);
Vec3f minusZ = new Vec3f( 0.0f, 0.0f, -1.0f);

m = Mat3f.createRotationMatrix(plusX);
System.out.println("Rotation matrix generated from plusX:\n" + m.toString() );
writer.println("Rotation matrix generated from plusX:\n" + m.toString() );
m = Mat3f.createRotationMatrix(plusY);
System.out.println("Rotation matrix generated from plusY:\n" + m.toString() );
writer.println("Rotation matrix generated from plusY:\n" + m.toString() );
m = Mat3f.createRotationMatrix(plusZ);
System.out.println("Rotation matrix generated from plusZ:\n" + m.toString() );
writer.println("Rotation matrix generated from plusZ:\n" + m.toString() );

m = Mat3f.createRotationMatrix(minusX);
System.out.println("Rotation matrix generated from minusX:\n" + m.toString() );
writer.println("Rotation matrix generated from minusX:\n" + m.toString() );
m = Mat3f.createRotationMatrix(minusY);
System.out.println("Rotation matrix generated from minusY:\n" + m.toString() );
writer.println("Rotation matrix generated from minusY:\n" + m.toString() );
m = Mat3f.createRotationMatrix(minusZ);
System.out.println("Rotation matrix generated from minusZ:\n" + m.toString() );
writer.println("Rotation matrix generated from minusZ:\n" + m.toString() );

System.out.println("\n -----------------\n");
writer.println("\n -----------------\n");

// Perform tests
int numTests = 3;
for (int loop = 1; loop <= numTests; ++loop)
Expand Down Expand Up @@ -159,6 +196,8 @@ private void assertChain(FabrikChain3D chain, int testNumber) throws IOException

private double solveChain(FabrikChain3D chain, int numIterations)
{
float avgSolveDistance = 0.0f;

// Get half the length of the chain (to ensure target can be reached)
float len = chain.getChainLength() / 2.0f;

Expand All @@ -175,8 +214,8 @@ private double solveChain(FabrikChain3D chain, int numIterations)
// Get start time
startNanos = System.nanoTime();

// Solve for target
chain.solveForTarget(target);
// Solve for target
avgSolveDistance += chain.solveForTarget(target);

writer.println(chain.toString());
writer.flush();
Expand All @@ -192,6 +231,10 @@ private double solveChain(FabrikChain3D chain, int numIterations)
long averageMicrosecondsPerIteration = combinedMicrosecondsForIteration / (long)numIterations;
averageMilliseconds = (double)averageMicrosecondsPerIteration / 1000.0;

// Calculate average solve distance & display it
avgSolveDistance /= numIterations;
System.out.println("Average solve distance: " + avgSolveDistance);

return averageMilliseconds;
}

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<artifactId>caliko-aggregate</artifactId>

<packaging>pom</packaging>
<version>1.3.7</version>
<version>1.3.8</version>
<name>Caliko library Aggregate POM</name>
<description>POM to build the Caliko library including the visualisation component, demo application, source and documentation archives.</description>
<url>https://github.com/FedUni/caliko</url>
Expand Down

0 comments on commit 1481c38

Please sign in to comment.