Merge pull request #6621 from samcake/controllers

Fixing the Collision Geometry display
This commit is contained in:
Brad Hefta-Gaub 2015-12-11 09:15:52 -08:00
commit ff49ed7a65
11 changed files with 443 additions and 190 deletions

View file

@ -106,6 +106,7 @@ public:
bool setAttribute(Slot slot, Frequency frequency = PER_VERTEX);
bool setAttribute(Slot slot, Slot channel, Frequency frequency = PER_VERTEX);
bool hasAttribute(Slot slot) const { return (_attributes.find(slot) != _attributes.end()); }
protected:
AttributeMap _attributes;

View file

@ -92,7 +92,7 @@ void Mesh::setPartBuffer(const BufferView& buffer) {
_partBuffer = buffer;
}
const Box Mesh::evalPartBound(int partNum) const {
Box Mesh::evalPartBound(int partNum) const {
Box box;
if (partNum < _partBuffer.getNum<Part>()) {
const Part& part = _partBuffer.get<Part>(partNum);
@ -111,7 +111,7 @@ const Box Mesh::evalPartBound(int partNum) const {
return box;
}
const Box Mesh::evalPartBounds(int partStart, int partEnd, Boxes& bounds) const {
Box Mesh::evalPartBounds(int partStart, int partEnd, Boxes& bounds) const {
Box totalBound;
auto part = _partBuffer.cbegin<Part>() + partStart;
auto partItEnd = _partBuffer.cbegin<Part>() + partEnd;

View file

@ -107,10 +107,10 @@ public:
uint getNumParts() const { return _partBuffer.getNumElements(); }
// evaluate the bounding box of A part
const Box evalPartBound(int partNum) const;
Box evalPartBound(int partNum) const;
// evaluate the bounding boxes of the parts in the range [start, end[ and fill the bounds parameter
// the returned box is the bounding box of ALL the evaluated part bounds.
const Box evalPartBounds(int partStart, int partEnd, Boxes& bounds) const;
Box evalPartBounds(int partStart, int partEnd, Boxes& bounds) const;
static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast<gpu::Primitive>(topo); }

View file

@ -25,7 +25,7 @@ namespace render {
// Return opaque for lack of a better idea
return ItemKey::Builder::opaqueShape();
}
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getBound();
@ -39,55 +39,40 @@ namespace render {
using namespace render;
MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex,
glm::vec3 position, glm::quat orientation) :
model(model),
meshIndex(meshIndex),
partIndex(partIndex),
_shapeID(shapeIndex),
_modelPosition(position),
_modelOrientation(orientation) {
initCache();
MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) {
updateMeshPart(mesh, partIndex);
updateMaterial(material);
updateTransform(transform, offsetTransform);
}
void MeshPartPayload::initCache() {
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = model->_geometry->getMeshes();
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
_drawMesh = networkMesh._mesh;
const FBXGeometry& geometry = model->_geometry->getFBXGeometry();
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
_hasColorAttrib = !mesh.colors.isEmpty();
_isBlendShaped = !mesh.blendshapes.isEmpty();
_isSkinned = !mesh.clusterIndices.isEmpty();
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
auto networkMaterial = model->_geometry->getShapeMaterial(_shapeID);
if (networkMaterial) {
_drawMaterial = networkMaterial->_material;
};
void MeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) {
_drawMesh = drawMesh;
if (_drawMesh) {
auto vertexFormat = _drawMesh->getVertexFormat();
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
_localBound = _drawMesh->evalPartBound(partIndex);
}
}
void MeshPartPayload::updateModelLocation(glm::vec3 position, glm::quat orientation) {
_modelPosition = position;
_modelOrientation = orientation;
void MeshPartPayload::updateTransform(const Transform& transform, const Transform& offsetTransform) {
_transform = transform;
_offsetTransform = offsetTransform;
Transform::mult(_drawTransform, _transform, _offsetTransform);
_worldBound = _localBound;
_worldBound.transform(_drawTransform);
}
void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) {
_drawMaterial = drawMaterial;
}
render::ItemKey MeshPartPayload::getKey() const {
ItemKey::Builder builder;
builder.withTypeShape();
if (!model->isVisible()) {
builder.withInvisible();
}
if (_isBlendShaped || _isSkinned) {
builder.withDeformed();
}
if (_drawMaterial) {
auto matKey = _drawMaterial->getKey();
if (matKey.isTransparent() || matKey.isTransparentMap()) {
@ -99,9 +84,7 @@ render::ItemKey MeshPartPayload::getKey() const {
}
render::Item::Bound MeshPartPayload::getBound() const {
// NOTE: we can't cache this bounds because we need to handle the case of a moving
// entity or mesh part.
return model->getPartBounds(meshIndex, partIndex, _modelPosition, _modelOrientation);
return _worldBound;
}
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
@ -109,22 +92,12 @@ void MeshPartPayload::drawCall(gpu::Batch& batch) const {
}
void MeshPartPayload::bindMesh(gpu::Batch& batch) const {
if (!_isBlendShaped) {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((_drawMesh->getVertexFormat()));
batch.setInputStream(0, _drawMesh->getVertexStream());
} else {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((_drawMesh->getVertexFormat()));
batch.setInputFormat((_drawMesh->getVertexFormat()));
batch.setInputStream(0, _drawMesh->getVertexStream());
batch.setInputBuffer(0, model->_blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3));
batch.setInputBuffer(1, model->_blendedVertexBuffers[meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
}
// TODO: Get rid of that extra call
if (!_hasColorAttrib) {
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
@ -215,31 +188,208 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio
}
void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const {
// Still relying on the raw data from the model
const Model::MeshState& state = model->_meshStates.at(meshIndex);
Transform transform;
if (state.clusterBuffer) {
if (model->_cauterizeBones) {
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.cauterizedClusterBuffer);
} else {
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer);
}
} else {
if (model->_cauterizeBones) {
transform = Transform(state.cauterizedClusterMatrices[0]);
} else {
transform = Transform(state.clusterMatrices[0]);
}
}
transform.preTranslate(_modelPosition);
batch.setModelTransform(transform);
batch.setModelTransform(_drawTransform);
}
void MeshPartPayload::render(RenderArgs* args) const {
PerformanceTimer perfTimer("MeshPartPayload::render");
if (!model->_readyWhenAdded || !model->_isVisible) {
gpu::Batch& batch = *(args->_batch);
auto mode = args->_renderMode;
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
model::MaterialKey drawMaterialKey;
if (_drawMaterial) {
drawMaterialKey = _drawMaterial->getKey();
}
bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
bool hasTangents = drawMaterialKey.isNormalMap();
bool hasSpecular = drawMaterialKey.isGlossMap();
bool hasLightmap = drawMaterialKey.isLightmapMap();
bool isSkinned = false;
bool wireframe = false;
if (wireframe) {
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
}
ModelRender::Locations* locations = nullptr;
ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
args, locations);
// Bind the model transform and the skinCLusterMatrices if needed
bindTransform(batch, locations);
//Bind the index buffer and vertex buffer and Blend shapes if needed
bindMesh(batch);
// apply material properties
bindMaterial(batch, locations);
// TODO: We should be able to do that just in the renderTransparentJob
if (translucentMesh && locations->lightBufferUnit >= 0) {
PerformanceTimer perfTimer("DLE->setupTransparent()");
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
}
if (args) {
args->_details._materialSwitches++;
}
// Draw!
{
PerformanceTimer perfTimer("batch.drawIndexed()");
drawCall(batch);
}
if (args) {
const int INDICES_PER_TRIANGLE = 3;
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
}
}
namespace render {
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getKey();
}
// Return opaque for lack of a better idea
return ItemKey::Builder::opaqueShape();
}
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getBound();
}
return render::Item::Bound();
}
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
return payload->render(args);
}
}
using namespace render;
ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) :
_model(model),
_meshIndex(_meshIndex),
_shapeID(shapeIndex) {
auto& modelMesh = _model->_geometry->getMeshes().at(_meshIndex)->_mesh;
updateMeshPart(modelMesh, partIndex);
updateTransform(transform, offsetTransform);
initCache();
}
void ModelMeshPartPayload::initCache() {
if (_drawMesh) {
auto vertexFormat = _drawMesh->getVertexFormat();
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
_isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX);
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
_isBlendShaped = !mesh.blendshapes.isEmpty();
}
auto networkMaterial = _model->_geometry->getShapeMaterial(_shapeID);
if (networkMaterial) {
_drawMaterial = networkMaterial->_material;
};
}
void ModelMeshPartPayload::notifyLocationChanged() {
_model->_needsUpdateClusterMatrices = true;
}
render::ItemKey ModelMeshPartPayload::getKey() const {
ItemKey::Builder builder;
builder.withTypeShape();
if (!_model->isVisible()) {
builder.withInvisible();
}
if (_isBlendShaped || _isSkinned) {
builder.withDeformed();
}
if (_drawMaterial) {
auto matKey = _drawMaterial->getKey();
if (matKey.isTransparent() || matKey.isTransparentMap()) {
builder.withTransparent();
}
}
return builder.build();
}
render::Item::Bound ModelMeshPartPayload::getBound() const {
// NOTE: we can't cache this bounds because we need to handle the case of a moving
// entity or mesh part.
return _model->getPartBounds(_meshIndex, _partIndex, _transform.getTranslation(), _transform.getRotation());
}
void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const {
if (!_isBlendShaped) {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((_drawMesh->getVertexFormat()));
batch.setInputStream(0, _drawMesh->getVertexStream());
} else {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((_drawMesh->getVertexFormat()));
batch.setInputBuffer(0, _model->_blendedVertexBuffers[_meshIndex], 0, sizeof(glm::vec3));
batch.setInputBuffer(1, _model->_blendedVertexBuffers[_meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
}
// TODO: Get rid of that extra call
if (!_hasColorAttrib) {
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
}
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const {
// Still relying on the raw data from the model
const Model::MeshState& state = _model->_meshStates.at(_meshIndex);
Transform transform;
if (state.clusterBuffer) {
if (_model->_cauterizeBones) {
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.cauterizedClusterBuffer);
} else {
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer);
}
} else {
if (_model->_cauterizeBones) {
transform = Transform(state.cauterizedClusterMatrices[0]);
} else {
transform = Transform(state.clusterMatrices[0]);
}
}
// transform.preTranslate(_modelPosition);
transform.preTranslate(_transform.getTranslation());
batch.setModelTransform(transform);
}
void ModelMeshPartPayload::render(RenderArgs* args) const {
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
if (!_model->_readyWhenAdded || !_model->_isVisible) {
return; // bail asap
}
@ -248,25 +398,25 @@ void MeshPartPayload::render(RenderArgs* args) const {
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
const FBXGeometry& geometry = model->_geometry->getFBXGeometry();
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = model->_geometry->getMeshes();
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _model->_geometry->getMeshes();
// guard against partially loaded meshes
if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)model->_meshStates.size() ) {
if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size() ) {
return;
}
// Back to model to update the cluster matrices right now
model->updateClusterMatrices(_modelPosition, _modelOrientation);
_model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation());
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
// to false to rebuild out mesh groups.
if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) {
model->_meshGroupsKnown = false; // regenerate these lists next time around.
model->_readyWhenAdded = false; // in case any of our users are using scenes
model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) {
_model->_meshGroupsKnown = false; // regenerate these lists next time around.
_model->_readyWhenAdded = false; // in case any of our users are using scenes
_model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
return; // FIXME!
}
@ -276,13 +426,7 @@ void MeshPartPayload::render(RenderArgs* args) const {
// sanity check
return; // FIXME!
}
// guard against partially loaded meshes
if (partIndex >= mesh.parts.size()) {
return;
}
model::MaterialKey drawMaterialKey;
if (_drawMaterial) {
drawMaterialKey = _drawMaterial->getKey();
@ -293,12 +437,12 @@ void MeshPartPayload::render(RenderArgs* args) const {
bool hasSpecular = drawMaterialKey.isGlossMap();
bool hasLightmap = drawMaterialKey.isLightmapMap();
bool isSkinned = _isSkinned;
bool wireframe = model->isWireframe();
bool wireframe = _model->isWireframe();
// render the part bounding box
#ifdef DEBUG_BOUNDING_PARTS
{
AABox partBounds = getPartBounds(meshIndex, partIndex);
AABox partBounds = getPartBounds(_meshIndex, partIndex);
bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE;
glm::vec4 cubeColor;

View file

@ -1,5 +1,5 @@
//
// MeshPartPayload.h
// ModelMeshPartPayload.h
// interface/src/renderer
//
// Created by Sam Gateau on 10/3/15.
@ -24,41 +24,44 @@ class Model;
class MeshPartPayload {
public:
MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, glm::vec3 position, glm::quat orientation);
MeshPartPayload() {}
MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform);
typedef render::Payload<MeshPartPayload> Payload;
typedef Payload::DataPointer Pointer;
Model* model;
int meshIndex;
int partIndex;
int _shapeID;
glm::vec3 _modelPosition;
glm::quat _modelOrientation;
virtual void updateMeshPart(model::MeshPointer drawMesh, int partIndex);
void updateModelLocation(glm::vec3 position, glm::quat orientation);
virtual void notifyLocationChanged() {}
virtual void updateTransform(const Transform& transform, const Transform& offsetTransform);
virtual void updateMaterial(model::MaterialPointer drawMaterial);
// Render Item interface
render::ItemKey getKey() const;
render::Item::Bound getBound() const;
void render(RenderArgs* args) const;
// MeshPartPayload functions to perform render
virtual render::ItemKey getKey() const;
virtual render::Item::Bound getBound() const;
virtual void render(RenderArgs* args) const;
// ModelMeshPartPayload functions to perform render
void drawCall(gpu::Batch& batch) const;
void bindMesh(gpu::Batch& batch) const;
void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const;
void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const;
void initCache();
virtual void bindMesh(gpu::Batch& batch) const;
virtual void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const;
virtual void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const;
// Payload resource cached values
model::MeshPointer _drawMesh;
int _partIndex = 0;
model::Mesh::Part _drawPart;
model::MaterialPointer _drawMaterial;
model::Box _localBound;
Transform _drawTransform;
Transform _transform;
Transform _offsetTransform;
mutable model::Box _worldBound;
bool _hasColorAttrib = false;
bool _isSkinned = false;
bool _isBlendShaped = false;
};
namespace render {
@ -67,4 +70,32 @@ namespace render {
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
}
class ModelMeshPartPayload : public MeshPartPayload {
public:
ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
typedef render::Payload<ModelMeshPartPayload> Payload;
typedef Payload::DataPointer Pointer;
void notifyLocationChanged() override;
// Render Item interface
render::ItemKey getKey() const override;
render::Item::Bound getBound() const override;
void render(RenderArgs* args) const override;
// ModelMeshPartPayload functions to perform render
void bindMesh(gpu::Batch& batch) const override;
void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const override;
void initCache();
Model* _model;
int _meshIndex;
int _shapeID;
bool _isSkinned = false;
bool _isBlendShaped = false;
};
#endif // hifi_MeshPartPayload_h

View file

@ -90,7 +90,7 @@ void Model::setScale(const glm::vec3& scale) {
_scaledToFit = false;
}
const float METERS_PER_MILLIMETER = 0.01f;
const float METERS_PER_MILLIMETER = 0.01f;
void Model::setScaleInternal(const glm::vec3& scale) {
if (glm::distance(_scale, scale) > METERS_PER_MILLIMETER) {
@ -110,11 +110,19 @@ void Model::setOffset(const glm::vec3& offset) {
void Model::enqueueLocationChange() {
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
Transform transform;
transform.setTranslation(_translation);
transform.setRotation(_rotation);
Transform offset;
offset.setScale(_scale);
offset.postTranslate(_offset);
render::PendingChanges pendingChanges;
foreach (auto itemID, _renderItems.keys()) {
pendingChanges.updateItem<MeshPartPayload>(itemID, [=](MeshPartPayload& data) {
data.updateModelLocation(_translation, _rotation);
data.model->_needsUpdateClusterMatrices = true;
data.updateTransform(transform, offset);
data.notifyLocationChanged();
});
}
@ -495,11 +503,10 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChan
foreach (auto renderItem, _renderItemsSet) {
auto item = scene->allocateID();
auto renderData = MeshPartPayload::Pointer(renderItem);
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderData);
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
pendingChanges.resetItem(item, renderPayload);
pendingChanges.updateItem<MeshPartPayload>(item, [&](MeshPartPayload& data) {
data.model->_needsUpdateClusterMatrices = true;
data.notifyLocationChanged();
});
_renderItems.insert(item, renderPayload);
somethingAdded = true;
@ -523,12 +530,11 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene,
foreach (auto renderItem, _renderItemsSet) {
auto item = scene->allocateID();
auto renderData = MeshPartPayload::Pointer(renderItem);
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderData);
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
renderPayload->addStatusGetters(statusGetters);
pendingChanges.resetItem(item, renderPayload);
pendingChanges.updateItem<MeshPartPayload>(item, [&](MeshPartPayload& data) {
data.model->_needsUpdateClusterMatrices = true;
data.notifyLocationChanged();
});
_renderItems.insert(item, renderPayload);
somethingAdded = true;
@ -1127,8 +1133,14 @@ AABox Model::getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition
void Model::segregateMeshGroups() {
QSharedPointer<NetworkGeometry> networkGeometry;
if (_showCollisionHull && _collisionGeometry && _collisionGeometry->isLoaded()) {
networkGeometry = _collisionGeometry;
bool showingCollisionHull = false;
if (_showCollisionHull && _collisionGeometry) {
if (_collisionGeometry->isLoaded()) {
networkGeometry = _collisionGeometry;
showingCollisionHull = true;
} else {
return;
}
} else {
networkGeometry = _geometry;
}
@ -1136,8 +1148,10 @@ void Model::segregateMeshGroups() {
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = networkGeometry->getMeshes();
// all of our mesh vectors must match in size
if ((int)networkMeshes.size() != geometry.meshes.size() ||
geometry.meshes.size() != _meshStates.size()) {
auto geoMeshesSize = geometry.meshes.size();
if ((int)networkMeshes.size() != geoMeshesSize ||
// geometry.meshes.size() != _meshStates.size()) {
geoMeshesSize > _meshStates.size()) {
qDebug() << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
return;
}
@ -1147,15 +1161,30 @@ void Model::segregateMeshGroups() {
_renderItemsSet.clear();
Transform transform;
transform.setTranslation(_translation);
transform.setRotation(_rotation);
Transform offset;
offset.setScale(_scale);
offset.postTranslate(_offset);
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
int shapeID = 0;
for (int i = 0; i < (int)networkMeshes.size(); i++) {
const FBXMesh& mesh = geometry.meshes.at(i);
const NetworkMesh& networkMesh = *(networkMeshes.at(i).get());
// Create the render payloads
int totalParts = mesh.parts.size();
for (int partIndex = 0; partIndex < totalParts; partIndex++) {
_renderItemsSet << std::make_shared<MeshPartPayload>(this, i, partIndex, shapeID, _translation, _rotation);
if (showingCollisionHull) {
_renderItemsSet << std::make_shared<MeshPartPayload>(networkMesh._mesh, partIndex, ModelRender::getCollisionHullMaterial(), transform, offset);
} else {
_renderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset);
}
shapeID++;
}
}
@ -1168,15 +1197,22 @@ bool Model::initWhenReady(render::ScenePointer scene) {
render::PendingChanges pendingChanges;
Transform transform;
transform.setTranslation(_translation);
transform.setRotation(_rotation);
Transform offset;
offset.setScale(_scale);
offset.postTranslate(_offset);
foreach (auto renderItem, _renderItemsSet) {
auto item = scene->allocateID();
auto renderData = MeshPartPayload::Pointer(renderItem);
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderData);
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
_renderItems.insert(item, renderPayload);
pendingChanges.resetItem(item, renderPayload);
pendingChanges.updateItem<MeshPartPayload>(item, [&](MeshPartPayload& data) {
data.updateModelLocation(_translation, _rotation);
data.model->_needsUpdateClusterMatrices = true;
data.updateTransform(transform, offset);
data.notifyLocationChanged();
});
}
scene->enqueuePendingChanges(pendingChanges);

View file

@ -366,7 +366,7 @@ private:
bool _needsUpdateClusterMatrices = true;
bool _showCollisionHull = false;
friend class MeshPartPayload;
friend class ModelMeshPartPayload;
protected:
RigPointer _rig;
};

View file

@ -280,3 +280,16 @@ void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, b
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
}
}
model::MaterialPointer ModelRender::_collisionHullMaterial;
model::MaterialPointer ModelRender::getCollisionHullMaterial() {
if (!_collisionHullMaterial) {
_collisionHullMaterial = std::make_shared<model::Material>();
_collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f));
_collisionHullMaterial->setMetallic(0.02f);
_collisionHullMaterial->setGloss(1.0f);
}
return _collisionHullMaterial;
}

View file

@ -149,6 +149,11 @@ public:
static const RenderPipelineLib& getRenderPipelineLib();
// Collision hull Material
static model::MaterialPointer _collisionHullMaterial;
static model::MaterialPointer getCollisionHullMaterial();
};
#endif // hifi_ModelRender_h

View file

@ -12,6 +12,7 @@
#include "AABox.h"
#include "AACube.h"
#include "Transform.h"
#include "Extents.h"
#include "GeometryUtil.h"
#include "NumericalConstants.h"
@ -42,50 +43,6 @@ glm::vec3 AABox::calcCenter() const {
return center;
}
void AABox::rotate(const glm::quat& rotation) {
auto minimum = _corner;
auto maximum = _corner + _scale;
glm::vec3 bottomLeftNear(minimum.x, minimum.y, minimum.z);
glm::vec3 bottomRightNear(maximum.x, minimum.y, minimum.z);
glm::vec3 bottomLeftFar(minimum.x, minimum.y, maximum.z);
glm::vec3 bottomRightFar(maximum.x, minimum.y, maximum.z);
glm::vec3 topLeftNear(minimum.x, maximum.y, minimum.z);
glm::vec3 topRightNear(maximum.x, maximum.y, minimum.z);
glm::vec3 topLeftFar(minimum.x, maximum.y, maximum.z);
glm::vec3 topRightFar(maximum.x, maximum.y, maximum.z);
glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear;
glm::vec3 bottomRightNearRotated = rotation * bottomRightNear;
glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar;
glm::vec3 bottomRightFarRotated = rotation * bottomRightFar;
glm::vec3 topLeftNearRotated = rotation * topLeftNear;
glm::vec3 topRightNearRotated = rotation * topRightNear;
glm::vec3 topLeftFarRotated = rotation * topLeftFar;
glm::vec3 topRightFarRotated = rotation * topRightFar;
minimum = glm::min(bottomLeftNearRotated,
glm::min(bottomRightNearRotated,
glm::min(bottomLeftFarRotated,
glm::min(bottomRightFarRotated,
glm::min(topLeftNearRotated,
glm::min(topRightNearRotated,
glm::min(topLeftFarRotated,
topRightFarRotated)))))));
maximum = glm::max(bottomLeftNearRotated,
glm::max(bottomRightNearRotated,
glm::max(bottomLeftFarRotated,
glm::max(bottomRightFarRotated,
glm::max(topLeftNearRotated,
glm::max(topRightNearRotated,
glm::max(topLeftFarRotated,
topRightFarRotated)))))));
_corner = minimum;
_scale = maximum - minimum;
}
glm::vec3 AABox::getVertex(BoxVertex vertex) const {
switch (vertex) {
case BOTTOM_LEFT_NEAR:
@ -525,3 +482,59 @@ AABox& AABox::operator += (const AABox& box) {
}
return (*this);
}
void AABox::scale(const glm::vec3& scale) {
_corner *= scale;
_scale *= scale;
}
void AABox::rotate(const glm::quat& rotation) {
auto minimum = _corner;
auto maximum = _corner + _scale;
glm::vec3 bottomLeftNear(minimum.x, minimum.y, minimum.z);
glm::vec3 bottomRightNear(maximum.x, minimum.y, minimum.z);
glm::vec3 bottomLeftFar(minimum.x, minimum.y, maximum.z);
glm::vec3 bottomRightFar(maximum.x, minimum.y, maximum.z);
glm::vec3 topLeftNear(minimum.x, maximum.y, minimum.z);
glm::vec3 topRightNear(maximum.x, maximum.y, minimum.z);
glm::vec3 topLeftFar(minimum.x, maximum.y, maximum.z);
glm::vec3 topRightFar(maximum.x, maximum.y, maximum.z);
glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear;
glm::vec3 bottomRightNearRotated = rotation * bottomRightNear;
glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar;
glm::vec3 bottomRightFarRotated = rotation * bottomRightFar;
glm::vec3 topLeftNearRotated = rotation * topLeftNear;
glm::vec3 topRightNearRotated = rotation * topRightNear;
glm::vec3 topLeftFarRotated = rotation * topLeftFar;
glm::vec3 topRightFarRotated = rotation * topRightFar;
minimum = glm::min(bottomLeftNearRotated,
glm::min(bottomRightNearRotated,
glm::min(bottomLeftFarRotated,
glm::min(bottomRightFarRotated,
glm::min(topLeftNearRotated,
glm::min(topRightNearRotated,
glm::min(topLeftFarRotated,
topRightFarRotated)))))));
maximum = glm::max(bottomLeftNearRotated,
glm::max(bottomRightNearRotated,
glm::max(bottomLeftFarRotated,
glm::max(bottomRightFarRotated,
glm::max(topLeftNearRotated,
glm::max(topRightNearRotated,
glm::max(topLeftFarRotated,
topRightFarRotated)))))));
_corner = minimum;
_scale = maximum - minimum;
}
void AABox::transform(const Transform& transform) {
scale(transform.getScale());
rotate(transform.getRotation());
translate(transform.getTranslation());
}

View file

@ -24,6 +24,7 @@
class AACube;
class Extents;
class Transform;
class AABox {
@ -40,12 +41,7 @@ public:
void setBox(const glm::vec3& corner, float scale);
glm::vec3 getVertexP(const glm::vec3& normal) const;
glm::vec3 getVertexN(const glm::vec3& normal) const;
void shiftBy(const glm::vec3& delta) { _corner += delta; }
void rotate(const glm::quat& rotation);
void scale(float scale) { _corner *= scale; _scale *= scale; }
void scale(const glm::vec3& scale) { _corner *= scale; _scale *= scale; }
const glm::vec3& getCorner() const { return _corner; }
const glm::vec3& getScale() const { return _scale; }
const glm::vec3& getDimensions() const { return _scale; }
@ -85,6 +81,20 @@ public:
AABox& operator += (const glm::vec3& point);
AABox& operator += (const AABox& box);
// Translate the AABox just moving the corner
void translate(const glm::vec3& translation) { _corner += translation; }
// Rotate the AABox around its frame origin
// meaning rotating the corners of the AABox around the point {0,0,0} and reevaluating the min max
void rotate(const glm::quat& rotation);
/// Scale the AABox
void scale(float scale);
void scale(const glm::vec3& scale);
// Transform the extents with transform
void transform(const Transform& transform);
bool isInvalid() const { return _corner == glm::vec3(std::numeric_limits<float>::infinity()); }
private: