mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 00:13:53 +02:00
Merge pull request #16460 from sabrina-shanman/instancing_collision
(DEV-564) computeShapeInfo fixes, Extent calculation optimization
This commit is contained in:
commit
04f38a01f1
10 changed files with 215 additions and 478 deletions
|
@ -121,8 +121,9 @@ bool CollisionPick::isLoaded() const {
|
|||
bool CollisionPick::getShapeInfoReady(const CollisionRegion& pick) {
|
||||
if (_mathPick.shouldComputeShapeInfo()) {
|
||||
if (_cachedResource && _cachedResource->isLoaded()) {
|
||||
computeShapeInfo(pick, *_mathPick.shapeInfo, _cachedResource);
|
||||
_mathPick.loaded = true;
|
||||
// TODO: Model CollisionPick support
|
||||
//computeShapeInfo(pick, *_mathPick.shapeInfo, _cachedResource);
|
||||
//_mathPick.loaded = true;
|
||||
} else {
|
||||
_mathPick.loaded = false;
|
||||
}
|
||||
|
@ -147,235 +148,6 @@ void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick,
|
|||
}
|
||||
}
|
||||
|
||||
void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<ModelResource> resource) {
|
||||
// This code was copied and modified from RenderableModelEntityItem::computeShapeInfo
|
||||
// TODO: Move to some shared code area (in entities-renderer? model-networking?)
|
||||
// after we verify this is working and do a diff comparison with RenderableModelEntityItem::computeShapeInfo
|
||||
// to consolidate the code.
|
||||
// We may also want to make computeShapeInfo always abstract away from the gpu model mesh, like it does here.
|
||||
const uint32_t TRIANGLE_STRIDE = 3;
|
||||
const uint32_t QUAD_STRIDE = 4;
|
||||
|
||||
ShapeType type = shapeInfo.getType();
|
||||
glm::vec3 dimensions = pick.transform.getScale();
|
||||
if (type == SHAPE_TYPE_COMPOUND) {
|
||||
// should never fall in here when collision model not fully loaded
|
||||
// TODO: assert that all geometries exist and are loaded
|
||||
//assert(_model && _model->isLoaded() && _compoundShapeResource && _compoundShapeResource->isLoaded());
|
||||
const HFMModel& collisionModel = resource->getHFMModel();
|
||||
|
||||
ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
|
||||
pointCollection.clear();
|
||||
uint32_t i = 0;
|
||||
|
||||
// the way OBJ files get read, each section under a "g" line is its own meshPart. We only expect
|
||||
// to find one actual "mesh" (with one or more meshParts in it), but we loop over the meshes, just in case.
|
||||
foreach (const HFMMesh& mesh, collisionModel.meshes) {
|
||||
// each meshPart is a convex hull
|
||||
foreach (const HFMMeshPart &meshPart, mesh.parts) {
|
||||
pointCollection.push_back(QVector<glm::vec3>());
|
||||
ShapeInfo::PointList& pointsInPart = pointCollection[i];
|
||||
|
||||
// run through all the triangles and (uniquely) add each point to the hull
|
||||
uint32_t numIndices = (uint32_t)meshPart.triangleIndices.size();
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices % TRIANGLE_STRIDE == 0);
|
||||
numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer
|
||||
|
||||
for (uint32_t j = 0; j < numIndices; j += TRIANGLE_STRIDE) {
|
||||
glm::vec3 p0 = mesh.vertices[meshPart.triangleIndices[j]];
|
||||
glm::vec3 p1 = mesh.vertices[meshPart.triangleIndices[j + 1]];
|
||||
glm::vec3 p2 = mesh.vertices[meshPart.triangleIndices[j + 2]];
|
||||
if (!pointsInPart.contains(p0)) {
|
||||
pointsInPart << p0;
|
||||
}
|
||||
if (!pointsInPart.contains(p1)) {
|
||||
pointsInPart << p1;
|
||||
}
|
||||
if (!pointsInPart.contains(p2)) {
|
||||
pointsInPart << p2;
|
||||
}
|
||||
}
|
||||
|
||||
// run through all the quads and (uniquely) add each point to the hull
|
||||
numIndices = (uint32_t)meshPart.quadIndices.size();
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices % QUAD_STRIDE == 0);
|
||||
numIndices -= numIndices % QUAD_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer
|
||||
|
||||
for (uint32_t j = 0; j < numIndices; j += QUAD_STRIDE) {
|
||||
glm::vec3 p0 = mesh.vertices[meshPart.quadIndices[j]];
|
||||
glm::vec3 p1 = mesh.vertices[meshPart.quadIndices[j + 1]];
|
||||
glm::vec3 p2 = mesh.vertices[meshPart.quadIndices[j + 2]];
|
||||
glm::vec3 p3 = mesh.vertices[meshPart.quadIndices[j + 3]];
|
||||
if (!pointsInPart.contains(p0)) {
|
||||
pointsInPart << p0;
|
||||
}
|
||||
if (!pointsInPart.contains(p1)) {
|
||||
pointsInPart << p1;
|
||||
}
|
||||
if (!pointsInPart.contains(p2)) {
|
||||
pointsInPart << p2;
|
||||
}
|
||||
if (!pointsInPart.contains(p3)) {
|
||||
pointsInPart << p3;
|
||||
}
|
||||
}
|
||||
|
||||
if (pointsInPart.size() == 0) {
|
||||
qCDebug(scriptengine) << "Warning -- meshPart has no faces";
|
||||
pointCollection.pop_back();
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// We expect that the collision model will have the same units and will be displaced
|
||||
// from its origin in the same way the visual model is. The visual model has
|
||||
// been centered and probably scaled. We take the scaling and offset which were applied
|
||||
// to the visual model and apply them to the collision model (without regard for the
|
||||
// collision model's extents).
|
||||
|
||||
glm::vec3 scaleToFit = dimensions / resource->getHFMModel().getUnscaledMeshExtents().size();
|
||||
// multiply each point by scale
|
||||
for (int32_t i = 0; i < pointCollection.size(); i++) {
|
||||
for (int32_t j = 0; j < pointCollection[i].size(); j++) {
|
||||
// back compensate for registration so we can apply that offset to the shapeInfo later
|
||||
pointCollection[i][j] = scaleToFit * pointCollection[i][j];
|
||||
}
|
||||
}
|
||||
shapeInfo.setParams(type, dimensions, resource->getURL().toString());
|
||||
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
|
||||
const HFMModel& hfmModel = resource->getHFMModel();
|
||||
uint32_t numHFMMeshes = (uint32_t)hfmModel.meshes.size();
|
||||
int totalNumVertices = 0;
|
||||
for (uint32_t i = 0; i < numHFMMeshes; i++) {
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(i);
|
||||
totalNumVertices += mesh.vertices.size();
|
||||
}
|
||||
const int32_t MAX_VERTICES_PER_STATIC_MESH = 1e6;
|
||||
if (totalNumVertices > MAX_VERTICES_PER_STATIC_MESH) {
|
||||
qWarning() << "model" << "has too many vertices" << totalNumVertices << "and will collide as a box.";
|
||||
shapeInfo.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& meshes = resource->getHFMModel().meshes;
|
||||
int32_t numMeshes = (int32_t)(meshes.size());
|
||||
|
||||
const int MAX_ALLOWED_MESH_COUNT = 1000;
|
||||
if (numMeshes > MAX_ALLOWED_MESH_COUNT) {
|
||||
// too many will cause the deadlock timer to throw...
|
||||
shapeInfo.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions);
|
||||
return;
|
||||
}
|
||||
|
||||
ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
|
||||
pointCollection.clear();
|
||||
if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
pointCollection.resize(numMeshes);
|
||||
} else {
|
||||
pointCollection.resize(1);
|
||||
}
|
||||
|
||||
ShapeInfo::TriangleIndices& triangleIndices = shapeInfo.getTriangleIndices();
|
||||
triangleIndices.clear();
|
||||
|
||||
Extents extents;
|
||||
int32_t meshCount = 0;
|
||||
int32_t pointListIndex = 0;
|
||||
for (auto& mesh : meshes) {
|
||||
if (!mesh.vertices.size()) {
|
||||
continue;
|
||||
}
|
||||
QVector<glm::vec3> vertices = mesh.vertices;
|
||||
|
||||
ShapeInfo::PointList& points = pointCollection[pointListIndex];
|
||||
|
||||
// reserve room
|
||||
int32_t sizeToReserve = (int32_t)(vertices.count());
|
||||
if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
// a list of points for each mesh
|
||||
pointListIndex++;
|
||||
} else {
|
||||
// only one list of points
|
||||
sizeToReserve += (int32_t)points.size();
|
||||
}
|
||||
points.reserve(sizeToReserve);
|
||||
|
||||
// copy points
|
||||
const glm::vec3* vertexItr = vertices.cbegin();
|
||||
while (vertexItr != vertices.cend()) {
|
||||
glm::vec3 point = *vertexItr;
|
||||
points.push_back(point);
|
||||
extents.addPoint(point);
|
||||
++vertexItr;
|
||||
}
|
||||
|
||||
if (type == SHAPE_TYPE_STATIC_MESH) {
|
||||
// copy into triangleIndices
|
||||
size_t triangleIndicesCount = 0;
|
||||
for (const HFMMeshPart& meshPart : mesh.parts) {
|
||||
triangleIndicesCount += meshPart.triangleIndices.count();
|
||||
}
|
||||
triangleIndices.reserve((int)triangleIndicesCount);
|
||||
|
||||
for (const HFMMeshPart& meshPart : mesh.parts) {
|
||||
const int* indexItr = meshPart.triangleIndices.cbegin();
|
||||
while (indexItr != meshPart.triangleIndices.cend()) {
|
||||
triangleIndices.push_back(*indexItr);
|
||||
++indexItr;
|
||||
}
|
||||
}
|
||||
} else if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
// for each mesh copy unique part indices, separated by special bogus (flag) index values
|
||||
for (const HFMMeshPart& meshPart : mesh.parts) {
|
||||
// collect unique list of indices for this part
|
||||
std::set<int32_t> uniqueIndices;
|
||||
auto numIndices = meshPart.triangleIndices.count();
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices% TRIANGLE_STRIDE == 0);
|
||||
numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer
|
||||
|
||||
auto indexItr = meshPart.triangleIndices.cbegin();
|
||||
while (indexItr != meshPart.triangleIndices.cend()) {
|
||||
uniqueIndices.insert(*indexItr);
|
||||
++indexItr;
|
||||
}
|
||||
|
||||
// store uniqueIndices in triangleIndices
|
||||
triangleIndices.reserve(triangleIndices.size() + (int32_t)uniqueIndices.size());
|
||||
for (auto index : uniqueIndices) {
|
||||
triangleIndices.push_back(index);
|
||||
}
|
||||
// flag end of part
|
||||
triangleIndices.push_back(END_OF_MESH_PART);
|
||||
}
|
||||
// flag end of mesh
|
||||
triangleIndices.push_back(END_OF_MESH);
|
||||
}
|
||||
++meshCount;
|
||||
}
|
||||
|
||||
// scale and shift
|
||||
glm::vec3 extentsSize = extents.size();
|
||||
glm::vec3 scaleToFit = dimensions / extentsSize;
|
||||
for (int32_t i = 0; i < 3; ++i) {
|
||||
if (extentsSize[i] < 1.0e-6f) {
|
||||
scaleToFit[i] = 1.0f;
|
||||
}
|
||||
}
|
||||
for (auto points : pointCollection) {
|
||||
for (int32_t i = 0; i < points.size(); ++i) {
|
||||
points[i] = (points[i] * scaleToFit);
|
||||
}
|
||||
}
|
||||
|
||||
shapeInfo.setParams(type, 0.5f * dimensions, resource->getURL().toString());
|
||||
}
|
||||
}
|
||||
|
||||
CollisionPick::CollisionPick(const PickFilter& filter, float maxDistance, bool enabled, bool scaleWithParent, CollisionRegion collisionRegion, PhysicsEnginePointer physicsEngine) :
|
||||
Pick(collisionRegion, filter, maxDistance, enabled),
|
||||
_scaleWithParent(scaleWithParent),
|
||||
|
|
|
@ -63,7 +63,6 @@ protected:
|
|||
bool isLoaded() const;
|
||||
// Returns true if _mathPick.shapeInfo is valid. Otherwise, attempts to get the _mathPick ready for use.
|
||||
bool getShapeInfoReady(const CollisionRegion& pick);
|
||||
void computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<ModelResource> resource);
|
||||
void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<ModelResource> resource);
|
||||
void filterIntersections(std::vector<ContactTestResult>& intersections) const;
|
||||
|
||||
|
|
|
@ -380,59 +380,43 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
|
||||
ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
|
||||
pointCollection.clear();
|
||||
uint32_t i = 0;
|
||||
|
||||
size_t numParts = 0;
|
||||
for (const HFMMesh& mesh : collisionGeometry.meshes) {
|
||||
numParts += mesh.triangleListMesh.parts.size();
|
||||
}
|
||||
pointCollection.reserve(numParts);
|
||||
|
||||
// the way OBJ files get read, each section under a "g" line is its own meshPart. We only expect
|
||||
// to find one actual "mesh" (with one or more meshParts in it), but we loop over the meshes, just in case.
|
||||
foreach (const HFMMesh& mesh, collisionGeometry.meshes) {
|
||||
for (const HFMMesh& mesh : collisionGeometry.meshes) {
|
||||
const hfm::TriangleListMesh& triangleListMesh = mesh.triangleListMesh;
|
||||
// each meshPart is a convex hull
|
||||
foreach (const HFMMeshPart &meshPart, mesh.parts) {
|
||||
pointCollection.push_back(QVector<glm::vec3>());
|
||||
ShapeInfo::PointList& pointsInPart = pointCollection[i];
|
||||
|
||||
for (const glm::ivec2& part : triangleListMesh.parts) {
|
||||
// run through all the triangles and (uniquely) add each point to the hull
|
||||
uint32_t numIndices = (uint32_t)meshPart.triangleIndices.size();
|
||||
|
||||
pointCollection.emplace_back();
|
||||
ShapeInfo::PointList& pointsInPart = pointCollection.back();
|
||||
|
||||
uint32_t numIndices = (uint32_t)part.y;
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices % TRIANGLE_STRIDE == 0);
|
||||
numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer
|
||||
|
||||
for (uint32_t j = 0; j < numIndices; j += TRIANGLE_STRIDE) {
|
||||
glm::vec3 p0 = mesh.vertices[meshPart.triangleIndices[j]];
|
||||
glm::vec3 p1 = mesh.vertices[meshPart.triangleIndices[j + 1]];
|
||||
glm::vec3 p2 = mesh.vertices[meshPart.triangleIndices[j + 2]];
|
||||
if (!pointsInPart.contains(p0)) {
|
||||
pointsInPart << p0;
|
||||
uint32_t indexStart = (uint32_t)part.x;
|
||||
uint32_t indexEnd = indexStart + numIndices;
|
||||
for (uint32_t j = indexStart; j < indexEnd; j += TRIANGLE_STRIDE) {
|
||||
// NOTE: It seems odd to skip vertices when initializing a btConvexHullShape, but let's keep the behavior similar to the old behavior for now
|
||||
glm::vec3 p0 = triangleListMesh.vertices[triangleListMesh.indices[j]];
|
||||
glm::vec3 p1 = triangleListMesh.vertices[triangleListMesh.indices[j + 1]];
|
||||
glm::vec3 p2 = triangleListMesh.vertices[triangleListMesh.indices[j + 2]];
|
||||
if (std::find(pointsInPart.cbegin(), pointsInPart.cend(), p0) == pointsInPart.cend()) {
|
||||
pointsInPart.push_back(p0);
|
||||
}
|
||||
if (!pointsInPart.contains(p1)) {
|
||||
pointsInPart << p1;
|
||||
if (std::find(pointsInPart.cbegin(), pointsInPart.cend(), p1) == pointsInPart.cend()) {
|
||||
pointsInPart.push_back(p1);
|
||||
}
|
||||
if (!pointsInPart.contains(p2)) {
|
||||
pointsInPart << p2;
|
||||
}
|
||||
}
|
||||
|
||||
// run through all the quads and (uniquely) add each point to the hull
|
||||
numIndices = (uint32_t)meshPart.quadIndices.size();
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices % QUAD_STRIDE == 0);
|
||||
numIndices -= numIndices % QUAD_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer
|
||||
|
||||
for (uint32_t j = 0; j < numIndices; j += QUAD_STRIDE) {
|
||||
glm::vec3 p0 = mesh.vertices[meshPart.quadIndices[j]];
|
||||
glm::vec3 p1 = mesh.vertices[meshPart.quadIndices[j + 1]];
|
||||
glm::vec3 p2 = mesh.vertices[meshPart.quadIndices[j + 2]];
|
||||
glm::vec3 p3 = mesh.vertices[meshPart.quadIndices[j + 3]];
|
||||
if (!pointsInPart.contains(p0)) {
|
||||
pointsInPart << p0;
|
||||
}
|
||||
if (!pointsInPart.contains(p1)) {
|
||||
pointsInPart << p1;
|
||||
}
|
||||
if (!pointsInPart.contains(p2)) {
|
||||
pointsInPart << p2;
|
||||
}
|
||||
if (!pointsInPart.contains(p3)) {
|
||||
pointsInPart << p3;
|
||||
if (std::find(pointsInPart.cbegin(), pointsInPart.cend(), p2) == pointsInPart.cend()) {
|
||||
pointsInPart.push_back(p2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,7 +425,6 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
pointCollection.pop_back();
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -473,44 +456,84 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
// compute meshPart local transforms
|
||||
QVector<glm::mat4> localTransforms;
|
||||
const HFMModel& hfmModel = model->getHFMModel();
|
||||
uint32_t numHFMMeshes = (uint32_t)hfmModel.meshes.size();
|
||||
int totalNumVertices = 0;
|
||||
uint32_t numHFMShapes = (uint32_t)hfmModel.shapes.size();
|
||||
localTransforms.reserve(numHFMShapes);
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
|
||||
for (uint32_t i = 0; i < numHFMMeshes; i++) {
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(i);
|
||||
if (i < hfmModel.skinDeformers.size() && hfmModel.skinDeformers[i].clusters.size() > 0) {
|
||||
const HFMCluster& cluster = hfmModel.skinDeformers[i].clusters.at(0);
|
||||
auto jointMatrix = model->getRig().getJointTransform(cluster.jointIndex);
|
||||
for (uint32_t s = 0; s < numHFMShapes; s++) {
|
||||
const HFMShape& shape = hfmModel.shapes[s];
|
||||
if (shape.joint != hfm::UNDEFINED_KEY) {
|
||||
auto jointMatrix = model->getRig().getJointTransform(shape.joint);
|
||||
// we backtranslate by the registration offset so we can apply that offset to the shapeInfo later
|
||||
localTransforms.push_back(invRegistraionOffset * jointMatrix * cluster.inverseBindMatrix);
|
||||
if (shape.skinDeformer != hfm::UNDEFINED_KEY) {
|
||||
const auto& skinDeformer = hfmModel.skinDeformers[shape.skinDeformer];
|
||||
glm::mat4 inverseBindMatrix;
|
||||
if (!skinDeformer.clusters.empty()) {
|
||||
const auto& cluster = skinDeformer.clusters.back();
|
||||
inverseBindMatrix = cluster.inverseBindMatrix;
|
||||
}
|
||||
localTransforms.push_back(invRegistraionOffset * jointMatrix * inverseBindMatrix);
|
||||
} else {
|
||||
localTransforms.push_back(invRegistraionOffset * jointMatrix);
|
||||
}
|
||||
} else {
|
||||
localTransforms.push_back(invRegistraionOffset);
|
||||
}
|
||||
totalNumVertices += mesh.vertices.size();
|
||||
}
|
||||
const int32_t MAX_VERTICES_PER_STATIC_MESH = 1e6;
|
||||
if (totalNumVertices > MAX_VERTICES_PER_STATIC_MESH) {
|
||||
qWarning() << "model" << getModelURL() << "has too many vertices" << totalNumVertices << "and will collide as a box.";
|
||||
|
||||
ShapeInfo::TriangleIndices& triangleIndices = shapeInfo.getTriangleIndices();
|
||||
triangleIndices.clear();
|
||||
|
||||
Extents extents;
|
||||
int32_t shapeCount = 0;
|
||||
int32_t instanceIndex = 0;
|
||||
|
||||
// NOTE: Each pointCollection corresponds to a mesh. Therefore, we should have one pointCollection per mesh instance
|
||||
// A mesh instance is a unique combination of mesh/transform. For every mesh instance, there are as many shapes as there are parts for that mesh.
|
||||
// We assume the shapes are grouped by mesh instance, and the group contains one of each mesh part.
|
||||
uint32_t numInstances = 0;
|
||||
std::vector<std::vector<std::vector<uint32_t>>> shapesPerInstancePerMesh;
|
||||
shapesPerInstancePerMesh.resize(hfmModel.meshes.size());
|
||||
for (uint32_t shapeIndex = 0; shapeIndex < hfmModel.shapes.size();) {
|
||||
const auto& shape = hfmModel.shapes[shapeIndex];
|
||||
uint32_t meshIndex = shape.mesh;
|
||||
const auto& mesh = hfmModel.meshes[meshIndex];
|
||||
uint32_t numMeshParts = (uint32_t)mesh.parts.size();
|
||||
assert(numMeshParts != 0);
|
||||
|
||||
auto& shapesPerInstance = shapesPerInstancePerMesh[meshIndex];
|
||||
shapesPerInstance.emplace_back();
|
||||
|
||||
auto& shapes = shapesPerInstance.back();
|
||||
shapes.resize(numMeshParts);
|
||||
std::iota(shapes.begin(), shapes.end(), shapeIndex);
|
||||
|
||||
shapeIndex += numMeshParts;
|
||||
++numInstances;
|
||||
}
|
||||
|
||||
const uint32_t MAX_ALLOWED_MESH_COUNT = 1000;
|
||||
if (numInstances > MAX_ALLOWED_MESH_COUNT) {
|
||||
// too many will cause the deadlock timer to throw...
|
||||
qWarning() << "model" << getModelURL() << "has too many collision meshes" << numInstances << "and will collide as a box.";
|
||||
shapeInfo.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<const graphics::Mesh>> meshes;
|
||||
if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
auto& hfmMeshes = _collisionGeometryResource->getHFMModel().meshes;
|
||||
meshes.reserve(hfmMeshes.size());
|
||||
for (auto& hfmMesh : hfmMeshes) {
|
||||
meshes.push_back(hfmMesh._mesh);
|
||||
size_t totalNumVertices = 0;
|
||||
for (const auto& shapesPerInstance : shapesPerInstancePerMesh) {
|
||||
for (const auto& instanceShapes : shapesPerInstance) {
|
||||
const uint32_t firstShapeIndex = instanceShapes.front();
|
||||
const auto& firstShape = hfmModel.shapes[firstShapeIndex];
|
||||
const auto& mesh = hfmModel.meshes[firstShape.mesh];
|
||||
const auto& triangleListMesh = mesh.triangleListMesh;
|
||||
// Added once per instance per mesh
|
||||
totalNumVertices += triangleListMesh.vertices.size();
|
||||
}
|
||||
} else {
|
||||
meshes = model->getNetworkModel()->getMeshes();
|
||||
}
|
||||
int32_t numMeshes = (int32_t)(meshes.size());
|
||||
|
||||
const int MAX_ALLOWED_MESH_COUNT = 1000;
|
||||
if (numMeshes > MAX_ALLOWED_MESH_COUNT) {
|
||||
// too many will cause the deadlock timer to throw...
|
||||
const size_t MAX_VERTICES_PER_STATIC_MESH = 1e6;
|
||||
if (totalNumVertices > MAX_VERTICES_PER_STATIC_MESH) {
|
||||
qWarning() << "model" << getModelURL() << "has too many vertices" << totalNumVertices << "and will collide as a box.";
|
||||
shapeInfo.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions);
|
||||
return;
|
||||
}
|
||||
|
@ -518,169 +541,118 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
|
||||
pointCollection.clear();
|
||||
if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
pointCollection.resize(numMeshes);
|
||||
pointCollection.resize(numInstances);
|
||||
} else {
|
||||
pointCollection.resize(1);
|
||||
}
|
||||
|
||||
ShapeInfo::TriangleIndices& triangleIndices = shapeInfo.getTriangleIndices();
|
||||
triangleIndices.clear();
|
||||
for (uint32_t meshIndex = 0; meshIndex < hfmModel.meshes.size(); ++meshIndex) {
|
||||
const auto& mesh = hfmModel.meshes[meshIndex];
|
||||
const auto& triangleListMesh = mesh.triangleListMesh;
|
||||
const auto& vertices = triangleListMesh.vertices;
|
||||
const auto& indices = triangleListMesh.indices;
|
||||
const std::vector<glm::ivec2>& parts = triangleListMesh.parts;
|
||||
|
||||
Extents extents;
|
||||
int32_t meshCount = 0;
|
||||
int32_t pointListIndex = 0;
|
||||
for (auto& mesh : meshes) {
|
||||
if (!mesh) {
|
||||
continue;
|
||||
}
|
||||
const gpu::BufferView& vertices = mesh->getVertexBuffer();
|
||||
const gpu::BufferView& indices = mesh->getIndexBuffer();
|
||||
const gpu::BufferView& parts = mesh->getPartBuffer();
|
||||
const auto& shapesPerInstance = shapesPerInstancePerMesh[meshIndex];
|
||||
for (const std::vector<uint32_t>& instanceShapes : shapesPerInstance) {
|
||||
ShapeInfo::PointList& points = pointCollection[instanceIndex];
|
||||
|
||||
ShapeInfo::PointList& points = pointCollection[pointListIndex];
|
||||
// reserve room
|
||||
int32_t sizeToReserve = (int32_t)(vertices.size());
|
||||
if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
// a list of points for each instance
|
||||
instanceIndex++;
|
||||
} else {
|
||||
// only one list of points
|
||||
sizeToReserve += (int32_t)((gpu::Size)points.size());
|
||||
}
|
||||
points.reserve(sizeToReserve);
|
||||
|
||||
// get mesh instance transform
|
||||
const uint32_t meshIndexOffset = (uint32_t)points.size();
|
||||
const uint32_t instanceShapeIndexForTransform = instanceShapes.front();
|
||||
const auto& instanceShapeForTransform = hfmModel.shapes[instanceShapeIndexForTransform];
|
||||
glm::mat4 localTransform;
|
||||
if (instanceShapeForTransform.joint != hfm::UNDEFINED_KEY) {
|
||||
auto jointMatrix = model->getRig().getJointTransform(instanceShapeForTransform.joint);
|
||||
// we backtranslate by the registration offset so we can apply that offset to the shapeInfo later
|
||||
if (instanceShapeForTransform.skinDeformer != hfm::UNDEFINED_KEY) {
|
||||
const auto& skinDeformer = hfmModel.skinDeformers[instanceShapeForTransform.skinDeformer];
|
||||
glm::mat4 inverseBindMatrix;
|
||||
if (!skinDeformer.clusters.empty()) {
|
||||
const auto& cluster = skinDeformer.clusters.back();
|
||||
inverseBindMatrix = cluster.inverseBindMatrix;
|
||||
}
|
||||
localTransform = invRegistraionOffset * jointMatrix * inverseBindMatrix;
|
||||
} else {
|
||||
localTransform = invRegistraionOffset * jointMatrix;
|
||||
}
|
||||
} else {
|
||||
localTransform = invRegistraionOffset;
|
||||
}
|
||||
|
||||
// reserve room
|
||||
int32_t sizeToReserve = (int32_t)(vertices.getNumElements());
|
||||
if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
// a list of points for each mesh
|
||||
pointListIndex++;
|
||||
} else {
|
||||
// only one list of points
|
||||
sizeToReserve += (int32_t)((gpu::Size)points.size());
|
||||
}
|
||||
points.reserve(sizeToReserve);
|
||||
// copy points
|
||||
auto vertexItr = vertices.cbegin();
|
||||
while (vertexItr != vertices.cend()) {
|
||||
glm::vec3 point = extractTranslation(localTransform * glm::translate(*vertexItr));
|
||||
points.push_back(point);
|
||||
++vertexItr;
|
||||
}
|
||||
for (const auto& instanceShapeIndex : instanceShapes) {
|
||||
const auto& instanceShape = hfmModel.shapes[instanceShapeIndex];
|
||||
extents.addExtents(instanceShape.transformedExtents);
|
||||
}
|
||||
|
||||
// copy points
|
||||
uint32_t meshIndexOffset = (uint32_t)points.size();
|
||||
const glm::mat4& localTransform = localTransforms[meshCount];
|
||||
gpu::BufferView::Iterator<const glm::vec3> vertexItr = vertices.cbegin<const glm::vec3>();
|
||||
while (vertexItr != vertices.cend<const glm::vec3>()) {
|
||||
glm::vec3 point = extractTranslation(localTransform * glm::translate(*vertexItr));
|
||||
points.push_back(point);
|
||||
extents.addPoint(point);
|
||||
++vertexItr;
|
||||
}
|
||||
|
||||
if (type == SHAPE_TYPE_STATIC_MESH) {
|
||||
// copy into triangleIndices
|
||||
triangleIndices.reserve((int32_t)((gpu::Size)(triangleIndices.size()) + indices.getNumElements()));
|
||||
gpu::BufferView::Iterator<const graphics::Mesh::Part> partItr = parts.cbegin<const graphics::Mesh::Part>();
|
||||
while (partItr != parts.cend<const graphics::Mesh::Part>()) {
|
||||
auto numIndices = partItr->_numIndices;
|
||||
if (partItr->_topology == graphics::Mesh::TRIANGLES) {
|
||||
if (type == SHAPE_TYPE_STATIC_MESH) {
|
||||
// copy into triangleIndices
|
||||
triangleIndices.reserve((int32_t)((gpu::Size)(triangleIndices.size()) + indices.size()));
|
||||
auto partItr = parts.cbegin();
|
||||
while (partItr != parts.cend()) {
|
||||
auto numIndices = partItr->y;
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices % TRIANGLE_STRIDE == 0);
|
||||
numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer
|
||||
|
||||
auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex;
|
||||
auto indexItr = indices.cbegin() + partItr->x;
|
||||
auto indexEnd = indexItr + numIndices;
|
||||
while (indexItr != indexEnd) {
|
||||
triangleIndices.push_back(*indexItr + meshIndexOffset);
|
||||
++indexItr;
|
||||
}
|
||||
} else if (partItr->_topology == graphics::Mesh::TRIANGLE_STRIP) {
|
||||
// TODO: resurrect assert after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices > 2);
|
||||
|
||||
uint32_t approxNumIndices = TRIANGLE_STRIDE * numIndices;
|
||||
if (approxNumIndices > (uint32_t)(triangleIndices.capacity() - triangleIndices.size())) {
|
||||
// we underestimated the final size of triangleIndices so we pre-emptively expand it
|
||||
triangleIndices.reserve(triangleIndices.size() + approxNumIndices);
|
||||
}
|
||||
|
||||
auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex;
|
||||
auto indexEnd = indexItr + (numIndices - 2);
|
||||
|
||||
// first triangle uses the first three indices
|
||||
triangleIndices.push_back(*(indexItr++) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr++) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr++) + meshIndexOffset);
|
||||
|
||||
// the rest use previous and next index
|
||||
uint32_t triangleCount = 1;
|
||||
while (indexItr != indexEnd) {
|
||||
if ((*indexItr) != graphics::Mesh::PRIMITIVE_RESTART_INDEX) {
|
||||
if (triangleCount % 2 == 0) {
|
||||
// even triangles use first two indices in order
|
||||
triangleIndices.push_back(*(indexItr - 2) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr - 1) + meshIndexOffset);
|
||||
} else {
|
||||
// odd triangles swap order of first two indices
|
||||
triangleIndices.push_back(*(indexItr - 1) + meshIndexOffset);
|
||||
triangleIndices.push_back(*(indexItr - 2) + meshIndexOffset);
|
||||
}
|
||||
triangleIndices.push_back(*indexItr + meshIndexOffset);
|
||||
++triangleCount;
|
||||
}
|
||||
++indexItr;
|
||||
}
|
||||
++partItr;
|
||||
}
|
||||
++partItr;
|
||||
}
|
||||
} else if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
// for each mesh copy unique part indices, separated by special bogus (flag) index values
|
||||
gpu::BufferView::Iterator<const graphics::Mesh::Part> partItr = parts.cbegin<const graphics::Mesh::Part>();
|
||||
while (partItr != parts.cend<const graphics::Mesh::Part>()) {
|
||||
// collect unique list of indices for this part
|
||||
std::set<int32_t> uniqueIndices;
|
||||
auto numIndices = partItr->_numIndices;
|
||||
if (partItr->_topology == graphics::Mesh::TRIANGLES) {
|
||||
} else if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
// for each mesh copy unique part indices, separated by special bogus (flag) index values
|
||||
auto partItr = parts.cbegin();
|
||||
while (partItr != parts.cend()) {
|
||||
// collect unique list of indices for this part
|
||||
std::set<int32_t> uniqueIndices;
|
||||
auto numIndices = partItr->y;
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices% TRIANGLE_STRIDE == 0);
|
||||
numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXSerializer
|
||||
|
||||
auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex;
|
||||
auto indexItr = indices.cbegin() + partItr->x;
|
||||
auto indexEnd = indexItr + numIndices;
|
||||
while (indexItr != indexEnd) {
|
||||
uniqueIndices.insert(*indexItr);
|
||||
++indexItr;
|
||||
}
|
||||
} else if (partItr->_topology == graphics::Mesh::TRIANGLE_STRIP) {
|
||||
// TODO: resurrect assert after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices > TRIANGLE_STRIDE - 1);
|
||||
|
||||
auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex;
|
||||
auto indexEnd = indexItr + (numIndices - 2);
|
||||
|
||||
// first triangle uses the first three indices
|
||||
uniqueIndices.insert(*(indexItr++));
|
||||
uniqueIndices.insert(*(indexItr++));
|
||||
uniqueIndices.insert(*(indexItr++));
|
||||
|
||||
// the rest use previous and next index
|
||||
uint32_t triangleCount = 1;
|
||||
while (indexItr != indexEnd) {
|
||||
if ((*indexItr) != graphics::Mesh::PRIMITIVE_RESTART_INDEX) {
|
||||
if (triangleCount % 2 == 0) {
|
||||
// EVEN triangles use first two indices in order
|
||||
uniqueIndices.insert(*(indexItr - 2));
|
||||
uniqueIndices.insert(*(indexItr - 1));
|
||||
} else {
|
||||
// ODD triangles swap order of first two indices
|
||||
uniqueIndices.insert(*(indexItr - 1));
|
||||
uniqueIndices.insert(*(indexItr - 2));
|
||||
}
|
||||
uniqueIndices.insert(*indexItr);
|
||||
++triangleCount;
|
||||
}
|
||||
++indexItr;
|
||||
// store uniqueIndices in triangleIndices
|
||||
triangleIndices.reserve(triangleIndices.size() + (int32_t)uniqueIndices.size());
|
||||
for (auto index : uniqueIndices) {
|
||||
triangleIndices.push_back(index);
|
||||
}
|
||||
}
|
||||
// flag end of part
|
||||
triangleIndices.push_back(END_OF_MESH_PART);
|
||||
|
||||
// store uniqueIndices in triangleIndices
|
||||
triangleIndices.reserve(triangleIndices.size() + (int32_t)uniqueIndices.size());
|
||||
for (auto index : uniqueIndices) {
|
||||
triangleIndices.push_back(index);
|
||||
++partItr;
|
||||
}
|
||||
// flag end of part
|
||||
triangleIndices.push_back(END_OF_MESH_PART);
|
||||
|
||||
++partItr;
|
||||
// flag end of mesh
|
||||
triangleIndices.push_back(END_OF_MESH);
|
||||
}
|
||||
// flag end of mesh
|
||||
triangleIndices.push_back(END_OF_MESH);
|
||||
}
|
||||
++meshCount;
|
||||
|
||||
++shapeCount;
|
||||
}
|
||||
|
||||
// scale and shift
|
||||
|
|
|
@ -1429,14 +1429,13 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorker() {
|
|||
|
||||
QtConcurrent::run([entity, voxelSurfaceStyle, voxelVolumeSize, mesh] {
|
||||
auto polyVoxEntity = std::static_pointer_cast<RenderablePolyVoxEntityItem>(entity);
|
||||
QVector<QVector<glm::vec3>> pointCollection;
|
||||
ShapeInfo::PointCollection pointCollection;
|
||||
AABox box;
|
||||
glm::mat4 vtoM = std::static_pointer_cast<RenderablePolyVoxEntityItem>(entity)->voxelToLocalMatrix();
|
||||
|
||||
if (voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_MARCHING_CUBES ||
|
||||
voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) {
|
||||
// pull each triangle in the mesh into a polyhedron which can be collided with
|
||||
unsigned int i = 0;
|
||||
|
||||
const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer();
|
||||
const gpu::BufferView& indexBufferView = mesh->getIndexBuffer();
|
||||
|
@ -1465,19 +1464,16 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorker() {
|
|||
box += p2Model;
|
||||
box += p3Model;
|
||||
|
||||
QVector<glm::vec3> pointsInPart;
|
||||
pointsInPart << p0Model;
|
||||
pointsInPart << p1Model;
|
||||
pointsInPart << p2Model;
|
||||
pointsInPart << p3Model;
|
||||
// add next convex hull
|
||||
QVector<glm::vec3> newMeshPoints;
|
||||
pointCollection << newMeshPoints;
|
||||
// add points to the new convex hull
|
||||
pointCollection[i++] << pointsInPart;
|
||||
ShapeInfo::PointList pointsInPart;
|
||||
pointsInPart.push_back(p0Model);
|
||||
pointsInPart.push_back(p1Model);
|
||||
pointsInPart.push_back(p2Model);
|
||||
pointsInPart.push_back(p3Model);
|
||||
|
||||
// add points to a new convex hull
|
||||
pointCollection.push_back(pointsInPart);
|
||||
}
|
||||
} else {
|
||||
unsigned int i = 0;
|
||||
polyVoxEntity->forEachVoxelValue(voxelVolumeSize, [&](const ivec3& v, uint8_t value) {
|
||||
if (value > 0) {
|
||||
const auto& x = v.x;
|
||||
|
@ -1496,7 +1492,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorker() {
|
|||
return;
|
||||
}
|
||||
|
||||
QVector<glm::vec3> pointsInPart;
|
||||
ShapeInfo::PointList pointsInPart;
|
||||
|
||||
float offL = -0.5f;
|
||||
float offH = 0.5f;
|
||||
|
@ -1523,20 +1519,17 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorker() {
|
|||
box += p110;
|
||||
box += p111;
|
||||
|
||||
pointsInPart << p000;
|
||||
pointsInPart << p001;
|
||||
pointsInPart << p010;
|
||||
pointsInPart << p011;
|
||||
pointsInPart << p100;
|
||||
pointsInPart << p101;
|
||||
pointsInPart << p110;
|
||||
pointsInPart << p111;
|
||||
pointsInPart.push_back(p000);
|
||||
pointsInPart.push_back(p001);
|
||||
pointsInPart.push_back(p010);
|
||||
pointsInPart.push_back(p011);
|
||||
pointsInPart.push_back(p100);
|
||||
pointsInPart.push_back(p101);
|
||||
pointsInPart.push_back(p110);
|
||||
pointsInPart.push_back(p111);
|
||||
|
||||
// add next convex hull
|
||||
QVector<glm::vec3> newMeshPoints;
|
||||
pointCollection << newMeshPoints;
|
||||
// add points to the new convex hull
|
||||
pointCollection[i++] << pointsInPart;
|
||||
// add points to a new convex hull
|
||||
pointCollection.push_back(pointsInPart);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1546,7 +1539,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorker() {
|
|||
|
||||
void RenderablePolyVoxEntityItem::setCollisionPoints(ShapeInfo::PointCollection pointCollection, AABox box) {
|
||||
// this catches the payload from computeShapeInfoWorker
|
||||
if (pointCollection.isEmpty()) {
|
||||
if (pointCollection.empty()) {
|
||||
EntityItem::computeShapeInfo(_shapeInfo);
|
||||
withWriteLock([&] {
|
||||
_shapeReady = true;
|
||||
|
|
|
@ -401,6 +401,7 @@ typedef hfm::Mesh HFMMesh;
|
|||
typedef hfm::SkinDeformer HFMSkinDeformer;
|
||||
typedef hfm::AnimationFrame HFMAnimationFrame;
|
||||
typedef hfm::Light HFMLight;
|
||||
typedef hfm::Shape HFMShape;
|
||||
typedef hfm::Model HFMModel;
|
||||
typedef hfm::FlowData FlowData;
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info) {
|
|||
}
|
||||
|
||||
const ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices();
|
||||
int32_t numIndices = triangleIndices.size();
|
||||
int32_t numIndices = (int32_t)triangleIndices.size();
|
||||
if (numIndices < 3) {
|
||||
// not enough indices to make a single triangle
|
||||
return nullptr;
|
||||
|
@ -237,7 +237,7 @@ btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info) {
|
|||
mesh.m_indexType = PHY_INTEGER;
|
||||
mesh.m_triangleIndexStride = VERTICES_PER_TRIANGLE * sizeof(int32_t);
|
||||
}
|
||||
mesh.m_numVertices = pointList.size();
|
||||
mesh.m_numVertices = (int)pointList.size();
|
||||
mesh.m_vertexBase = new unsigned char[VERTICES_PER_TRIANGLE * sizeof(btScalar) * (size_t)mesh.m_numVertices];
|
||||
mesh.m_vertexStride = VERTICES_PER_TRIANGLE * sizeof(btScalar);
|
||||
mesh.m_vertexType = PHY_FLOAT;
|
||||
|
@ -362,7 +362,7 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info)
|
|||
const ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
|
||||
uint32_t numSubShapes = info.getNumSubShapes();
|
||||
if (numSubShapes == 1) {
|
||||
if (!pointCollection.isEmpty()) {
|
||||
if (!pointCollection.empty()) {
|
||||
shape = createConvexHull(pointCollection[0]);
|
||||
}
|
||||
} else {
|
||||
|
@ -380,7 +380,7 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info)
|
|||
case SHAPE_TYPE_SIMPLE_COMPOUND: {
|
||||
const ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
|
||||
const ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices();
|
||||
uint32_t numIndices = triangleIndices.size();
|
||||
uint32_t numIndices = (uint32_t)triangleIndices.size();
|
||||
uint32_t numMeshes = info.getNumSubShapes();
|
||||
const uint32_t MIN_NUM_SIMPLE_COMPOUND_INDICES = 2; // END_OF_MESH_PART + END_OF_MESH
|
||||
if (numMeshes > 0 && numIndices > MIN_NUM_SIMPLE_COMPOUND_INDICES) {
|
||||
|
|
|
@ -116,7 +116,7 @@ static const uint SHAPE_TANGENT_OFFSET = offsetof(GeometryCache::ShapeVertex, ta
|
|||
std::map<std::pair<bool, bool>, gpu::PipelinePointer> GeometryCache::_webPipelines;
|
||||
std::map<std::pair<bool, bool>, gpu::PipelinePointer> GeometryCache::_gridPipelines;
|
||||
|
||||
void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) {
|
||||
void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, ShapeInfo::PointList &outPointList) {
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
const GeometryCache::Shape geometryShape = GeometryCache::getShapeForEntityShape( entityShape );
|
||||
|
|
|
@ -155,7 +155,7 @@ public:
|
|||
static GeometryCache::Shape getShapeForEntityShape(int entityShapeEnum);
|
||||
static QString stringFromShape(GeometryCache::Shape geoShape);
|
||||
|
||||
static void computeSimpleHullPointListForShape(int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList);
|
||||
static void computeSimpleHullPointListForShape(int entityShape, const glm::vec3 &entityExtents, ShapeInfo::PointList &outPointList);
|
||||
|
||||
int allocateID() { return _nextID++; }
|
||||
void releaseID(int id);
|
||||
|
|
|
@ -189,7 +189,7 @@ uint32_t ShapeInfo::getNumSubShapes() const {
|
|||
return 0;
|
||||
case SHAPE_TYPE_COMPOUND:
|
||||
case SHAPE_TYPE_SIMPLE_COMPOUND:
|
||||
return _pointCollection.size();
|
||||
return (uint32_t)_pointCollection.size();
|
||||
case SHAPE_TYPE_MULTISPHERE:
|
||||
case SHAPE_TYPE_SIMPLE_HULL:
|
||||
case SHAPE_TYPE_STATIC_MESH:
|
||||
|
@ -200,10 +200,10 @@ uint32_t ShapeInfo::getNumSubShapes() const {
|
|||
}
|
||||
}
|
||||
|
||||
int ShapeInfo::getLargestSubshapePointCount() const {
|
||||
int numPoints = 0;
|
||||
for (int i = 0; i < _pointCollection.size(); ++i) {
|
||||
int n = _pointCollection[i].size();
|
||||
uint32_t ShapeInfo::getLargestSubshapePointCount() const {
|
||||
uint32_t numPoints = 0;
|
||||
for (uint32_t i = 0; i < (uint32_t)_pointCollection.size(); ++i) {
|
||||
uint32_t n = (uint32_t)_pointCollection[i].size();
|
||||
if (n > numPoints) {
|
||||
numPoints = n;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#ifndef hifi_ShapeInfo_h
|
||||
#define hifi_ShapeInfo_h
|
||||
|
||||
#include <QVector>
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <glm/glm.hpp>
|
||||
|
@ -53,11 +53,11 @@ class ShapeInfo {
|
|||
|
||||
public:
|
||||
|
||||
using PointList = QVector<glm::vec3>;
|
||||
using PointCollection = QVector<PointList>;
|
||||
using TriangleIndices = QVector<int32_t>;
|
||||
using PointList = std::vector<glm::vec3>;
|
||||
using PointCollection = std::vector<PointList>;
|
||||
using TriangleIndices = std::vector<int32_t>;
|
||||
using SphereData = glm::vec4;
|
||||
using SphereCollection = QVector<SphereData>;
|
||||
using SphereCollection = std::vector<SphereData>;
|
||||
|
||||
static QString getNameForShapeType(ShapeType type);
|
||||
static ShapeType getShapeTypeForName(QString string);
|
||||
|
@ -85,7 +85,7 @@ public:
|
|||
TriangleIndices& getTriangleIndices() { return _triangleIndices; }
|
||||
const TriangleIndices& getTriangleIndices() const { return _triangleIndices; }
|
||||
|
||||
int getLargestSubshapePointCount() const;
|
||||
uint32_t getLargestSubshapePointCount() const;
|
||||
|
||||
float computeVolume() const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue