even more inane code cleanup, migrated immediate mode debug draw into its own file, added transform flattening pre/post physics step (for two reasons)
This commit is contained in:
parent
0a92fed14a
commit
94ce7be618
@ -350,8 +350,8 @@
|
||||
"max": 0.01 // 0.2
|
||||
},
|
||||
"debug draw": {
|
||||
"static": false,
|
||||
"dynamic": false
|
||||
"static": true,
|
||||
"dynamic": true
|
||||
},
|
||||
"fixed step": true,
|
||||
"substeps": 4
|
||||
|
||||
55
bin/data/entities/cesiumMan.json
Normal file
55
bin/data/entities/cesiumMan.json
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"type": "Object",
|
||||
"name": "Cesium Man Model",
|
||||
"ignore": false,
|
||||
"import": "/model.json",
|
||||
"assets": [
|
||||
// "/cesiumMan/cesiumMan.glb"
|
||||
{ "filename": "/cesiumMan/cesiumMan/graph.json" }
|
||||
],
|
||||
"behaviors": [],
|
||||
"transform": {
|
||||
"position": [ -10, 1, -50 ],
|
||||
"rotation": {
|
||||
"axis": [ 0, 1, 0 ],
|
||||
"angle": 0
|
||||
},
|
||||
"scale": [ 5.0, 5.0, 5.0 ]
|
||||
},
|
||||
"system": {
|
||||
"hot reload": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"graph": {
|
||||
"key": "CesiumMan",
|
||||
"debug": {
|
||||
"print": {
|
||||
"animations": true
|
||||
}
|
||||
},
|
||||
"exporter": {
|
||||
"enabled": true,
|
||||
"unwrap": false,
|
||||
"optimize": false
|
||||
},
|
||||
"baking": {
|
||||
"enabled": false
|
||||
},
|
||||
"lights": {
|
||||
"lightmap": false
|
||||
},
|
||||
"renderer": {
|
||||
"cull mode": "front",
|
||||
"filter": "linear",
|
||||
"flip textures": false,
|
||||
"invert": false,
|
||||
"skinned": true
|
||||
},
|
||||
"physics": {
|
||||
"ragdoll": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,7 @@
|
||||
"events": {
|
||||
"click": {
|
||||
"name": "game:Scene.Load",
|
||||
"payload": { "scene": "Sponza" },
|
||||
"payload": { "scene": "SourceEngine" },
|
||||
"delay": 0.125
|
||||
}
|
||||
},
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
"assets": [
|
||||
// { "filename": "./models/mds_mcdonalds.glb" }
|
||||
{ "filename": "./models/mds_mcdonalds/graph.json" }
|
||||
,{ "filename": "/ragdoll.json", "delay": 1 }
|
||||
// ,{ "filename": "/ragdoll.json", "delay": 1 }
|
||||
,{ "filename": "/craeture.json", "delay": 2.0 }
|
||||
// ,{ "filename": "/cesiumMan.json", "delay": 2.0 }
|
||||
],
|
||||
"metadata": {
|
||||
"graph": {
|
||||
@ -16,7 +17,7 @@
|
||||
"func_door_rotating_5568": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [1,0,0] } } },
|
||||
"func_door_rotating_5584": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [1,0,0] } } },
|
||||
|
||||
"prop_physics_override_5813": { "action": "load", "payload": { "import": "/physics_prop.json" } },
|
||||
// "prop_physics_override_5813": { "action": "load", "payload": { "import": "/physics_prop.json" } },
|
||||
|
||||
// regex matches
|
||||
"/^prop_physics_[^o]/": { "action": "load", "payload": { "import": "/prop.json" } },
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
#endif
|
||||
#if BARYCENTRIC
|
||||
#ifndef BARYCENTRIC_CALCULATE
|
||||
#define BARYCENTRIC_CALCULATE 1
|
||||
#define BARYCENTRIC_CALCULATE 0
|
||||
#endif
|
||||
#ifndef BUFFER_REFERENCE
|
||||
#define BUFFER_REFERENCE 1
|
||||
|
||||
21
engine/inc/uf/utils/debug/draw.h
Normal file
21
engine/inc/uf/utils/debug/draw.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <uf/config.h>
|
||||
#include <uf/utils/math/shapes.h>
|
||||
#include <uf/utils/math/vector.h>
|
||||
#include <uf/utils/math/transform.h>
|
||||
|
||||
namespace uf {
|
||||
namespace debug {
|
||||
void UF_API drawLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color = { 1, 1, 1, 1 } );
|
||||
void UF_API drawAabb( pod::AABB aabb, pod::Transform<> transform = {} );
|
||||
void UF_API drawObb( pod::OBB obb, pod::Transform<> transform = {} );
|
||||
void UF_API drawSphere( pod::Sphere sphere, pod::Transform<> transform = {} );
|
||||
void UF_API drawCapsule( pod::Capsule capsule, pod::Transform<> transform = {} );
|
||||
void UF_API drawPlane( pod::Plane plane, pod::Transform<> transform = {} );
|
||||
void UF_API drawTriangle( pod::Triangle tri, pod::Transform<> transform = {} );
|
||||
|
||||
void UF_API addLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color = { 1, 1, 1, 1 }, float ttl = 1.0f );
|
||||
void UF_API draw( float dt = 0 );
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace impl {
|
||||
void solveBallSocketConstraint( pod::Constraint& constraint, float dt );
|
||||
void drawBallSocket( const pod::Constraint& constraint );
|
||||
}
|
||||
|
||||
namespace uf {
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace impl {
|
||||
void solveConeTwistConstraint( pod::Constraint& constraint, float dt );
|
||||
void drawConeTwist( const pod::Constraint& constraint );
|
||||
}
|
||||
|
||||
namespace uf {
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace impl {
|
||||
void solveDistanceConstraint( pod::Constraint& constraint, float dt );
|
||||
void drawDistance( const pod::Constraint& contact );
|
||||
}
|
||||
|
||||
namespace uf {
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace impl {
|
||||
void solveHingeConstraint( pod::Constraint& constraint, float dt );
|
||||
void drawHinge( const pod::Constraint& constraint );
|
||||
}
|
||||
|
||||
namespace uf {
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace impl {
|
||||
void solveSliderConstraint( pod::Constraint& constraint, float dt );
|
||||
void drawSlider( const pod::Constraint& constraint );
|
||||
}
|
||||
|
||||
namespace uf {
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace impl {
|
||||
void solveSpringConstraint( pod::Constraint& constraint, float dt );
|
||||
void drawSpring( const pod::Constraint& constraint );
|
||||
}
|
||||
|
||||
namespace uf {
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
namespace impl {
|
||||
void solveWeldConstraint( pod::Constraint& constraint, float dt );
|
||||
void drawWeld( const pod::Constraint& constraint );
|
||||
}
|
||||
|
||||
namespace uf {
|
||||
|
||||
@ -1,19 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "structs.h"
|
||||
#include <uf/utils/debug/draw.h>
|
||||
|
||||
namespace impl {
|
||||
struct Vertex {
|
||||
pod::Vector3f position;
|
||||
pod::Vector4f color;
|
||||
|
||||
static uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
|
||||
};
|
||||
|
||||
/*FORCE_INLINE*/ void addLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color = { 1, 1, 1, 1 } );
|
||||
/*FORCE_INLINE*/ void addTransientLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color = { 1, 1, 1, 1 }, const pod::PhysicsBody* a = NULL, const pod::PhysicsBody* b = NULL );
|
||||
|
||||
void drawManifold( const pod::Manifold& manifold );
|
||||
void drawBody( const pod::PhysicsBody& body );
|
||||
void drawConstraint( const pod::Constraint& constraint );
|
||||
void draw( const pod::World& world, float dt = 0 );
|
||||
}
|
||||
@ -447,6 +447,8 @@ namespace pod {
|
||||
uint32_t broadphaseBvhCapacity = 1; // number of bodies per leaf node
|
||||
uint32_t meshBvhCapacity = 1; // number of triangles per leaf node
|
||||
|
||||
bool flattenTransforms = true; // flatten transforms before a step, then unflattens it at end of step (to solve a problem involving hierarchies)
|
||||
|
||||
// additionally flattens a BVH for linear iteration, rather than a recursive / stack-based traversal
|
||||
bool flattenBvhBodies = true;
|
||||
bool flattenBvhMeshes = true;
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#include <uf/engine/graph/graph.h>
|
||||
#include <uf/ext/gltf/gltf.h>
|
||||
#include <uf/utils/math/physics.h>
|
||||
#include <uf/utils/math/physics/constraints.h>
|
||||
#include <uf/utils/math/physics/common.h>
|
||||
#include <uf/utils/mesh/grid.h>
|
||||
#include <uf/utils/thread/thread.h>
|
||||
#include <uf/utils/string/base64.h>
|
||||
@ -301,72 +303,12 @@ uf::stl::vector<pod::OBB> uf::graph::obbFromSkin( const pod::Graph& graph, const
|
||||
for ( auto& box : bounds ) {
|
||||
auto extent = (box.extent - box.center) * 0.5f;
|
||||
auto center = (box.extent + box.center) * 0.5f;
|
||||
box = pod::OBB{ center, extent * 0.5f };
|
||||
box = pod::OBB{ center, extent };
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
void uf::graph::rigRagdoll( pod::Graph& graph, pod::Node& node ) {
|
||||
auto& storage = ::getGraphStorage(uf::scene::getCurrentScene());
|
||||
auto& name = graph.skins[node.skin];
|
||||
auto& skin = storage.skins[name];
|
||||
|
||||
auto bounds = uf::graph::obbFromSkin( graph, node );
|
||||
uf::stl::unordered_map<int32_t, pod::PhysicsBody*> bodies;
|
||||
|
||||
// create physics bodies
|
||||
const float density = 1.0f;
|
||||
for ( auto i = 0; i < skin.joints.size(); ++i ) {
|
||||
auto& obb = bounds[i];
|
||||
if ( obb.extent.x < 0 ) continue; // invalid bounds
|
||||
auto jointID = skin.joints[i]; // gLTF standard guarantees a jointID is the nodeID
|
||||
|
||||
auto& node = graph.nodes[jointID];
|
||||
auto& entity = *node.entity;
|
||||
|
||||
auto offset = obb.center;
|
||||
/*
|
||||
auto matrix = ::worldMatrix( graph, jointID );
|
||||
auto offset = uf::matrix::multiply( matrix, obb.center );
|
||||
*/
|
||||
|
||||
float volume = 8.0f * obb.extent.x * obb.extent.y * obb.extent.z;
|
||||
float mass = 10.0f; // volume * density;
|
||||
|
||||
auto& body = uf::physics::create( entity, mass, offset );
|
||||
uf::physics::initialize( body, pod::OBB{ pod::Vector3f{}, obb.extent } );
|
||||
bodies[jointID] = &body;
|
||||
}
|
||||
|
||||
// create constraints
|
||||
for ( auto i = 0; i < skin.joints.size(); ++i ) {
|
||||
int32_t jointID = skin.joints[i];
|
||||
auto& node = graph.nodes[jointID];
|
||||
|
||||
// no body: cannot constrain
|
||||
if ( bodies.count( jointID ) == 0 ) continue;
|
||||
// no parent: cannot constrain
|
||||
if ( bodies.count( node.parent ) == 0 ) continue;
|
||||
|
||||
auto* bodyA = bodies[node.parent];
|
||||
auto* bodyB = bodies[jointID];
|
||||
|
||||
auto matrixA = ::worldMatrix( graph, node.parent );
|
||||
auto matrixB = ::worldMatrix( graph, jointID );
|
||||
|
||||
auto pivotA = uf::matrix::extractTranslation( matrixA );
|
||||
auto pivotB = uf::matrix::extractTranslation( matrixB );
|
||||
|
||||
auto pivot = pivotB; // pivot is where the bone starts
|
||||
auto axis = uf::vector::normalize( pivotB - pivotA );
|
||||
|
||||
// fallback
|
||||
if ( uf::vector::distanceSquared( pivotB, pivotA ) < EPS2 ) {
|
||||
axis = uf::quaternion::rotate( uf::matrix::extractRotation(matrixB), pod::Vector3f{0, 1, 0} );
|
||||
}
|
||||
|
||||
// auto& constraint = uf::physics::constrain( *bodyA, *bodyB );
|
||||
// uf::physics::constrainConeTwist( constraint, pivot, axis );
|
||||
}
|
||||
// scrapped for now
|
||||
}
|
||||
@ -1105,6 +1105,12 @@ void uf::graph::process( pod::Graph& graph ) {
|
||||
UF_MSG_DEBUG("\tImage: {}", name);
|
||||
}
|
||||
}
|
||||
if ( graphMetadataJson["debug"]["print"]["animations"].as<bool>() ) {
|
||||
UF_MSG_DEBUG("Animations: {}", graph.animations.size());
|
||||
for ( auto& name : graph.animations ) {
|
||||
UF_MSG_DEBUG("\tAnimation: {}", name);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
UF_DEBUG_TIMER_MULTITRACE("Rigging ragdolls");
|
||||
@ -1358,7 +1364,10 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto index : node.children ) uf::graph::process( graph, index, entity );
|
||||
for ( auto childIndex : node.children ) {
|
||||
uf::graph::process( graph, childIndex, entity );
|
||||
graph.nodes[childIndex].parent = index;
|
||||
}
|
||||
}
|
||||
|
||||
void uf::graph::destroy( pod::Graph& graph ) {
|
||||
@ -1397,6 +1406,7 @@ void uf::graph::initialize( pod::Graph& graph ) {
|
||||
if ( entity->getUid() == 0 ) entity->initialize();
|
||||
});
|
||||
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
scene.invalidateGraph();
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <uf/utils/camera/camera.h>
|
||||
#include <uf/utils/math/physics.h>
|
||||
#include <uf/utils/renderer/renderer.h>
|
||||
#include <uf/utils/debug/draw.h>
|
||||
#include <uf/utils/io/fmt.h>
|
||||
#include <uf/engine/ext.h>
|
||||
#include <regex>
|
||||
@ -294,6 +295,8 @@ void uf::scene::tick() {
|
||||
}
|
||||
|
||||
uf::graph::tick( scene );
|
||||
|
||||
uf::debug::draw( uf::time::delta );
|
||||
}
|
||||
void uf::scene::render() {
|
||||
if ( scenes.empty() ) return;
|
||||
|
||||
@ -21,7 +21,10 @@
|
||||
#if BARYCENTRIC
|
||||
// 0 keeps a buffer for barycentric coordinates, 1 will reconstruct in the deferred pass
|
||||
#ifndef BARYCENTRIC_CALCULATE
|
||||
#define BARYCENTRIC_CALCULATE 1
|
||||
// currently has issues with:
|
||||
// * skinned meshes because I'm not applying joint transformations
|
||||
// * this weird texture offsetting from movement despite having fixed this with the original camera buffers
|
||||
#define BARYCENTRIC_CALCULATE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
254
engine/src/utils/debug/draw.cpp
Normal file
254
engine/src/utils/debug/draw.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
#include <uf/utils/debug/draw.h>
|
||||
|
||||
#include <uf/engine/scene/scene.h>
|
||||
#include <uf/engine/graph/graph.h>
|
||||
|
||||
namespace impl {
|
||||
struct Vertex {
|
||||
pod::Vector3f position;
|
||||
pod::Vector4f color;
|
||||
|
||||
static uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
|
||||
};
|
||||
|
||||
struct Line {
|
||||
pod::Vector3f start = {};
|
||||
pod::Vector3f end = {};
|
||||
pod::Vector4f color = { 1, 1, 1, 1 };
|
||||
float ttl = 0;
|
||||
};
|
||||
|
||||
float decayRate = 0.25f;
|
||||
uf::stl::vector<impl::Vertex> lines;
|
||||
uf::stl::unordered_map<size_t, impl::Line> transientLines;
|
||||
|
||||
size_t getHash( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color ) {
|
||||
size_t hash = 0;
|
||||
uf::hash(hash, start, end, color);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
UF_VERTEX_DESCRIPTOR(impl::Vertex,
|
||||
UF_VERTEX_DESCRIPTION(impl::Vertex, R32G32B32_SFLOAT, position)
|
||||
UF_VERTEX_DESCRIPTION(impl::Vertex, R32G32B32A32_SFLOAT, color)
|
||||
)
|
||||
|
||||
void uf::debug::drawLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color ) {
|
||||
impl::lines.emplace_back( impl::Vertex{ start, color } );
|
||||
impl::lines.emplace_back( impl::Vertex{ end, color } );
|
||||
}
|
||||
void uf::debug::drawAabb( pod::AABB aabb, pod::Transform<> transform ) {
|
||||
pod::Vector3f corners[8] = {
|
||||
{aabb.min.x, aabb.min.y, aabb.min.z}, {aabb.max.x, aabb.min.y, aabb.min.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.min.z}, {aabb.min.x, aabb.max.y, aabb.min.z},
|
||||
{aabb.min.x, aabb.min.y, aabb.max.z}, {aabb.max.x, aabb.min.y, aabb.max.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.max.z}, {aabb.min.x, aabb.max.y, aabb.max.z}
|
||||
};
|
||||
|
||||
// bottom face
|
||||
uf::debug::drawLine( corners[0], corners[1] ); uf::debug::drawLine( corners[1], corners[2] );
|
||||
uf::debug::drawLine( corners[2], corners[3] ); uf::debug::drawLine( corners[3], corners[0] );
|
||||
// top face
|
||||
uf::debug::drawLine( corners[4], corners[5] ); uf::debug::drawLine( corners[5], corners[6] );
|
||||
uf::debug::drawLine( corners[6], corners[7] ); uf::debug::drawLine( corners[7], corners[4] );
|
||||
// vertical edges
|
||||
uf::debug::drawLine( corners[0], corners[4] ); uf::debug::drawLine( corners[1], corners[5] );
|
||||
uf::debug::drawLine( corners[2], corners[6] ); uf::debug::drawLine( corners[3], corners[7] );
|
||||
}
|
||||
void uf::debug::drawObb( pod::OBB obb, pod::Transform<> transform ) {
|
||||
auto aabb = pod::AABB{
|
||||
.min = obb.center - obb.extent,
|
||||
.max = obb.center + obb.extent,
|
||||
};
|
||||
pod::Vector3f corners[8] = {
|
||||
{aabb.min.x, aabb.min.y, aabb.min.z}, {aabb.max.x, aabb.min.y, aabb.min.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.min.z}, {aabb.min.x, aabb.max.y, aabb.min.z},
|
||||
{aabb.min.x, aabb.min.y, aabb.max.z}, {aabb.max.x, aabb.min.y, aabb.max.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.max.z}, {aabb.min.x, aabb.max.y, aabb.max.z}
|
||||
};
|
||||
|
||||
FOR_EACH( 8, {
|
||||
corners[i] = uf::transform::apply(transform, corners[i]);
|
||||
});
|
||||
|
||||
// bottom face
|
||||
uf::debug::drawLine( corners[0], corners[1] ); uf::debug::drawLine( corners[1], corners[2] );
|
||||
uf::debug::drawLine( corners[2], corners[3] ); uf::debug::drawLine( corners[3], corners[0] );
|
||||
// top face
|
||||
uf::debug::drawLine( corners[4], corners[5] ); uf::debug::drawLine( corners[5], corners[6] );
|
||||
uf::debug::drawLine( corners[6], corners[7] ); uf::debug::drawLine( corners[7], corners[4] );
|
||||
// vertical edges
|
||||
uf::debug::drawLine( corners[0], corners[4] ); uf::debug::drawLine( corners[1], corners[5] );
|
||||
uf::debug::drawLine( corners[2], corners[6] ); uf::debug::drawLine( corners[3], corners[7] );
|
||||
}
|
||||
|
||||
void uf::debug::drawSphere( pod::Sphere sphere, pod::Transform<> transform ) {
|
||||
const int segments = 16;
|
||||
const float angleIncrement = (2.0f * M_PI) / segments;
|
||||
for ( auto i = 0; i < segments; ++i ) {
|
||||
float theta1 = i * angleIncrement;
|
||||
float theta2 = (i + 1) * angleIncrement;
|
||||
|
||||
float c1 = std::cos(theta1) * sphere.radius;
|
||||
float s1 = std::sin(theta1) * sphere.radius;
|
||||
float c2 = std::cos(theta2) * sphere.radius;
|
||||
float s2 = std::sin(theta2) * sphere.radius;
|
||||
|
||||
pod::Vector3f xy1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c1, s1, 0.0f});
|
||||
pod::Vector3f xy2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c2, s2, 0.0f});
|
||||
|
||||
pod::Vector3f xz1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c1, 0.0f, s1});
|
||||
pod::Vector3f xz2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c2, 0.0f, s2});
|
||||
|
||||
pod::Vector3f yz1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, c1, s1});
|
||||
pod::Vector3f yz2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, c2, s2});
|
||||
|
||||
uf::debug::drawLine( transform.position + xy1, transform.position + xy2 );
|
||||
uf::debug::drawLine( transform.position + xz1, transform.position + xz2 );
|
||||
uf::debug::drawLine( transform.position + yz1, transform.position + yz2 );
|
||||
}
|
||||
}
|
||||
// for some reason compiling these two and not even using them causes physics to break
|
||||
/*
|
||||
void uf::debug::drawCapsule( pod::Capsule capsule, pod::Transform<> transform ) {
|
||||
const pod::Vector3f up = uf::quaternion::rotate( transform.orientation, pod::Vector3f{0,1,0} );
|
||||
auto p1 = transform.position + up * capsule.halfHeight;
|
||||
auto p2 = transform.position - up * capsule.halfHeight;
|
||||
|
||||
const int segments = 16;
|
||||
const float angleIncrement = (2.0f * M_PI) / segments;
|
||||
|
||||
for ( auto i = 0; i < segments; ++i ) {
|
||||
float theta1 = i * angleIncrement;
|
||||
float theta2 = (i + 1) * angleIncrement;
|
||||
|
||||
float c1 = std::cos(theta1) * capsule.radius;
|
||||
float s1 = std::sin(theta1) * capsule.radius;
|
||||
float c2 = std::cos(theta2) * capsule.radius;
|
||||
float s2 = std::sin(theta2) * capsule.radius;
|
||||
|
||||
pod::Vector3f xy1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c1, s1, 0.0f});
|
||||
pod::Vector3f xy2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c2, s2, 0.0f});
|
||||
|
||||
pod::Vector3f xz1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c1, 0.0f, s1});
|
||||
pod::Vector3f xz2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c2, 0.0f, s2});
|
||||
|
||||
pod::Vector3f yz1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, c1, s1});
|
||||
pod::Vector3f yz2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, c2, s2});
|
||||
|
||||
uf::debug::drawLine( p1 + xy1, p1 + xy2 );
|
||||
uf::debug::drawLine( p1 + xz1, p1 + xz2 );
|
||||
uf::debug::drawLine( p1 + yz1, p1 + yz2 );
|
||||
|
||||
uf::debug::drawLine( p2 + xy1, p2 + xy2 );
|
||||
uf::debug::drawLine( p2 + xz1, p2 + xz2 );
|
||||
uf::debug::drawLine( p2 + yz1, p2 + yz2 );
|
||||
}
|
||||
|
||||
pod::Vector3f rx = uf::quaternion::rotate(transform.orientation, pod::Vector3f{capsule.radius, 0.0f, 0.0f});
|
||||
pod::Vector3f ry = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, capsule.radius, 0.0f});
|
||||
pod::Vector3f rz = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, 0.0f, capsule.radius});
|
||||
|
||||
uf::debug::drawLine( p1 + rx, p2 + rx );
|
||||
uf::debug::drawLine( p1 - rx, p2 - rx );
|
||||
|
||||
uf::debug::drawLine( p1 + ry, p2 + ry );
|
||||
uf::debug::drawLine( p1 - ry, p2 - ry );
|
||||
|
||||
uf::debug::drawLine( p1 + rz, p2 + rz );
|
||||
uf::debug::drawLine( p1 - rz, p2 - rz );
|
||||
}
|
||||
// to-do: properly implement this
|
||||
void uf::debug::drawPlane( pod::Plane plane, pod::Transform<> transform ) {
|
||||
pod::Vector3f right = uf::quaternion::rotate(transform.orientation, pod::Vector3f{1, 0, 0});
|
||||
pod::Vector3f forward = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0, 0, 1});
|
||||
|
||||
float size = 10.0f;
|
||||
pod::Vector3f p0 = transform.position + (right * size) + (forward * size);
|
||||
pod::Vector3f p1 = transform.position - (right * size) + (forward * size);
|
||||
pod::Vector3f p2 = transform.position - (right * size) - (forward * size);
|
||||
pod::Vector3f p3 = transform.position + (right * size) - (forward * size);
|
||||
|
||||
uf::debug::drawLine( p0, p1 );
|
||||
uf::debug::drawLine( p1, p2 );
|
||||
uf::debug::drawLine( p2, p3 );
|
||||
uf::debug::drawLine( p3, p0 );
|
||||
|
||||
uf::debug::drawLine( p0, p2 );
|
||||
uf::debug::drawLine( p1, p3 );
|
||||
}
|
||||
*/
|
||||
void uf::debug::drawTriangle( pod::Triangle tri, pod::Transform<> transform ) {
|
||||
pod::Vector3f v0 = uf::transform::apply(transform, tri.points[0]);
|
||||
pod::Vector3f v1 = uf::transform::apply(transform, tri.points[1]);
|
||||
pod::Vector3f v2 = uf::transform::apply(transform, tri.points[2]);
|
||||
|
||||
uf::debug::drawLine( v0, v1 );
|
||||
uf::debug::drawLine( v1, v2 );
|
||||
uf::debug::drawLine( v2, v0 );
|
||||
}
|
||||
void uf::debug::addLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color, float ttl ) {
|
||||
impl::transientLines[impl::getHash( start, end, color )] = impl::Line{ start, end, color, ttl };
|
||||
}
|
||||
|
||||
void uf::debug::draw( float dt ) {
|
||||
for ( auto it = impl::transientLines.begin(); it != impl::transientLines.end(); ) {
|
||||
auto& line = it->second;
|
||||
|
||||
if ( line.ttl <= 0 ) it = impl::transientLines.erase( it );
|
||||
else {
|
||||
uf::debug::drawLine( line.start, line.end, line.color * pod::Vector4f{ 1, 1, 1, CLAMP( line.ttl, 0, 1 ) } );
|
||||
line.ttl -= dt * impl::decayRate;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if ( impl::lines.empty() ) return;
|
||||
|
||||
// to-do: make this static to avoid additional allocations
|
||||
uf::Mesh mesh;
|
||||
mesh.bind<impl::Vertex>();
|
||||
mesh.insertVertices<impl::Vertex>(impl::lines);
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& graphics = scene.getComponent<uf::renderer::Graphics>();
|
||||
auto& graphic = graphics["immediate"];
|
||||
if ( !graphic.initialized ) {
|
||||
graphic.device = &uf::renderer::device;
|
||||
graphic.material.device = &uf::renderer::device;
|
||||
|
||||
// to-do: bin by descriptor instead of one global set
|
||||
graphic.descriptor.depth.test = true;
|
||||
graphic.descriptor.depth.write = false;
|
||||
graphic.descriptor.renderTarget = 1; // "forward";
|
||||
graphic.descriptor.topology = uf::renderer::enums::PrimitiveTopology::LINE_LIST;
|
||||
graphic.descriptor.fill = uf::renderer::enums::PolygonMode::LINE;
|
||||
graphic.descriptor.lineWidth = 2;
|
||||
|
||||
uf::stl::string vertexShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/base/line/vert.spv");
|
||||
uf::stl::string fragmentShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/base/line/frag.spv");
|
||||
|
||||
graphic.material.metadata.autoInitializeUniformBuffers = false;
|
||||
graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX);
|
||||
graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT);
|
||||
graphic.material.metadata.autoInitializeUniformBuffers = true;
|
||||
|
||||
auto& storage = uf::graph::globalStorage ? uf::graph::storage : scene.getComponent<pod::Graph::Storage>();
|
||||
|
||||
// vertex shader
|
||||
{
|
||||
auto& shader = graphic.material.getShader("vertex");
|
||||
shader.aliasBuffer( storage.buffers.camera );
|
||||
}
|
||||
|
||||
graphic.initialize();
|
||||
graphic.initializeMesh( mesh );
|
||||
UF_MSG_DEBUG("Initialized graphic");
|
||||
} else {
|
||||
bool rebuild = graphic.updateMesh( mesh );
|
||||
if ( rebuild ) uf::renderer::states::rebuild = true; // to-do: rebuild the defer mode only
|
||||
}
|
||||
|
||||
impl::lines.clear();
|
||||
}
|
||||
@ -66,7 +66,11 @@ void impl::updateActivity( pod::PhysicsBody& body, float dt ) {
|
||||
pod::Transform<> impl::getTransform( const pod::PhysicsBody& body ) {
|
||||
pod::Transform<> t;
|
||||
t.position = body.offset;
|
||||
#if UF_PHYSICS_SYNC_TRANSFORMS
|
||||
t.reference = const_cast<pod::Transform<>*>( &body.flattenedTransform );
|
||||
#else
|
||||
t.reference = body.transform;
|
||||
#endif
|
||||
return uf::transform::flatten( t );
|
||||
}
|
||||
// get position of a body, uses bounds center or transform's position
|
||||
@ -112,8 +116,9 @@ bool impl::shouldCollide( const pod::PhysicsBody& a, const pod::PhysicsBody& b )
|
||||
pod::Matrix3f impl::computeWorldInverseInertia( const pod::PhysicsBody& b ) {
|
||||
if ( b.inverseMass == 0.0f ) return pod::Matrix3f{};
|
||||
|
||||
auto t = impl::getTransform( b );
|
||||
pod::Matrix3f invI_local = uf::matrix::diagonal( b.inverseInertiaTensor );
|
||||
pod::Matrix3f R = uf::quaternion::matrix3(b.transform->orientation);
|
||||
pod::Matrix3f R = uf::quaternion::matrix3( t.orientation );
|
||||
|
||||
#if 1
|
||||
return R * invI_local * uf::matrix::transpose(R);
|
||||
|
||||
@ -58,4 +58,27 @@ pod::Constraint& uf::physics::constrainBallSocket( pod::Constraint& constraint,
|
||||
joint.accumulatedImpulse = {};
|
||||
|
||||
return constraint;
|
||||
}
|
||||
|
||||
void impl::drawBallSocket( const pod::Constraint& constraint ) {
|
||||
if ( !constraint.a || !constraint.b ) return;
|
||||
|
||||
auto tA = impl::getTransform(*constraint.a);
|
||||
auto tB = impl::getTransform(*constraint.b);
|
||||
|
||||
const auto& joint = constraint.ballSocket;
|
||||
|
||||
auto pA = tA.position + uf::quaternion::rotate(tA.orientation, joint.localAnchorA);
|
||||
auto pB = tB.position + uf::quaternion::rotate(tB.orientation, joint.localAnchorB);
|
||||
|
||||
uf::debug::drawLine( tA.position, pA );
|
||||
uf::debug::drawLine( tB.position, pB );
|
||||
|
||||
uf::debug::drawLine( pA, pB );
|
||||
|
||||
// crosshair
|
||||
float size = 0.1f;
|
||||
uf::debug::drawLine( pA - pod::Vector3f{size, 0.0f, 0.0f}, pA + pod::Vector3f{size, 0.0f, 0.0f} );
|
||||
uf::debug::drawLine( pA - pod::Vector3f{0.0f, size, 0.0f}, pA + pod::Vector3f{0.0f, size, 0.0f} );
|
||||
uf::debug::drawLine( pA - pod::Vector3f{0.0f, 0.0f, size}, pA + pod::Vector3f{0.0f, 0.0f, size} );
|
||||
}
|
||||
@ -166,4 +166,32 @@ pod::Constraint& uf::physics::constrainConeTwist( pod::Constraint& constraint, c
|
||||
joint.twistLimit = twistLimit;
|
||||
|
||||
return constraint;
|
||||
}
|
||||
|
||||
|
||||
void impl::drawConeTwist( const pod::Constraint& constraint ) {
|
||||
if ( !constraint.a || !constraint.b ) return;
|
||||
|
||||
auto tA = impl::getTransform(*constraint.a);
|
||||
auto tB = impl::getTransform(*constraint.b);
|
||||
const auto& joint = constraint.coneTwist;
|
||||
|
||||
auto pA = tA.position + uf::quaternion::rotate(tA.orientation, joint.localAnchorA);
|
||||
auto pB = tB.position + uf::quaternion::rotate(tB.orientation, joint.localAnchorB);
|
||||
|
||||
auto taA = uf::quaternion::rotate(tA.orientation, joint.localTwistAxisA);
|
||||
auto taB = uf::quaternion::rotate(tB.orientation, joint.localTwistAxisB);
|
||||
|
||||
auto raA = uf::quaternion::rotate(tA.orientation, joint.localReferenceAxisA);
|
||||
auto raB = uf::quaternion::rotate(tB.orientation, joint.localReferenceAxisB);
|
||||
|
||||
uf::debug::drawLine( pA, pB );
|
||||
|
||||
float axisLength = 0.5f;
|
||||
uf::debug::drawLine( pA, pA + taA * axisLength );
|
||||
uf::debug::drawLine( pB, pB + taB * axisLength );
|
||||
|
||||
float refLength = 0.25f;
|
||||
uf::debug::drawLine( pA, pA + raA * refLength );
|
||||
uf::debug::drawLine( pB, pB + raB * refLength );
|
||||
}
|
||||
@ -53,4 +53,28 @@ pod::Constraint& uf::physics::constrainDistance( pod::Constraint& constraint, co
|
||||
joint.isRope = isRope;
|
||||
|
||||
return constraint;
|
||||
}
|
||||
|
||||
void impl::drawDistance( const pod::Constraint& constraint ) {
|
||||
if ( !constraint.a || !constraint.b ) return;
|
||||
|
||||
auto tA = impl::getTransform(*constraint.a);
|
||||
auto tB = impl::getTransform(*constraint.b);
|
||||
|
||||
const auto& joint = constraint.distance;
|
||||
|
||||
auto pA = tA.position + uf::quaternion::rotate(tA.orientation, joint.localAnchorA);
|
||||
auto pB = tB.position + uf::quaternion::rotate(tB.orientation, joint.localAnchorB);
|
||||
|
||||
uf::debug::drawLine( tA.position, pA );
|
||||
uf::debug::drawLine( tB.position, pB );
|
||||
|
||||
uf::debug::drawLine( pA, pB );
|
||||
|
||||
// crosshair
|
||||
float size = 0.1f;
|
||||
uf::debug::drawLine( pA - pod::Vector3f{size, 0.0f, 0.0f}, pA + pod::Vector3f{size, 0.0f, 0.0f} );
|
||||
uf::debug::drawLine( pA - pod::Vector3f{0.0f, size, 0.0f}, pA + pod::Vector3f{0.0f, size, 0.0f} );
|
||||
uf::debug::drawLine( pA - pod::Vector3f{0.0f, 0.0f, size}, pA + pod::Vector3f{0.0f, 0.0f, size} );
|
||||
|
||||
}
|
||||
@ -71,4 +71,25 @@ pod::Constraint& uf::physics::constrainHinge( pod::Constraint& constraint, const
|
||||
joint.accumulatedAngularImpulse = {};
|
||||
|
||||
return constraint;
|
||||
}
|
||||
|
||||
void impl::drawHinge( const pod::Constraint& constraint ) {
|
||||
if ( !constraint.a || !constraint.b ) return;
|
||||
|
||||
auto tA = impl::getTransform(*constraint.a);
|
||||
auto tB = impl::getTransform(*constraint.b);
|
||||
|
||||
const auto& joint = constraint.hinge;
|
||||
|
||||
auto pA = tA.position + uf::quaternion::rotate(tA.orientation, joint.localAnchorA);
|
||||
auto pB = tB.position + uf::quaternion::rotate(tB.orientation, joint.localAnchorB);
|
||||
|
||||
auto aA = uf::quaternion::rotate(tA.orientation, joint.localAxisA);
|
||||
auto aB = uf::quaternion::rotate(tB.orientation, joint.localAxisB);
|
||||
|
||||
uf::debug::drawLine( pA, pB );
|
||||
|
||||
float pin = 0.5f;
|
||||
uf::debug::drawLine( pA - pod::Vector3f{aA.x * pin, aA.y * pin, aA.z * pin}, pA + pod::Vector3f{aA.x * pin, aA.y * pin, aA.z * pin} );
|
||||
uf::debug::drawLine( pB - pod::Vector3f{aB.x * pin, aB.y * pin, aB.z * pin}, pB + pod::Vector3f{aB.x * pin, aB.y * pin, aB.z * pin} );
|
||||
}
|
||||
@ -132,4 +132,9 @@ pod::Constraint& uf::physics::constrainSlider( pod::Constraint& constraint, cons
|
||||
joint.accumulatedLimitImpulse = 0.0f;
|
||||
|
||||
return constraint;
|
||||
}
|
||||
|
||||
void impl::drawSlider( const pod::Constraint& constraint ) {
|
||||
if ( !constraint.a || !constraint.b ) return;
|
||||
|
||||
}
|
||||
@ -58,4 +58,9 @@ pod::Constraint& uf::physics::constrainSpring( pod::Constraint& constraint, cons
|
||||
joint.accumulatedImpulse = 0.0f;
|
||||
|
||||
return constraint;
|
||||
}
|
||||
|
||||
void impl::drawSpring( const pod::Constraint& constraint ) {
|
||||
if ( !constraint.a || !constraint.b ) return;
|
||||
|
||||
}
|
||||
@ -71,4 +71,9 @@ pod::Constraint& uf::physics::constrainWeld( pod::Constraint& constraint, const
|
||||
joint.accumulatedAngularImpulse = {};
|
||||
|
||||
return constraint;
|
||||
}
|
||||
|
||||
void impl::drawWeld( const pod::Constraint& constraint ) {
|
||||
if ( !constraint.a || !constraint.b ) return;
|
||||
|
||||
}
|
||||
@ -1,52 +1,17 @@
|
||||
#include <uf/utils/math/physics/common.h>
|
||||
#include <uf/utils/math/physics/narrowphase.h>
|
||||
#include <uf/utils/math/physics/constraints.h>
|
||||
#include <uf/utils/math/physics/draw.h>
|
||||
#include <uf/engine/scene/scene.h>
|
||||
#include <uf/engine/graph/graph.h>
|
||||
|
||||
namespace {
|
||||
// define a struct for a line because I hate hate hate tuple syntax
|
||||
struct Line {
|
||||
pod::Vector3f start = {};
|
||||
pod::Vector3f end = {};
|
||||
pod::Vector4f color = { 1, 1, 1, 1 };
|
||||
float ttl = 0;
|
||||
};
|
||||
|
||||
uf::stl::vector<impl::Vertex> lines;
|
||||
uf::stl::unordered_map<size_t, Line> transientLines;
|
||||
|
||||
size_t getHash( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color, const pod::PhysicsBody* a, const pod::PhysicsBody* b ) {
|
||||
size_t hash = 0;
|
||||
/*
|
||||
int qx = static_cast<int>(start.x * 10.0f);
|
||||
int qy = static_cast<int>(start.y * 10.0f);
|
||||
int qz = static_cast<int>(start.z * 10.0f);
|
||||
uf::hash(hash, a, b, qx, qy, qz);
|
||||
*/
|
||||
uf::hash(hash, start, end, color);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
UF_VERTEX_DESCRIPTOR(impl::Vertex,
|
||||
UF_VERTEX_DESCRIPTION(impl::Vertex, R32G32B32_SFLOAT, position)
|
||||
UF_VERTEX_DESCRIPTION(impl::Vertex, R32G32B32A32_SFLOAT, color)
|
||||
)
|
||||
|
||||
void impl::addLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color ) {
|
||||
::lines.emplace_back( impl::Vertex{ start, color } );
|
||||
::lines.emplace_back( impl::Vertex{ end, color } );
|
||||
}
|
||||
void impl::addTransientLine( const pod::Vector3f& start, const pod::Vector3f& end, const pod::Vector4f& color, const pod::PhysicsBody* a, const pod::PhysicsBody* b ) {
|
||||
::transientLines[::getHash( start, end, color, a, b )] = Line{ start, end, color, 1.0f };
|
||||
}
|
||||
|
||||
void impl::drawManifold( const pod::Manifold& manifold ) {
|
||||
for ( auto& contact : manifold.points ) {
|
||||
auto& start = contact.point;
|
||||
auto end = contact.point + (contact.normal * MIN(contact.penetration, 0.1f) * 2);
|
||||
|
||||
impl::addTransientLine( start, end, pod::Vector4f{ 1, 0, 0, 1 }, manifold.a, manifold.b );
|
||||
uf::debug::addLine( start, end, pod::Vector4f{ 1, 0, 0, 1 } );
|
||||
}
|
||||
}
|
||||
void impl::drawBody( const pod::PhysicsBody& body ) {
|
||||
@ -78,65 +43,36 @@ void impl::drawBody( const pod::PhysicsBody& body ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
void impl::drawConstraint( const pod::Constraint& constraint ) {
|
||||
if ( !(constraint.a->collider.category & uf::physics::settings.debugDraw) ) return;
|
||||
if ( !(constraint.b->collider.category & uf::physics::settings.debugDraw) ) return;
|
||||
|
||||
void impl::draw( const pod::World& world, float dt ) {
|
||||
if ( world.bodies.empty() ) return;
|
||||
|
||||
::lines.clear();
|
||||
|
||||
for ( auto* body : world.bodies ) impl::drawBody( *body );
|
||||
for ( auto it = ::transientLines.begin(); it != ::transientLines.end(); ) {
|
||||
auto& line = it->second;
|
||||
|
||||
if ( line.ttl <= 0 ) it = ::transientLines.erase( it );
|
||||
else {
|
||||
impl::addLine( line.start, line.end, line.color * pod::Vector4f{ 1, 1, 1, line.ttl } );
|
||||
line.ttl -= dt * 0.25f;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ::lines.empty() ) return;
|
||||
|
||||
uf::Mesh mesh;
|
||||
mesh.bind<impl::Vertex>();
|
||||
mesh.insertVertices<impl::Vertex>(::lines);
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& graphics = scene.getComponent<uf::renderer::Graphics>();
|
||||
auto& graphic = graphics["physics"];
|
||||
if ( !graphic.initialized ) {
|
||||
graphic.device = &uf::renderer::device;
|
||||
graphic.material.device = &uf::renderer::device;
|
||||
|
||||
//graphic.descriptor.depth.test = false;
|
||||
graphic.descriptor.depth.write = false;
|
||||
graphic.descriptor.renderTarget = 1; // "forward";
|
||||
graphic.descriptor.topology = uf::renderer::enums::PrimitiveTopology::LINE_LIST;
|
||||
graphic.descriptor.fill = uf::renderer::enums::PolygonMode::LINE;
|
||||
graphic.descriptor.lineWidth = 2;
|
||||
|
||||
uf::stl::string vertexShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/base/line/vert.spv");
|
||||
uf::stl::string fragmentShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/base/line/frag.spv");
|
||||
|
||||
graphic.material.metadata.autoInitializeUniformBuffers = false;
|
||||
graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX);
|
||||
graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT);
|
||||
graphic.material.metadata.autoInitializeUniformBuffers = true;
|
||||
|
||||
auto& storage = uf::graph::globalStorage ? uf::graph::storage : scene.getComponent<pod::Graph::Storage>();
|
||||
|
||||
// vertex shader
|
||||
{
|
||||
auto& shader = graphic.material.getShader("vertex");
|
||||
shader.aliasBuffer( storage.buffers.camera );
|
||||
}
|
||||
|
||||
graphic.initialize();
|
||||
graphic.initializeMesh( mesh );
|
||||
UF_MSG_DEBUG("Initialized graphic");
|
||||
} else {
|
||||
bool rebuild = graphic.updateMesh( mesh );
|
||||
if ( rebuild ) uf::renderer::states::rebuild = true;
|
||||
switch( constraint.type ) {
|
||||
case pod::ConstraintType::BALL_AND_SOCKET:
|
||||
impl::drawBallSocket( constraint );
|
||||
break;
|
||||
case pod::ConstraintType::HINGE:
|
||||
impl::drawHinge( constraint );
|
||||
break;
|
||||
case pod::ConstraintType::CONE_TWIST:
|
||||
impl::drawConeTwist( constraint );
|
||||
break;
|
||||
case pod::ConstraintType::SLIDER:
|
||||
impl::drawSlider( constraint );
|
||||
break;
|
||||
case pod::ConstraintType::DISTANCE:
|
||||
impl::drawDistance( constraint );
|
||||
break;
|
||||
case pod::ConstraintType::WELD:
|
||||
impl::drawWeld( constraint );
|
||||
break;
|
||||
case pod::ConstraintType::SPRING:
|
||||
impl::drawSpring( constraint );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void impl::draw( const pod::World& world, float dt ) {
|
||||
for ( auto* body : world.bodies ) impl::drawBody( *body );
|
||||
for ( auto* constraint : world.constraints ) impl::drawConstraint( *constraint );
|
||||
}
|
||||
@ -103,6 +103,31 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
|
||||
++uf::physics::settings.frameCounter;
|
||||
|
||||
// flatten all transforms into a contiguous buffer
|
||||
static thread_local uf::stl::vector<pod::Transform<>*> originalTransforms; // stores the pointer to the original transform
|
||||
static thread_local uf::stl::vector<pod::Transform<>> flattenedTransforms; // stores the flattened transforms
|
||||
static thread_local uf::stl::unordered_map<pod::Transform<>*, pod::Transform<>*> transformsMap; // maps the original transform to the flattened one (for querying)
|
||||
|
||||
if ( uf::physics::settings.flattenTransforms ) {
|
||||
originalTransforms.resize( bodies.size() );
|
||||
flattenedTransforms.resize( bodies.size() );
|
||||
transformsMap.clear();
|
||||
|
||||
// copy all transforms, flatten them, and map the original to the reference
|
||||
for ( auto i = 0; i < bodies.size(); ++i ) {
|
||||
auto& body = *bodies[i];
|
||||
//if ( body.inverseMass == 0.0f ) continue; // static bodies don't ever move, so the hierarchy problem doesn't affect it (right?)
|
||||
auto& transform = *body.transform;
|
||||
auto& flattenedTransform = flattenedTransforms[i];
|
||||
auto& originalTransform = originalTransforms[i];
|
||||
|
||||
originalTransform = body.transform;
|
||||
flattenedTransform = uf::transform::flatten( transform );
|
||||
transformsMap[originalTransform] = &flattenedTransform;
|
||||
body.transform = &flattenedTransform; // body now points to the flattened transform
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto* body : bodies ) {
|
||||
impl::integrate( *body, dt );
|
||||
}
|
||||
@ -232,6 +257,41 @@ void uf::physics::step( pod::World& world, float dt ) {
|
||||
|
||||
// snap velocities of bodies
|
||||
for ( auto* b : bodies ) impl::snapVelocity( *b, dt );
|
||||
|
||||
// unflatten all transforms
|
||||
if ( uf::physics::settings.flattenTransforms ) for ( auto i = 0; i < bodies.size(); ++i ) {
|
||||
auto& body = *bodies[i];
|
||||
//if ( body.inverseMass == 0.0f ) continue; // do not bother with static bodies
|
||||
auto& originalTransform = originalTransforms[i];
|
||||
auto& flattenedTransform = flattenedTransforms[i];
|
||||
|
||||
// now points back to original transform
|
||||
body.transform = originalTransform;
|
||||
auto& transform = *body.transform;
|
||||
|
||||
// solo transform: simply update
|
||||
if ( !transform.reference ) {
|
||||
// update position and orientation
|
||||
transform.position = flattenedTransform.position;
|
||||
transform.orientation = flattenedTransform.orientation;
|
||||
// referential transform: convert new world space into local space (to original transform)
|
||||
} else {
|
||||
pod::Transform<> parentTransform;
|
||||
// parent is not within the physics system, use original reference
|
||||
if ( transformsMap.count( originalTransform->reference ) == 0 ) {
|
||||
parentTransform = uf::transform::flatten( *originalTransform->reference );
|
||||
// parent is within the physics system, use the already-flattened transform
|
||||
} else {
|
||||
parentTransform = *transformsMap[originalTransform->reference];
|
||||
}
|
||||
|
||||
transform.position = uf::transform::applyInverse( parentTransform, flattenedTransform.position );
|
||||
transform.orientation = uf::quaternion::multiply(
|
||||
uf::quaternion::inverse( parentTransform.orientation ),
|
||||
flattenedTransform.orientation
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uf::physics::setMass( pod::PhysicsBody& body, float mass ) {
|
||||
@ -452,7 +512,7 @@ void uf::physics::applyAngularVelocity( pod::PhysicsBody& body, const pod::Quate
|
||||
}
|
||||
void uf::physics::applyRotation( pod::PhysicsBody& body, const pod::Quaternion<>& q ) {
|
||||
impl::wakeBody( body );
|
||||
uf::transform::rotate( *body.transform/*.reference*/, q );
|
||||
uf::transform::rotate( *body.transform, q );
|
||||
}
|
||||
void uf::physics::applyRotation( pod::PhysicsBody& body, const pod::Vector3f& axis, float angle ) {
|
||||
uf::physics::applyRotation( body, uf::quaternion::axisAngle( axis, angle ) );
|
||||
@ -481,7 +541,10 @@ pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, fl
|
||||
// initial initialization
|
||||
body.world = &world;
|
||||
body.object = &object;
|
||||
body.transform/*.reference*/ = &object.getComponent<pod::Transform<>>();
|
||||
body.transform = &object.getComponent<pod::Transform<>>();
|
||||
#if UF_PHYSICS_SYNC_TRANSFORMS
|
||||
body.flattenedTransform = uf::transform::flatten( *body.transform );
|
||||
#endif
|
||||
body.offset = offset;
|
||||
body.inverseMass = mass == 0.0f ? 0.0f : 1.0f / mass;
|
||||
body.collider.type = {};
|
||||
|
||||
@ -186,6 +186,8 @@ void impl::integrate( pod::PhysicsBody& body, float dt ) {
|
||||
if ( !body.activity.awake || body.inverseMass == 0.0f ) return;
|
||||
|
||||
auto& world = *body.world;
|
||||
auto& transform = *body.transform;
|
||||
auto fT = uf::transform::flatten( transform );
|
||||
|
||||
// linear integration
|
||||
pod::Vector3f acceleration = body.forceAccumulator * body.inverseMass;
|
||||
@ -194,26 +196,26 @@ void impl::integrate( pod::PhysicsBody& body, float dt ) {
|
||||
|
||||
// angular integration
|
||||
{
|
||||
pod::Matrix3f R = uf::quaternion::matrix3(body.transform->orientation);
|
||||
pod::Matrix3f R = uf::quaternion::matrix3( fT.orientation );
|
||||
pod::Vector3f localTorque = uf::matrix::multiply( uf::matrix::transpose(R), body.torqueAccumulator );
|
||||
pod::Vector3f localAngAccel = localTorque * body.inverseInertiaTensor; // element-wise
|
||||
body.angularVelocity += uf::matrix::multiply( R, localAngAccel ) * dt;
|
||||
}
|
||||
|
||||
// update position
|
||||
body.transform/*.reference*/->position += body.velocity * dt;
|
||||
transform.position += body.velocity * dt;
|
||||
|
||||
// update orientation
|
||||
float angularSpeed2 = uf::vector::magnitude( body.angularVelocity );
|
||||
if ( angularSpeed2 > EPS2 ) {
|
||||
float angularSpeed = std::sqrt( angularSpeed2 );
|
||||
pod::Quaternion<> dq = uf::quaternion::axisAngle( body.angularVelocity / angularSpeed, angularSpeed * dt);
|
||||
uf::transform::rotate( *body.transform/*.reference*/, dq );
|
||||
uf::transform::rotate( transform, dq );
|
||||
}
|
||||
|
||||
// pseudo-impulse position correction
|
||||
if ( !uf::physics::settings.ngsPositionSolver ) {
|
||||
body.transform->position += body.pseudoVelocity * dt;
|
||||
transform.position += body.pseudoVelocity * dt;
|
||||
|
||||
float pseudoAngularSpeed2 = uf::vector::magnitude( body.pseudoAngularVelocity );
|
||||
if ( pseudoAngularSpeed2 > EPS ) {
|
||||
@ -222,7 +224,7 @@ void impl::integrate( pod::PhysicsBody& body, float dt ) {
|
||||
|
||||
float clampedSpeed = std::min(pseudoAngularSpeed, (2.0f * M_PI / 180.0f) / dt);
|
||||
pod::Quaternion<> dq = uf::quaternion::axisAngle( axis, clampedSpeed * dt );
|
||||
uf::transform::rotate( *body.transform, dq );
|
||||
uf::transform::rotate( transform, dq );
|
||||
}
|
||||
|
||||
// reset
|
||||
|
||||
@ -79,24 +79,9 @@ bool impl::aabbHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
}
|
||||
|
||||
void impl::drawAabb( const pod::PhysicsBody& body ) {
|
||||
auto& aabb = body.bounds;
|
||||
|
||||
pod::Vector3f corners[8] = {
|
||||
{aabb.min.x, aabb.min.y, aabb.min.z}, {aabb.max.x, aabb.min.y, aabb.min.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.min.z}, {aabb.min.x, aabb.max.y, aabb.min.z},
|
||||
{aabb.min.x, aabb.min.y, aabb.max.z}, {aabb.max.x, aabb.min.y, aabb.max.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.max.z}, {aabb.min.x, aabb.max.y, aabb.max.z}
|
||||
};
|
||||
|
||||
// bottom face
|
||||
impl::addLine( corners[0], corners[1] ); impl::addLine( corners[1], corners[2] );
|
||||
impl::addLine( corners[2], corners[3] ); impl::addLine( corners[3], corners[0] );
|
||||
// top face
|
||||
impl::addLine( corners[4], corners[5] ); impl::addLine( corners[5], corners[6] );
|
||||
impl::addLine( corners[6], corners[7] ); impl::addLine( corners[7], corners[4] );
|
||||
// vertical edges
|
||||
impl::addLine( corners[0], corners[4] ); impl::addLine( corners[1], corners[5] );
|
||||
impl::addLine( corners[2], corners[6] ); impl::addLine( corners[3], corners[7] );
|
||||
const auto& aabb = body.bounds;
|
||||
auto transform = impl::getTransform( body );
|
||||
uf::debug::drawAabb( aabb, transform );
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::AABB& aabb ) {
|
||||
|
||||
@ -107,26 +107,55 @@ bool impl::capsuleHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, po
|
||||
}
|
||||
|
||||
void impl::drawCapsule( const pod::PhysicsBody& body ) {
|
||||
float radius = body.collider.capsule.radius;
|
||||
const auto& capsule = body.collider.capsule;
|
||||
auto transform = impl::getTransform(body);
|
||||
#if 0
|
||||
uf::debug::drawCapsule( capsule, transform );
|
||||
#else
|
||||
auto [p1, p2] = impl::getCapsuleSegment(body);
|
||||
const int segments = 16;
|
||||
const float angleIncrement = (2.0f * M_PI) / segments;
|
||||
|
||||
pod::Vector3f up = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0, 1, 0});
|
||||
pod::Vector3f right = uf::vector::normalize(impl::computeTangent(up));
|
||||
pod::Vector3f forward = uf::vector::cross(up, right);
|
||||
for ( auto i = 0; i < segments; ++i ) {
|
||||
float theta1 = i * angleIncrement;
|
||||
float theta2 = (i + 1) * angleIncrement;
|
||||
|
||||
pod::Vector3f rightOffset = right * radius;
|
||||
pod::Vector3f forwardOffset = forward * radius;
|
||||
float c1 = std::cos(theta1) * capsule.radius;
|
||||
float s1 = std::sin(theta1) * capsule.radius;
|
||||
float c2 = std::cos(theta2) * capsule.radius;
|
||||
float s2 = std::sin(theta2) * capsule.radius;
|
||||
|
||||
impl::addLine( p1 + rightOffset, p2 + rightOffset );
|
||||
impl::addLine( p1 - rightOffset, p2 - rightOffset );
|
||||
impl::addLine( p1 + forwardOffset, p2 + forwardOffset );
|
||||
impl::addLine( p1 - forwardOffset, p2 - forwardOffset );
|
||||
pod::Vector3f xy1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c1, s1, 0.0f});
|
||||
pod::Vector3f xy2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c2, s2, 0.0f});
|
||||
|
||||
impl::addLine( p1 + rightOffset, p1 - rightOffset );
|
||||
impl::addLine( p1 + forwardOffset, p1 - forwardOffset );
|
||||
impl::addLine( p2 + rightOffset, p2 - rightOffset );
|
||||
impl::addLine( p2 + forwardOffset, p2 - forwardOffset );
|
||||
pod::Vector3f xz1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c1, 0.0f, s1});
|
||||
pod::Vector3f xz2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c2, 0.0f, s2});
|
||||
|
||||
pod::Vector3f yz1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, c1, s1});
|
||||
pod::Vector3f yz2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, c2, s2});
|
||||
|
||||
uf::debug::drawLine( p1 + xy1, p1 + xy2 );
|
||||
uf::debug::drawLine( p1 + xz1, p1 + xz2 );
|
||||
uf::debug::drawLine( p1 + yz1, p1 + yz2 );
|
||||
|
||||
uf::debug::drawLine( p2 + xy1, p2 + xy2 );
|
||||
uf::debug::drawLine( p2 + xz1, p2 + xz2 );
|
||||
uf::debug::drawLine( p2 + yz1, p2 + yz2 );
|
||||
}
|
||||
|
||||
pod::Vector3f rx = uf::quaternion::rotate(transform.orientation, pod::Vector3f{capsule.radius, 0.0f, 0.0f});
|
||||
pod::Vector3f ry = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, capsule.radius, 0.0f});
|
||||
pod::Vector3f rz = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, 0.0f, capsule.radius});
|
||||
|
||||
uf::debug::drawLine( p1 + rx, p2 + rx );
|
||||
uf::debug::drawLine( p1 - rx, p2 - rx );
|
||||
|
||||
uf::debug::drawLine( p1 + ry, p2 + ry );
|
||||
uf::debug::drawLine( p1 - ry, p2 - ry );
|
||||
|
||||
uf::debug::drawLine( p1 + rz, p2 + rz );
|
||||
uf::debug::drawLine( p1 - rz, p2 - rz );
|
||||
#endif
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::Capsule& capsule ) {
|
||||
|
||||
@ -84,16 +84,14 @@ bool impl::hullHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
|
||||
void impl::drawHull( const pod::PhysicsBody& body ) {
|
||||
const uf::Mesh* meshData = body.collider.convexHull.mesh;
|
||||
auto transform = impl::getTransform( body );
|
||||
if ( !meshData ) return;
|
||||
|
||||
size_t totalTriangles = 0;
|
||||
for ( const auto& view : meshData->buffer_views ) totalTriangles += view.index.count / 3;
|
||||
|
||||
for ( size_t i = 0; i < totalTriangles; ++i ) {
|
||||
auto tri = impl::fetchTriangle(*meshData, i, body);
|
||||
|
||||
impl::addLine( tri.points[0], tri.points[1] );
|
||||
impl::addLine( tri.points[1], tri.points[2] );
|
||||
impl::addLine( tri.points[2], tri.points[0] );
|
||||
auto tri = uf::mesh::fetchTriangle( *meshData, i );
|
||||
uf::debug::drawTriangle( tri, transform );
|
||||
}
|
||||
}
|
||||
@ -189,18 +189,18 @@ bool impl::meshHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::
|
||||
}
|
||||
|
||||
void impl::drawMesh( const pod::PhysicsBody& body ) {
|
||||
|
||||
const uf::Mesh* meshData = body.collider.mesh.mesh;
|
||||
auto transform = impl::getTransform( body );
|
||||
if ( !meshData ) return;
|
||||
if ( body.inverseMass == 0.0f ) return;
|
||||
|
||||
size_t totalTriangles = 0;
|
||||
for ( const auto& view : meshData->buffer_views ) totalTriangles += view.index.count / 3;
|
||||
|
||||
for ( size_t i = 0; i < totalTriangles; ++i ) {
|
||||
auto tri = impl::fetchTriangle(*meshData, i, body);
|
||||
|
||||
impl::addLine( tri.points[0], tri.points[1] );
|
||||
impl::addLine( tri.points[1], tri.points[2] );
|
||||
impl::addLine( tri.points[2], tri.points[0] );
|
||||
auto tri = uf::mesh::fetchTriangle( *meshData, i );
|
||||
uf::debug::drawTriangle( tri, transform );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -299,28 +299,9 @@ bool impl::obbHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod::M
|
||||
}
|
||||
|
||||
void impl::drawObb( const pod::PhysicsBody& body ) {
|
||||
auto aabb = impl::obbToAabb( body.collider.obb );
|
||||
pod::Vector3f corners[8] = {
|
||||
{aabb.min.x, aabb.min.y, aabb.min.z}, {aabb.max.x, aabb.min.y, aabb.min.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.min.z}, {aabb.min.x, aabb.max.y, aabb.min.z},
|
||||
{aabb.min.x, aabb.min.y, aabb.max.z}, {aabb.max.x, aabb.min.y, aabb.max.z},
|
||||
{aabb.max.x, aabb.max.y, aabb.max.z}, {aabb.min.x, aabb.max.y, aabb.max.z}
|
||||
};
|
||||
|
||||
auto transform = impl::getTransform(body);
|
||||
FOR_EACH( 8, {
|
||||
corners[i] = uf::transform::apply(transform, corners[i]);
|
||||
});
|
||||
|
||||
// bottom face
|
||||
impl::addLine( corners[0], corners[1] ); impl::addLine( corners[1], corners[2] );
|
||||
impl::addLine( corners[2], corners[3] ); impl::addLine( corners[3], corners[0] );
|
||||
// top face
|
||||
impl::addLine( corners[4], corners[5] ); impl::addLine( corners[5], corners[6] );
|
||||
impl::addLine( corners[6], corners[7] ); impl::addLine( corners[7], corners[4] );
|
||||
// vertical edges
|
||||
impl::addLine( corners[0], corners[4] ); impl::addLine( corners[1], corners[5] );
|
||||
impl::addLine( corners[2], corners[6] ); impl::addLine( corners[3], corners[7] );
|
||||
const auto& obb = body.collider.obb;
|
||||
auto transform = impl::getTransform(body);
|
||||
uf::debug::drawObb( obb, transform );
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::OBB& obb ) {
|
||||
|
||||
@ -67,8 +67,12 @@ bool impl::planeHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod:
|
||||
}
|
||||
|
||||
void impl::drawPlane( const pod::PhysicsBody& body ) {
|
||||
const auto& plane = body.collider.plane;
|
||||
auto transform = impl::getTransform(body);
|
||||
|
||||
#if 0
|
||||
uf::debug::drawPlane( plane, transform );
|
||||
#else
|
||||
pod::Vector3f right = uf::quaternion::rotate(transform.orientation, pod::Vector3f{1, 0, 0});
|
||||
pod::Vector3f forward = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0, 0, 1});
|
||||
|
||||
@ -78,13 +82,14 @@ void impl::drawPlane( const pod::PhysicsBody& body ) {
|
||||
pod::Vector3f p2 = transform.position - (right * size) - (forward * size);
|
||||
pod::Vector3f p3 = transform.position + (right * size) - (forward * size);
|
||||
|
||||
impl::addLine( p0, p1 );
|
||||
impl::addLine( p1, p2 );
|
||||
impl::addLine( p2, p3 );
|
||||
impl::addLine( p3, p0 );
|
||||
uf::debug::drawLine( p0, p1 );
|
||||
uf::debug::drawLine( p1, p2 );
|
||||
uf::debug::drawLine( p2, p3 );
|
||||
uf::debug::drawLine( p3, p0 );
|
||||
|
||||
impl::addLine( p0, p2 );
|
||||
impl::addLine( p1, p3 );
|
||||
uf::debug::drawLine( p0, p2 );
|
||||
uf::debug::drawLine( p1, p3 );
|
||||
#endif
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::Plane& plane ) {
|
||||
|
||||
@ -304,7 +304,7 @@ void impl::drawRay( const pod::Ray& ray, const pod::RayQuery& query ) {
|
||||
auto& start = ray.origin;
|
||||
auto end = ray.origin + ray.direction * query.contact.penetration;
|
||||
|
||||
impl::addTransientLine( start, end, query.hit ? pod::Vector4f{ 0, 1, 0, 1 } : pod::Vector4f{ 1, 0, 0, 1 }, query.invoker, query.body );
|
||||
uf::debug::addLine( start, end, query.hit ? pod::Vector4f{ 0, 1, 0, 1 } : pod::Vector4f{ 1, 0, 0, 1 } );
|
||||
}
|
||||
|
||||
pod::RayQuery uf::physics::rayCast( const pod::Ray& ray, const pod::PhysicsBody& body, float maxDistance ) {
|
||||
|
||||
@ -69,35 +69,9 @@ bool impl::sphereHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, pod
|
||||
}
|
||||
|
||||
void impl::drawSphere( const pod::PhysicsBody& body ) {
|
||||
float radius = body.collider.sphere.radius;
|
||||
const auto& sphere = body.collider.sphere;
|
||||
auto transform = impl::getTransform(body);
|
||||
|
||||
const int segments = 16;
|
||||
const float PI = 3.14159265359f;
|
||||
const float angleIncrement = (2.0f * PI) / segments;
|
||||
|
||||
for ( auto i = 0; i < segments; ++i ) {
|
||||
float theta1 = i * angleIncrement;
|
||||
float theta2 = (i + 1) * angleIncrement;
|
||||
|
||||
float c1 = std::cos(theta1) * radius;
|
||||
float s1 = std::sin(theta1) * radius;
|
||||
float c2 = std::cos(theta2) * radius;
|
||||
float s2 = std::sin(theta2) * radius;
|
||||
|
||||
pod::Vector3f xy1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c1, s1, 0.0f});
|
||||
pod::Vector3f xy2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c2, s2, 0.0f});
|
||||
|
||||
pod::Vector3f xz1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c1, 0.0f, s1});
|
||||
pod::Vector3f xz2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{c2, 0.0f, s2});
|
||||
|
||||
pod::Vector3f yz1 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, c1, s1});
|
||||
pod::Vector3f yz2 = uf::quaternion::rotate(transform.orientation, pod::Vector3f{0.0f, c2, s2});
|
||||
|
||||
impl::addLine( transform.position + xy1, transform.position + xy2 );
|
||||
impl::addLine( transform.position + xz1, transform.position + xz2 );
|
||||
impl::addLine( transform.position + yz1, transform.position + yz2 );
|
||||
}
|
||||
uf::debug::drawSphere( sphere, transform );
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::Sphere& sphere ) {
|
||||
|
||||
@ -358,14 +358,7 @@ bool impl::triangleHull( const pod::PhysicsBody& a, const pod::PhysicsBody& b, p
|
||||
void impl::drawTriangle( const pod::PhysicsBody& body ) {
|
||||
const auto& tri = body.collider.triangle;
|
||||
auto transform = impl::getTransform(body);
|
||||
|
||||
pod::Vector3f v0 = uf::transform::apply(transform, tri.points[0]);
|
||||
pod::Vector3f v1 = uf::transform::apply(transform, tri.points[1]);
|
||||
pod::Vector3f v2 = uf::transform::apply(transform, tri.points[2]);
|
||||
|
||||
impl::addLine( v0, v1 );
|
||||
impl::addLine( v1, v2 );
|
||||
impl::addLine( v2, v0 );
|
||||
uf::debug::drawTriangle( tri, transform );
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::TriangleWithNormal& tri ) {
|
||||
|
||||
@ -12,6 +12,9 @@ void impl::solvePositions( uf::stl::vector<pod::Manifold>& manifolds, float dt,
|
||||
auto tA = impl::getTransform( a );
|
||||
auto tB = impl::getTransform( b );
|
||||
|
||||
auto& aT = *a.transform;
|
||||
auto& bT = *b.transform;
|
||||
|
||||
if ( a.inverseMass == 0.0f && b.inverseMass == 0.0f ) continue;
|
||||
|
||||
for ( auto& c : manifold.points ) {
|
||||
@ -38,7 +41,7 @@ void impl::solvePositions( uf::stl::vector<pod::Manifold>& manifolds, float dt,
|
||||
// apply impulses directly
|
||||
if ( ctxA.invM > 0.0f ) {
|
||||
pod::Vector3f translation = P * ctxA.invM;
|
||||
a.transform->position -= translation;
|
||||
aT.position -= translation;
|
||||
tA.position -= translation;
|
||||
|
||||
pod::Vector3f deltaAngleA = uf::matrix::multiply(ctxA.invI, uf::vector::cross(rA, -P));
|
||||
@ -53,7 +56,7 @@ void impl::solvePositions( uf::stl::vector<pod::Manifold>& manifolds, float dt,
|
||||
|
||||
if ( ctxB.invM > 0.0f ) {
|
||||
pod::Vector3f translation = P * ctxB.invM;
|
||||
b.transform->position += translation;
|
||||
bT.position += translation;
|
||||
tB.position += translation;
|
||||
|
||||
pod::Vector3f deltaAngleB = uf::matrix::multiply(ctxB.invI, uf::vector::cross(rB, P));
|
||||
|
||||
@ -157,7 +157,7 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) {
|
||||
void ext::CraetureBehavior::tick( uf::Object& self ) {
|
||||
auto& metadata = this->getComponent<ext::CraetureBehavior::Metadata>();
|
||||
|
||||
if ( this->hasComponent<pod::Graph>() ) {
|
||||
if ( this->hasComponent<pod::Graph>() && metadata.animation != "" ) {
|
||||
auto& graph = this->getComponent<pod::Graph>();
|
||||
pod::payloads::QueueAnimationPayload payload;
|
||||
payload.name = metadata.animation;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user