assimp / assimp

The official Open-Asset-Importer-Library Repository. Loads 40+ 3D-file-formats into one unified and clean data structure.
https://www.assimp.org
Other
10.96k stars 2.91k forks source link

glTF: Importing nodes with partly negative scale values -> all scale values are negative #3784

Open ParadoxDaKo opened 3 years ago

ParadoxDaKo commented 3 years ago

When decomposing a transformation matrix, Assimp uses the trafo matrix's determinant to assign the sign of the scaling values:

    /* extract the scaling factors */ \
    pScaling.x = vCols[0].Length(); \
    pScaling.y = vCols[1].Length(); \
    pScaling.z = vCols[2].Length(); \
    \
    /* and the sign of the scaling */ \
    if (Determinant() < 0) pScaling = -pScaling; \

Now, when we have glTF nodes with partly negative scale values such as this one:

{
    "mesh" : 0,
    "name" : "Cube",
    "scale" : [
        -1,
        1,
        1
    ],
    "translation" : [
        0,
        -1,
        0
    ]
}

, then load a scene with this node with Assimp into our aiScene, then try to read the scale values of this aiNode via aiMatrix4x4t<TReal>::Decompose (aiVector3t<TReal>& pScaling, aiQuaterniont<TReal>& pRotation, aiVector3t<TReal>& pPosition), the scale vector is [-1, -1, -1].

Exporting a mesh node with this scale in Blender, then reimporting it in Blender gives me the scale values [-1, 1, 1].

What exactly is going wrong and where?

JC3 commented 3 years ago

Just out of curiosity, what is the rotation in the transform decomposition for a scaled and unscaled node?

I ask because [1, -1, -1] (the inappropriate scale component - flip Y and Z) is equivalent to a 180 degree rotation around the X axis; so I'm wondering if it's compensated for in the rotation.


FYI quaternion [x,y,z,w] = [1,0,0,0] is 180 degrees around X, that's what I'm looking for, as opposed to [0,0,0,1], which is identity. You can use https://www.andre-gaschler.com/rotationconverter/ to convert between forms.

This means that the following rotation / scaling matrix:

-1  0  0
 0  1  0
 0  0  1

Has two equivalent decompositions:

ParadoxDaKo commented 3 years ago

The rotation quarternions for both scaled and unscaled nodes are both [1, 0, 0, 0] it is actually [0,0,0,1] if the scale values are positive.

For negative values, the rotation quaternion is [x, y, z, 0], with x,y,z >= 0, depending on which scale value is negative.

So this means that for nodes with negative scale values, Assimp applies the second decomposition out of the two you described? Ergo compensating flipped scale components in the rotation? If so, that's good to know - after applying the first decomposed rotation and scale values to my imported node manually, the results look equivalent, too.

... I assume there is no way to make Assimp use the first decomposition? 😅

JC3 commented 3 years ago

So this means that for nodes with negative scale values, Assimp applies the second decomposition out of the two you described? Ergo compensating flipped scale components in the rotation?

Yes, it appears to be producing a different decomposition, equivalent to but different than the one you expect.

If so, that's good to know - after applying the first decomposed rotation and scale values to my imported node manually, the results look equivalent, too.

That's good confirmation.

... I assume there is no way to make Assimp use the first decomposition? 😅

Unfortunately I'm not that familiar with assimp's internals but, my gut says no (I could be wrong though). What you're seeing is like you trying to figure out how I got from the left image to the right image:

image

Did I rotate it 180 degrees? Or did I mirror it horizontally, then vertically? Looking at the image alone, there's no way to know, so you'd have to just pick one. Both have the same end result, and if you wanted to do the same thing, you could do either and it wouldn't matter.

The decomposition you prefer sort of depends on your specific needs. The decomposition that the program produces just... is what it is. It's the decomposition you deserve, but maybe not the one you need right now. 😂

You could adjust it heuristically, though. For example, if it's important to you to minimize the number of negative scale values, then you could check to see if 2 or 3 of them are negative and, if so, flip the sign of two of the negative ones then rotate your quaternion to make up for it. Or whatever. Otoh, if all you're after is the end result, then it doesn't really matter.