载入中...
搜索中...
未找到
ProceduralBoneConfig.cpp
浏览该文件的文档.
14bool number(const Value& object,const char* name,float& out){const Value* value=field(object,name);if(!value||(!value->isInt64()&&!value->isDouble()))return false;out=static_cast<float>(value->isInt64()?value->asInt():value->asDouble());return std::isfinite(out);}
15bool integer(const Value& object,const char* name,int& out){const Value* value=field(object,name);if(!value||!value->isInt64())return false;out=static_cast<int>(value->asInt());return true;}
16bool boolean(const Value& object,const char* name,bool& out){const Value* value=field(object,name);if(!value||!value->isBool())return false;out=value->asBool();return true;}
17bool string(const Value& object,const char* name,std::string& out){const Value* value=field(object,name);if(!value||!value->isString())return false;out=value->asString();return true;}
18Value particleValue(const DynamicBoneParticleConfig& p){Value::Object o;o["stiffness"]=p.stiffness;o["damping"]=p.damping;o["inertia"]=p.inertia;o["gravityScale"]=p.gravityScale;o["radius"]=p.radius;return Value(std::move(o));}
23 if(!unit(weight)||!unit(objectMoveResponse)||!std::isfinite(updateRate)||updateRate<0.f||!std::isfinite(teleportThreshold)||teleportThreshold<0.f||!std::isfinite(distanceLimit)||distanceLimit<0.f)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"invalid global dynamic-bone parameter","dynamicBone"));
25 for(size_t i=0;i<chains.size();++i){const auto& c=chains[i];if(c.rootBone.empty()||c.endBone.empty()||!roots.emplace(c.rootBone,c.endBone).second||!unit(c.stiffness)||!unit(c.damping)||!unit(c.inertia)||c.radius<0.f||c.iterations<1||c.freezeAxis<0||c.freezeAxis>3||c.endMode<0||c.endMode>2)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"invalid or duplicate chain","chains["+std::to_string(i)+"]"));for(const auto& p:c.particles)if(!unit(p.stiffness)||!unit(p.damping)||!unit(p.inertia)||p.radius<0.f)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"invalid particle profile","chains.particles"));}
26 for(size_t i=0;i<colliders.size();++i)if(!std::isfinite(colliders[i].radius)||colliders[i].radius<=0.f)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"invalid collider radius","colliders["+std::to_string(i)+"].radius"));
27 if(footIK.enabled){if(footIK.pelvisBone.empty()||footIK.left.hip.empty()||footIK.left.knee.empty()||footIK.left.foot.empty()||footIK.maxPelvisOffset<0.f||footIK.minGroundNormalY<0.f||footIK.minGroundNormalY>1.f||footIK.positionResponse<0.f||footIK.rotationResponse<0.f||footIK.groundStartHeight<0.f||footIK.groundQueryDistance<0.f||footIK.contactGraceTime<0.f||footIK.lockEnterWeight<0.f||footIK.lockEnterWeight>1.f||footIK.lockExitWeight<0.f||footIK.lockExitWeight>footIK.lockEnterWeight)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"invalid Foot IK configuration","footIK"));}
33 Value::Object root=unknownFields;root["schema"]=std::string(SchemaId);root["schemaVersion"]=static_cast<std::int64_t>(SchemaVersion);
34 root["gravityX"]=gravityX;root["gravityY"]=gravityY;root["gravityZ"]=gravityZ;root["externalX"]=externalX;root["externalY"]=externalY;root["externalZ"]=externalZ;root["weight"]=weight;root["updateRate"]=updateRate;root["teleportThreshold"]=teleportThreshold;root["objectMoveResponse"]=objectMoveResponse;root["distanceLimit"]=distanceLimit;
35 Value::Array chainValues;for(const auto& c:chains){Value::Object o;o["rootBone"]=c.rootBone;o["endBone"]=c.endBone;o["stiffness"]=c.stiffness;o["damping"]=c.damping;o["inertia"]=c.inertia;o["gravityScale"]=c.gravityScale;o["radius"]=c.radius;o["iterations"]=static_cast<std::int64_t>(c.iterations);o["freezeAxis"]=static_cast<std::int64_t>(c.freezeAxis);o["selfCollision"]=c.selfCollision;o["endMode"]=static_cast<std::int64_t>(c.endMode);o["endLength"]=c.endLength;o["endX"]=c.endX;o["endY"]=c.endY;o["endZ"]=c.endZ;Value::Array particles;for(const auto& p:c.particles)particles.push_back(particleValue(p));o["particles"]=Value(std::move(particles));chainValues.emplace_back(std::move(o));}root["chains"]=Value(std::move(chainValues));
36 Value::Array colliderValues;for(const auto& c:colliders){Value::Object o;o["bone"]=c.bone;o["startX"]=c.startX;o["startY"]=c.startY;o["startZ"]=c.startZ;o["endX"]=c.endX;o["endY"]=c.endY;o["endZ"]=c.endZ;o["radius"]=c.radius;o["capsule"]=c.capsule;o["inside"]=c.inside;o["enabled"]=c.enabled;colliderValues.emplace_back(std::move(o));}root["colliders"]=Value(std::move(colliderValues));
37 auto legValue=[](const FootIKLegConfig& leg){Value::Object o;o["hip"]=leg.hip;o["knee"]=leg.knee;o["foot"]=leg.foot;o["toe"]=leg.toe;o["soleOffset"]=leg.soleOffset;o["toeSoleOffset"]=leg.toeSoleOffset;return Value(std::move(o));};Value::Object foot;foot["enabled"]=footIK.enabled;foot["footLockEnabled"]=footIK.footLockEnabled;foot["pelvisBone"]=footIK.pelvisBone;foot["left"]=legValue(footIK.left);foot["right"]=legValue(footIK.right);foot["maxPelvisOffset"]=footIK.maxPelvisOffset;foot["minGroundNormalY"]=footIK.minGroundNormalY;foot["positionResponse"]=footIK.positionResponse;foot["rotationResponse"]=footIK.rotationResponse;foot["groundStartHeight"]=footIK.groundStartHeight;foot["groundQueryDistance"]=footIK.groundQueryDistance;foot["contactGraceTime"]=footIK.contactGraceTime;foot["lockEnterWeight"]=footIK.lockEnterWeight;foot["lockExitWeight"]=footIK.lockExitWeight;root["footIK"]=Value(std::move(foot));
42 if(!value.isObject())return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"expected object","dynamicBone"));
44 std::string schema;int version=0;if(!string(value,"schema",schema)||schema!=SchemaId)return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"unexpected schema","schema"));if(!integer(value,"schemaVersion",version)||version!=static_cast<int>(SchemaVersion))return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"unsupported schema version","schemaVersion"));
45 if(!number(value,"gravityX",out.gravityX)||!number(value,"gravityY",out.gravityY)||!number(value,"gravityZ",out.gravityZ)||!number(value,"externalX",out.externalX)||!number(value,"externalY",out.externalY)||!number(value,"externalZ",out.externalZ)||!number(value,"weight",out.weight)||!number(value,"updateRate",out.updateRate)||!number(value,"teleportThreshold",out.teleportThreshold)||!number(value,"objectMoveResponse",out.objectMoveResponse)||!number(value,"distanceLimit",out.distanceLimit))return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"missing numeric global field","dynamicBone"));
46 const Value* chainArray=field(value,"chains");const Value* colliderArray=field(value,"colliders");const Value* foot=field(value,"footIK");if(!chainArray||!chainArray->isArray()||!colliderArray||!colliderArray->isArray()||!foot||!foot->isObject())return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"expected chain, collider and Foot IK values","dynamicBone"));
47 for(const auto& item:*chainArray->getIf<Value::Array>()){if(!item.isObject())return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"expected chain object","chains"));DynamicBoneChainConfig c;if(!string(item,"rootBone",c.rootBone)||!string(item,"endBone",c.endBone)||!number(item,"stiffness",c.stiffness)||!number(item,"damping",c.damping)||!number(item,"inertia",c.inertia)||!number(item,"gravityScale",c.gravityScale)||!number(item,"radius",c.radius)||!integer(item,"iterations",c.iterations)||!integer(item,"freezeAxis",c.freezeAxis)||!boolean(item,"selfCollision",c.selfCollision)||!integer(item,"endMode",c.endMode)||!number(item,"endLength",c.endLength)||!number(item,"endX",c.endX)||!number(item,"endY",c.endY)||!number(item,"endZ",c.endZ))return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"invalid chain field","chains"));const Value* profiles=field(item,"particles");if(!profiles||!profiles->isArray())return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"expected particle array","chains.particles"));for(const auto& profile:*profiles->getIf<Value::Array>()){DynamicBoneParticleConfig p;if(!profile.isObject()||!number(profile,"stiffness",p.stiffness)||!number(profile,"damping",p.damping)||!number(profile,"inertia",p.inertia)||!number(profile,"gravityScale",p.gravityScale)||!number(profile,"radius",p.radius))return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"invalid particle","chains.particles"));c.particles.push_back(p);}out.chains.push_back(std::move(c));}
48 for(const auto& item:*colliderArray->getIf<Value::Array>()){if(!item.isObject())return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"expected collider object","colliders"));DynamicBoneColliderConfig c;if(!string(item,"bone",c.bone)||!number(item,"startX",c.startX)||!number(item,"startY",c.startY)||!number(item,"startZ",c.startZ)||!number(item,"endX",c.endX)||!number(item,"endY",c.endY)||!number(item,"endZ",c.endZ)||!number(item,"radius",c.radius)||!boolean(item,"capsule",c.capsule)||!boolean(item,"inside",c.inside)||!boolean(item,"enabled",c.enabled))return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"invalid collider field","colliders"));out.colliders.push_back(std::move(c));}
49 if(!boolean(*foot,"enabled",out.footIK.enabled)||!boolean(*foot,"footLockEnabled",out.footIK.footLockEnabled)||!string(*foot,"pelvisBone",out.footIK.pelvisBone)||!number(*foot,"maxPelvisOffset",out.footIK.maxPelvisOffset)||!number(*foot,"minGroundNormalY",out.footIK.minGroundNormalY)||!number(*foot,"positionResponse",out.footIK.positionResponse)||!number(*foot,"rotationResponse",out.footIK.rotationResponse)||!number(*foot,"groundStartHeight",out.footIK.groundStartHeight)||!number(*foot,"groundQueryDistance",out.footIK.groundQueryDistance)||!number(*foot,"contactGraceTime",out.footIK.contactGraceTime)||!number(*foot,"lockEnterWeight",out.footIK.lockEnterWeight)||!number(*foot,"lockExitWeight",out.footIK.lockExitWeight))return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"invalid Foot IK field","footIK"));
50 auto decodeLeg=[&](const char* name,FootIKLegConfig& leg){const Value* item=field(*foot,name);return item&&item->isObject()&&string(*item,"hip",leg.hip)&&string(*item,"knee",leg.knee)&&string(*item,"foot",leg.foot)&&string(*item,"toe",leg.toe)&&number(*item,"soleOffset",leg.soleOffset)&&number(*item,"toeSoleOffset",leg.toeSoleOffset);};if(!decodeLeg("left",out.footIK.left)||!decodeLeg("right",out.footIK.right))return Result<DynamicBoneConfig>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"invalid Foot IK leg","footIK"));
51 out.unknownFields=*value.getIf<Value::Object>();for(const char* key:{"schema","schemaVersion","gravityX","gravityY","gravityZ","externalX","externalY","externalZ","weight","updateRate","teleportThreshold","objectMoveResponse","distanceLimit","chains","colliders","footIK"})out.unknownFields.erase(key);
52 auto valid=out.validate();if(!valid)return Result<DynamicBoneConfig>::failure(valid.status());return Result<DynamicBoneConfig>::success(std::move(out));
56 auto valid=validate();if(!valid)return valid;DynamicBoneSolver candidate(&skeleton);candidate.setGlobalGravity(gravityX,gravityY,gravityZ);candidate.setExternalForce(externalX,externalY,externalZ);candidate.setWeight(weight);candidate.setUpdateRate(updateRate);candidate.setTeleportThreshold(teleportThreshold);candidate.setObjectMoveResponse(objectMoveResponse);candidate.setDistanceLimit(distanceLimit);
57 for(const auto& c:chains){const int chain=candidate.addChainByName(c.rootBone,c.endBone,c.stiffness,c.damping,c.inertia,c.gravityScale,c.radius,c.iterations);if(chain<0)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"chain bone path cannot be resolved",c.rootBone+"->"+c.endBone));candidate.setChainFreezeAxis(chain,c.freezeAxis);candidate.setChainSelfCollision(chain,c.selfCollision);if(c.endMode==1)candidate.setChainEndLength(chain,c.endLength);else if(c.endMode==2)candidate.setChainEndOffset(chain,c.endX,c.endY,c.endZ);for(size_t i=0;i<c.particles.size();++i){const auto& p=c.particles[i];candidate.setChainParticleParameters(chain,static_cast<int>(i),p.stiffness,p.damping,p.inertia,p.gravityScale,p.radius);}}
58 for(const auto& c:colliders){const int bone=c.bone.empty()?-1:skeleton.findBone(c.bone);if(!c.bone.empty()&&bone<0)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"collider bone cannot be resolved",c.bone));if(c.capsule){if(bone<0)candidate.addColliderCapsule(c.startX,c.startY,c.startZ,c.endX,c.endY,c.endZ,c.radius);else candidate.addBoneColliderCapsule(bone,c.startX,c.startY,c.startZ,c.endX,c.endY,c.endZ,c.radius);}else{if(bone<0)candidate.addColliderSphere(c.startX,c.startY,c.startZ,c.radius);else candidate.addBoneColliderSphere(bone,c.startX,c.startY,c.startZ,c.radius);}const int index=candidate.getColliderCount()-1;candidate.setColliderInside(index,c.inside);candidate.setColliderEnabled(index,c.enabled);}
62Result<void> DynamicBoneConfig::apply(AnimSkeleton& skeleton,DynamicBoneSolver& dynamicSolver,FootIKSolver& footSolver) const {
63 DynamicBoneSolver dynamicCandidate(&skeleton);auto dynamicResult=apply(skeleton,dynamicCandidate);if(!dynamicResult)return dynamicResult;
64 FootIKSolver footCandidate(&skeleton);if(footIK.enabled){const int pelvis=skeleton.findBone(footIK.pelvisBone);const int lh=skeleton.findBone(footIK.left.hip),lk=skeleton.findBone(footIK.left.knee),lf=skeleton.findBone(footIK.left.foot);if(pelvis<0||lh<0||lk<0||lf<0)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"Foot IK bone cannot be resolved","footIK.left"));footCandidate.setPelvisBone(pelvis);footCandidate.configureLeftLeg(lh,lk,lf,footIK.left.soleOffset);if(!footIK.left.toe.empty()){const int toe=skeleton.findBone(footIK.left.toe);if(toe<0)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"left toe cannot be resolved","footIK.left.toe"));footCandidate.configureLeftToe(toe,footIK.left.toeSoleOffset);}if(!footIK.right.hip.empty()||!footIK.right.knee.empty()||!footIK.right.foot.empty()){const int rh=skeleton.findBone(footIK.right.hip),rk=skeleton.findBone(footIK.right.knee),rf=skeleton.findBone(footIK.right.foot);if(rh<0||rk<0||rf<0)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"right leg cannot be resolved","footIK.right"));footCandidate.configureRightLeg(rh,rk,rf,footIK.right.soleOffset);if(!footIK.right.toe.empty()){const int toe=skeleton.findBone(footIK.right.toe);if(toe<0)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"right toe cannot be resolved","footIK.right.toe"));footCandidate.configureRightToe(toe,footIK.right.toeSoleOffset);}}footCandidate.setMaxPelvisOffset(footIK.maxPelvisOffset);footCandidate.setMinGroundNormalY(footIK.minGroundNormalY);footCandidate.setPositionResponse(footIK.positionResponse);footCandidate.setRotationResponse(footIK.rotationResponse);footCandidate.setGroundQuery(footIK.groundStartHeight,footIK.groundQueryDistance);footCandidate.setContactGraceTime(footIK.contactGraceTime);footCandidate.setFootLockThresholds(footIK.lockEnterWeight,footIK.lockExitWeight);footCandidate.setFootLockEnabled(footIK.footLockEnabled);}
Stable, structured diagnostics shared by engine modules.
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
const T * getIf() const noexcept
Return a typed pointer, or nullptr when the kind differs.
Definition Value.h:180
3D bone hierarchy + bind-pose local TRS for skeletal animation. Independent of ik::Skeleton3D (FABRIK...
Definition AnimSkeleton.h:16
World-space spring-chain solver that writes results as local bone rotations.
Definition DynamicBoneSolver.h:37
void setObjectMoveResponse(float value)
Set how much simulated particles follow root translation, from zero to one.
Definition DynamicBoneSolver.cpp:105
void setColliderInside(int index, bool inside)
Select inside containment or outside exclusion for a collider.
Definition DynamicBoneSolver.cpp:117
void setChainParticleParameters(int chainIndex, int particleIndex, float stiffness, float damping, float inertia, float gravityScale, float radius)
Override simulation parameters for one chain particle, where zero is the root.
Definition DynamicBoneSolver.cpp:89
void setDistanceLimit(float value)
Set sleep distance; zero disables distance sleeping.
Definition DynamicBoneSolver.cpp:107
void setWeight(float weight)
Set final rotation blend weight in [0, 1].
Definition DynamicBoneSolver.cpp:102
void addBoneColliderCapsule(int boneIndex, float startX, float startY, float startZ, float endX, float endY, float endZ, float radius)
Add a capsule whose endpoints follow bone-local offsets.
Definition DynamicBoneSolver.cpp:112
void addColliderSphere(float centerX, float centerY, float centerZ, float radius)
Add a fixed model-space sphere collider; non-positive radii are ignored.
Definition DynamicBoneSolver.cpp:109
void addColliderCapsule(float startX, float startY, float startZ, float endX, float endY, float endZ, float radius)
Add a fixed model-space capsule collider.
Definition DynamicBoneSolver.cpp:111
void setTeleportThreshold(float distance)
Set root movement distance that triggers a simulation reset.
Definition DynamicBoneSolver.cpp:104
void setUpdateRate(float updatesPerSecond)
Set preferred simulation frequency; zero means one step per update.
Definition DynamicBoneSolver.cpp:103
void setChainEndOffset(int chainIndex, float x, float y, float z)
Add a virtual particle at a last-bone-local offset; this replaces end length mode.
Definition DynamicBoneSolver.cpp:98
void setColliderEnabled(int index, bool enabled)
Enable or disable a collider without changing its index.
Definition DynamicBoneSolver.cpp:116
void setExternalForce(float x, float y, float z)
Set additional model-space acceleration such as wind.
Definition DynamicBoneSolver.cpp:101
void setGlobalGravity(float x, float y, float z)
Set model-space gravity acceleration.
Definition DynamicBoneSolver.cpp:100
void setChainSelfCollision(int chainIndex, bool enabled)
Enable or disable non-adjacent particle self-collision for a chain.
Definition DynamicBoneSolver.cpp:88
void setChainEndLength(int chainIndex, float length)
Add a virtual particle after the last bone along the animated terminal direction.
Definition DynamicBoneSolver.cpp:97
void addBoneColliderSphere(int boneIndex, float offsetX, float offsetY, float offsetZ, float radius)
Add a sphere collider following a bone-local offset.
Definition DynamicBoneSolver.cpp:110
int addChainByName(const std::string &rootBone, const std::string &endBone, float stiffness, float damping, float inertia, float gravityScale=1.f, float radius=0.f, int iterations=4)
Name-based addChain variant; returns -1 for invalid input.
Definition DynamicBoneSolver.cpp:79
void setChainFreezeAxis(int chainIndex, int axis)
Restrict a chain to its animated model-space plane.
Definition DynamicBoneSolver.cpp:87
Paired-foot IK with contact smoothing and pelvis compensation.
Definition FootIKSolver.h:32
void setMinGroundNormalY(float value)
Set minimum accepted upward normal cosine in [0, 1].
Definition FootIKSolver.cpp:60
void setMaxPelvisOffset(float distance)
Set maximum pelvis compensation distance.
Definition FootIKSolver.cpp:59
void setGroundQuery(float startHeight, float distance)
Set ray origin height and downward query distance.
Definition FootIKSolver.cpp:45
void configureLeftToe(int toe, float soleOffset=0.f)
Configure an optional left toe child and its sole offset.
Definition FootIKSolver.cpp:43
void configureRightLeg(int hip, int knee, int foot, float soleOffset=0.f)
Configure the right hip-knee-foot chain and sole offset.
Definition FootIKSolver.cpp:37
void setFootLockEnabled(bool enabled)
Enable or disable world-space foot locking.
Definition FootIKSolver.cpp:64
void setPositionResponse(float value)
Set contact interpolation response in inverse seconds.
Definition FootIKSolver.cpp:61
void setRotationResponse(float value)
Set foot-normal interpolation response in inverse seconds.
Definition FootIKSolver.cpp:62
void setContactGraceTime(float seconds)
Set how long a missing automatic contact retains its prior target.
Definition FootIKSolver.cpp:63
void setFootLockThresholds(float enterWeight, float exitWeight)
Set lock enter and release contact-weight thresholds.
Definition FootIKSolver.cpp:65
void configureLeftLeg(int hip, int knee, int foot, float soleOffset=0.f)
Configure the left hip-knee-foot chain and sole offset.
Definition FootIKSolver.cpp:36
void configureRightToe(int toe, float soleOffset=0.f)
Configure an optional right toe child and its sole offset.
Definition FootIKSolver.cpp:44
Definition Animation.cpp:58
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
Definition Database.h:26
const EditorValue * field(const EditorValue &value, const char *name)
Definition RoadNetworkEditTarget.cpp:15
@ InvalidArgument
Persisted name-based dynamic-bone chain configuration.
Definition ProceduralBoneConfig.h:23
Persisted fixed or bone-following sphere/capsule configuration.
Definition ProceduralBoneConfig.h:33
Versioned, forward-compatible dynamic-bone asset definition.
Definition ProceduralBoneConfig.h:56
static Result< DynamicBoneConfig > fromValue(const Value &value)
Decode schema v1 transactionally; future versions are rejected.
Definition ProceduralBoneConfig.cpp:41
Result< void > validate() const
Validate ranges and structural resource invariants.
Definition ProceduralBoneConfig.cpp:21
float distanceLimit
Definition ProceduralBoneConfig.h:62
float objectMoveResponse
Definition ProceduralBoneConfig.h:62
Result< Value > toValue() const
Encode schema v1 while preserving unknown root fields.
Definition ProceduralBoneConfig.cpp:31
Value::Object unknownFields
Definition ProceduralBoneConfig.h:66
Result< void > apply(AnimSkeleton &skeleton, DynamicBoneSolver &solver) const
Resolve bone names and atomically replace a solver configuration.
Definition ProceduralBoneConfig.cpp:55
std::vector< DynamicBoneColliderConfig > colliders
Definition ProceduralBoneConfig.h:64
static constexpr std::string_view SchemaId
Definition ProceduralBoneConfig.h:57
std::vector< DynamicBoneChainConfig > chains
Definition ProceduralBoneConfig.h:63
float teleportThreshold
Definition ProceduralBoneConfig.h:62
static constexpr std::uint32_t SchemaVersion
Definition ProceduralBoneConfig.h:58
Persisted particle profile for one dynamic-bone chain particle.
Definition ProceduralBoneConfig.h:18
bool footLockEnabled
Definition ProceduralBoneConfig.h:47
float positionResponse
Definition ProceduralBoneConfig.h:50
float groundStartHeight
Definition ProceduralBoneConfig.h:51
float lockExitWeight
Definition ProceduralBoneConfig.h:52
float contactGraceTime
Definition ProceduralBoneConfig.h:51
float maxPelvisOffset
Definition ProceduralBoneConfig.h:50
float rotationResponse
Definition ProceduralBoneConfig.h:50
float groundQueryDistance
Definition ProceduralBoneConfig.h:51
float minGroundNormalY
Definition ProceduralBoneConfig.h:50
float lockEnterWeight
Definition ProceduralBoneConfig.h:52
Persisted name-based leg and optional toe mapping.
Definition ProceduralBoneConfig.h:40
float toeSoleOffset
Definition ProceduralBoneConfig.h:42