more fixes (to-do: fix BVH serialization/deserialization since I'm very sure it's wrong, but everything else should be plumbed right)
This commit is contained in:
parent
24d1d63516
commit
992556b054
@ -48,5 +48,6 @@ namespace uf {
|
||||
size_t UF_API serialize( const pod::BVH& bvh, uf::stl::vector<uint8_t>& outBuffer, uint32_t offset = 0 );
|
||||
bool UF_API deserialize( pod::BVH& bvh, const uf::stl::vector<uint8_t>& buffer, uint32_t offset = 0, uint32_t length = 0 );
|
||||
void UF_API flagAsActive( pod::BVH& bvh, uint32_t index, bool active );
|
||||
void UF_API flagAsActive( pod::BVH& bvh, uint32_t index, uint32_t count, bool active );
|
||||
}
|
||||
}
|
||||
@ -36,6 +36,7 @@ namespace uf {
|
||||
void UF_API setGravity( pod::PhysicsBody&, const pod::Vector3f& = { NAN, NAN, NAN } );
|
||||
pod::Vector3f UF_API getGravity( pod::PhysicsBody& );
|
||||
|
||||
void UF_API update( pod::PhysicsBody& body );
|
||||
void UF_API updateInertia( pod::PhysicsBody& body );
|
||||
|
||||
void UF_API applyForce( pod::PhysicsBody& body, const pod::Vector3f& force );
|
||||
|
||||
@ -200,7 +200,7 @@ namespace pod {
|
||||
uf::stl::vector<pod::BVH::index_t> indices;
|
||||
uf::stl::vector<pod::BVH::Node> nodes;
|
||||
uf::stl::vector<pod::BVH::FlatNode> flattened;
|
||||
uf::stl::vector<uint32_t> primitiveToNode;
|
||||
uf::stl::vector<pod::BVH::index_t> indicesToNodes;
|
||||
|
||||
uf::stl::vector<pod::AABB> bounds;
|
||||
uf::stl::vector<pod::AABB> flatBounds;
|
||||
|
||||
@ -39,7 +39,7 @@ namespace {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uf::Image decodeImage( ext::json::Value& json, pod::Graph& graph, const uf::stl::string& imageName, uf::stl::vector<PendingImage>& pendingImages ) {
|
||||
uf::Image decodeImage( ext::json::Value& json, pod::Graph& graph, const uf::stl::string& key ) {
|
||||
uf::Image image;
|
||||
|
||||
uf::stl::string filename = "";
|
||||
@ -89,23 +89,17 @@ namespace {
|
||||
|
||||
if ( graph.settings.stream.textures ) {
|
||||
auto& storage = uf::graph::getStorage(graph);
|
||||
graph.streams.images[imageName] = { fullPath, offset, length };
|
||||
graph.streams.images[key] = { fullPath, offset, length };
|
||||
} else {
|
||||
pendingImages.push_back({ imageName, {}, extension, layers });
|
||||
auto& pending = pendingImages.back();
|
||||
|
||||
size_t readLen = length > 0 ? length : uf::io::size( fullPath );
|
||||
if ( readLen > 0 ) {
|
||||
pending.buffer.resize(readLen);
|
||||
uf::asset::read( fullPath, offset, readLen, pending.buffer.data()/*, [&graph, &pending]() {
|
||||
uf::asset::read( fullPath, offset, readLen, [&graph, key, extension, layers]( uf::stl::vector<uint8_t>&& buffer ) {
|
||||
auto& storage = uf::graph::getStorage(graph);
|
||||
auto& image = storage.images[pending.name].data;
|
||||
auto& image = storage.images[key].data;
|
||||
|
||||
uf::image::open( image, pending.buffer, pending.extension, false );
|
||||
uf::image::layers( image, pending.layers );
|
||||
|
||||
pending.buffer.clear();
|
||||
}*/ );
|
||||
uf::image::open( image, buffer, extension, false );
|
||||
uf::image::layers( image, layers );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
@ -279,10 +273,10 @@ namespace {
|
||||
return mesh;
|
||||
}
|
||||
|
||||
pod::BVH decodeBvh( ext::json::Value& json, pod::Graph& graph, const uf::stl::string& bvhName ) {
|
||||
pod::BVH decodeBvh( ext::json::Value& json, pod::Graph& graph, const uf::stl::string& key ) {
|
||||
pod::BVH bvh;
|
||||
auto& storage = uf::graph::getStorage(graph);
|
||||
auto& bvhStream = graph.streams.bvhs[bvhName];
|
||||
auto& bvhStream = graph.streams.bvhs[key];
|
||||
|
||||
uf::stl::string filename = json["filename"].as<uf::stl::string>();
|
||||
size_t offset = json["offset"].as<size_t>();
|
||||
@ -293,9 +287,14 @@ namespace {
|
||||
|
||||
bool deferred = graph.settings.stream.enabled;
|
||||
if ( !deferred ) {
|
||||
uf::stl::vector<uint8_t> tempBuffer(length);
|
||||
uf::asset::read( fullPath, offset, length, tempBuffer.data() );
|
||||
uf::bvh::deserialize( bvh, tempBuffer, 0, length );
|
||||
size_t readLen = length > 0 ? length : uf::io::size( fullPath );
|
||||
if ( readLen > 0 ) {
|
||||
uf::asset::read( fullPath, offset, readLen, [&graph, key]( uf::stl::vector<uint8_t>&& buffer ) {
|
||||
auto& storage = uf::graph::getStorage(graph);
|
||||
auto& bvh = storage.bvhs[key];
|
||||
uf::bvh::deserialize( bvh, buffer );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
return bvh;
|
||||
@ -534,14 +533,12 @@ void uf::graph::load( pod::Graph& graph, const uf::stl::string& filename, const
|
||||
UF_DEBUG_TIMER_MULTITRACE("Reading images...");
|
||||
graph.images.reserve( serializer["images"].size() );
|
||||
|
||||
pendingImages.reserve( serializer["images"].size() );
|
||||
|
||||
ext::json::forEach( serializer["images"], [&]( ext::json::Value& value ){
|
||||
auto name = key + value["name"].as<uf::stl::string>();
|
||||
|
||||
//UF_DEBUG_TIMER_MULTITRACE("Reading image={}", name);
|
||||
storage.images[name] = {
|
||||
.data = decodeImage( value, graph, name, pendingImages ),
|
||||
.data = decodeImage( value, graph, name ),
|
||||
};
|
||||
graph.images.emplace_back(name);
|
||||
});
|
||||
@ -568,11 +565,6 @@ void uf::graph::load( pod::Graph& graph, const uf::stl::string& filename, const
|
||||
storage.meshes[name] = decodeMesh( json, graph, name );
|
||||
graph.meshes.emplace_back(name);
|
||||
|
||||
// should probably be under serializer["bvhs"]
|
||||
if ( value["bvh"].isObject() ) {
|
||||
storage.bvhs[name] = decodeBvh( value["bvh"], graph, name );
|
||||
}
|
||||
|
||||
if ( preferMinified && !hasMinifiedAsset && !graph.settings.stream.enabled )
|
||||
meshesToMinify.emplace_back( name );
|
||||
});
|
||||
@ -580,6 +572,16 @@ void uf::graph::load( pod::Graph& graph, const uf::stl::string& filename, const
|
||||
UF_DEBUG_TIMER_MULTITRACE("Read meshes");
|
||||
});
|
||||
|
||||
tasks.queue([&]{
|
||||
UF_DEBUG_TIMER_MULTITRACE("Reading BVHs...");
|
||||
ext::json::forEach( serializer["bvhs"], [&]( ext::json::Value& value ){
|
||||
auto name = key + value["name"].as<uf::stl::string>();
|
||||
// storage.bvhs[name] = decodeBvh( value, graph, name );
|
||||
});
|
||||
|
||||
UF_DEBUG_TIMER_MULTITRACE("Read BVHs");
|
||||
});
|
||||
|
||||
tasks.queue([&]{
|
||||
UF_DEBUG_TIMER_MULTITRACE("Reading animation information...");
|
||||
auto& animNode = serializer["animations"];
|
||||
@ -639,16 +641,6 @@ void uf::graph::load( pod::Graph& graph, const uf::stl::string& filename, const
|
||||
UF_DEBUG_TIMER_MULTITRACE("Processing IO");
|
||||
uf::asset::processIO();
|
||||
|
||||
// process images
|
||||
UF_DEBUG_TIMER_MULTITRACE("Processing pending images");
|
||||
for ( auto& pending : pendingImages ) {
|
||||
auto& image = storage.images[pending.name].data;
|
||||
|
||||
uf::image::open( image, pending.buffer, pending.extension, false );
|
||||
uf::image::layers( image, pending.layers );
|
||||
|
||||
pending.buffer.clear();
|
||||
}
|
||||
|
||||
// process meshes that need to be minified because I can't easily tie it to the callback
|
||||
UF_DEBUG_TIMER_MULTITRACE("Processing meshes for minification");
|
||||
|
||||
@ -352,20 +352,6 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
|
||||
json["min"] = encode( minMesh, settings, graph, minBuffer, minBinName );
|
||||
}
|
||||
|
||||
// to-do: should probably be in its own file in the event the broadphase physics BVH gets saved too
|
||||
// it seems that it does cause issues when writing to the mesh's buffer
|
||||
if ( false ) {
|
||||
pod::BVH bvh;
|
||||
uf::bvh::build( bvh, mesh );
|
||||
|
||||
auto offset = meshesBuffer.size();
|
||||
auto length = uf::bvh::serialize( bvh, meshesBuffer );
|
||||
|
||||
json["bvh"]["filename"] = binName;
|
||||
json["bvh"]["offset"] = offset;
|
||||
json["bvh"]["length"] = length;
|
||||
}
|
||||
|
||||
serializer["meshes"].emplace_back(json);
|
||||
}
|
||||
|
||||
@ -377,6 +363,35 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
|
||||
}
|
||||
});
|
||||
|
||||
tasks.queue([&]{
|
||||
ext::json::reserve( serializer["bvhs"], graph.meshes.size() );
|
||||
|
||||
uf::stl::vector<uint8_t> buffer;
|
||||
uf::stl::string binName = "bvhs." + (settings.compression == "none" ? "bin" : settings.compression);
|
||||
|
||||
auto offset = 0;
|
||||
for ( auto& name : graph.meshes ) {
|
||||
auto& mesh = storage.meshes.map.at(name);
|
||||
pod::BVH bvh;
|
||||
uf::bvh::build( bvh, mesh );
|
||||
|
||||
auto length = uf::bvh::serialize( bvh, buffer );
|
||||
|
||||
uf::Serializer json;
|
||||
json["name"] = name;
|
||||
json["filename"] = binName;
|
||||
json["offset"] = offset;
|
||||
json["length"] = length;
|
||||
serializer["bvhs"].emplace_back(json);
|
||||
|
||||
offset += length;
|
||||
}
|
||||
|
||||
if ( !buffer.empty() ) {
|
||||
uf::io::write(directory + "/" + binName, buffer);
|
||||
}
|
||||
});
|
||||
|
||||
tasks.queue([&]{
|
||||
ext::json::reserve( serializer["animations"], graph.animations.size() );
|
||||
|
||||
|
||||
@ -2228,10 +2228,10 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
|
||||
|
||||
// update bounds
|
||||
if ( exists ) {
|
||||
// body.bounds = impl::computeAABB( body );
|
||||
bvh = {};
|
||||
auto& body = entity.getComponent<pod::PhysicsBody>();
|
||||
uf::physics::update( body );
|
||||
}
|
||||
{
|
||||
if ( !exists ) {
|
||||
// only need to initialize once, as the pointers will remain the same
|
||||
float mass = phyziks["mass"].as(0.0f);
|
||||
auto center = uf::vector::decode( phyziks["center"], pod::Vector3f{} );
|
||||
@ -2306,6 +2306,9 @@ void uf::graph::reload( pod::Graph& graph ) {
|
||||
bool needsGraphicBinding = !entity.hasComponent<uf::renderer::Graphic>();
|
||||
auto& work = pendingMeshes[node.mesh];
|
||||
work.dependentNodes.push_back(node.index);
|
||||
if ( work.queuedLODs.empty() && primitives.size() > 0 ) {
|
||||
work.queuedLODs.resize( primitives.size(), -1 );
|
||||
}
|
||||
|
||||
auto& bvh = storage.bvhs.map[meshName];
|
||||
auto& bvhStream = graph.streams.bvhs[meshName];
|
||||
@ -2313,10 +2316,6 @@ void uf::graph::reload( pod::Graph& graph ) {
|
||||
work.needsBvhLoad = true;
|
||||
}
|
||||
|
||||
if ( work.queuedLODs.empty() && primitives.size() > 0 ) {
|
||||
work.queuedLODs.resize( primitives.size(), -1 );
|
||||
}
|
||||
|
||||
if ( radius > 0 && mesh.indirect.count && mesh.indirect.count <= primitives.size() ) {
|
||||
float closestDistance = std::numeric_limits<float>::max();
|
||||
size_t closestDrawID = 0;
|
||||
@ -2562,22 +2561,18 @@ void uf::graph::reload( pod::Graph& graph ) {
|
||||
uniqueIndexBuffers[attr.buffer] = attr.stride > 0 ? attr.stride : attr.descriptor.size;
|
||||
}
|
||||
|
||||
int actualReadsToPerform = 0;
|
||||
|
||||
if ( work.needsBvhLoad ) {
|
||||
actualReadsToPerform += 1;
|
||||
}
|
||||
int totalReads = work.needsBvhLoad ? 1 : 0;
|
||||
for ( auto& active : activeDraws ) {
|
||||
auto& lod = primitives[active.drawID].lod.levels[active.lodLevel];
|
||||
|
||||
if ( lod.indices > 0 ) {
|
||||
actualReadsToPerform += uniqueIndexBuffers.size();
|
||||
totalReads += uniqueIndexBuffers.size();
|
||||
for ( auto& [bufID, stride] : uniqueIndexBuffers ) {
|
||||
ctx->bufferSizes[bufID] += lod.indices * stride;
|
||||
}
|
||||
}
|
||||
if ( lod.vertices > 0 ) {
|
||||
actualReadsToPerform += uniqueVertexBuffers.size();
|
||||
totalReads += uniqueVertexBuffers.size();
|
||||
for ( auto& [bufID, stride] : uniqueVertexBuffers ) {
|
||||
ctx->bufferSizes[bufID] += lod.vertices * stride;
|
||||
}
|
||||
@ -2590,46 +2585,60 @@ void uf::graph::reload( pod::Graph& graph ) {
|
||||
}
|
||||
}
|
||||
|
||||
ctx->pendingReads.store(actualReadsToPerform);
|
||||
ctx->pendingReads.store(totalReads);
|
||||
|
||||
auto finalizeStream = [ctx, graphPtr = &graph]() {
|
||||
auto& currentGraph = *graphPtr;
|
||||
auto& storage = uf::graph::getStorage(currentGraph);
|
||||
auto& meshKey = currentGraph.meshes[ctx->meshID];
|
||||
auto& targetMesh = storage.meshes.map[meshKey];
|
||||
auto& targetPrimitives = storage.primitives.map[currentGraph.primitives[ctx->meshID]];
|
||||
auto& targetBvh = storage.bvhs.map[meshKey];
|
||||
auto& graph = *graphPtr;
|
||||
auto& storage = uf::graph::getStorage(graph);
|
||||
auto& meshKey = graph.meshes[ctx->meshID];
|
||||
auto& mesh = storage.meshes.map[meshKey];
|
||||
auto& primitives = storage.primitives.map[graph.primitives[ctx->meshID]];
|
||||
auto& bvh = storage.bvhs.map[meshKey];
|
||||
auto& bvhStream = graph.streams.bvhs[meshKey];
|
||||
|
||||
for ( auto& [b, buf] : ctx->completedBuffers ) {
|
||||
std::swap(targetMesh.buffers[b], buf);
|
||||
std::swap(mesh.buffers[b], buf);
|
||||
}
|
||||
|
||||
targetMesh.vertex.count = ctx->vertexCount;
|
||||
targetMesh.index.count = ctx->indexCount;
|
||||
mesh.vertex.count = ctx->vertexCount;
|
||||
mesh.index.count = ctx->indexCount;
|
||||
|
||||
bool rebuildBvh = true;/*
|
||||
if ( !ctx->bvhRawBuffer.empty() ) {
|
||||
uf::bvh::deserialize( targetBvh, ctx->bvhRawBuffer, 0, ctx->bvhRawBuffer.size() );
|
||||
if ( !uf::bvh::deserialize( bvh, ctx->bvhRawBuffer ) ) {
|
||||
bvhStream.buffer.length = 0;
|
||||
}
|
||||
ctx->bvhRawBuffer.clear();
|
||||
ctx->bvhRawBuffer.shrink_to_fit();
|
||||
}
|
||||
bool bvhValid = !targetBvh.flattened.empty() || !targetBvh.nodes.empty();
|
||||
if ( bvhStream.buffer.length == 0 ) {
|
||||
rebuildBvh = true;
|
||||
}*/
|
||||
bool bvhValid = !bvh.flattened.empty() || !bvh.nodes.empty();
|
||||
|
||||
auto& indirectAttr = targetMesh.indirect.attributes.front();
|
||||
pod::DrawCommand* targetDrawCommands = (pod::DrawCommand*) targetMesh.buffers[indirectAttr.buffer].data();
|
||||
auto& indirectAttr = mesh.indirect.attributes.front();
|
||||
pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.buffers[indirectAttr.buffer].data();
|
||||
|
||||
for ( auto& [drawID, cmd] : ctx->updatedCommands ) {
|
||||
targetPrimitives[drawID].drawCommand = cmd;
|
||||
targetDrawCommands[drawID] = cmd;
|
||||
primitives[drawID].drawCommand = cmd;
|
||||
drawCommands[drawID] = cmd;
|
||||
|
||||
if ( bvhValid ) {
|
||||
uf::bvh::flagAsActive( targetBvh, drawID, (cmd.vertices > 0 && cmd.indices > 0) );
|
||||
if ( bvhValid && !rebuildBvh ) {
|
||||
auto& lod = primitives[drawID].lod.levels[0];
|
||||
|
||||
uint32_t startTri = lod.indexID / 3;
|
||||
uint32_t triCount = lod.indices / 3;
|
||||
uf::bvh::flagAsActive( bvh, startTri, triCount, (cmd.vertices > 0 && cmd.indices > 0) );
|
||||
}
|
||||
}
|
||||
|
||||
targetMesh.updateDescriptor();
|
||||
mesh.updateDescriptor();
|
||||
if ( rebuildBvh ) {
|
||||
uf::bvh::build( bvh, mesh );
|
||||
}
|
||||
|
||||
for ( auto nodeID : ctx->deps ) {
|
||||
uf::graph::reload( currentGraph, currentGraph.nodes[nodeID] );
|
||||
uf::graph::reload( graph, graph.nodes[nodeID] );
|
||||
}
|
||||
|
||||
#if UF_USE_OPENGL
|
||||
@ -2643,7 +2652,7 @@ void uf::graph::reload( pod::Graph& graph ) {
|
||||
}
|
||||
};
|
||||
|
||||
if ( actualReadsToPerform > 0 ) {
|
||||
if ( totalReads > 0 ) {
|
||||
uf::stl::unordered_map<size_t, size_t> bufferWriteOffsets;
|
||||
|
||||
if ( work.needsBvhLoad ) {
|
||||
@ -2718,25 +2727,25 @@ void uf::graph::reload( pod::Graph& graph ) {
|
||||
ctx->pendingReads.store(totalReads);
|
||||
|
||||
auto finalizeFullLoad = [ctx, graphPtr = &graph]() {
|
||||
auto& currentGraph = *graphPtr;
|
||||
auto& storage = uf::graph::getStorage(currentGraph);
|
||||
auto& meshKey = currentGraph.meshes[ctx->meshID];
|
||||
auto& targetMesh = storage.meshes.map[meshKey];
|
||||
auto& targetBvh = storage.bvhs.map[meshKey];
|
||||
auto& graph = *graphPtr;
|
||||
auto& storage = uf::graph::getStorage(graph);
|
||||
auto& meshKey = graph.meshes[ctx->meshID];
|
||||
auto& mesh = storage.meshes.map[meshKey];
|
||||
auto& bvh = storage.bvhs.map[meshKey];
|
||||
|
||||
for ( auto& [b, buf] : ctx->newBuffers ) {
|
||||
std::swap(targetMesh.buffers[b], buf);
|
||||
std::swap(mesh.buffers[b], buf);
|
||||
}
|
||||
targetMesh.updateDescriptor();
|
||||
mesh.updateDescriptor();
|
||||
|
||||
if ( !ctx->bvhRawBuffer.empty() ) {
|
||||
uf::bvh::deserialize( targetBvh, ctx->bvhRawBuffer, 0, ctx->bvhRawBuffer.size() );
|
||||
uf::bvh::deserialize( bvh, ctx->bvhRawBuffer );
|
||||
ctx->bvhRawBuffer.clear();
|
||||
ctx->bvhRawBuffer.shrink_to_fit();
|
||||
}
|
||||
|
||||
for ( auto nodeID : ctx->deps ) {
|
||||
uf::graph::reload( currentGraph, currentGraph.nodes[nodeID] );
|
||||
uf::graph::reload( graph, graph.nodes[nodeID] );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -184,7 +184,10 @@ void impl::buildBroadphaseBVH( pod::BVH& bvh, const uf::stl::vector<pod::Physics
|
||||
bvh.indices.clear();
|
||||
bvh.nodes.clear();
|
||||
bvh.bounds.clear();
|
||||
bvh.indicesToNodes.clear();
|
||||
bvh.bounds.reserve(bodies.size());
|
||||
bvh.indices.reserve(bodies.size());
|
||||
bvh.indicesToNodes.resize(bodies.size(), 0);
|
||||
|
||||
// stores bounds
|
||||
uf::stl::vector<pod::AABB> bounds(bodies.size(), { {FLT_MAX, FLT_MAX, FLT_MAX}, {-FLT_MAX, -FLT_MAX, -FLT_MAX} });
|
||||
@ -203,7 +206,14 @@ void impl::buildBroadphaseBVH( pod::BVH& bvh, const uf::stl::vector<pod::Physics
|
||||
if ( uf::physics::settings.useBvhSahBodies ) impl::buildBVHNode_SAH( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
else impl::buildBVHNode( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
// flatten if requested
|
||||
if ( uf::physics::settings.flattenBvhBodies ) impl::flattenBVH( bvh, 0 );
|
||||
if ( uf::physics::settings.flattenBvhBodies ) {
|
||||
impl::flattenBVH( bvh, 0 );
|
||||
// refitting code requires these to exist still
|
||||
// bvh.nodes.clear();
|
||||
// bvh.bounds.clear();
|
||||
// bvh.nodes.shrink_to_fit();
|
||||
// bvh.bounds.shrink_to_fit();
|
||||
}
|
||||
|
||||
// mark as clean
|
||||
bvh.dirty = false;
|
||||
@ -214,7 +224,11 @@ void impl::buildMeshBVH( pod::BVH& bvh, const uf::Mesh& mesh, pod::BVH::index_t
|
||||
|
||||
bvh.indices.clear();
|
||||
bvh.nodes.clear();
|
||||
bvh.bounds.clear();
|
||||
bvh.indicesToNodes.clear();
|
||||
bvh.bounds.reserve( triangles );
|
||||
bvh.indices.reserve( triangles );
|
||||
bvh.indicesToNodes.resize( triangles, 0 );
|
||||
|
||||
// stores bounds
|
||||
uf::stl::vector<pod::AABB> bounds;
|
||||
@ -249,7 +263,14 @@ void impl::buildMeshBVH( pod::BVH& bvh, const uf::Mesh& mesh, pod::BVH::index_t
|
||||
if ( uf::physics::settings.useBvhSahMeshes ) impl::buildBVHNode_SAH( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
else impl::buildBVHNode( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
// flatten if requested
|
||||
if ( uf::physics::settings.flattenBvhMeshes ) impl::flattenBVH( bvh, 0 );
|
||||
if ( uf::physics::settings.flattenBvhMeshes ) {
|
||||
impl::flattenBVH( bvh, 0 );
|
||||
// unstable at times
|
||||
//bvh.nodes.clear();
|
||||
//bvh.bounds.clear();
|
||||
//bvh.nodes.shrink_to_fit();
|
||||
//bvh.bounds.shrink_to_fit();
|
||||
}
|
||||
|
||||
// mark as clean
|
||||
bvh.dirty = false;
|
||||
@ -263,7 +284,11 @@ void impl::buildConvexHullBVH( pod::BVH& bvh, const uf::Mesh& mesh, pod::BVH::in
|
||||
|
||||
bvh.indices.clear();
|
||||
bvh.nodes.clear();
|
||||
bvh.bounds.clear();
|
||||
bvh.indicesToNodes.clear();
|
||||
bvh.bounds.reserve( hullCount );
|
||||
bvh.indices.reserve( hullCount );
|
||||
bvh.indicesToNodes.resize( hullCount, 0 );
|
||||
|
||||
// stores bounds
|
||||
uf::stl::vector<pod::AABB> bounds;
|
||||
@ -285,7 +310,13 @@ void impl::buildConvexHullBVH( pod::BVH& bvh, const uf::Mesh& mesh, pod::BVH::in
|
||||
else impl::buildBVHNode( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
|
||||
// flatten if requested
|
||||
if ( uf::physics::settings.flattenBvhMeshes ) impl::flattenBVH( bvh, 0 );
|
||||
if ( uf::physics::settings.flattenBvhMeshes ) {
|
||||
impl::flattenBVH( bvh, 0 );
|
||||
//bvh.nodes.clear();
|
||||
//bvh.bounds.clear();
|
||||
//bvh.nodes.shrink_to_fit();
|
||||
//bvh.bounds.shrink_to_fit();
|
||||
}
|
||||
|
||||
// mark as clean
|
||||
bvh.dirty = false;
|
||||
@ -464,11 +495,9 @@ pod::BVH::index_t impl::flattenBVH( pod::BVH& bvh, pod::BVH::index_t nodeID ) {
|
||||
if ( nodeID == 0 ) {
|
||||
bvh.flattened.clear();
|
||||
bvh.flatBounds.clear();
|
||||
bvh.primitiveToNode.clear();
|
||||
|
||||
bvh.flattened.reserve(bvh.nodes.size());
|
||||
bvh.flatBounds.reserve(bvh.bounds.size());
|
||||
bvh.primitiveToNode.resize(bvh.indices.size());
|
||||
}
|
||||
|
||||
const auto& node = bvh.nodes[nodeID];
|
||||
@ -491,7 +520,7 @@ pod::BVH::index_t impl::flattenBVH( pod::BVH& bvh, pod::BVH::index_t nodeID ) {
|
||||
bvh.flattened[flatID] = flat;
|
||||
|
||||
for ( uint32_t i = 0; i < node.getCount(); ++i ) {
|
||||
bvh.primitiveToNode[bvh.indices[node.start + i]] = flatID;
|
||||
bvh.indicesToNodes[bvh.indices[node.start + i]] = flatID;
|
||||
}
|
||||
return flatID + 1;
|
||||
}
|
||||
@ -997,8 +1026,8 @@ void impl::postprocessPairs( pod::BVH::pairs_t& pairs ) {
|
||||
}
|
||||
|
||||
void uf::bvh::flagAsActive( pod::BVH& bvh, uint32_t index, bool active ) {
|
||||
if ( index < bvh.primitiveToNode.size() ) {
|
||||
uint32_t flatNodeID = bvh.primitiveToNode[index];
|
||||
if ( index < bvh.indicesToNodes.size() ) {
|
||||
uint32_t flatNodeID = bvh.indicesToNodes[index];
|
||||
if ( flatNodeID < bvh.flattened.size() ) {
|
||||
bvh.flattened[flatNodeID].setUnloaded(!active);
|
||||
}
|
||||
@ -1019,16 +1048,42 @@ void uf::bvh::flagAsActive( pod::BVH& bvh, uint32_t index, bool active ) {
|
||||
}
|
||||
}
|
||||
|
||||
void uf::bvh::flagAsActive( pod::BVH& bvh, uint32_t index, uint32_t count, bool active ) {
|
||||
if ( !bvh.indicesToNodes.empty() ) {
|
||||
for ( uint32_t i = 0; i < count; ++i ) {
|
||||
if ( index + i < bvh.indicesToNodes.size() ) {
|
||||
uint32_t flatNodeID = bvh.indicesToNodes[index + i];
|
||||
if ( flatNodeID < bvh.flattened.size() ) {
|
||||
bvh.flattened[flatNodeID].setUnloaded(!active);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ( !bvh.nodes.empty() ) {
|
||||
for ( auto& node : bvh.nodes ) {
|
||||
if ( node.getCount() > 0 ) {
|
||||
for ( uint32_t i = 0; i < node.getCount(); ++i ) {
|
||||
uint32_t idx = bvh.indices[node.start + i];
|
||||
if ( idx >= index && idx < index + count ) {
|
||||
node.setUnloaded(!active);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t uf::bvh::serialize( const pod::BVH& bvh, uf::stl::vector<uint8_t>& outBuffer, uint32_t offset ) {
|
||||
uf::stl::writer writer( outBuffer, offset, true );
|
||||
|
||||
writer.write( (uint32_t)( bvh.indices.size() ) );
|
||||
writer.write( (uint32_t)( bvh.indicesToNodes.size() ) );
|
||||
writer.write( (uint32_t)( bvh.nodes.size() ) );
|
||||
writer.write( (uint32_t)( bvh.flattened.size() ) );
|
||||
|
||||
if ( !bvh.indices.empty() ) writer.write( bvh.indices );
|
||||
if ( !bvh.indicesToNodes.empty() ) writer.write( bvh.indicesToNodes );
|
||||
if ( !bvh.nodes.empty() ) { writer.write( bvh.nodes ); writer.write( bvh.bounds); }
|
||||
if ( !bvh.flattened.empty() ) { writer.write( bvh.flattened ); writer.write( bvh.flatBounds ); writer.write( bvh.primitiveToNode ); }
|
||||
if ( !bvh.flattened.empty() ) { writer.write( bvh.flattened ); writer.write( bvh.flatBounds ); }
|
||||
|
||||
return writer.offset() - offset;
|
||||
}
|
||||
@ -1037,33 +1092,34 @@ bool uf::bvh::deserialize( pod::BVH& bvh, const uf::stl::vector<uint8_t>& buffer
|
||||
uf::stl::reader reader( buffer, offset, length > 0 ? length : buffer.size(), true, true );
|
||||
|
||||
const uint32_t* pNumIndices = reader.read<uint32_t>();
|
||||
const uint32_t* pNumMap = reader.read<uint32_t>();
|
||||
const uint32_t* pNumNodes = reader.read<uint32_t>();
|
||||
const uint32_t* pNumFlat = reader.read<uint32_t>();
|
||||
|
||||
if ( !pNumIndices || !pNumNodes || !pNumFlat ) return false;
|
||||
if ( !pNumIndices || !pNumNodes || !pNumMap || !pNumFlat ) return false;
|
||||
|
||||
uint32_t numIndices = *pNumIndices;
|
||||
uint32_t numMap = *pNumMap;
|
||||
uint32_t numNodes = *pNumNodes;
|
||||
uint32_t numFlat = *pNumFlat;
|
||||
|
||||
// UF_MSG_DEBUG("Indices={}, Map={}, Nodes={}, Flat={}", numIndices, numMap, numNodes, numFlat);
|
||||
|
||||
if ( numIndices > 0 ) {
|
||||
if ( !reader.read( numIndices, bvh.indices ) ) return false;
|
||||
} else {
|
||||
bvh.indices.clear();
|
||||
}
|
||||
|
||||
if ( numMap ) {
|
||||
if ( !reader.read( numMap, bvh.indicesToNodes ) ) return false;
|
||||
} else {
|
||||
bvh.indicesToNodes.clear();
|
||||
}
|
||||
|
||||
if ( numNodes > 0 ) {
|
||||
if ( numFlat > 0 ) {
|
||||
reader.skip( numNodes * sizeof(pod::BVH::Node) );
|
||||
reader.skip( numNodes * sizeof(pod::AABB) );
|
||||
bvh.nodes.clear();
|
||||
bvh.nodes.shrink_to_fit();
|
||||
bvh.bounds.clear();
|
||||
bvh.bounds.shrink_to_fit();
|
||||
} else {
|
||||
if ( !reader.read( numNodes, bvh.nodes ) ) return false;
|
||||
if ( !reader.read( numNodes, bvh.bounds ) ) return false;
|
||||
}
|
||||
if ( !reader.read( numNodes, bvh.nodes ) ) return false;
|
||||
if ( !reader.read( numNodes, bvh.bounds ) ) return false;
|
||||
} else {
|
||||
bvh.nodes.clear();
|
||||
bvh.bounds.clear();
|
||||
@ -1072,11 +1128,9 @@ bool uf::bvh::deserialize( pod::BVH& bvh, const uf::stl::vector<uint8_t>& buffer
|
||||
if ( numFlat > 0 ) {
|
||||
if ( !reader.read( numFlat, bvh.flattened ) ) return false;
|
||||
if ( !reader.read( numFlat, bvh.flatBounds ) ) return false;
|
||||
if ( !reader.read( numIndices, bvh.primitiveToNode ) ) return false;
|
||||
} else {
|
||||
bvh.flattened.clear();
|
||||
bvh.flatBounds.clear();
|
||||
bvh.primitiveToNode.clear();
|
||||
}
|
||||
|
||||
bvh.dirty = false;
|
||||
|
||||
@ -745,8 +745,11 @@ pod::AABB impl::computeAABB( const pod::PhysicsBody& body ) {
|
||||
} break;
|
||||
case pod::ShapeType::MESH:
|
||||
case pod::ShapeType::CONVEX_HULL: {
|
||||
if ( body.collider.mesh.bvh && !body.collider.mesh.bvh->bounds.empty() )
|
||||
return impl::transformAabbToWorld( body.collider.mesh.bvh->bounds[0], transform );
|
||||
if ( body.collider.mesh.bvh ) {
|
||||
const auto& bvh = *body.collider.mesh.bvh;
|
||||
if ( !bvh.flatBounds.empty() ) return impl::transformAabbToWorld( bvh.flatBounds[0], transform );
|
||||
if ( !bvh.bounds.empty() ) return impl::transformAabbToWorld( bvh.bounds[0], transform );
|
||||
}
|
||||
const auto& meshData = *body.collider.mesh.mesh;
|
||||
pod::AABB bounds = { { FLT_MAX, FLT_MAX, FLT_MAX }, { -FLT_MAX, -FLT_MAX, -FLT_MAX } };
|
||||
for ( const auto& view : meshData.buffer_views ) impl::computeConvexHullAABB( view, view["position"], bounds );
|
||||
|
||||
@ -446,6 +446,16 @@ pod::Vector3f uf::physics::getGravity( pod::PhysicsBody& body ) {
|
||||
return uf::vector::isValid( body.gravity ) ? body.gravity : body.world->gravity;
|
||||
}
|
||||
|
||||
void uf::physics::update( pod::PhysicsBody& body ) {
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
|
||||
if ( body.inverseMass == 0.0f ) {
|
||||
body.world->staticBvh.dirty = true;
|
||||
} else {
|
||||
body.world->dynamicBvh.dirty = true;
|
||||
}
|
||||
}
|
||||
void uf::physics::updateInertia( pod::PhysicsBody& body ) {
|
||||
if ( body.inverseMass == 0.0f ) {
|
||||
body.inverseInertiaTensor = { 0.0f, 0.0f, 0.0f };
|
||||
|
||||
@ -101,8 +101,6 @@ void impl::drawAabb( const pod::PhysicsBody& body ) {
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::AABB& aabb ) {
|
||||
body.collider.type = pod::ShapeType::AABB;
|
||||
body.collider.aabb = aabb;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
|
||||
uf::physics::updateInertia( body );
|
||||
uf::physics::update( body );
|
||||
return body;
|
||||
}
|
||||
@ -161,7 +161,6 @@ void impl::drawCapsule( const pod::PhysicsBody& body ) {
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::Capsule& capsule ) {
|
||||
body.collider.type = pod::ShapeType::CAPSULE;
|
||||
body.collider.capsule = capsule;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
uf::physics::update( body );
|
||||
return body;
|
||||
}
|
||||
@ -213,7 +213,18 @@ 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;
|
||||
// draw BVH instead
|
||||
if ( body.inverseMass == 0.0f ) {
|
||||
const auto& bvh = *body.collider.mesh.bvh;
|
||||
if ( !bvh.flatBounds.empty() ) {
|
||||
for ( const auto& bound : bvh.flatBounds ) uf::debug::drawShape( bound, transform );
|
||||
return;
|
||||
}
|
||||
if ( !bvh.bounds.empty() ) {
|
||||
for ( const auto& bound : bvh.bounds ) uf::debug::drawShape( bound, transform );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
size_t totalTriangles = 0;
|
||||
for ( const auto& view : meshData->buffer_views ) totalTriangles += view.index.count / 3;
|
||||
@ -237,24 +248,25 @@ void impl::drawMesh( const pod::PhysicsBody& body ) {
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const uf::Mesh& mesh, bool convex ) {
|
||||
if ( !body.collider.mesh.bvh ) {
|
||||
body.collider.mesh.bvh = new pod::BVH;
|
||||
body.collider.mesh.ownsBvh = true;
|
||||
} else {
|
||||
*body.collider.mesh.bvh = {};
|
||||
}
|
||||
return uf::physics::initialize( body, mesh, *body.collider.mesh.bvh, convex );
|
||||
uf::physics::initialize( body, mesh, *body.collider.mesh.bvh, convex );
|
||||
body.collider.mesh.ownsBvh = true;
|
||||
return body;
|
||||
}
|
||||
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const uf::Mesh& mesh, pod::BVH& bvh, bool convex ) {
|
||||
body.collider.type = convex ? pod::ShapeType::CONVEX_HULL : pod::ShapeType::MESH;
|
||||
body.collider.mesh.mesh = &mesh;
|
||||
body.collider.mesh.bvh = &bvh;
|
||||
body.collider.mesh.ownsBvh = false;
|
||||
|
||||
// to-do: move this to the above initialize to allow for deferred BVH building?
|
||||
if ( bvh.nodes.empty() && bvh.flattened.empty() ) {
|
||||
impl::buildMeshBVH( bvh, mesh, uf::physics::settings.meshBvhCapacity );
|
||||
}
|
||||
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
uf::physics::update( body );
|
||||
return body;
|
||||
}
|
||||
@ -326,8 +326,6 @@ void impl::drawObb( const pod::PhysicsBody& body ) {
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::OBB& obb ) {
|
||||
body.collider.type = pod::ShapeType::OBB;
|
||||
body.collider.obb = obb;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
|
||||
uf::physics::updateInertia( body );
|
||||
uf::physics::update( body );
|
||||
return body;
|
||||
}
|
||||
@ -95,7 +95,6 @@ void impl::drawPlane( const pod::PhysicsBody& body ) {
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::Plane& plane ) {
|
||||
body.collider.type = pod::ShapeType::PLANE;
|
||||
body.collider.plane = plane;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
uf::physics::update( body );
|
||||
return body;
|
||||
}
|
||||
@ -104,7 +104,6 @@ void impl::drawSphere( const pod::PhysicsBody& body ) {
|
||||
pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::Sphere& sphere ) {
|
||||
body.collider.type = pod::ShapeType::SPHERE;
|
||||
body.collider.sphere = sphere;
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
uf::physics::update( body );
|
||||
return body;
|
||||
}
|
||||
@ -377,7 +377,6 @@ pod::PhysicsBody& uf::physics::initialize( pod::PhysicsBody& body, const pod::Tr
|
||||
if ( uf::vector::magnitude( body.collider.triangle.normal ) < 0.001f ) {
|
||||
body.collider.triangle.normal = impl::triangleNormal( (const pod::Triangle&) tri );
|
||||
}
|
||||
body.bounds = impl::computeAABB( body );
|
||||
uf::physics::updateInertia( body );
|
||||
uf::physics::update( body );
|
||||
return body;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user