Skip to content

Commit

Permalink
ImportGltf: experimental support for non-uniform scaling
Browse files Browse the repository at this point in the history
  • Loading branch information
fo76utils committed Nov 12, 2024
1 parent 435dbc4 commit de109e2
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* The Texture/Info spell is now applicable to any string item that ends with ".dds", and it opens a dialog showing information and a preview of the texture.
* Implemented Transform/Apply for Starfield (internal geometry only).
* Starfield and Fallout 76 shading fixes.
* Experimental support for importing glTF models that use anisotropic scaling. Non-uniform scale factors are applied to the rotation matrix, so the model should be fixed manually by applying the transform and recalculating normals and tangents.
* Optimizations to the texture and material browsers, and to PBR cube map filtering and loading Radiance HDR format files.
* Fixed the 'Texture/Choose' spell being incorrectly applicable to items that are not texture paths, and the spell can now also be used on Starfield texture set items without expanding the structure.
* Fixed error on BSFaceFX and BoneModifierExtra blocks.
Expand Down
42 changes: 34 additions & 8 deletions src/lib/importex/gltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -982,10 +982,12 @@ class ImportGltf {
const tinygltf::Model & model;
NifModel * nif;
bool lodEnabled;
bool scaleWarningFlag;
std::vector< int > nodeStack;
bool nodeHasMeshes( const tinygltf::Node & node, int d = 0 ) const;
static void normalizeFloats( float * p, size_t n, int dataType );
template< typename T > bool loadBuffer( std::vector< T > & outBuf, int accessor, int typeRequired );
void applyXYZScale( Transform & t, const Vector3 & scale );
void loadSkin( const QPersistentModelIndex & index, const tinygltf::Skin & skin );
int loadTriangles( const QModelIndex & index, const tinygltf::Primitive & p );
void loadSkinnedLODMesh( const QPersistentModelIndex & index, const tinygltf::Primitive & p, int lod );
Expand All @@ -996,7 +998,7 @@ class ImportGltf {
void loadNode( const QPersistentModelIndex & index, int nodeNum, bool isRoot );
public:
ImportGltf( NifModel * nifModel, const tinygltf::Model & gltfModel, bool enableLOD )
: model( gltfModel ), nif( nifModel ), lodEnabled( enableLOD )
: model( gltfModel ), nif( nifModel ), lodEnabled( enableLOD ), scaleWarningFlag( false )
{
}
void importModel( const QPersistentModelIndex & iBlock );
Expand Down Expand Up @@ -1121,6 +1123,30 @@ template< typename T > bool ImportGltf::loadBuffer( std::vector< T > & outBuf, i
return true;
}

void ImportGltf::applyXYZScale( Transform & t, const Vector3 & scale )
{
float avgScale = ( scale[0] + scale[1] + scale[2] ) / 3.0f;
t.scale = avgScale;
FloatVector4 tmp = FloatVector4( scale ) / avgScale;
if ( ( ( ( tmp - 1.0f ).absValues() - 0.000001f ).getSignMask() & 0x07 ) == 0x07 )
return;
if ( !scaleWarningFlag ) {
scaleWarningFlag = true;
QMessageBox::warning( nullptr, "NifSkope warning",
tr( "glTF model uses anisotropic scaling, use Transform/Apply to fix transforms, "
"and recalculate normals and tangents" ) );
}
t.rotation( 0, 0 ) *= tmp[0];
t.rotation( 1, 0 ) *= tmp[0];
t.rotation( 2, 0 ) *= tmp[0];
t.rotation( 0, 1 ) *= tmp[1];
t.rotation( 1, 1 ) *= tmp[1];
t.rotation( 2, 1 ) *= tmp[1];
t.rotation( 0, 2 ) *= tmp[2];
t.rotation( 1, 2 ) *= tmp[2];
t.rotation( 2, 2 ) *= tmp[2];
}

void ImportGltf::loadSkin( const QPersistentModelIndex & index, const tinygltf::Skin & skin )
{
QPersistentModelIndex iSkinBMP = nif->insertNiBlock( "SkinAttach" );
Expand Down Expand Up @@ -1204,7 +1230,7 @@ void ImportGltf::loadSkin( const QPersistentModelIndex & index, const tinygltf::
Transform t;
Vector3 tmpScale;
m.decompose( t.translation, t.rotation, tmpScale );
t.scale = ( tmpScale[0] + tmpScale[1] + tmpScale[2] ) / 3.0f;
applyXYZScale( t, tmpScale );
QModelIndex iBone = nif->getIndex( iBones, int(i) );
if ( iBone.isValid() )
t.writeBack( nif, iBone );
Expand Down Expand Up @@ -1610,19 +1636,19 @@ void ImportGltf::loadNode( const QPersistentModelIndex & index, int nodeNum, boo
const_cast< float * >( m.data() )[i] = float( node.matrix[i] );
Vector3 tmpScale;
m.decompose( t.translation, t.rotation, tmpScale );
t.scale = ( tmpScale[0] + tmpScale[1] + tmpScale[2] ) / 3.0f;
applyXYZScale( t, tmpScale );
} else {
if ( node.rotation.size() >= 4 ) {
Quat r;
for ( size_t i = 0; i < 4; i++ )
r[(i + 1) & 3] = float( node.rotation[i] );
t.rotation.fromQuat( r );
}
if ( node.scale.size() >= 1 ) {
double s = 0.0;
for ( double i : node.scale )
s += i;
t.scale = float( s / double( int(node.scale.size()) ) );
if ( node.scale.size() >= 3 ) {
Vector3 tmpScale( float( node.scale[0] ), float( node.scale[1] ), float( node.scale[2] ) );
applyXYZScale( t, tmpScale );
} else if ( node.scale.size() >= 1 ) {
t.scale = float( node.scale[0] );
}
if ( node.translation.size() >= 3 ) {
t.translation[0] = float( node.translation[0] );
Expand Down

0 comments on commit de109e2

Please sign in to comment.