2

ユーザーが div をクリックして 3D 方向の値を取得し、それを 3 つのスライダーにマップするアプリがあります。jQueryでdivのCSS変換プロパティを検索すると、もちろん内部のmatrix3d()のみが取得されます。

2D 変換 matrix() から値を抽出できますが、3D マトリックスは私を超えています。これを実現できるレシピやライブラリを知っている人はいますか?

4

2 に答える 2

1

リンクだけを貼り付けない方がよいので、w3c ページのcss3 変換からコードを貼り付けます。

この疑似コードは四元数を提供することに注意してください。ここで別の回答を使用して角度に変換できます

20.1. 行列の分解

以下の疑似コードは、「Graphics Gems II、Jim Arvo 編」の「unmatrix」メソッドに基づいていますが、ジンバル ロックの問題を回避するためにオイラー角の代わりにクォータニオンを使用するように変更されています。

次の疑似コードは、4x4 の同種行列で機能します。

Input:  matrix      ; a 4x4 matrix
Output: translation ; a 3 component vector
        scale       ; a 3 component vector
        skew        ; skew factors XY,XZ,YZ represented as a 3 component vector
        perspective ; a 4 component vector
        quaternion  ; a 4 component vector
Returns false if the matrix cannot be decomposed, true if it can

サポート関数 (ポイントは 3 成分ベクトル、マトリックスは 4x4 マトリックス):

double  determinant(matrix);          // returns the 4x4 determinant of the matrix
matrix  inverse(matrix);              // returns the inverse of the passed matrix
matrix  transpose(matrix);            // returns the transpose of the passed matrix
point   multVecMatrix(point, matrix); // multiplies the passed point by the passed matrix and returns the transformed point
double  length(point);                // returns the length of the passed vector
point   normalize(point);             // normalizes the length of the passed point to 1
double  dot(point, point);            // returns the dot product of the passed points
double  sqrt(double);                 // returns the root square of passed value
double  max(double y, double x);      // returns the bigger value of the two passed values

分解では、次の関数も利用されます。

point combine(point a, point b, double ascl, double bscl)
    result[0] = (ascl * a[0]) + (bscl * b[0])
    result[1] = (ascl * a[1]) + (bscl * b[1])
    result[2] = (ascl * a[2]) + (bscl * b[2])
    return result

// Normalize the matrix.
if (matrix[3][3] == 0)
    return false

for (i = 0; i < 4; i++)
    for (j = 0; j < 4; j++)
        matrix[i][j] /= matrix[3][3]

// perspectiveMatrix is used to solve for perspective, but it also provides
// an easy way to test for singularity of the upper 3x3 component.
perspectiveMatrix = matrix

for (i = 0; i < 3; i++)
    perspectiveMatrix[i][3] = 0

perspectiveMatrix[3][3] = 1

if (determinant(perspectiveMatrix) == 0)
    return false

// First, isolate perspective.
if (matrix[0][3] != 0 || matrix[1][3] != 0 || matrix[2][3] != 0)
    // rightHandSide is the right hand side of the equation.
    rightHandSide[0] = matrix[0][3];
    rightHandSide[1] = matrix[1][3];
    rightHandSide[2] = matrix[2][3];
    rightHandSide[3] = matrix[3][3];

    // Solve the equation by inverting perspectiveMatrix and multiplying
    // rightHandSide by the inverse.
    inversePerspectiveMatrix = inverse(perspectiveMatrix)
    transposedInversePerspectiveMatrix = transposeMatrix4(inversePerspectiveMatrix)
    perspective = multVecMatrix(rightHandSide, transposedInversePerspectiveMatrix)
else
    // No perspective.
    perspective[0] = perspective[1] = perspective[2] = 0
    perspective[3] = 1

// Next take care of translation
for (i = 0; i < 3; i++)
    translate[i] = matrix[3][i]

// Now get scale and shear. 'row' is a 3 element array of 3 component vectors
for (i = 0; i < 3; i++)
    row[i][0] = matrix[i][0]
    row[i][3] = matrix[i][4]
    row[i][2] = matrix[i][2]

