gltfio: fix up and enhance AABB functionality.

gltfio computes two types of bounding boxes: one for renderables (used
for frustum culling) and one for the overall asset (used for
positioning the camera or asset).

Both of these are based on the min+max attributes in the glTF file, but
the asset-level box was incorrect because only two corners of the
transformed AABB were considered.

This CL also adds optional computation of bounding boxes that crawls
through the vertex positions. This is useful when diagnosing potential
issues with the asset's min+max info.

These enhancements are motivated by a culling issue seen with the voxel
Cathedral on sketchfab.
This commit is contained in:
Philip Rideout
2019-03-06 19:08:33 -08:00
parent d2afc27703
commit 1ccf2d6a08
3 changed files with 86 additions and 12 deletions

View File

@@ -138,7 +138,11 @@ bool ResourceLoader::loadResources(FilamentAsset* asset) {
// feature, and instead simply require correct models. See also:
// https://github.com/KhronosGroup/glTF-Sample-Models/issues/215
if (mConfig.normalizeSkinningWeights) {
normalizeWeights(fasset);
normalizeSkinningWeights(fasset);
}
if (mConfig.recomputeBoundingBoxes) {
updateBoundingBoxes(fasset);
}
// Upload data to the GPU.
@@ -377,7 +381,7 @@ void ResourceLoader::computeTangents(FFilamentAsset* asset) const {
}
}
void ResourceLoader::normalizeWeights(details::FFilamentAsset* asset) const {
void ResourceLoader::normalizeSkinningWeights(details::FFilamentAsset* asset) const {
auto normalize = [](cgltf_accessor* data) {
if (data->type != cgltf_type_vec4 || data->component_type != cgltf_component_type_r_32f) {
slog.w << "Cannot normalize weights, unsupported attribute type." << io::endl;
@@ -409,4 +413,62 @@ void ResourceLoader::normalizeWeights(details::FFilamentAsset* asset) const {
}
}
void ResourceLoader::updateBoundingBoxes(details::FFilamentAsset* asset) const {
auto& rm = mConfig.engine->getRenderableManager();
auto& tm = mConfig.engine->getTransformManager();
auto computeBoundingBox = [&](const cgltf_primitive& prim) {
Aabb aabb;
for (cgltf_size slot = 0; slot < prim.attributes_count; slot++) {
const cgltf_attribute& attr = prim.attributes[slot];
if (attr.type == cgltf_attribute_type_position) {
const cgltf_accessor* accessor = attr.data;
float3 pt;
for (cgltf_size i = 0, n = accessor->count; i < n; ++i) {
cgltf_accessor_read_float(accessor, i, &pt.x, 3);
aabb.min = min(aabb.min, pt);
aabb.max = max(aabb.max, pt);
}
break;
}
}
return aabb;
};
Aabb assetBounds;
for (auto iter : asset->mNodeMap) {
const cgltf_mesh* mesh = iter.first->mesh;
if (mesh) {
// Find the object-space bounds for the renderable by unioning the bounds of each prim.
Aabb aabb;
for (cgltf_size index = 0, nprims = mesh->primitives_count; index < nprims; ++index) {
Aabb primBounds = computeBoundingBox(mesh->primitives[index]);
aabb.min = min(aabb.min, primBounds.min);
aabb.max = max(aabb.max, primBounds.max);
}
auto renderable = rm.getInstance(iter.second);
rm.setAxisAlignedBoundingBox(renderable, Box().set(aabb.min, aabb.max));
// Transform all eight corners of the bounding box to world space and find the new AABB.
// This is used for the asset-level bounding box.
auto transformable = tm.getInstance(iter.second);
mat4f worldTransform = tm.getWorldTransform(transformable);
float3 a = (worldTransform * float4(aabb.min.x, aabb.min.y, aabb.min.z, 1.0)).xyz;
float3 b = (worldTransform * float4(aabb.min.x, aabb.min.y, aabb.max.z, 1.0)).xyz;
float3 c = (worldTransform * float4(aabb.min.x, aabb.max.y, aabb.min.z, 1.0)).xyz;
float3 d = (worldTransform * float4(aabb.min.x, aabb.max.y, aabb.max.z, 1.0)).xyz;
float3 e = (worldTransform * float4(aabb.max.x, aabb.min.y, aabb.min.z, 1.0)).xyz;
float3 f = (worldTransform * float4(aabb.max.x, aabb.min.y, aabb.max.z, 1.0)).xyz;
float3 g = (worldTransform * float4(aabb.max.x, aabb.max.y, aabb.min.z, 1.0)).xyz;
float3 h = (worldTransform * float4(aabb.max.x, aabb.max.y, aabb.max.z, 1.0)).xyz;
float3 minpt = min(min(min(min(min(min(min(a, b), c), d), e), f), g), h);
float3 maxpt = max(max(max(max(max(max(max(a, b), c), d), e), f), g), h);
assetBounds.min = min(assetBounds.min, minpt);
assetBounds.max = max(assetBounds.max, maxpt);
}
}
asset->mBoundingBox = assetBounds;
}
} // namespace gltfio