- Added possibility to use Focal Length / FOV animation with GLTF Camera animations.

- Added blenderPy script which shows howto set lenscurves as a custom prop float array containing all evaluated fov values
- minor cleanup to gltfparser and gltfExtras.
- gltfExtra key value pairs can now contain a bracket enclosed string as value

# Conflicts:
#	neo/idlib/gltfProperties.h
This commit is contained in:
HarrievG 2023-04-27 00:27:42 +02:00 committed by Robert Beckebans
parent edb62c15d9
commit ab7fefcadc
9 changed files with 223 additions and 59 deletions

View file

@ -32,6 +32,7 @@ If you have questions concerning this license or the applicable additional terms
#include "Game_local.h"
#include "gltfParser.h"
#include "gltfExtras.h"
static const byte BCANIM_VERSION = 100;
@ -771,7 +772,7 @@ void idCameraAnim::gltfLoadAnim( idStr gltfFileName, idStr animName )
{
gameLocal.Error( "Missing 'anim.%s' on '%s'", animName.c_str(), gltfFileName.c_str() );
}
//check for
cameraCuts.Clear();
cameraCuts.SetGranularity( 1 );
camera.Clear();
@ -853,15 +854,43 @@ void idCameraAnim::gltfLoadAnim( idStr gltfFileName, idStr animName )
}
break;
case gltfAnimation_Channel_Target::scale:
{
idList<idVec3*>& values = data->GetAccessorView<idVec3>( output );
if( values.Num() > i )
{
gameLocal.Printf( "^5Frame: ^7%i ignored scale on /%s \n\n\n", i, anim->name.c_str() );
}
break;
}
break;
}
}
}
//check for extra anim data
if( anim->extras.json.Length() )
{
gltfItemArray animExtras;
GLTFARRAYITEM( animExtras, CameraLensFrames, gltfExtra_CameraLensFrames );
idLexer lexer( LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_NOSTRINGESCAPECHARS );
lexer.LoadMemory( anim->extras.json, anim->extras.json.Size(), "idCameraAnim_gltfExtra", 0 );
animExtras.Parse( &lexer , true );
if( CameraLensFrames->item )
{
auto* lensFrameValues = ( idList<double, TAG_IDLIB_LIST>* )CameraLensFrames->item;
if( lensFrameValues )
{
assert( lensFrameValues->Num() == camera.Num() );
for( int i = 0; i < lensFrameValues->Num(); i++ )
{
camera[i].fov = ( float )( *lensFrameValues )[i];
}
}
//Dont forget to free! normally a gltfPropertyArray destructor frees the itemdata
delete CameraLensFrames->item;
}
}
}
else
{

View file

@ -1915,6 +1915,92 @@ const char* idLexer::ParseBracedSectionExact( idStr& out, int tabs )
return out.c_str();
}
/*
=================
idParser::ParseBracedSection
The next token should be an open brace.
Parses until a matching close brace is found.
Maintains exact characters between braces.
FIXME: this should use ReadToken and replace the token white space with correct indents and newlines
=================
*/
const char* idLexer::ParseBracketSectionExact( idStr& out, int tabs )
{
int depth;
bool doTabs;
bool skipWhite;
out.Empty();
if( !idLexer::ExpectTokenString( "[" ) )
{
return out.c_str();
}
out = "[";
depth = 1;
skipWhite = false;
doTabs = tabs >= 0;
while( depth && *idLexer::script_p )
{
char c = *( idLexer::script_p++ );
switch( c )
{
case '\t':
case ' ':
{
if( skipWhite )
{
continue;
}
break;
}
case '\n':
{
if( doTabs )
{
skipWhite = true;
out += c;
continue;
}
break;
}
case '[':
{
depth++;
tabs++;
break;
}
case ']':
{
depth--;
tabs--;
break;
}
}
if( skipWhite )
{
int i = tabs;
if( c == '[' )
{
i--;
}
skipWhite = false;
for( ; i > 0; i-- )
{
out += '\t';
}
}
out += c;
}
return out.c_str();
}
/*
=================
idLexer::ParseBracedSection

View file

@ -218,6 +218,7 @@ public:
const char* ParseBracedSection( idStr& out );
// parse a braced section into a string, maintaining indents and newlines
const char* ParseBracedSectionExact( idStr& out, int tabs = -1 );
const char* ParseBracketSectionExact( idStr& out, int tabs = -1 );
// parse the rest of the line
const char* ParseRestOfLine( idStr& out );
// pulls the entire line, including the \n at the end

View file

@ -41,23 +41,10 @@ void gltfExtra_Scatter::parse( idToken& token, idLexer* parser )
scatterInfo.Parse( parser, true );
}
void gltfExtra_cvar::parse( idToken& token, idLexer* parser )
void gltfExtra_CameraLensFrames::parse( idToken& token, idLexer* parser )
{
parser->UnreadToken( &token );
gltfItemArray cvarInfo;
idStr n, t, v, d;
GLTFARRAYITEMREF( cvarInfo, name, gltfItem , n );
GLTFARRAYITEMREF( cvarInfo, type, gltfItem , t );
GLTFARRAYITEMREF( cvarInfo, value, gltfItem, v );
GLTFARRAYITEMREF( cvarInfo, desc, gltfItem , d );
int total = cvarInfo.Parse( parser );
assert( total == 3 );
idCVar* gltExtra_cvar = new idCVar(
n.c_str(),
v.c_str(),
CVAR_SYSTEM | CVAR_BOOL,
d.c_str()
);
cvarSystem->Register( gltExtra_cvar );
item = new idList<double>();
auto* numbers = new gltfItem_number_array( "" );
numbers->Set( item, parser );
numbers->parse( token );
}

View file

@ -2,7 +2,7 @@
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 2022 Harrie van Ginneken
Copyright (C) 2022 - 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -29,36 +29,34 @@ If you have questions concerning this license or the applicable additional terms
#include "gltfParser.h"
#ifndef gltfExtraParser
#define gltfExtraParser(className,ptype) \
class gltfExtra_##className : public parsable, public parseType<ptype> \
{public: \
gltfExtra_##className( idStr Name ) : name( Name ){ item = nullptr; } \
virtual void parse( idToken &token ){parse(token,nullptr);} \
virtual void parse( idToken &token , idLexer * parser ); \
virtual idStr &Name() { return name; } \
private: \
#define gltfExtraParser(className,ptype) \
class gltfExtra_##className : public parsable, public parseType<ptype> \
{public: \
gltfExtra_##className( idStr Name ) : name( Name ){ item = nullptr; } \
virtual void parse( idToken &token ) {parse(token,nullptr); } \
virtual void parse( idToken &token , idLexer * parser ); \
virtual idStr &Name() { return name; } \
private: \
idStr name;}
#pragma endregion
#endif
//Helper macros for gltf data deserialize
#define GLTFARRAYITEM(target,name,type) auto * name = new type (#name); target.AddItemDef((parsable*)name)
#define GLTFARRAYITEMREF(target,name,type,ref) auto * name = new type (#name); target.AddItemDef((parsable*)name); name->Set(&ref)
#ifndef GLTF_EXTRAS_H
#define GLTF_EXTRAS_H
class test
class gltfExtraStub
{
public:
test() { }
gltfExtraStub() { }
};
gltfExtraParser( Scatter, gltfExtraStub );
gltfExtraParser( Scatter, test );
gltfExtraParser( CameraLensFrames, idList<double> );
gltfExtraParser( cvar, idCVar );
#endif // GLTF_EXTRAS_H
#ifndef gltfExternalParser
#undef gltfExtraParser
#endif
#undef gltfExtraParser

View file

@ -163,7 +163,6 @@ gltf_accessor_component::Type GetComponentTypeEnum( int id , uint* sizeInBytes
idList<gltfData*> gltfData::dataList;
idHashIndex gltfData::fileDataHash;
gltfItemArray* gltfItem_Extra::items = new gltfItemArray();
//Helper macros for gltf data deserialize
//NOTE: gltfItems that deviate from the default SET(T*) function cannot be handled with itemref macro.
@ -300,14 +299,20 @@ int gltfItemArray::Fill( idLexer* lexer, idDict* strPairs )
idToken token;
bool parsing = true;
int parseCount = 0;
lexer->ExpectTokenString( "{" );
lexer->ReadToken( &token );
while( parsing && !lexer->PeekTokenString( "}" ) && lexer->ExpectAnyToken( &token ) )
{
lexer->ExpectTokenString( ":" );
idStr key = token;
idStr value;
key.StripTrailingWhitespace();
if( lexer->PeekTokenString( "{" ) )
if( lexer->PeekTokenString( "[" ) )
{
lexer->ParseBracketSectionExact( value );
value.StripTrailingWhitespace();
strPairs->Set( key, value );
}
else if( lexer->PeekTokenString( "{" ) )
{
lexer->ParseBracedSectionExact( value );
value.StripTrailingWhitespace();
@ -338,6 +343,7 @@ int gltfItemArray::Parse( idLexer* lexer, bool forwardLexer/* = false*/ )
idToken token;
bool parsing = true;
int parseCount = 0;
lexer->ExpectTokenString( "{" );
while( parsing && !lexer->PeekTokenString( "}" ) && lexer->ExpectAnyToken( &token ) )
{
@ -362,7 +368,7 @@ int gltfItemArray::Parse( idLexer* lexer, bool forwardLexer/* = false*/ )
}
if( !parsed )
{
lexer->SkipBracedSection();
lexer->SkipBracedSection( true, lexer->PeekTokenString( "{" ) ? BRSKIP_BRACES : BRSKIP_BRACKET );
}
else
{
@ -452,12 +458,11 @@ void gltfItem_Extra::parse( idToken& token )
{
parser->UnreadToken( &token );
parser->ParseBracedSectionExact( item->json );
gltfItemArray items;
idLexer lexer( LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_NOSTRINGESCAPECHARS );
lexer.LoadMemory( item->json, item->json.Size(), "gltfItem_Extra", 0 );
items->Fill( &lexer, &item->strPairs );
items.Fill( &lexer, &item->strPairs );
lexer.Reset();
items->Parse( &lexer , true );
if( gltf_parseVerbose.GetBool() )
{
@ -465,12 +470,6 @@ void gltfItem_Extra::parse( idToken& token )
}
}
void gltfItem_Extra::Register( parsable* extra )
{
common->DPrintf( "...Registering gltf Extra \"%s\" total(%i)\n", extra->Name().c_str(), items->Num() );
items->AddItemDef( extra );
}
void gltfItem_animation_sampler::parse( idToken& token )
{
gltfItemArray animSampler;
@ -692,7 +691,6 @@ void gltfItem_number_array::parse( idToken& token )
void gltfItem_vec4::parse( idToken& token )
{
auto* numbers = new gltfItem_number_array( "" );
idList<double> numberarray;
numbers->Set( &numberarray, parser );
@ -704,6 +702,7 @@ void gltfItem_vec4::parse( idToken& token )
double* val = numbers->item->Ptr();
*item = idVec4( val[0], val[1], val[2], val[3] );
delete numbers;
}
void gltfItem_vec3::parse( idToken& token )
@ -719,6 +718,7 @@ void gltfItem_vec3::parse( idToken& token )
double* val = numbers->item->Ptr();
*item = idVec3( val[0], val[1], val[2] );
delete numbers;
}
void gltfItem_vec2::parse( idToken& token )
@ -734,6 +734,7 @@ void gltfItem_vec2::parse( idToken& token )
double* val = numbers->item->Ptr();
*item = idVec2( val[0], val[1] );
delete numbers;
}
void gltfItem_quat::parse( idToken& token )
@ -749,6 +750,7 @@ void gltfItem_quat::parse( idToken& token )
double* val = numbers->item->Ptr();
*item = idQuat( val[0] , val[1] , val[2] , val[3] );
delete numbers;
}
void gltfItem_mat4::parse( idToken& token )
@ -769,6 +771,7 @@ void gltfItem_mat4::parse( idToken& token )
val[8], val[9], val[10], val[11],
val[12], val[13], val[14], val[15]
);
delete numbers;
}
void gltfItem_accessor_sparse::parse( idToken& token )

