imagine my shock the week-long issue predicated on scaling issues (constraint solving is now scaling aware, automatic ragdoll rigging seems to work, but need to actually bind the transforms to joint matrices)
This commit is contained in:
parent
94ce7be618
commit
5402aff2a8
@ -8,7 +8,7 @@
|
|||||||
"useLightmaps": false,
|
"useLightmaps": false,
|
||||||
"max": 32,
|
"max": 32,
|
||||||
"shadows": {
|
"shadows": {
|
||||||
"enabled": false,
|
"enabled": true,
|
||||||
"update": 4,
|
"update": 4,
|
||||||
"max": 16,
|
"max": 16,
|
||||||
"samples": 2
|
"samples": 2
|
||||||
@ -351,7 +351,10 @@
|
|||||||
},
|
},
|
||||||
"debug draw": {
|
"debug draw": {
|
||||||
"static": true,
|
"static": true,
|
||||||
"dynamic": true
|
"dynamic": true,
|
||||||
|
"contacts": false,
|
||||||
|
"constraints": true,
|
||||||
|
"rays": false
|
||||||
},
|
},
|
||||||
"fixed step": true,
|
"fixed step": true,
|
||||||
"substeps": 4
|
"substeps": 4
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
"axis": [ 0, 1, 0 ],
|
"axis": [ 0, 1, 0 ],
|
||||||
"angle": 0
|
"angle": 0
|
||||||
},
|
},
|
||||||
"scale": [ 5.0, 5.0, 5.0 ]
|
"scale": [ 10.0, 10.0, 10.0 ]
|
||||||
},
|
},
|
||||||
"system": {
|
"system": {
|
||||||
"hot reload": {
|
"hot reload": {
|
||||||
@ -27,6 +27,9 @@
|
|||||||
"debug": {
|
"debug": {
|
||||||
"print": {
|
"print": {
|
||||||
"animations": true
|
"animations": true
|
||||||
|
},
|
||||||
|
"draw": {
|
||||||
|
"armature": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exporter": {
|
"exporter": {
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
"type": "Object",
|
"type": "Object",
|
||||||
"name": "Craeture",
|
"name": "Craeture",
|
||||||
"ignore": false,
|
"ignore": false,
|
||||||
|
"import": "./craetureModel.json",
|
||||||
"assets": [
|
"assets": [
|
||||||
"./craetureModel.json",
|
|
||||||
"./scripts/craeture.lua"
|
"./scripts/craeture.lua"
|
||||||
],
|
],
|
||||||
"behaviors": [
|
"behaviors": [
|
||||||
@ -11,13 +11,10 @@
|
|||||||
"SoundEmitterBehavior"
|
"SoundEmitterBehavior"
|
||||||
],
|
],
|
||||||
"transform": {
|
"transform": {
|
||||||
|
"position": [ -7.04676, 10.169565, -44.0822 ],
|
||||||
//"position": [ 0, 1.5, 21 ],
|
//"position": [ 0, 1.5, 21 ],
|
||||||
"position": [ 16.3489, 1.37972, -68.1571 ],
|
//"position": [ 16.3489, 1.37972, -68.1571 ],
|
||||||
"rotation": {
|
"scale": [ 0.3, 0.3, 0.3 ]
|
||||||
"axis": [ 0, 1, 0 ],
|
|
||||||
"angle": 0
|
|
||||||
},
|
|
||||||
"scale": [ 1, 1, 1 ]
|
|
||||||
},
|
},
|
||||||
"system": {
|
"system": {
|
||||||
"hot reload": {
|
"hot reload": {
|
||||||
@ -26,7 +23,17 @@
|
|||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "Craeture",
|
"name": "Craeture",
|
||||||
|
"graph": {
|
||||||
|
"debug": {
|
||||||
|
"draw": {
|
||||||
|
"armature": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"physics": {
|
||||||
|
"ragdoll": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
"physics": {
|
"physics": {
|
||||||
"gravity": [ 0, -9.81, 0 ],
|
"gravity": [ 0, -9.81, 0 ],
|
||||||
"inertia": [ 0, 0, 0 ],
|
"inertia": [ 0, 0, 0 ],
|
||||||
@ -41,5 +48,6 @@
|
|||||||
|
|
||||||
"shared": false
|
"shared": false
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,9 +7,7 @@
|
|||||||
// "/player/bear.glb"
|
// "/player/bear.glb"
|
||||||
{ "filename": "/player/bear/graph.json" }
|
{ "filename": "/player/bear/graph.json" }
|
||||||
],
|
],
|
||||||
"behaviors": [
|
"behaviors": [],
|
||||||
"CraetureBehavior"
|
|
||||||
],
|
|
||||||
"transform": {
|
"transform": {
|
||||||
"position": [ 0, -2.5, 0 ],
|
"position": [ 0, -2.5, 0 ],
|
||||||
// "position": [ 12.5715, 3.53811, 7.6238 ],
|
// "position": [ 12.5715, 3.53811, 7.6238 ],
|
||||||
@ -18,7 +16,7 @@
|
|||||||
"axis": [ 0, 1, 0 ],
|
"axis": [ 0, 1, 0 ],
|
||||||
"angle": 0
|
"angle": 0
|
||||||
},
|
},
|
||||||
"scale": [ 0.35, 0.35, 0.35 ],
|
// "scale": [ 0.35, 0.35, 0.35 ],
|
||||||
"reference": "parent"
|
"reference": "parent"
|
||||||
},
|
},
|
||||||
"system": {
|
"system": {
|
||||||
@ -50,6 +48,7 @@
|
|||||||
"filter": "linear",
|
"filter": "linear",
|
||||||
"flip textures": false,
|
"flip textures": false,
|
||||||
"invert": false,
|
"invert": false,
|
||||||
|
"render": false,
|
||||||
"skinned": true
|
"skinned": true
|
||||||
},
|
},
|
||||||
"animations": {
|
"animations": {
|
||||||
|
|||||||
@ -6,8 +6,9 @@
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"physics": {
|
"physics": {
|
||||||
"mass": 0,
|
"mass": 0,
|
||||||
"inertia": [0, 0, 0],
|
// "inertia": [0, 0, 0],
|
||||||
"type": "bounding box"
|
// "type": "bounding box"
|
||||||
|
"type": "mesh"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,5 +5,7 @@ layout (location = 0) in vec4 inColor;
|
|||||||
layout (location = 0) out vec4 outColor;
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
outColor = inColor;
|
// needs to be specified like this for some unknown reason
|
||||||
|
outColor.rgb = inColor.rgb;
|
||||||
|
outColor.a = inColor.a;
|
||||||
}
|
}
|
||||||
@ -150,6 +150,7 @@ namespace uf {
|
|||||||
void UF_API override( pod::Graph& );
|
void UF_API override( pod::Graph& );
|
||||||
void UF_API animate( pod::Graph&, const uf::stl::string&, float = 1, bool = true );
|
void UF_API animate( pod::Graph&, const uf::stl::string&, float = 1, bool = true );
|
||||||
|
|
||||||
|
uf::stl::vector<pod::Bone> collectBones( const pod::Graph& graph, const pod::Node& node );
|
||||||
uf::stl::vector<pod::OBB> obbFromSkin( const pod::Graph& graph, const pod::Node& node );
|
uf::stl::vector<pod::OBB> obbFromSkin( const pod::Graph& graph, const pod::Node& node );
|
||||||
void rigRagdoll( pod::Graph& graph, pod::Node& node );
|
void rigRagdoll( pod::Graph& graph, pod::Node& node );
|
||||||
|
|
||||||
|
|||||||
@ -58,6 +58,11 @@ namespace pod {
|
|||||||
uf::stl::vector<pod::Matrix4f> inverseBindMatrices;
|
uf::stl::vector<pod::Matrix4f> inverseBindMatrices;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct UF_API Bone {
|
||||||
|
pod::Vector3f start;
|
||||||
|
pod::Vector3f end;
|
||||||
|
};
|
||||||
|
|
||||||
struct UF_API Animation {
|
struct UF_API Animation {
|
||||||
struct Sampler {
|
struct Sampler {
|
||||||
uf::stl::string interpolator;
|
uf::stl::string interpolator;
|
||||||
|
|||||||
@ -12,6 +12,8 @@ namespace impl {
|
|||||||
|
|
||||||
pod::Transform<> getTransform( const pod::PhysicsBody& body );
|
pod::Transform<> getTransform( const pod::PhysicsBody& body );
|
||||||
pod::Vector3f getPosition( const pod::PhysicsBody& body, bool useTransform = false );
|
pod::Vector3f getPosition( const pod::PhysicsBody& body, bool useTransform = false );
|
||||||
|
pod::Vector3f apply( const pod::Transform<>& t, const pod::Vector3f& p );
|
||||||
|
pod::Vector3f applyInverse( const pod::Transform<>& t, const pod::Vector3f& p );
|
||||||
|
|
||||||
pod::PhysicsBody physicsBodyHullView( const pod::PhysicsBody& body, int32_t index = -1 );
|
pod::PhysicsBody physicsBodyHullView( const pod::PhysicsBody& body, int32_t index = -1 );
|
||||||
pod::PhysicsBody physicsBodyTriView( const pod::TriangleWithNormal triangle, const pod::PhysicsBody& body = {} );
|
pod::PhysicsBody physicsBodyTriView( const pod::TriangleWithNormal triangle, const pod::PhysicsBody& body = {} );
|
||||||
|
|||||||
@ -58,8 +58,8 @@ namespace uf {
|
|||||||
const pod::CollisionEvent::events_t& UF_API getCollisionEvents( const pod::World& world );
|
const pod::CollisionEvent::events_t& UF_API getCollisionEvents( const pod::World& world );
|
||||||
pod::CollisionEvent::events_t UF_API getCollisionEvents( const pod::PhysicsBody& body );
|
pod::CollisionEvent::events_t UF_API getCollisionEvents( const pod::PhysicsBody& body );
|
||||||
|
|
||||||
pod::PhysicsBody& UF_API create( uf::Object&, float mass = 0.0f, const pod::Vector3f& = {} );
|
pod::PhysicsBody& UF_API create( uf::Object&, float mass = 0.0f, const pod::Vector3f& = {}, const pod::Quaternion<>& = {0,0,0,1} );
|
||||||
pod::PhysicsBody& UF_API create( pod::World&, uf::Object&, float mass = 0.0f, const pod::Vector3f& = {} );
|
pod::PhysicsBody& UF_API create( pod::World&, uf::Object&, float mass = 0.0f, const pod::Vector3f& = {}, const pod::Quaternion<>& = {0,0,0,1} );
|
||||||
void UF_API destroy( uf::Object& );
|
void UF_API destroy( uf::Object& );
|
||||||
void UF_API destroy( pod::PhysicsBody& );
|
void UF_API destroy( pod::PhysicsBody& );
|
||||||
}
|
}
|
||||||
|
|||||||
@ -407,7 +407,8 @@ namespace pod {
|
|||||||
float inverseMass = 0.0f;
|
float inverseMass = 0.0f;
|
||||||
int32_t viewIndex = -1; // -1 means it's not an aliased view
|
int32_t viewIndex = -1; // -1 means it's not an aliased view
|
||||||
|
|
||||||
pod::Vector3f offset = {};
|
pod::Vector3f offsetPosition = {};
|
||||||
|
pod::Quaternion<> offsetOrientation = { 0, 0, 0, 1 };
|
||||||
|
|
||||||
pod::Vector3f velocity = {};
|
pod::Vector3f velocity = {};
|
||||||
pod::Vector3f forceAccumulator = {};
|
pod::Vector3f forceAccumulator = {};
|
||||||
@ -437,7 +438,6 @@ namespace pod {
|
|||||||
bool resolveBlockContact = true; // attempts to resolve an invalid BlockNxN solve with an BlockN-1xN-1 solve
|
bool resolveBlockContact = true; // attempts to resolve an invalid BlockNxN solve with an BlockN-1xN-1 solve
|
||||||
bool useGjk = false; // currently don't have a way to broadphase mesh => narrowphase tri via GJK
|
bool useGjk = false; // currently don't have a way to broadphase mesh => narrowphase tri via GJK
|
||||||
|
|
||||||
pod::CollisionMask debugDraw = pod::Collider::CATEGORY_NONE; // draws wireframe of collision bodies
|
|
||||||
bool async = false; // dedicated thread for physics sim
|
bool async = false; // dedicated thread for physics sim
|
||||||
float timestep = 1.0f / 60.0f; // timestep for fixed step ticks
|
float timestep = 1.0f / 60.0f; // timestep for fixed step ticks
|
||||||
bool fixedStep = true; // run physics simulation with a fixed delta time (with accumulation), rather than rely on actual engine deltatime
|
bool fixedStep = true; // run physics simulation with a fixed delta time (with accumulation), rather than rely on actual engine deltatime
|
||||||
@ -485,6 +485,13 @@ namespace pod {
|
|||||||
};
|
};
|
||||||
|
|
||||||
float groundedThreshold = 0.7f; // threshold before marking a body as grounded
|
float groundedThreshold = 0.7f; // threshold before marking a body as grounded
|
||||||
|
|
||||||
|
struct {
|
||||||
|
pod::CollisionMask mask = pod::Collider::CATEGORY_NONE; // draws wireframe of collision bodies
|
||||||
|
bool contacts = false;
|
||||||
|
bool constraints = false;
|
||||||
|
bool rays = false;
|
||||||
|
} debugDraw;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct World {
|
struct World {
|
||||||
|
|||||||
@ -223,17 +223,24 @@ void UF_API uf::load( ext::json::Value& json ) {
|
|||||||
}
|
}
|
||||||
auto& configEnginePhysicsDebugDrawJson = configEnginePhysicsJson["debug draw"];
|
auto& configEnginePhysicsDebugDrawJson = configEnginePhysicsJson["debug draw"];
|
||||||
if ( ext::json::isObject( configEnginePhysicsDebugDrawJson ) ) {
|
if ( ext::json::isObject( configEnginePhysicsDebugDrawJson ) ) {
|
||||||
if ( configEnginePhysicsDebugDrawJson["static"].as<bool>() ) uf::physics::settings.debugDraw |= pod::Collider::CATEGORY_STATIC;
|
if ( configEnginePhysicsDebugDrawJson["static"].as<bool>() ) uf::physics::settings.debugDraw.mask |= pod::Collider::CATEGORY_STATIC;
|
||||||
if ( configEnginePhysicsDebugDrawJson["dynamic"].as<bool>() ) uf::physics::settings.debugDraw |= pod::Collider::CATEGORY_DYNAMIC;
|
if ( configEnginePhysicsDebugDrawJson["dynamic"].as<bool>() ) uf::physics::settings.debugDraw.mask |= pod::Collider::CATEGORY_DYNAMIC;
|
||||||
if ( configEnginePhysicsDebugDrawJson["player"].as<bool>() ) uf::physics::settings.debugDraw |= pod::Collider::CATEGORY_PLAYER;
|
if ( configEnginePhysicsDebugDrawJson["player"].as<bool>() ) uf::physics::settings.debugDraw.mask |= pod::Collider::CATEGORY_PLAYER;
|
||||||
if ( configEnginePhysicsDebugDrawJson["npc"].as<bool>() ) uf::physics::settings.debugDraw |= pod::Collider::CATEGORY_NPC;
|
if ( configEnginePhysicsDebugDrawJson["npc"].as<bool>() ) uf::physics::settings.debugDraw.mask |= pod::Collider::CATEGORY_NPC;
|
||||||
if ( configEnginePhysicsDebugDrawJson["trigger"].as<bool>() ) uf::physics::settings.debugDraw |= pod::Collider::CATEGORY_TRIGGER;
|
if ( configEnginePhysicsDebugDrawJson["trigger"].as<bool>() ) uf::physics::settings.debugDraw.mask |= pod::Collider::CATEGORY_TRIGGER;
|
||||||
if ( configEnginePhysicsDebugDrawJson["projectile"].as<bool>() ) uf::physics::settings.debugDraw |= pod::Collider::CATEGORY_PROJECTILE;
|
if ( configEnginePhysicsDebugDrawJson["projectile"].as<bool>() ) uf::physics::settings.debugDraw.mask |= pod::Collider::CATEGORY_PROJECTILE;
|
||||||
if ( configEnginePhysicsDebugDrawJson["character"].as<bool>() ) uf::physics::settings.debugDraw |= pod::Collider::CATEGORY_CHARACTER;
|
if ( configEnginePhysicsDebugDrawJson["character"].as<bool>() ) uf::physics::settings.debugDraw.mask |= pod::Collider::CATEGORY_CHARACTER;
|
||||||
if ( configEnginePhysicsDebugDrawJson["all"].as<bool>() ) uf::physics::settings.debugDraw |= pod::Collider::CATEGORY_ALL;
|
if ( configEnginePhysicsDebugDrawJson["all"].as<bool>() ) uf::physics::settings.debugDraw.mask |= pod::Collider::CATEGORY_ALL;
|
||||||
|
|
||||||
|
uf::physics::settings.debugDraw.contacts = configEnginePhysicsDebugDrawJson["contacts"].as( uf::physics::settings.debugDraw.contacts );
|
||||||
|
uf::physics::settings.debugDraw.constraints = configEnginePhysicsDebugDrawJson["constraints"].as( uf::physics::settings.debugDraw.constraints );
|
||||||
|
uf::physics::settings.debugDraw.rays = configEnginePhysicsDebugDrawJson["rays"].as( uf::physics::settings.debugDraw.rays );
|
||||||
|
|
||||||
} else if ( configEnginePhysicsDebugDrawJson.is<bool>() && configEnginePhysicsDebugDrawJson.as<bool>() ) {
|
} else if ( configEnginePhysicsDebugDrawJson.is<bool>() && configEnginePhysicsDebugDrawJson.as<bool>() ) {
|
||||||
uf::physics::settings.debugDraw = pod::Collider::CATEGORY_ALL;
|
uf::physics::settings.debugDraw.mask = pod::Collider::CATEGORY_ALL;
|
||||||
|
uf::physics::settings.debugDraw.contacts = true;
|
||||||
|
uf::physics::settings.debugDraw.constraints = true;
|
||||||
|
uf::physics::settings.debugDraw.rays = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -76,17 +76,18 @@ namespace {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
pod::Matrix4f localMatrix( pod::Graph& graph, int32_t index ) {
|
pod::Matrix4f localMatrix( const pod::Graph& graph, int32_t index ) {
|
||||||
auto& node = 0 < index && index <= graph.nodes.size() ? graph.nodes[index] : graph.root;
|
auto& node = 0 < index && index <= graph.nodes.size() ? graph.nodes[index] : graph.root;
|
||||||
|
auto& transform = node.transform;
|
||||||
return
|
return
|
||||||
uf::matrix::translate( uf::matrix::identity(), node.transform.position ) *
|
uf::matrix::translate( uf::matrix::identity(), transform.position ) *
|
||||||
uf::quaternion::matrix(node.transform.orientation) *
|
uf::quaternion::matrix(transform.orientation) *
|
||||||
uf::matrix::scale( uf::matrix::identity(), node.transform.scale ) *
|
uf::matrix::scale( uf::matrix::identity(), transform.scale ) *
|
||||||
node.transform.model;
|
transform.model;
|
||||||
}
|
}
|
||||||
pod::Matrix4f worldMatrix( pod::Graph& graph, int32_t index ) {
|
pod::Matrix4f worldMatrix( const pod::Graph& graph, int32_t index ) {
|
||||||
pod::Matrix4f matrix = ::localMatrix( graph, index );
|
pod::Matrix4f matrix = ::localMatrix( graph, index );
|
||||||
auto& node = *uf::graph::find( graph, index );
|
auto& node = 0 < index && index <= graph.nodes.size() ? graph.nodes[index] : graph.root;
|
||||||
int32_t parent = node.parent;
|
int32_t parent = node.parent;
|
||||||
while ( 0 < parent && parent <= graph.nodes.size() ) {
|
while ( 0 < parent && parent <= graph.nodes.size() ) {
|
||||||
matrix = ::localMatrix( graph, parent ) * matrix;
|
matrix = ::localMatrix( graph, parent ) * matrix;
|
||||||
@ -261,6 +262,25 @@ void uf::graph::updateAnimation( pod::Graph& graph, pod::Node& node ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// separate function in the event something later might need it
|
// separate function in the event something later might need it
|
||||||
|
uf::stl::vector<pod::Bone> uf::graph::collectBones( const pod::Graph& graph, const pod::Node& node ) {
|
||||||
|
auto& storage = ::getGraphStorage(uf::scene::getCurrentScene());
|
||||||
|
auto& name = graph.skins[node.skin];
|
||||||
|
auto& skin = storage.skins[name];
|
||||||
|
|
||||||
|
uf::stl::vector<pod::Bone> bones( graph.nodes.size() );
|
||||||
|
for ( auto i = 0; i < skin.joints.size(); ++i ) {
|
||||||
|
auto nodeID = skin.joints[i];
|
||||||
|
auto& node = graph.nodes[nodeID];
|
||||||
|
if ( node.parent < 0 ) continue;
|
||||||
|
auto& parent = graph.nodes[node.parent];
|
||||||
|
|
||||||
|
auto tA = uf::transform::flatten( parent.transform );
|
||||||
|
auto tB = uf::transform::flatten( node.transform );
|
||||||
|
|
||||||
|
bones[nodeID] = pod::Bone{ tA.position, tB.position };
|
||||||
|
}
|
||||||
|
return bones;
|
||||||
|
}
|
||||||
uf::stl::vector<pod::OBB> uf::graph::obbFromSkin( const pod::Graph& graph, const pod::Node& node ) {
|
uf::stl::vector<pod::OBB> uf::graph::obbFromSkin( const pod::Graph& graph, const pod::Node& node ) {
|
||||||
const float wThresold = 0.15f;
|
const float wThresold = 0.15f;
|
||||||
|
|
||||||
@ -290,11 +310,11 @@ uf::stl::vector<pod::OBB> uf::graph::obbFromSkin( const pod::Graph& graph, const
|
|||||||
|
|
||||||
for ( auto w = 0; w < 4; ++w ) {
|
for ( auto w = 0; w < 4; ++w ) {
|
||||||
if ( weights[w] <= wThresold ) continue;
|
if ( weights[w] <= wThresold ) continue;
|
||||||
uint16_t boneID = joints[w];
|
uint16_t jointID = joints[w];
|
||||||
pod::Vector3f localPos = uf::matrix::multiply( skin.inverseBindMatrices[boneID], pos );
|
pod::Vector3f localPos = uf::matrix::multiply( skin.inverseBindMatrices[jointID], pos );
|
||||||
|
|
||||||
bounds[boneID].center = uf::vector::min( bounds[boneID].center, localPos );
|
bounds[jointID].center = uf::vector::min( bounds[jointID].center, localPos );
|
||||||
bounds[boneID].extent = uf::vector::max( bounds[boneID].extent, localPos );
|
bounds[jointID].extent = uf::vector::max( bounds[jointID].extent, localPos );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,5 +330,107 @@ uf::stl::vector<pod::OBB> uf::graph::obbFromSkin( const pod::Graph& graph, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void uf::graph::rigRagdoll( pod::Graph& graph, pod::Node& node ) {
|
void uf::graph::rigRagdoll( pod::Graph& graph, pod::Node& node ) {
|
||||||
// scrapped for now
|
auto& storage = ::getGraphStorage(uf::scene::getCurrentScene());
|
||||||
|
auto& name = graph.skins[node.skin];
|
||||||
|
auto& skin = storage.skins[name];
|
||||||
|
|
||||||
|
auto bounds = uf::graph::obbFromSkin( graph, node );
|
||||||
|
auto bones = uf::graph::collectBones( graph, node );
|
||||||
|
auto armatureTransform = uf::transform::flatten( graph.root.entity->getComponent<pod::Transform<>>() );
|
||||||
|
|
||||||
|
// create physics bodies
|
||||||
|
uf::stl::vector<pod::PhysicsBody*> bodies( graph.nodes.size(), NULL );
|
||||||
|
|
||||||
|
for ( auto i = 0; i < skin.joints.size(); ++i ) {
|
||||||
|
auto nodeID = skin.joints[i];
|
||||||
|
auto& node = graph.nodes[nodeID];
|
||||||
|
if ( node.parent < 0 ) continue;
|
||||||
|
auto& entity = *node.entity;
|
||||||
|
auto transform = uf::transform::flatten( entity.getComponent<pod::Transform<>>() );
|
||||||
|
|
||||||
|
// this definitely could be done better......
|
||||||
|
auto& bone = bones[nodeID];
|
||||||
|
auto& obb = bounds[i];
|
||||||
|
// if ( obb.extent.x < 0 ) continue;
|
||||||
|
// transform center into world space
|
||||||
|
auto boneCenter = uf::transform::apply( armatureTransform, (bone.end + bone.start) * 0.5f );
|
||||||
|
// transform back into local space
|
||||||
|
auto offset = uf::transform::applyInverse( transform, boneCenter );
|
||||||
|
auto orientation = uf::quaternion::identity();
|
||||||
|
float length = uf::vector::norm( offset ) * 2.0f;
|
||||||
|
|
||||||
|
float mass = 100.0f;
|
||||||
|
auto& body = uf::physics::create( entity, mass, offset, orientation );
|
||||||
|
if ( obb.extent.x < 0 ) {
|
||||||
|
uf::physics::initialize( body, pod::Sphere{ 0.1f } );
|
||||||
|
} else {
|
||||||
|
uf::physics::initialize( body, pod::OBB{ pod::Vector3f{}, obb.extent * armatureTransform.scale } );
|
||||||
|
}
|
||||||
|
//uf::physics::initialize( body, pod::Capsule{ 0.5f, length * 0.5f } );
|
||||||
|
|
||||||
|
bodies[nodeID] = &body;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create constraints
|
||||||
|
for ( auto i = 0; i < skin.joints.size(); ++i ) {
|
||||||
|
auto nodeID = skin.joints[i];
|
||||||
|
auto& node = graph.nodes[nodeID];
|
||||||
|
if ( !bodies[node.parent] ) continue; // no parent body, skip constraint
|
||||||
|
if ( !bodies[nodeID] ) continue; // no node body, skip constraint
|
||||||
|
|
||||||
|
auto& bodyA = *bodies[node.parent];
|
||||||
|
auto& bodyB = *bodies[nodeID];
|
||||||
|
|
||||||
|
auto tA = uf::transform::flatten( *bodyA.transform ); // bone start
|
||||||
|
auto tB = uf::transform::flatten( *bodyB.transform ); // bone end
|
||||||
|
|
||||||
|
auto pivot = tA.position;
|
||||||
|
auto axis = uf::vector::normalize( tB.position - tA.position );
|
||||||
|
|
||||||
|
auto& constraint = uf::physics::constrain( bodyA, bodyB );
|
||||||
|
uf::physics::constrainConeTwist( constraint, pivot, axis );
|
||||||
|
}
|
||||||
|
|
||||||
|
// works only pre-init and for no scaling
|
||||||
|
#if 0
|
||||||
|
for ( auto i = 0; i < skin.joints.size(); ++i ) {
|
||||||
|
auto nodeID = skin.joints[i];
|
||||||
|
auto& node = graph.nodes[nodeID];
|
||||||
|
if ( node.parent < 0 ) continue;
|
||||||
|
auto& entity = *node.entity;
|
||||||
|
|
||||||
|
auto boneStart = uf::transform::applyInverse( node.transform, pod::Vector3f{0, 0, 0} );
|
||||||
|
auto offset = uf::vector::lerp( boneStart, pod::Vector3f{}, 0.5f );
|
||||||
|
auto orientation = uf::quaternion::identity();
|
||||||
|
// float length = ...
|
||||||
|
|
||||||
|
float mass = 0.0f;
|
||||||
|
auto& body = uf::physics::create( entity, mass, offset, orientation );
|
||||||
|
uf::physics::initialize( body, pod::Sphere{ 0.5f } );
|
||||||
|
|
||||||
|
bodies[nodeID] = &body;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create constraints
|
||||||
|
for ( auto i = 0; i < skin.joints.size(); ++i ) {
|
||||||
|
auto nodeID = skin.joints[i];
|
||||||
|
auto& node = graph.nodes[nodeID];
|
||||||
|
if ( node.parent < 0 ) continue;
|
||||||
|
auto& parent = graph.nodes[node.parent];
|
||||||
|
if ( bodies.count( node.parent ) == 0 ) continue;
|
||||||
|
if ( bodies.count( nodeID ) == 0 ) continue;
|
||||||
|
|
||||||
|
auto& bodyA = bodies[node.parent];
|
||||||
|
auto& bodyB = bodies[nodeID];
|
||||||
|
|
||||||
|
auto tA = uf::transform::flatten( parent.transform );
|
||||||
|
auto tB = uf::transform::flatten( node.transform );
|
||||||
|
|
||||||
|
auto pivot = tA.position;
|
||||||
|
auto axis = uf::vector::normalize( tB.position - tA.position );
|
||||||
|
|
||||||
|
auto& constraint = uf::physics::constrain( *bodyA, *bodyB );
|
||||||
|
uf::physics::constrainConeTwist( constraint, pivot, axis );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
@ -1113,17 +1113,6 @@ void uf::graph::process( pod::Graph& graph ) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
UF_DEBUG_TIMER_MULTITRACE("Rigging ragdolls");
|
|
||||||
for ( auto& node : graph.nodes ) {
|
|
||||||
if ( node.skin < 0 || node.mesh < 0 ) continue;
|
|
||||||
ext::json::Value tag = ext::json::find( node.name, graphMetadataJson["tags"] );
|
|
||||||
if ( ext::json::isNull( tag ) ) tag["physics"] = graphMetadataJson["physics"];
|
|
||||||
if ( tag["physics"]["ragdoll"].as<bool>(false) ) {
|
|
||||||
uf::graph::rigRagdoll( graph, node );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UF_DEBUG_TIMER_MULTITRACE_END("Rigged ragdolls.");
|
|
||||||
|
|
||||||
UF_DEBUG_TIMER_MULTITRACE("Updating master graph");
|
UF_DEBUG_TIMER_MULTITRACE("Updating master graph");
|
||||||
#if UF_GRAPH_EXTENDED
|
#if UF_GRAPH_EXTENDED
|
||||||
uf::graph::reload( graph );
|
uf::graph::reload( graph );
|
||||||
@ -1406,6 +1395,15 @@ void uf::graph::initialize( pod::Graph& graph ) {
|
|||||||
if ( entity->getUid() == 0 ) entity->initialize();
|
if ( entity->getUid() == 0 ) entity->initialize();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
auto& graphMetadataJson = graph.metadata;
|
||||||
|
for ( auto& node : graph.nodes ) {
|
||||||
|
if ( node.skin < 0 || node.mesh < 0 ) continue;
|
||||||
|
ext::json::Value tag = ext::json::find( node.name, graphMetadataJson["tags"] );
|
||||||
|
if ( ext::json::isNull( tag ) ) tag["physics"] = graphMetadataJson["physics"];
|
||||||
|
if ( tag["physics"]["ragdoll"].as<bool>(false) ) {
|
||||||
|
uf::graph::rigRagdoll( graph, node );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto& scene = uf::scene::getCurrentScene();
|
auto& scene = uf::scene::getCurrentScene();
|
||||||
scene.invalidateGraph();
|
scene.invalidateGraph();
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
#include <uf/utils/mesh/mesh.h>
|
#include <uf/utils/mesh/mesh.h>
|
||||||
#include <uf/utils/string/hash.h>
|
#include <uf/utils/string/hash.h>
|
||||||
#include <uf/utils/io/inputs.h>
|
#include <uf/utils/io/inputs.h>
|
||||||
|
#include <uf/utils/debug/draw.h>
|
||||||
|
|
||||||
UF_BEHAVIOR_REGISTER_CPP(uf::GraphBehavior)
|
UF_BEHAVIOR_REGISTER_CPP(uf::GraphBehavior)
|
||||||
UF_BEHAVIOR_TRAITS_CPP(uf::GraphBehavior, ticks = true, renders = false, thread = "")
|
UF_BEHAVIOR_TRAITS_CPP(uf::GraphBehavior, ticks = true, renders = false, thread = "")
|
||||||
@ -68,13 +69,32 @@ void uf::GraphBehavior::initialize( uf::Object& self ) {
|
|||||||
}
|
}
|
||||||
void uf::GraphBehavior::destroy( uf::Object& self ) {}
|
void uf::GraphBehavior::destroy( uf::Object& self ) {}
|
||||||
void uf::GraphBehavior::tick( uf::Object& self ) {
|
void uf::GraphBehavior::tick( uf::Object& self ) {
|
||||||
/* Test */ {
|
if ( !this->hasComponent<pod::Graph>() ) return;
|
||||||
TIMER(1, uf::inputs::kbm::states::T ) {
|
|
||||||
UF_MSG_DEBUG("Regenerating graph graphics...");
|
|
||||||
auto& graph = this->getComponent<pod::Graph>();
|
auto& graph = this->getComponent<pod::Graph>();
|
||||||
uf::graph::reload( graph );
|
if ( !graph.metadata["debug"]["draw"]["armature"].as<bool>(false) ) return;
|
||||||
|
auto& transform = this->getComponent<pod::Transform<>>();
|
||||||
|
for ( auto& node : graph.nodes ) {
|
||||||
|
if ( node.skin < 0 || node.mesh < 0 ) continue;
|
||||||
|
auto bones = uf::graph::collectBones( graph, node );
|
||||||
|
for ( auto& bone : bones ) {
|
||||||
|
bone.start = uf::transform::apply( transform, bone.start );
|
||||||
|
bone.end = uf::transform::apply( transform, bone.end );
|
||||||
|
|
||||||
|
uf::debug::drawLine( bone.start, bone.end, pod::Vector4f{ 0, 1, 0, 1 } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool hid = false;
|
||||||
|
if ( hid ) return;
|
||||||
|
hid = true;
|
||||||
|
this->process([&](uf::Entity* entity){
|
||||||
|
if ( !entity->hasComponent<uf::Graphic>() ) return;
|
||||||
|
auto& graphic = entity->getComponent<uf::Graphic>();
|
||||||
|
if ( !graphic.initialized ) return;
|
||||||
|
auto& descriptorSet = graphic.getDescriptorSet();
|
||||||
|
descriptorSet.metadata.process = false;
|
||||||
|
uf::renderer::states::rebuild = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
void uf::GraphBehavior::render( uf::Object& self ) {}
|
void uf::GraphBehavior::render( uf::Object& self ) {}
|
||||||
void uf::GraphBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ) {}
|
void uf::GraphBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ) {}
|
||||||
|
|||||||
@ -31,7 +31,8 @@ namespace binds {
|
|||||||
|
|
||||||
pod::Transform<> getTransform( pod::PhysicsBody& body ) {
|
pod::Transform<> getTransform( pod::PhysicsBody& body ) {
|
||||||
pod::Transform<> t;
|
pod::Transform<> t;
|
||||||
t.position = body.offset;
|
t.position = body.offsetPosition;
|
||||||
|
t.orientation = body.offsetOrientation;
|
||||||
t.reference = body.transform;
|
t.reference = body.transform;
|
||||||
return uf::transform::flatten( t );
|
return uf::transform::flatten( t );
|
||||||
}
|
}
|
||||||
|
|||||||
@ -219,7 +219,7 @@ void uf::debug::draw( float dt ) {
|
|||||||
graphic.material.device = &uf::renderer::device;
|
graphic.material.device = &uf::renderer::device;
|
||||||
|
|
||||||
// to-do: bin by descriptor instead of one global set
|
// to-do: bin by descriptor instead of one global set
|
||||||
graphic.descriptor.depth.test = true;
|
graphic.descriptor.depth.test = false;
|
||||||
graphic.descriptor.depth.write = false;
|
graphic.descriptor.depth.write = false;
|
||||||
graphic.descriptor.renderTarget = 1; // "forward";
|
graphic.descriptor.renderTarget = 1; // "forward";
|
||||||
graphic.descriptor.topology = uf::renderer::enums::PrimitiveTopology::LINE_LIST;
|
graphic.descriptor.topology = uf::renderer::enums::PrimitiveTopology::LINE_LIST;
|
||||||
|
|||||||
@ -65,12 +65,9 @@ void impl::updateActivity( pod::PhysicsBody& body, float dt ) {
|
|||||||
// to-do: find a succinct way to explain this madness
|
// to-do: find a succinct way to explain this madness
|
||||||
pod::Transform<> impl::getTransform( const pod::PhysicsBody& body ) {
|
pod::Transform<> impl::getTransform( const pod::PhysicsBody& body ) {
|
||||||
pod::Transform<> t;
|
pod::Transform<> t;
|
||||||
t.position = body.offset;
|
t.position = body.offsetPosition;
|
||||||
#if UF_PHYSICS_SYNC_TRANSFORMS
|
t.orientation = body.offsetOrientation;
|
||||||
t.reference = const_cast<pod::Transform<>*>( &body.flattenedTransform );
|
|
||||||
#else
|
|
||||||
t.reference = body.transform;
|
t.reference = body.transform;
|
||||||
#endif
|
|
||||||
return uf::transform::flatten( t );
|
return uf::transform::flatten( t );
|
||||||
}
|
}
|
||||||
// get position of a body, uses bounds center or transform's position
|
// get position of a body, uses bounds center or transform's position
|
||||||
@ -78,6 +75,23 @@ pod::Vector3f impl::getPosition( const pod::PhysicsBody& body, bool useTransform
|
|||||||
if ( !useTransform ) return impl::aabbCenter( body.bounds );
|
if ( !useTransform ) return impl::aabbCenter( body.bounds );
|
||||||
return impl::getTransform( body ).position;
|
return impl::getTransform( body ).position;
|
||||||
}
|
}
|
||||||
|
// applies a transform
|
||||||
|
pod::Vector3f impl::apply( const pod::Transform<>& t, const pod::Vector3f& p ) {
|
||||||
|
return uf::transform::apply( t, p );
|
||||||
|
}
|
||||||
|
// applies an inverse transform
|
||||||
|
pod::Vector3f impl::applyInverse( const pod::Transform<>& t, const pod::Vector3f& p ) {
|
||||||
|
return uf::transform::applyInverse( t, p );
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
// these isometrically applies a transform
|
||||||
|
pod::Vector3f impl::apply( const pod::Transform<>& t, const pod::Vector3f& p ) {
|
||||||
|
return uf::quaternion::rotate( t.orientation, p + t.position );
|
||||||
|
}
|
||||||
|
pod::Vector3f impl::applyInverse( const pod::Transform<>& t, const pod::Vector3f& p ) {
|
||||||
|
return uf::quaternion::rotate( uf::quaternion::inverse( t.orientation ), p - t.position );
|
||||||
|
}
|
||||||
|
*/
|
||||||
// creates a view of a hull body
|
// creates a view of a hull body
|
||||||
pod::PhysicsBody impl::physicsBodyHullView( const pod::PhysicsBody& body, int32_t index ) {
|
pod::PhysicsBody impl::physicsBodyHullView( const pod::PhysicsBody& body, int32_t index ) {
|
||||||
pod::PhysicsBody view = body;
|
pod::PhysicsBody view = body;
|
||||||
@ -94,7 +108,8 @@ pod::PhysicsBody impl::physicsBodyTriView( const pod::TriangleWithNormal triangl
|
|||||||
view.collider.triangle.normal = impl::triangleNormal( (const pod::Triangle&) triangle );
|
view.collider.triangle.normal = impl::triangleNormal( (const pod::Triangle&) triangle );
|
||||||
}
|
}
|
||||||
// assume triangle is already transformed
|
// assume triangle is already transformed
|
||||||
view.offset = {};
|
view.offsetPosition = {};
|
||||||
|
view.offsetOrientation = {0,0,0,1};
|
||||||
view.transform = NULL;
|
view.transform = NULL;
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,8 +14,11 @@ void impl::solveBallSocketConstraint( pod::Constraint& constraint, float dt ) {
|
|||||||
auto tA = impl::getTransform( a );
|
auto tA = impl::getTransform( a );
|
||||||
auto tB = impl::getTransform( b );
|
auto tB = impl::getTransform( b );
|
||||||
|
|
||||||
auto rA = uf::quaternion::rotate( tA.orientation, joint.localAnchorA );
|
auto anchorA = joint.localAnchorA * tA.scale;
|
||||||
auto rB = uf::quaternion::rotate( tB.orientation, joint.localAnchorB );
|
auto anchorB = joint.localAnchorB * tB.scale;
|
||||||
|
|
||||||
|
auto rA = uf::quaternion::rotate( tA.orientation, anchorA );
|
||||||
|
auto rB = uf::quaternion::rotate( tB.orientation, anchorB );
|
||||||
|
|
||||||
pod::Matrix3f K = {};
|
pod::Matrix3f K = {};
|
||||||
pod::Vector3f axes[3] = { {1,0,0}, {0,1,0}, {0,0,1} };
|
pod::Vector3f axes[3] = { {1,0,0}, {0,1,0}, {0,0,1} };
|
||||||
@ -63,13 +66,12 @@ pod::Constraint& uf::physics::constrainBallSocket( pod::Constraint& constraint,
|
|||||||
void impl::drawBallSocket( const pod::Constraint& constraint ) {
|
void impl::drawBallSocket( const pod::Constraint& constraint ) {
|
||||||
if ( !constraint.a || !constraint.b ) return;
|
if ( !constraint.a || !constraint.b ) return;
|
||||||
|
|
||||||
auto tA = impl::getTransform(*constraint.a);
|
|
||||||
auto tB = impl::getTransform(*constraint.b);
|
|
||||||
|
|
||||||
const auto& joint = constraint.ballSocket;
|
const auto& joint = constraint.ballSocket;
|
||||||
|
auto tA = impl::getTransform( *constraint.a );
|
||||||
|
auto tB = impl::getTransform( *constraint.b );
|
||||||
|
|
||||||
auto pA = tA.position + uf::quaternion::rotate(tA.orientation, joint.localAnchorA);
|
auto pA = uf::transform::apply( tA, joint.localAnchorA );
|
||||||
auto pB = tB.position + uf::quaternion::rotate(tB.orientation, joint.localAnchorB);
|
auto pB = uf::transform::apply( tB, joint.localAnchorB );
|
||||||
|
|
||||||
uf::debug::drawLine( tA.position, pA );
|
uf::debug::drawLine( tA.position, pA );
|
||||||
uf::debug::drawLine( tB.position, pB );
|
uf::debug::drawLine( tB.position, pB );
|
||||||
|
|||||||
@ -172,26 +172,26 @@ pod::Constraint& uf::physics::constrainConeTwist( pod::Constraint& constraint, c
|
|||||||
void impl::drawConeTwist( const pod::Constraint& constraint ) {
|
void impl::drawConeTwist( const pod::Constraint& constraint ) {
|
||||||
if ( !constraint.a || !constraint.b ) return;
|
if ( !constraint.a || !constraint.b ) return;
|
||||||
|
|
||||||
auto tA = impl::getTransform(*constraint.a);
|
|
||||||
auto tB = impl::getTransform(*constraint.b);
|
|
||||||
const auto& joint = constraint.coneTwist;
|
const auto& joint = constraint.coneTwist;
|
||||||
|
auto tA = impl::getTransform( *constraint.a );
|
||||||
|
auto tB = impl::getTransform( *constraint.b );
|
||||||
|
|
||||||
auto pA = tA.position + uf::quaternion::rotate(tA.orientation, joint.localAnchorA);
|
auto pA = uf::transform::apply( tA, joint.localAnchorA );
|
||||||
auto pB = tB.position + uf::quaternion::rotate(tB.orientation, joint.localAnchorB);
|
auto pB = uf::transform::apply( tB, joint.localAnchorB );
|
||||||
|
|
||||||
auto taA = uf::quaternion::rotate(tA.orientation, joint.localTwistAxisA);
|
auto taA = uf::quaternion::rotate( tA.orientation, joint.localTwistAxisA );
|
||||||
auto taB = uf::quaternion::rotate(tB.orientation, joint.localTwistAxisB);
|
auto taB = uf::quaternion::rotate( tB.orientation, joint.localTwistAxisB );
|
||||||
|
|
||||||
auto raA = uf::quaternion::rotate(tA.orientation, joint.localReferenceAxisA);
|
auto raA = uf::quaternion::rotate( tA.orientation, joint.localReferenceAxisA );
|
||||||
auto raB = uf::quaternion::rotate(tB.orientation, joint.localReferenceAxisB);
|
auto raB = uf::quaternion::rotate( tB.orientation, joint.localReferenceAxisB );
|
||||||
|
|
||||||
uf::debug::drawLine( pA, pB );
|
uf::debug::drawLine( pA, pB, pod::Vector4f{ 1, 1, 0, 1 } ); // yellow
|
||||||
|
|
||||||
float axisLength = 0.5f;
|
float axisLength = 0.5f;
|
||||||
uf::debug::drawLine( pA, pA + taA * axisLength );
|
uf::debug::drawLine( pA, pA + taA * axisLength, pod::Vector4f{ 1, 0, 1, 1 } ); // pink
|
||||||
uf::debug::drawLine( pB, pB + taB * axisLength );
|
uf::debug::drawLine( pB, pB + taB * axisLength, pod::Vector4f{ 1, 0, 1, 1 } );
|
||||||
|
|
||||||
float refLength = 0.25f;
|
float refLength = 0.25f;
|
||||||
uf::debug::drawLine( pA, pA + raA * refLength );
|
uf::debug::drawLine( pA, pA + raA * refLength, pod::Vector4f{ 0, 1, 1, 1 } ); // cyan
|
||||||
uf::debug::drawLine( pB, pB + raB * refLength );
|
uf::debug::drawLine( pB, pB + raB * refLength, pod::Vector4f{ 0, 1, 1, 1 } );
|
||||||
}
|
}
|
||||||
@ -11,8 +11,11 @@ void impl::solveDistanceConstraint( pod::Constraint& constraint, float dt ) {
|
|||||||
auto tA = impl::getTransform( a );
|
auto tA = impl::getTransform( a );
|
||||||
auto tB = impl::getTransform( b );
|
auto tB = impl::getTransform( b );
|
||||||
|
|
||||||
auto rA = uf::quaternion::rotate( tA.orientation, joint.localAnchorA );
|
auto anchorA = joint.localAnchorA * tA.scale;
|
||||||
auto rB = uf::quaternion::rotate( tB.orientation, joint.localAnchorB );
|
auto anchorB = joint.localAnchorB * tB.scale;
|
||||||
|
|
||||||
|
auto rA = uf::quaternion::rotate( tA.orientation, anchorA );
|
||||||
|
auto rB = uf::quaternion::rotate( tB.orientation, anchorB );
|
||||||
|
|
||||||
auto pA = tA.position + rA;
|
auto pA = tA.position + rA;
|
||||||
auto pB = tB.position + rB;
|
auto pB = tB.position + rB;
|
||||||
@ -58,13 +61,12 @@ pod::Constraint& uf::physics::constrainDistance( pod::Constraint& constraint, co
|
|||||||
void impl::drawDistance( const pod::Constraint& constraint ) {
|
void impl::drawDistance( const pod::Constraint& constraint ) {
|
||||||
if ( !constraint.a || !constraint.b ) return;
|
if ( !constraint.a || !constraint.b ) return;
|
||||||
|
|
||||||
auto tA = impl::getTransform(*constraint.a);
|
|
||||||
auto tB = impl::getTransform(*constraint.b);
|
|
||||||
|
|
||||||
const auto& joint = constraint.distance;
|
const auto& joint = constraint.distance;
|
||||||
|
auto tA = impl::getTransform( *constraint.a );
|
||||||
|
auto tB = impl::getTransform( *constraint.b );
|
||||||
|
|
||||||
auto pA = tA.position + uf::quaternion::rotate(tA.orientation, joint.localAnchorA);
|
auto pA = uf::transform::apply( tA, joint.localAnchorA );
|
||||||
auto pB = tB.position + uf::quaternion::rotate(tB.orientation, joint.localAnchorB);
|
auto pB = uf::transform::apply( tB, joint.localAnchorB );
|
||||||
|
|
||||||
uf::debug::drawLine( tA.position, pA );
|
uf::debug::drawLine( tA.position, pA );
|
||||||
uf::debug::drawLine( tB.position, pB );
|
uf::debug::drawLine( tB.position, pB );
|
||||||
|
|||||||
@ -76,16 +76,15 @@ pod::Constraint& uf::physics::constrainHinge( pod::Constraint& constraint, const
|
|||||||
void impl::drawHinge( const pod::Constraint& constraint ) {
|
void impl::drawHinge( const pod::Constraint& constraint ) {
|
||||||
if ( !constraint.a || !constraint.b ) return;
|
if ( !constraint.a || !constraint.b ) return;
|
||||||
|
|
||||||
auto tA = impl::getTransform(*constraint.a);
|
|
||||||
auto tB = impl::getTransform(*constraint.b);
|
|
||||||
|
|
||||||
const auto& joint = constraint.hinge;
|
const auto& joint = constraint.hinge;
|
||||||
|
auto tA = impl::getTransform( *constraint.a );
|
||||||
|
auto tB = impl::getTransform( *constraint.b );
|
||||||
|
|
||||||
auto pA = tA.position + uf::quaternion::rotate(tA.orientation, joint.localAnchorA);
|
auto pA = uf::transform::apply( tA, joint.localAnchorA );
|
||||||
auto pB = tB.position + uf::quaternion::rotate(tB.orientation, joint.localAnchorB);
|
auto pB = uf::transform::apply( tB, joint.localAnchorB );
|
||||||
|
|
||||||
auto aA = uf::quaternion::rotate(tA.orientation, joint.localAxisA);
|
auto aA = uf::quaternion::rotate( tA.orientation, joint.localAxisA );
|
||||||
auto aB = uf::quaternion::rotate(tB.orientation, joint.localAxisB);
|
auto aB = uf::quaternion::rotate( tB.orientation, joint.localAxisB );
|
||||||
|
|
||||||
uf::debug::drawLine( pA, pB );
|
uf::debug::drawLine( pA, pB );
|
||||||
|
|
||||||
|
|||||||
@ -12,8 +12,11 @@ void impl::solveSliderConstraint( pod::Constraint& constraint, float dt ) {
|
|||||||
auto tA = impl::getTransform( a );
|
auto tA = impl::getTransform( a );
|
||||||
auto tB = impl::getTransform( b );
|
auto tB = impl::getTransform( b );
|
||||||
|
|
||||||
auto rA = uf::quaternion::rotate( tA.orientation, joint.localAnchorA );
|
auto anchorA = joint.localAnchorA * tA.scale;
|
||||||
auto rB = uf::quaternion::rotate( tB.orientation, joint.localAnchorB );
|
auto anchorB = joint.localAnchorB * tB.scale;
|
||||||
|
|
||||||
|
auto rA = uf::quaternion::rotate( tA.orientation, anchorA );
|
||||||
|
auto rB = uf::quaternion::rotate( tB.orientation, anchorB );
|
||||||
|
|
||||||
auto pA = tA.position + rA;
|
auto pA = tA.position + rA;
|
||||||
auto pB = tB.position + rB;
|
auto pB = tB.position + rB;
|
||||||
|
|||||||
@ -11,8 +11,11 @@ void impl::solveSpringConstraint( pod::Constraint& constraint, float dt ) {
|
|||||||
auto tA = impl::getTransform( a );
|
auto tA = impl::getTransform( a );
|
||||||
auto tB = impl::getTransform( b );
|
auto tB = impl::getTransform( b );
|
||||||
|
|
||||||
auto rA = uf::quaternion::rotate( tA.orientation, joint.localAnchorA );
|
auto anchorA = joint.localAnchorA * tA.scale;
|
||||||
auto rB = uf::quaternion::rotate( tB.orientation, joint.localAnchorB );
|
auto anchorB = joint.localAnchorB * tB.scale;
|
||||||
|
|
||||||
|
auto rA = uf::quaternion::rotate( tA.orientation, anchorA );
|
||||||
|
auto rB = uf::quaternion::rotate( tB.orientation, anchorB );
|
||||||
|
|
||||||
auto worldAnchorA = tA.position + rA;
|
auto worldAnchorA = tA.position + rA;
|
||||||
auto worldAnchorB = tB.position + rB;
|
auto worldAnchorB = tB.position + rB;
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
|
|
||||||
void impl::drawManifold( const pod::Manifold& manifold ) {
|
void impl::drawManifold( const pod::Manifold& manifold ) {
|
||||||
|
if ( !uf::physics::settings.debugDraw.contacts ) return;
|
||||||
for ( auto& contact : manifold.points ) {
|
for ( auto& contact : manifold.points ) {
|
||||||
auto& start = contact.point;
|
auto& start = contact.point;
|
||||||
auto end = contact.point + (contact.normal * MIN(contact.penetration, 0.1f) * 2);
|
auto end = contact.point + (contact.normal * MIN(contact.penetration, 0.1f) * 2);
|
||||||
@ -15,7 +16,7 @@ void impl::drawManifold( const pod::Manifold& manifold ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void impl::drawBody( const pod::PhysicsBody& body ) {
|
void impl::drawBody( const pod::PhysicsBody& body ) {
|
||||||
if ( !(body.collider.category & uf::physics::settings.debugDraw) ) return;
|
if ( !(body.collider.category & uf::physics::settings.debugDraw.mask) ) return;
|
||||||
switch( body.collider.type ) {
|
switch( body.collider.type ) {
|
||||||
case pod::ShapeType::AABB:
|
case pod::ShapeType::AABB:
|
||||||
impl::drawAabb( body );
|
impl::drawAabb( body );
|
||||||
@ -44,8 +45,9 @@ void impl::drawBody( const pod::PhysicsBody& body ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void impl::drawConstraint( const pod::Constraint& constraint ) {
|
void impl::drawConstraint( const pod::Constraint& constraint ) {
|
||||||
if ( !(constraint.a->collider.category & uf::physics::settings.debugDraw) ) return;
|
if ( !uf::physics::settings.debugDraw.constraints ) return;
|
||||||
if ( !(constraint.b->collider.category & uf::physics::settings.debugDraw) ) return;
|
if ( !(constraint.a->collider.category & uf::physics::settings.debugDraw.mask) ) return;
|
||||||
|
if ( !(constraint.b->collider.category & uf::physics::settings.debugDraw.mask) ) return;
|
||||||
|
|
||||||
switch( constraint.type ) {
|
switch( constraint.type ) {
|
||||||
case pod::ConstraintType::BALL_AND_SOCKET:
|
case pod::ConstraintType::BALL_AND_SOCKET:
|
||||||
|
|||||||
@ -66,7 +66,7 @@ void uf::physics::tick( pod::World& world, float dt ) {
|
|||||||
accumulator -= timestep;
|
accumulator -= timestep;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( uf::physics::settings.debugDraw != pod::Collider::CATEGORY_NONE ) impl::draw( world, dt );
|
if ( uf::physics::settings.debugDraw.mask != pod::Collider::CATEGORY_NONE ) impl::draw( world, dt );
|
||||||
}
|
}
|
||||||
void uf::physics::terminate() {
|
void uf::physics::terminate() {
|
||||||
uf::physics::terminate( uf::scene::getCurrentScene() );
|
uf::physics::terminate( uf::scene::getCurrentScene() );
|
||||||
@ -241,7 +241,7 @@ void uf::physics::step( pod::World& world, float dt ) {
|
|||||||
// dispatch collision events
|
// dispatch collision events
|
||||||
impl::dispatchManifold( manifold, collisionEvents, activeCollisions, previousCollisions );
|
impl::dispatchManifold( manifold, collisionEvents, activeCollisions, previousCollisions );
|
||||||
// draw collision events
|
// draw collision events
|
||||||
if ( uf::physics::settings.debugDraw ) impl::drawManifold( manifold );
|
if ( uf::physics::settings.debugDraw.contacts ) impl::drawManifold( manifold );
|
||||||
}
|
}
|
||||||
// dispatch exiting collisions
|
// dispatch exiting collisions
|
||||||
for ( auto& [ key, pair ] : previousCollisions ) {
|
for ( auto& [ key, pair ] : previousCollisions ) {
|
||||||
@ -534,7 +534,7 @@ pod::CollisionEvent::events_t uf::physics::getCollisionEvents( const pod::Physic
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
// body creation
|
// body creation
|
||||||
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, float mass, const pod::Vector3f& offset ) {
|
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, float mass, const pod::Vector3f& positionOffset, const pod::Quaternion<>& orientationOffset ) {
|
||||||
auto& root = object.getComponent<pod::PhysicsBody>();
|
auto& root = object.getComponent<pod::PhysicsBody>();
|
||||||
auto isRoot = !root.world;
|
auto isRoot = !root.world;
|
||||||
auto& body = isRoot ? root : *(new pod::PhysicsBody);
|
auto& body = isRoot ? root : *(new pod::PhysicsBody);
|
||||||
@ -542,10 +542,8 @@ pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, fl
|
|||||||
body.world = &world;
|
body.world = &world;
|
||||||
body.object = &object;
|
body.object = &object;
|
||||||
body.transform = &object.getComponent<pod::Transform<>>();
|
body.transform = &object.getComponent<pod::Transform<>>();
|
||||||
#if UF_PHYSICS_SYNC_TRANSFORMS
|
body.offsetPosition = positionOffset;
|
||||||
body.flattenedTransform = uf::transform::flatten( *body.transform );
|
body.offsetOrientation = orientationOffset;
|
||||||
#endif
|
|
||||||
body.offset = offset;
|
|
||||||
body.inverseMass = mass == 0.0f ? 0.0f : 1.0f / mass;
|
body.inverseMass = mass == 0.0f ? 0.0f : 1.0f / mass;
|
||||||
body.collider.type = {};
|
body.collider.type = {};
|
||||||
|
|
||||||
@ -578,8 +576,8 @@ pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, fl
|
|||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
pod::PhysicsBody& uf::physics::create( uf::Object& object, float mass, const pod::Vector3f& offset ) {
|
pod::PhysicsBody& uf::physics::create( uf::Object& object, float mass, const pod::Vector3f& positionOffset, const pod::Quaternion<>& orientationOffset ) {
|
||||||
return create( getWorld(), object, mass, offset );
|
return create( getWorld(), object, mass, positionOffset, orientationOffset );
|
||||||
}
|
}
|
||||||
|
|
||||||
void uf::physics::destroy( uf::Object& object ) {
|
void uf::physics::destroy( uf::Object& object ) {
|
||||||
|
|||||||
@ -178,7 +178,7 @@ void impl::getSupportFace( const pod::PhysicsBody& body, const pod::Vector3f& di
|
|||||||
bool impl::generateClippingManifold( const pod::PhysicsBody& a, const pod::PhysicsBody& b, const pod::Contact& contact, pod::Manifold& manifold ) {
|
bool impl::generateClippingManifold( const pod::PhysicsBody& a, const pod::PhysicsBody& b, const pod::Contact& contact, pod::Manifold& manifold ) {
|
||||||
if ( !uf::vector::isValid(contact.point) ) return false;
|
if ( !uf::vector::isValid(contact.point) ) return false;
|
||||||
|
|
||||||
auto& normal = contact.normal;
|
auto normal = contact.normal;
|
||||||
|
|
||||||
pod::Vector3f polyA[4];
|
pod::Vector3f polyA[4];
|
||||||
pod::Vector3f polyB[4];
|
pod::Vector3f polyB[4];
|
||||||
@ -192,18 +192,31 @@ bool impl::generateClippingManifold( const pod::PhysicsBody& a, const pod::Physi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// to-do: reference face is the most perpendicular face
|
pod::Vector3f normalA = uf::vector::normalize(uf::vector::cross(polyA[1] - polyA[0], polyA[2] - polyA[0]));
|
||||||
pod::Vector3f* refPoly = polyA;
|
pod::Vector3f normalB = uf::vector::normalize(uf::vector::cross(polyB[1] - polyB[0], polyB[2] - polyB[0]));
|
||||||
pod::Vector3f* incPoly = polyB;
|
|
||||||
int refCount = countA;
|
float dotA = uf::vector::dot(normalA, normal);
|
||||||
int incCount = countB;
|
float dotB = uf::vector::dot(normalB, -normal);
|
||||||
|
|
||||||
|
pod::Vector3f* refPoly;
|
||||||
|
pod::Vector3f* incPoly;
|
||||||
|
int refCount, incCount;
|
||||||
|
pod::Vector3f refNormal;
|
||||||
|
|
||||||
|
if ( dotA > dotB ) {
|
||||||
|
refPoly = polyA; refCount = countA; refNormal = normalA;
|
||||||
|
incPoly = polyB; incCount = countB;
|
||||||
|
} else {
|
||||||
|
refPoly = polyB; refCount = countB; refNormal = normalB;
|
||||||
|
incPoly = polyA; incCount = countA;
|
||||||
|
|
||||||
|
normal = -normal;
|
||||||
|
}
|
||||||
|
|
||||||
pod::Vector3f clipBuffer[8];
|
pod::Vector3f clipBuffer[8];
|
||||||
int clipCount = incCount;
|
int clipCount = incCount;
|
||||||
for ( auto i = 0; i < incCount; ++i ) clipBuffer[i] = incPoly[i];
|
for ( auto i = 0; i < incCount; ++i ) clipBuffer[i] = incPoly[i];
|
||||||
|
|
||||||
pod::Vector3f refNormal = uf::vector::normalize(uf::vector::cross(refPoly[1] - refPoly[0], refPoly[2] - refPoly[0]));
|
|
||||||
|
|
||||||
for ( auto i = 0; i < refCount; ++i ) {
|
for ( auto i = 0; i < refCount; ++i ) {
|
||||||
pod::Vector3f edgeStart = refPoly[i];
|
pod::Vector3f edgeStart = refPoly[i];
|
||||||
pod::Vector3f edgeEnd = refPoly[(i + 1) % refCount];
|
pod::Vector3f edgeEnd = refPoly[(i + 1) % refCount];
|
||||||
|
|||||||
@ -342,7 +342,7 @@ pod::RayQuery uf::physics::rayCast( const pod::Ray& ray, const pod::World& world
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( uf::physics::settings.debugDraw ) impl::drawRay( ray, rayHit );
|
if ( uf::physics::settings.debugDraw.rays ) impl::drawRay( ray, rayHit );
|
||||||
|
|
||||||
return rayHit;
|
return rayHit;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user