-
Notifications
You must be signed in to change notification settings - Fork 175
Reinstate Model Instancing #417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
two-one-five
wants to merge
5
commits into
master
Choose a base branch
from
fix/reinstate-instancing
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
1850c18
Revert "Merge pull request #414 from kasenvr/fix/revert-instancing-te…
0c455ea
merge with master
HifiExperiments cda77eb
possible fix for geometricOffset issues
HifiExperiments 7bb95a5
fix merge issues
HifiExperiments 21259aa
trying to fix merge conflicts but maybe breaking everything
HifiExperiments File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
| } | ||
|
|
@@ -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() : ""); | ||
|
|
@@ -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(); | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.