Skip to content

Instantly share code, notes, and snippets.

@d3x0r
Last active July 8, 2020 07:21
Show Gist options
  • Select an option

  • Save d3x0r/9ffea1d55f079b8ce4d958ddf0ad6d0c to your computer and use it in GitHub Desktop.

Select an option

Save d3x0r/9ffea1d55f079b8ce4d958ddf0ad6d0c to your computer and use it in GitHub Desktop.

Revisions

  1. d3x0r revised this gist Jul 8, 2020. 1 changed file with 68 additions and 8 deletions.
    76 changes: 68 additions & 8 deletions AAA-Matrix.md
    Original file line number Diff line number Diff line change
    @@ -10,14 +10,14 @@ This is the base form... the steps will be broken out for phases of substitution
    As implemented here https://github.com/d3x0r/STFRPhysics/blob/master/3d/src/dual-quat.js#L347


    ```
    ``` js
    const q = { x: AngleX, y:AngleY, z:AngleZ } ;
    ```

    Compute the total rotation of the system (angle is sum of angles). If there is no rotation, return the default basis.
    Also compute a square normal; take the reciprical for multiplation later instead of division.

    ```
    ``` js
    const nt = (Math.abs(q.x)+Math.abs(q.y)+Math.abs(q.z)) / 2;
    if( !nt ) {
    return {forward:{x:0,y:0,z:1}, right:{x:1,y:0,z:0}, up:{x:0,y:1,z:0}, origin:{x:0,y:0,z:0 }};
    @@ -28,23 +28,23 @@ Also compute a square normal; take the reciprical for multiplation later instead
    Use the total angle, and get the sin/cos of that angle; a quaternion has this
    already built into its factors.

    ```
    ``` js
    const s = Math.sin( del * nt ); // sin/cos are the function of exp()
    const qw = Math.cos( del * nt ); // sin/cos are the function of exp()
    ```

    Normalize the inputs, and multiply by the sin of the angle/2; this is already a factor
    of a quaternion, and q.w would be the cos above...

    ```
    ``` js
    const qx = q.x * nR * s; // normalizes the imaginary parts
    const qy = q.y * nR * s; // set the sin of their composite angle as their total
    const qz = q.z * nR * s; // output = 1(unit vector) * sin in x,y,z parts.
    ```

    Finally; these are all of the common factors.

    ```
    ``` js
    const xy = 2*qx*qy; // sin(t)*sin(t) * x * y / (xx+yy+zz)
    const yz = 2*qy*qz; // sin(t)*sin(t) * y * z / (xx+yy+zz)
    const xz = 2*qx*qz; // sin(t)*sin(t) * x * z / (xx+yy+zz)
    @@ -61,7 +61,7 @@ Finally; these are all of the common factors.

    Which can be used to create a matrix like this.

    ```
    ``` js
    const basis = { right :{ x : 1 - ( yy + zz ), y : ( wz + xy ), z : ( xz - wy ) }
    , up :{ x : ( xy - wz ), y : 1 - ( zz + xx ), z : ( wx + yz ) }
    , forward:{ x : ( wy + xz ), y : ( yz - wx ), z : 1 - ( xx + yy ) }
    @@ -75,7 +75,7 @@ Which can be used to create a matrix like this.

    Update() does the 'heavy' work, the sin/cos lookup, sqrt normal calculation....

    ```
    ``` js
    lnQuat.prototype.update = function() {
    // sqrt, 3 mul 2 add 1 div 1 sin 1 cos
    if( !this.dirty ) return;
    @@ -106,7 +106,7 @@ lnQuat.prototype.update = function() {

    And then Apply() takes a vector(v) and applys the log-quaternion rotation to it....

    ```
    ``` js

    // https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/
    //
    @@ -135,3 +135,63 @@ lnQuat.prototype.apply = function( v ) {
    , y : v.y + qw * ty + ( qz * tx - tz * qx )
    , z : v.z + qw * tz + ( qx * ty - tx * qy ) };
    }
    ```

    ## Reversing Matrix to Angles



    The trace of the matrix gives the angle.

    ``` js
    lnQuat.prototype.fromBasis = function( basis ) {
    // tr(M)=2cos(theta)+1 .
    const t = ( ( basis.right.x + basis.up.y + basis.forward.z ) - 1 )/2;
    let angle = acos(t);
    if( !angle ) {
    this.x = this.y = this.z = this.nx = this.ny = this.nz = this.nL = this.nR = 0;
    this.ny = 1; // axis normal.
    this.s = 0; // sin(angle)
    this.qw = 1; // cos(angle)
    return this; // set to 0.
    }
    /*
    from another page (missing reference)
    x = (R21 - R12)/sqrt((R21 - R12)^2+(R02 - R20)^2+(R10 - R01)^2);
    y = (R02 - R20)/sqrt((R21 - R12)^2+(R02 - R20)^2+(R10 - R01)^2);
    z = (R10 - R01)/sqrt((R21 - R12)^2+(R02 - R20)^2+(R10 - R01)^2);
    */
    // Recommend: Add +/- 2PI occasionally, since any +/- n* 2PI
    // rotation is this same matrix, but we don't really know which this came from...

    const yz = basis.up .z - basis.forward.y;
    const xz = basis.forward.x - basis.right .z;
    const xy = basis.right .y - basis.up .x;
    const tmp = 1 /Math.sqrt( yz*yz + xz*xz + xy*xy );

    this.nx = yz *tmp;
    this.ny = xz *tmp;
    this.nz = xy *tmp;
    const lNorm = angle / (Math.abs(this.nx)+Math.abs(this.ny)+Math.abs(this.nz));
    this.x = this.nx * lNorm;
    this.y = this.ny * lNorm;
    this.z = this.nz * lNorm;

    return this;
    }
    ```

    ## arccos > 1

    did a lot of research leading up to this, and this works for arccos(cos(a)+cos(b))...

    ``` js
    // 'fixed' acos for inputs > 1
    function acos(x) {
    const mod = (x,y)=>y * (x / y - Math.floor(x / y)) ;
    const plusminus = (x)=>mod( x+1,2)-1;
    const trunc = (x,y)=>x-mod(x,y);
    return Math.acos(plusminus(x));
    }
    ```

  2. d3x0r created this gist Jul 8, 2020.
    137 changes: 137 additions & 0 deletions AAA-Matrix.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,137 @@

    This is an alternative method to get a basis from a quaternion (log quaternion)... or from angle/angle/angle.
    This is built by rotating the constant vectors (1,0,0), (0,1,0), (0,0,1) via standard quaternion
    rotation, and reducing common factors. The `0`s and `1`s collapse out a lot of the terms of
    apply. It ends up being less work to get the 3 vector basis than to rotate a single point;
    although if you USE the basis to multiply with the point; that increases the work to excess of
    just rotating a vector directly...

    This is the base form... the steps will be broken out for phases of substitution.
    As implemented here https://github.com/d3x0r/STFRPhysics/blob/master/3d/src/dual-quat.js#L347


    ```
    const q = { x: AngleX, y:AngleY, z:AngleZ } ;
    ```

    Compute the total rotation of the system (angle is sum of angles). If there is no rotation, return the default basis.
    Also compute a square normal; take the reciprical for multiplation later instead of division.

    ```
    const nt = (Math.abs(q.x)+Math.abs(q.y)+Math.abs(q.z)) / 2;
    if( !nt ) {
    return {forward:{x:0,y:0,z:1}, right:{x:1,y:0,z:0}, up:{x:0,y:1,z:0}, origin:{x:0,y:0,z:0 }};
    }
    const nR = 1/Math.sqrt( q.x*q.x + q.y*q.y + q.z*q.z );
    ```

    Use the total angle, and get the sin/cos of that angle; a quaternion has this
    already built into its factors.

    ```
    const s = Math.sin( del * nt ); // sin/cos are the function of exp()
    const qw = Math.cos( del * nt ); // sin/cos are the function of exp()
    ```

    Normalize the inputs, and multiply by the sin of the angle/2; this is already a factor
    of a quaternion, and q.w would be the cos above...

    ```
    const qx = q.x * nR * s; // normalizes the imaginary parts
    const qy = q.y * nR * s; // set the sin of their composite angle as their total
    const qz = q.z * nR * s; // output = 1(unit vector) * sin in x,y,z parts.
    ```

    Finally; these are all of the common factors.

    ```
    const xy = 2*qx*qy; // sin(t)*sin(t) * x * y / (xx+yy+zz)
    const yz = 2*qy*qz; // sin(t)*sin(t) * y * z / (xx+yy+zz)
    const xz = 2*qx*qz; // sin(t)*sin(t) * x * z / (xx+yy+zz)
    const wx = 2*qw*qx; // cos(t)*sin(t) * x / sqrt(xx+yy+zz)
    const wy = 2*qw*qy; // cos(t)*sin(t) * y / sqrt(xx+yy+zz)
    const wz = 2*qw*qz; // cos(t)*sin(t) * z / sqrt(xx+yy+zz)
    const xx = 2*qx*qx; // sin(t)*sin(t) * y * y / (xx+yy+zz)
    const yy = 2*qy*qy; // sin(t)*sin(t) * x * x / (xx+yy+zz)
    const zz = 2*qz*qz; // sin(t)*sin(t) * z * z / (xx+yy+zz)
    ```

    Which can be used to create a matrix like this.

    ```
    const basis = { right :{ x : 1 - ( yy + zz ), y : ( wz + xy ), z : ( xz - wy ) }
    , up :{ x : ( xy - wz ), y : 1 - ( zz + xx ), z : ( wx + yz ) }
    , forward:{ x : ( wy + xz ), y : ( yz - wx ), z : 1 - ( xx + yy ) }
    };
    ```




    ## Update/Apply

    Update() does the 'heavy' work, the sin/cos lookup, sqrt normal calculation....

    ```
    lnQuat.prototype.update = function() {
    // sqrt, 3 mul 2 add 1 div 1 sin 1 cos
    if( !this.dirty ) return;
    this.dirty = false;
    // norm-rect
    this.nR = Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
    // norm-linear this is / 3 usually, but the sine lookup would
    // adds a /3 back in which reverses it.
    this.nL = (Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z))/2;///(2*Math.PI); // average of total
    if( this.nR ){
    this.nx = this.x/this.nR /* * this.nL*/;
    this.ny = this.y/this.nR /* * this.nL*/;
    this.nz = this.z/this.nR /* * this.nL*/;
    }else {
    this.nx = 0;
    this.ny = 0;
    this.nz = 0;
    }
    this.s = Math.sin(this.nL); // only want one half wave... 0-pi total.
    this.qw = Math.cos(this.nL);
    return this;
    }
    ```

    And then Apply() takes a vector(v) and applys the log-quaternion rotation to it....

    ```
    // https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/
    //
    lnQuat.prototype.apply = function( v ) {
    //return this.applyDel( v, 1.0 );
    const q = this;
    this.update();
    if( !q.nL ) {
    // v is unmodified.
    return {x:v.x, y:v.y, z:v.z }; // 1.0
    }
    // q.s and q.qw are set in update(); they are constants for a quat in a location.
    const nst = q.s/this.nR; // normal * sin_theta
    const qw = q.qw; //Math.cos( pl ); quaternion q.w = (exp(lnQ)) [ *exp(lnQ.W=0) ]
    const qx = q.x*nst;
    const qy = q.y*nst;
    const qz = q.z*nst;
    //p’ = (v*v.dot(p) + v.cross(p)*(w))*2 + p*(w*w – v.dot(v))
    const tx = 2 * (qy * v.z - qz * v.y); // v.cross(p)*w*2
    const ty = 2 * (qz * v.x - qx * v.z);
    const tz = 2 * (qx * v.y - qy * v.x);
    return { x : v.x + qw * tx + ( qy * tz - ty * qz )
    , y : v.y + qw * ty + ( qz * tx - tz * qx )
    , z : v.z + qw * tz + ( qx * ty - tx * qy ) };
    }