View file

@ -52,9 +52,6 @@ public:
{
item = type;
}
virtual ~parseType()
{
}
T* item;
};
@ -97,7 +94,6 @@ private:
idStr object;
};
class gltfItemArray;
class gltfItem_Extra : public parsable, public parseType<gltfExtra>
{
public:
@ -120,7 +116,6 @@ private:
idStr name;
gltfData* data;
idLexer* parser;
static gltfItemArray* items;
};
class gltfItem_uri : public parsable, public parseType<idStr>

View file

@ -92,8 +92,6 @@ public:
idStr json;
//str:str pairs of each item
idDict strPairs;
//specialized parsers
idList<gltfExtra*> extras;
};
class gltfExt_KHR_lights_punctual;

View file

@ -0,0 +1,67 @@
import bpy
import numpy as np
import functools
import bpy
from pathlib import Path
from mathutils import Matrix
import math
C = bpy.context
data = bpy.data
########################################
# arguments #
########################################
gltfExtraIdentifier = 'CameraLensFrames'
LensFcurveTarget = 'CameraAction'
actionTarget = 'intro_anim'
cameraTarget = 'Camera'
########################################
print("///////////////////////////////////////////////////////////////////////////////")
print("sample Camera Lens fcurve and set as extra float array prop on target animation")
lensFcurveAction = None
lensFcurve = None
action = None
camera = None
#find camera object
for obj in data.cameras:
if (obj.name == cameraTarget):
camera = obj
break
# iterate over all actions and find target camera with focal length fcurve and target action to add it to
for obj in data.actions:
if (not lensFcurve and obj.fcurves and obj.id_root == 'CAMERA' and obj.name == LensFcurveTarget):
for fc in obj.fcurves:
if "lens" in fc.data_path:
lensFcurve = fc
lensFcurveAction = obj
if (not action and obj.name == actionTarget):
action = obj
if (action and lensFcurve):
break
print ("LensCurve: {0} in action {1}".format(lensFcurve,lensFcurveAction))
print ('action: %s' % action)
print ('camera: %s' % camera)
if action and lensFcurve and camera:
if gltfExtraIdentifier in action:
print("Property reset")
del action[gltfExtraIdentifier]
action[gltfExtraIdentifier] = np.array([], dtype = np.float32)
print ("setting {0} values from action {1} ".format(action.frame_range[1],lensFcurveAction.name) )
for val in range(0,int(action.frame_range[1] + 1)):
hFov = math.degrees(2 * math.atan(camera.sensor_width /(2 * lensFcurve.evaluate(val))))
action[gltfExtraIdentifier] = np.append(action[gltfExtraIdentifier], hFov)
else:
print("Failed! Property NOT SET")
print ("Done!")