Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ find_package( Threads )
add_definitions(-DGLM_FORCE_RADIANS)
add_definitions(-DGLM_ENABLE_EXPERIMENTAL)
add_definitions(-DGLM_FORCE_CTOR_INIT)
add_definitions(-DGLM_LANG_STL11_FORCED) # Workaround for GLM not detecting support for C++11 templates on Android

if (WIN32)
# Deal with fakakta Visual Studo 2017 bug
Expand Down
4 changes: 2 additions & 2 deletions assignment-client/src/avatars/ScriptableAvatar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ void ScriptableAvatar::update(float deltatime) {
}
_animationDetails.currentFrame = currentFrame;

const QVector<HFMJoint>& modelJoints = _bind->getHFMModel().joints;
const std::vector<HFMJoint>& modelJoints = _bind->getHFMModel().joints;
Comment thread
daleglass marked this conversation as resolved.
QStringList animationJointNames = _animation->getJointNames();

const int nJoints = modelJoints.size();
const auto nJoints = (int)modelJoints.size();
if (_jointData.size() != nJoints) {
_jointData.resize(nJoints);
}
Expand Down
2 changes: 1 addition & 1 deletion interface/src/ModelPropertiesDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ QVariantHash ModelPropertiesDialog::getMapping() const {

// update the joint indices
QVariantHash jointIndices;
for (int i = 0; i < _hfmModel.joints.size(); i++) {
for (size_t i = 0; i < _hfmModel.joints.size(); i++) {
jointIndices.insert(_hfmModel.joints.at(i).name, QString::number(i));
}
mapping.insert(JOINT_INDEX_FIELD, jointIndices);
Expand Down
8 changes: 4 additions & 4 deletions interface/src/avatar/AvatarDoctor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ void AvatarDoctor::startDiagnosing() {
_missingTextureCount = 0;
_unsupportedTextureCount = 0;

const auto resource = DependencyManager::get<ModelCache>()->getGeometryResource(_avatarFSTFileUrl);
const auto resource = DependencyManager::get<ModelCache>()->getModelResource(_avatarFSTFileUrl);
resource->refresh();

const auto resourceLoaded = [this, resource](bool success) {
Expand All @@ -99,12 +99,12 @@ void AvatarDoctor::startDiagnosing() {
}

// RIG
if (avatarModel.joints.isEmpty()) {
if (avatarModel.joints.empty()) {
addError("Avatar has no rig.", "no-rig");
} else {
auto jointNames = avatarModel.getJointNames();

if (avatarModel.joints.length() > NETWORKED_JOINTS_LIMIT) {
if (avatarModel.joints.size() > NETWORKED_JOINTS_LIMIT) {
addError(tr( "Avatar has over %n bones.", "", NETWORKED_JOINTS_LIMIT), "maximum-bone-limit");
}
// Avatar does not have Hips bone mapped
Expand Down Expand Up @@ -297,7 +297,7 @@ void AvatarDoctor::startDiagnosing() {
if (resource->isLoaded()) {
resourceLoaded(!resource->isFailed());
} else {
connect(resource.data(), &GeometryResource::finished, this, resourceLoaded);
connect(resource.data(), &ModelResource::finished, this, resourceLoaded);
}
} else {
addError("Model file cannot be opened", "missing-file");
Expand Down
2 changes: 1 addition & 1 deletion interface/src/avatar/AvatarDoctor.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class AvatarDoctor : public QObject {
int _materialMappingCount = 0;
int _materialMappingLoadedCount = 0;

GeometryResource::Pointer _model;
ModelResource::Pointer _model;

bool _isDiagnosing = false;
};
Expand Down
4 changes: 2 additions & 2 deletions interface/src/avatar/MyAvatar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2477,15 +2477,15 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {

if (_fullAvatarModelName.isEmpty()) {
// Store the FST file name into preferences
const auto& mapping = _skeletonModel->getGeometry()->getMapping();
const auto& mapping = _skeletonModel->getNetworkModel()->getMapping();
if (mapping.value("name").isValid()) {
_fullAvatarModelName = mapping.value("name").toString();
}
}

initHeadBones();
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
_fstAnimGraphOverrideUrl = _skeletonModel->getNetworkModel()->getAnimGraphOverrideUrl();
initAnimGraph();
initFlowFromFST();
}
Expand Down
238 changes: 5 additions & 233 deletions interface/src/raypick/CollisionPick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a "TODO" here. What does missing this part imply?

//computeShapeInfo(pick, *_mathPick.shapeInfo, _cachedResource);
//_mathPick.loaded = true;
} else {
_mathPick.loaded = false;
}
Expand All @@ -134,7 +135,7 @@ bool CollisionPick::getShapeInfoReady(const CollisionRegion& pick) {
return _mathPick.loaded;
}

void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> resource) {
void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<ModelResource> resource) {
ShapeType type = shapeInfo.getType();
glm::vec3 dimensions = pick.transform.getScale();
QString modelURL = (resource ? resource->getURL().toString() : "");
Expand All @@ -147,241 +148,12 @@ void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick,
}
}

void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> 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();
int numHFMMeshes = hfmModel.meshes.size();
int totalNumVertices = 0;
for (int 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),
_physicsEngine(physicsEngine) {
if (collisionRegion.shouldComputeShapeInfo()) {
_cachedResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(collisionRegion.modelURL);
_cachedResource = DependencyManager::get<ModelCache>()->getCollisionModelResource(collisionRegion.modelURL);
}
_mathPick.loaded = isLoaded();
}
Expand Down
5 changes: 2 additions & 3 deletions interface/src/raypick/CollisionPick.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,13 @@ class CollisionPick : public Pick<CollisionRegion> {
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<GeometryResource> resource);
void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> resource);
void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<ModelResource> resource);
void filterIntersections(std::vector<ContactTestResult>& intersections) const;

bool _scaleWithParent;

PhysicsEnginePointer _physicsEngine;
QSharedPointer<GeometryResource> _cachedResource;
QSharedPointer<ModelResource> _cachedResource;

// Options for what information to get from collision results
bool _includeNormals;
Expand Down
Loading