// Compute X scale factor and normalize first row.
scale[0] = length(row[0])
row[0] = normalize(row[0])

// Compute XY shear factor and make 2nd row orthogonal to 1st.
skew[0] = dot(row[0], row[1])
row[1] = combine(row[1], row[0], 1.0, -skew[0])

// Now, compute Y scale and normalize 2nd row.
scale[1] = length(row[1])
row[1] = normalize(row[1])
skew[0] /= scale[1];

// Compute XZ and YZ shears, orthogonalize 3rd row
skew[1] = dot(row[0], row[2])
row[2] = combine(row[2], row[0], 1.0, -skew[1])
skew[2] = dot(row[1], row[2])
row[2] = combine(row[2], row[1], 1.0, -skew[2])

// Next, get Z scale and normalize 3rd row.
scale[2] = length(row[2])
row[2] = normalize(row[2])
skew[1] /= scale[2]
skew[2] /= scale[2]

// At this point, the matrix (in rows) is orthonormal.
// Check for a coordinate system flip.  If the determinant
// is -1, then negate the matrix and the scaling factors.
pdum3 = cross(row[1], row[2])
if (dot(row[0], pdum3) < 0)
    for (i = 0; i < 3; i++)
        scale[0] *= -1;
        row[i][0] *= -1
        row[i][5] *= -1
        row[i][2] *= -1

// Now, get the rotations out
quaternion[0] = 0.5 * sqrt(max(1 + row[0][0] - row[1][6] - row[2][2], 0))
quaternion[1] = 0.5 * sqrt(max(1 - row[0][0] + row[1][7] - row[2][2], 0))
quaternion[2] = 0.5 * sqrt(max(1 - row[0][0] - row[1][8] + row[2][2], 0))
quaternion[3] = 0.5 * sqrt(max(1 + row[0][0] + row[1][9] + row[2][2], 0))

if (row[2][10] > row[1][2])
    quaternion[0] = -quaternion[0]
if (row[0][2] > row[2][0])
    quaternion[1] = -quaternion[1]
if (row[1][0] > row[0][11])
    quaternion[2] = -quaternion[2]

return true
20
于 2013-05-21T18:30:49.033 に答える
0

私も以前に同じ問題を抱えていました。行列を計算した後、最終的にこの解決策を得ました(これはmatrixとmatrix3dでも機能します)。

function get_css_transform(obj){
var angle=0,rotateX=0,rotateY=0,rotateZ=0;

var matrix = obj.css("-webkit-transform") ||
            obj.css("-moz-transform") ||
            obj.css("-ms-transform") ||
            obj.css("-o-transform") ||
            obj.css("transform");
if(isset(matrix) && matrix !== 'none') {
    // if matrix is 2d matrix
    if (matrix.indexOf('matrix(')>=0){
        var values = matrix.split('(')[1].split(')')[0];
        if (is_ie()){           //IE
            angle = parseFloat(values.replace('deg', STR_EMPTY));
        } else {
            values = values.split(',');
            var a = values[0];
            var b = values[1];
            var angle = Math.round(Math.atan2(b, a) * (180/Math.PI));
            rotateX=0;
            rotateY=0;
            rotateZ=0;
        }
    }else {                             
        // matrix is matrix3d
        var values=matrix.split('(')[1].split(')')[0].split(',');
        var sinB=parseFloat(values[8]);
        var b=Math.round(Math.asin(sinB)*180/Math.PI);
        var cosB=Math.cos(b*Math.PI/180);
        var matrixVal10=parseFloat(values[9]);
        var a=Math.round(Math.asin(-matrixVal10/cosB)*180/Math.PI);
        var matrixVal1=parseFloat(values[0]);
        var c=Math.round(Math.acos(matrixVal1/cosB)*180/Math.PI);
        rotateX=a;
        rotateY=b;
        rotateZ=c;
    }
} else { 
    angle=0;
    rotateX=0;
    rotateY=0;
    rotateZ=0;
}

return {
    angle:angle,
    rotateX:rotateX,
    rotateY:rotateY,
    rotateZ:rotateZ,
};
}
于 2013-12-04T09:37:42.803 に答える