billboarding for model entities

This commit is contained in:
HifiExperiments 2021-01-13 22:31:21 -08:00
parent 6d1667df5a
commit 2a27fc4de2
32 changed files with 328 additions and 558 deletions

View file

@ -2455,7 +2455,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value);
});
EntityItem::setBillboardRotationOperator([](const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos, bool rotate90x) {
BillboardModeHelpers::setBillboardRotationOperator([](const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos, bool rotate90x) {
const glm::quat ROTATE_90X = glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
if (billboardMode == BillboardMode::YAW) {
//rotate about vertical to face the camera
@ -2484,7 +2484,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
}
return rotation;
});
EntityItem::setPrimaryViewFrustumPositionOperator([this]() {
BillboardModeHelpers::setPrimaryViewFrustumPositionOperator([this]() {
ViewFrustum viewFrustum;
copyViewFrustum(viewFrustum);
return viewFrustum.getPosition();

View file

@ -509,7 +509,7 @@ Menu::Menu() {
action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::MaterialProceduralShaders, 0, false);
connect(action, &QAction::triggered, [action] {
MeshPartPayload::enableMaterialProceduralShaders = action->isChecked();
ModelMeshPartPayload::enableMaterialProceduralShaders = action->isChecked();
});
{

View file

@ -254,8 +254,8 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) {
geometryCache->bindSimpleProgram(batch, false, transparent, wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? EntityItem::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true));
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true));
batch.setModelTransform(transform);
// Background circle

View file

@ -103,8 +103,8 @@ void GridEntityRenderer::doRender(RenderArgs* args) {
} else {
transform.setTranslation(renderTransform.getTranslation());
}
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? EntityItem::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch->setModelTransform(transform);
auto minCorner = glm::vec2(-0.5f, -0.5f);

View file

@ -97,8 +97,8 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
Q_ASSERT(args->_batch);
gpu::Batch* batch = args->_batch;
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? EntityItem::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch->setModelTransform(transform);
batch->setResourceTexture(0, _texture->getGPUTexture());

View file

@ -47,8 +47,8 @@ void LineEntityRenderer::doRender(RenderArgs* args) {
const auto& modelTransform = getModelTransform();
Transform transform = Transform();
transform.setTranslation(modelTransform.getTranslation());
transform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? EntityItem::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
transform.setRotation(BillboardModeHelpers::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch.setModelTransform(transform);
if (_linePoints.size() > 1) {
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, false, false, true,

View file

@ -272,8 +272,8 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
proceduralRender = true;
}
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? EntityItem::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch.setModelTransform(transform);
if (!proceduralRender) {

View file

@ -1254,6 +1254,7 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
_model->setTagMask(getTagMask(), scene);
_model->setHifiRenderLayer(getHifiRenderLayer(), scene);
_model->setPrimitiveMode(_primitiveMode, scene);
_model->setBillboardMode(_billboardMode, scene);
_model->setCullWithParent(_cullWithParent, scene);
_model->setRenderWithZones(_renderWithZones, scene);
});
@ -1332,6 +1333,7 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
model->setTagMask(getTagMask(), scene);
model->setHifiRenderLayer(getHifiRenderLayer(), scene);
model->setPrimitiveMode(_primitiveMode, scene);
model->setBillboardMode(_billboardMode, scene);
model->setCullWithParent(_cullWithParent, scene);
model->setRenderWithZones(_renderWithZones, scene);
});

View file

@ -325,8 +325,8 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
buildPipelines();
}
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? EntityItem::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch.setModelTransform(transform);
batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]);

View file

@ -1820,8 +1820,8 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render");
gpu::Batch& batch = *args->_batch;
glm::mat4 rotation = glm::mat4_cast(EntityItem::getBillboardRotation(_position, _orientation, _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? EntityItem::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(_position, _orientation, _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
Transform transform(glm::translate(_position) * rotation * _lastVoxelToLocalMatrix);
batch.setModelTransform(transform);

View file

@ -238,8 +238,8 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
return;
}
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? EntityItem::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(),
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(),
_shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron));
batch.setModelTransform(transform);

View file

@ -131,8 +131,8 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
return;
}
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? EntityItem::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch.setModelTransform(transform);
auto geometryCache = DependencyManager::get<GeometryCache>();
@ -313,8 +313,8 @@ void entities::TextPayload::render(RenderArgs* args) {
return;
}
modelTransform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), textRenderable->_billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? EntityItem::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
modelTransform.setRotation(BillboardModeHelpers::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), textRenderable->_billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
float scale = textRenderable->_lineHeight / textRenderer->getFontSize();
modelTransform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z));

View file

@ -302,8 +302,8 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
batch.setResourceTexture(0, _texture);
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? EntityItem::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
batch.setModelTransform(transform);
// Turn off jitter for these entities

View file

@ -51,9 +51,6 @@ int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
QString EntityItem::_marketplacePublicKey;
std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode, const glm::vec3&, bool)> EntityItem::_getBillboardRotationOperator = [](const glm::vec3&, const glm::quat& rotation, BillboardMode, const glm::vec3&, bool) { return rotation; };
std::function<glm::vec3()> EntityItem::_getPrimaryViewFrustumPositionOperator = []() { return glm::vec3(0.0f); };
EntityItem::EntityItem(const EntityItemID& entityItemID) :
SpatiallyNestable(NestableType::Entity, entityItemID)
{

View file

@ -572,11 +572,6 @@ public:
virtual void removeGrab(GrabPointer grab) override;
virtual void disableGrab(GrabPointer grab) override;
static void setBillboardRotationOperator(std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode, const glm::vec3&, bool)> getBillboardRotationOperator) { _getBillboardRotationOperator = getBillboardRotationOperator; }
static glm::quat getBillboardRotation(const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos, bool rotate90x = false) { return _getBillboardRotationOperator(position, rotation, billboardMode, frustumPos, rotate90x); }
static void setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; }
static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); }
bool stillHasMyGrab() const;
bool needsRenderUpdate() const { return _needsRenderUpdate; }
@ -786,10 +781,6 @@ protected:
bool _cullWithParent { false };
mutable bool _needsRenderUpdate { false };
private:
static std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode, const glm::vec3&, bool)> _getBillboardRotationOperator;
static std::function<glm::vec3()> _getPrimaryViewFrustumPositionOperator;
};
#endif // hifi_EntityItem_h

View file

@ -222,7 +222,7 @@ EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& ori
glm::vec3 position = entity->getWorldPosition();
glm::mat4 translation = glm::translate(position);
glm::quat orientation = entity->getWorldOrientation();
glm::mat4 rotation = glm::mat4_cast(EntityItem::getBillboardRotation(position, orientation, entity->getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition()));
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, entity->getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition()));
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
@ -373,7 +373,7 @@ EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3
glm::vec3 position = entity->getWorldPosition();
glm::mat4 translation = glm::translate(position);
glm::quat orientation = entity->getWorldOrientation();
glm::mat4 rotation = glm::mat4_cast(EntityItem::getBillboardRotation(position, orientation, entity->getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition()));
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, entity->getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition()));
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
@ -479,7 +479,7 @@ void EntityTreeElement::evalEntitiesInSphere(const glm::vec3& position, float ra
glm::vec3 position = entity->getWorldPosition();
glm::mat4 translation = glm::translate(position);
glm::quat orientation = entity->getWorldOrientation();
glm::mat4 rotation = glm::mat4_cast(EntityItem::getBillboardRotation(position, orientation, entity->getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition()));
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, entity->getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition()));
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
@ -535,7 +535,7 @@ void EntityTreeElement::evalEntitiesInSphereWithType(const glm::vec3& position,
glm::vec3 position = entity->getWorldPosition();
glm::mat4 translation = glm::translate(position);
glm::quat orientation = entity->getWorldOrientation();
glm::mat4 rotation = glm::mat4_cast(EntityItem::getBillboardRotation(position, orientation, entity->getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition()));
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, entity->getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition()));
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
@ -596,7 +596,7 @@ void EntityTreeElement::evalEntitiesInSphereWithName(const glm::vec3& position,
glm::vec3 position = entity->getWorldPosition();
glm::mat4 translation = glm::translate(position);
glm::quat orientation = entity->getWorldOrientation();
glm::mat4 rotation = glm::mat4_cast(EntityItem::getBillboardRotation(position, orientation, entity->getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition()));
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, entity->getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition()));
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);

View file

@ -111,7 +111,7 @@ bool GizmoEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
glm::quat rotation = getWorldOrientation();
rotation *= glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition(), false);
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition(), false);
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 hitPosition = origin + (distance * direction);
@ -146,7 +146,7 @@ bool GizmoEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin,
glm::quat rotation = getWorldOrientation();
rotation *= glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
glm::vec3 position = getWorldPosition();
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition(), true);
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition(), true);
glm::quat inverseRot = glm::inverse(rotation);
glm::vec3 localOrigin = inverseRot * (origin - position);

View file

@ -133,7 +133,7 @@ bool GridEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition());
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition());
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT;
@ -157,7 +157,7 @@ bool GridEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, c
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition());
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition());
glm::quat inverseRot = glm::inverse(rotation);
glm::vec3 localOrigin = inverseRot * (origin - position);

View file

@ -135,7 +135,7 @@ bool ImageEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition());
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition());
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT;
@ -159,7 +159,7 @@ bool ImageEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin,
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition());
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition());
glm::quat inverseRot = glm::inverse(rotation);
glm::vec3 localOrigin = inverseRot * (origin - position);

View file

@ -383,7 +383,7 @@ glm::mat4 PolyVoxEntityItem::voxelToWorldMatrix(bool includeBillboard) const {
glm::mat4 translation = glm::translate(position);
glm::mat4 rotation;
if (includeBillboard) {
rotation = glm::mat4_cast(EntityItem::getBillboardRotation(position, orientation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition()));
rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition()));
} else {
rotation = glm::mat4_cast(orientation);
}

View file

@ -279,7 +279,7 @@ bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
glm::vec3 dimensions = getScaledDimensions();
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition());
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition());
// determine the ray in the frame of the entity transformed from a unit sphere
glm::mat4 entityToWorldMatrix = glm::translate(position) * glm::mat4_cast(rotation) * glm::scale(dimensions);
@ -315,7 +315,7 @@ bool ShapeEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin,
glm::vec3 dimensions = getScaledDimensions();
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition());
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition());
// determine the parabola in the frame of the entity transformed from a unit sphere
glm::mat4 entityToWorldMatrix = glm::translate(position) * glm::mat4_cast(rotation) * glm::scale(dimensions);

View file

@ -199,7 +199,7 @@ bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition());
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition());
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT;
@ -223,7 +223,7 @@ bool TextEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, c
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition());
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition());
glm::quat inverseRot = glm::inverse(rotation);
glm::vec3 localOrigin = inverseRot * (origin - position);

View file

@ -165,7 +165,7 @@ bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const g
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition());
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition());
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT;
@ -190,7 +190,7 @@ bool WebEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, co
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, getBillboardMode(), EntityItem::getPrimaryViewFrustumPosition());
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition());
glm::quat inverseRot = glm::inverse(rotation);
glm::vec3 localOrigin = inverseRot * (origin - position);

View file

@ -19,8 +19,8 @@
using namespace render;
CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex,
const Transform& transform, const Transform& offsetTransform, const uint64_t& created)
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform, created) {}
const Transform& transform, const uint64_t& created)
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, created) {}
void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,
const std::vector<glm::mat4>& cauterizedClusterMatrices) {
@ -52,11 +52,26 @@ void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<Model::Tra
}
}
void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform& renderTransform) {
void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning) {
Transform renderTransform = modelTransform;
if (useDualQuaternionSkinning) {
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
const auto& dq = meshState.clusterDualQuaternions[0];
Transform transform(dq.getRotation(),
dq.getScale(),
dq.getTranslation());
renderTransform = modelTransform.worldTransform(Transform(transform));
}
} else {
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
}
}
_cauterizedTransform = renderTransform;
}
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const {
bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization;
if (useCauterizedMesh) {
if (_cauterizedClusterBuffer) {
@ -64,7 +79,6 @@ void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::Ren
}
batch.setModelTransform(_cauterizedTransform);
} else {
ModelMeshPartPayload::bindTransform(batch, renderMode);
ModelMeshPartPayload::bindTransform(batch, transform, renderMode);
}
}

View file

@ -13,7 +13,7 @@
class CauterizedMeshPartPayload : public ModelMeshPartPayload {
public:
CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform, const uint64_t& created);
CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const uint64_t& created);
// matrix palette skinning
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,
@ -23,9 +23,9 @@ public:
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions,
const std::vector<Model::TransformDualQuaternion>& cauterizedClusterQuaternions);
void updateTransformForCauterizedMesh(const Transform& renderTransform);
void updateTransformForCauterizedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning);
void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override;
void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const override;
void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; }

View file

@ -69,10 +69,6 @@ void CauterizedModel::createRenderItemSet() {
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;
uint32_t numMeshes = (uint32_t)meshes.size();
@ -85,7 +81,7 @@ void CauterizedModel::createRenderItemSet() {
// Create the render payloads
int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) {
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset, _created);
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, _created);
_modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr);
auto material = getGeometry()->getShapeMaterial(shapeID);
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
@ -235,37 +231,8 @@ void CauterizedModel::updateRenderItems() {
data.computeAdjustedLocalBound(meshState.clusterMatrices);
}
Transform renderTransform = modelTransform;
if (useDualQuaternionSkinning) {
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
const auto& dq = meshState.clusterDualQuaternions[0];
Transform transform(dq.getRotation(),
dq.getScale(),
dq.getTranslation());
renderTransform = modelTransform.worldTransform(transform);
}
} else {
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
}
}
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
renderTransform = modelTransform;
if (useDualQuaternionSkinning) {
if (cauterizedMeshState.clusterDualQuaternions.size() == 1 || cauterizedMeshState.clusterDualQuaternions.size() == 2) {
const auto& dq = cauterizedMeshState.clusterDualQuaternions[0];
Transform transform(dq.getRotation(),
dq.getScale(),
dq.getTranslation());
renderTransform = modelTransform.worldTransform(Transform(transform));
}
} else {
if (cauterizedMeshState.clusterMatrices.size() == 1 || cauterizedMeshState.clusterMatrices.size() == 2) {
renderTransform = modelTransform.worldTransform(Transform(cauterizedMeshState.clusterMatrices[0]));
}
}
data.updateTransformForCauterizedMesh(renderTransform);
data.updateTransformForSkinnedMesh(modelTransform, meshState, useDualQuaternionSkinning);
data.updateTransformForCauterizedMesh(modelTransform, cauterizedMeshState, useDualQuaternionSkinning);
data.setEnableCauterization(enableCauterization);
data.updateKey(renderItemKeyGlobalFlags);

View file

@ -11,8 +11,7 @@
#include "MeshPartPayload.h"
#include <QProcess>
#include <BillboardMode.h>
#include <PerfStat.h>
#include <DualQuaternion.h>
#include <graphics/ShaderConstants.h>
@ -23,292 +22,33 @@
#include "RenderPipelines.h"
// static const QString ENABLE_MATERIAL_PROCEDURAL_SHADERS_STRING { "HIFI_ENABLE_MATERIAL_PROCEDURAL_SHADERS" };
// static bool ENABLE_MATERIAL_PROCEDURAL_SHADERS = QProcessEnvironment::systemEnvironment().contains(ENABLE_MATERIAL_PROCEDURAL_SHADERS_STRING);
bool MeshPartPayload::enableMaterialProceduralShaders = false;
using namespace render;
namespace render {
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getKey();
}
return ItemKey::Builder::opaqueShape(); // for lack of a better idea
}
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getBound();
}
return Item::Bound();
}
template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getShapeKey();
}
return ShapeKey::Builder::invalid();
}
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) {
return payload->render(args);
}
template <> bool payloadPassesZoneOcclusionTest(const MeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones) {
if (payload) {
return payload->passesZoneOcclusionTest(containingZones);
}
return false;
}
}
MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material, const uint64_t& created) :
_created(created)
{
updateMeshPart(mesh, partIndex);
addMaterial(graphics::MaterialLayer(material, 0));
}
void MeshPartPayload::updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex) {
_drawMesh = drawMesh;
if (_drawMesh) {
auto vertexFormat = _drawMesh->getVertexFormat();
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
_drawPart = _drawMesh->getPartBuffer().get<graphics::Mesh::Part>(partIndex);
_localBound = _drawMesh->evalPartBound(partIndex);
}
}
void MeshPartPayload::updateTransform(const Transform& transform, const Transform& offsetTransform) {
_transform = transform;
Transform::mult(_drawTransform, _transform, offsetTransform);
_worldBound = _localBound;
_worldBound.transform(_drawTransform);
}
void MeshPartPayload::addMaterial(graphics::MaterialLayer material) {
_drawMaterials.push(material);
}
void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) {
_drawMaterials.remove(material);
}
void MeshPartPayload::updateKey(const render::ItemKey& key) {
ItemKey::Builder builder(key);
builder.withTypeShape();
if (_drawMaterials.shouldUpdate()) {
RenderPipelines::updateMultiMaterial(_drawMaterials);
}
auto matKey = _drawMaterials.getMaterialKey();
if (matKey.isTranslucent()) {
builder.withTransparent();
}
if (_cullWithParent) {
builder.withSubMetaCulled();
}
_itemKey = builder.build();
}
ItemKey MeshPartPayload::getKey() const {
return _itemKey;
}
Item::Bound MeshPartPayload::getBound() const {
graphics::MaterialPointer material = _drawMaterials.empty() ? nullptr : _drawMaterials.top().material;
if (material && material->isProcedural() && material->isReady()) {
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(_drawMaterials.top().material);
if (procedural->hasVertexShader() && procedural->hasBoundOperator()) {
return procedural->getBound();
}
}
return _worldBound;
}
ShapeKey MeshPartPayload::getShapeKey() const {
ShapeKey::Builder builder;
graphics::MaterialPointer material = _drawMaterials.empty() ? nullptr : _drawMaterials.top().material;
graphics::MaterialKey drawMaterialKey = _drawMaterials.getMaterialKey();
if (drawMaterialKey.isTranslucent()) {
builder.withTranslucent();
}
if (material && material->isProcedural() && material->isReady()) {
builder.withOwnPipeline();
} else {
builder.withMaterial();
if (drawMaterialKey.isNormalMap()) {
builder.withTangents();
}
if (drawMaterialKey.isLightMap()) {
builder.withLightMap();
}
if (drawMaterialKey.isUnlit()) {
builder.withUnlit();
}
if (material) {
builder.withCullFaceMode(material->getCullFaceMode());
}
}
return builder.build();
}
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
}
void MeshPartPayload::bindMesh(gpu::Batch& batch) {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((_drawMesh->getVertexFormat()));
batch.setInputStream(0, _drawMesh->getVertexStream());
}
void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
batch.setModelTransform(_drawTransform);
}
bool MeshPartPayload::passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const {
if (!_renderWithZones.isEmpty()) {
if (!containingZones.empty()) {
for (auto renderWithZone : _renderWithZones) {
if (containingZones.find(renderWithZone) != containingZones.end()) {
return true;
}
}
}
return false;
}
return true;
}
void MeshPartPayload::render(RenderArgs* args) {
PerformanceTimer perfTimer("MeshPartPayload::render");
if (!args) {
return;
}
gpu::Batch& batch = *(args->_batch);
// Bind the model transform and the skinCLusterMatrices if needed
bindTransform(batch, args->_renderMode);
//Bind the index buffer and vertex buffer and Blend shapes if needed
bindMesh(batch);
if (!_drawMaterials.empty() && _drawMaterials.top().material && _drawMaterials.top().material->isProcedural() &&
_drawMaterials.top().material->isReady()) {
if (!enableMaterialProceduralShaders) {
return;
}
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(_drawMaterials.top().material);
auto& schema = _drawMaterials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
glm::vec4 outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
outColor = procedural->getColor(outColor);
procedural->prepare(batch, _drawTransform.getTranslation(), _drawTransform.getScale(), _drawTransform.getRotation(), _created,
ProceduralProgramKey(outColor.a < 1.0f));
batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
} else {
// apply material properties
if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) {
args->_details._materialSwitches++;
}
}
// Draw!
{
PerformanceTimer perfTimer("batch.drawIndexed()");
drawCall(batch);
}
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 ItemKey::Builder::opaqueShape(); // for lack of a better idea
}
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getBound();
}
return Item::Bound();
}
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getShapeKey();
}
return ShapeKey::Builder::invalid();
}
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
return payload->render(args);
}
template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones) {
if (payload) {
return payload->passesZoneOcclusionTest(containingZones);
}
return false;
}
}
bool ModelMeshPartPayload::enableMaterialProceduralShaders = false;
ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex,
const Transform& transform, const Transform& offsetTransform, const uint64_t& created) :
const Transform& transform, const uint64_t& created) :
_meshIndex(meshIndex),
_shapeID(shapeIndex) {
_created(created) {
assert(model && model->isLoaded());
bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning();
auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex);
_meshNumVertices = (int)modelMesh->getNumVertices();
const Model::MeshState& state = model->getMeshState(_meshIndex);
updateMeshPart(modelMesh, partIndex);
bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning();
if (useDualQuaternionSkinning) {
computeAdjustedLocalBound(state.clusterDualQuaternions);
} else {
computeAdjustedLocalBound(state.clusterMatrices);
}
updateTransform(transform, offsetTransform);
Transform renderTransform = transform;
if (useDualQuaternionSkinning) {
if (state.clusterDualQuaternions.size() == 1) {
const auto& dq = state.clusterDualQuaternions[0];
Transform transform(dq.getRotation(),
dq.getScale(),
dq.getTranslation());
renderTransform = transform.worldTransform(Transform(transform));
}
} else {
if (state.clusterMatrices.size() == 1) {
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
}
}
updateTransformForSkinnedMesh(renderTransform, transform);
updateTransformForSkinnedMesh(transform, state, useDualQuaternionSkinning);
initCache(model);
initCache(model, shapeIndex);
#if defined(Q_OS_MAC) || defined(Q_OS_ANDROID)
// On mac AMD, we specifically need to have a _meshBlendshapeBuffer bound when using a deformed mesh pipeline
@ -322,14 +62,11 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
_meshBlendshapeBuffer = std::make_shared<gpu::Buffer>(sizeof(BlendshapeOffset), reinterpret_cast<const gpu::Byte*>(&data), sizeof(BlendshapeOffset));
}
#endif
_created = created;
}
void ModelMeshPartPayload::initCache(const ModelPointer& model) {
void ModelMeshPartPayload::initCache(const ModelPointer& model, int shapeID) {
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 HFMModel& hfmModel = model->getHFMModel();
@ -339,18 +76,22 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) {
_hasTangents = !mesh.tangents.isEmpty();
}
auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID);
auto networkMaterial = model->getGeometry()->getShapeMaterial(shapeID);
if (networkMaterial) {
addMaterial(graphics::MaterialLayer(networkMaterial, 0));
}
}
void ModelMeshPartPayload::notifyLocationChanged() {
void ModelMeshPartPayload::updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex) {
_drawMesh = drawMesh;
if (_drawMesh) {
auto vertexFormat = _drawMesh->getVertexFormat();
_drawPart = _drawMesh->getPartBuffer().get<graphics::Mesh::Part>(partIndex);
_localBound = _drawMesh->evalPartBound(partIndex);
}
}
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices) {
// reset cluster buffer if we change the cluster buffer type
if (_clusterBufferType != ClusterBufferType::Matrices) {
_clusterBuffer.reset();
@ -370,7 +111,6 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clu
}
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
// reset cluster buffer if we change the cluster buffer type
if (_clusterBufferType != ClusterBufferType::DualQuaternions) {
_clusterBuffer.reset();
@ -389,13 +129,78 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector<Model::Transfor
}
}
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform) {
_transform = renderTransform;
_worldBound = _adjustedLocalBound;
_worldBound.transform(boundTransform);
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices) {
_adjustedLocalBound = _localBound;
if (clusterMatrices.size() > 0) {
_adjustedLocalBound.transform(clusterMatrices.back());
for (int i = 0; i < (int)clusterMatrices.size() - 1; ++i) {
AABox clusterBound = _localBound;
clusterBound.transform(clusterMatrices[i]);
_adjustedLocalBound += clusterBound;
}
}
}
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
_adjustedLocalBound = _localBound;
if (clusterDualQuaternions.size() > 0) {
Transform rootTransform(clusterDualQuaternions.back().getRotation(),
clusterDualQuaternions.back().getScale(),
clusterDualQuaternions.back().getTranslation());
_adjustedLocalBound.transform(rootTransform);
for (int i = 0; i < (int)clusterDualQuaternions.size() - 1; ++i) {
AABox clusterBound = _localBound;
Transform transform(clusterDualQuaternions[i].getRotation(),
clusterDualQuaternions[i].getScale(),
clusterDualQuaternions[i].getTranslation());
clusterBound.transform(transform);
_adjustedLocalBound += clusterBound;
}
}
}
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning) {
_localTransform = Transform();
if (useDualQuaternionSkinning) {
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
const auto& dq = meshState.clusterDualQuaternions[0];
_localTransform = Transform(dq.getRotation(),
dq.getScale(),
dq.getTranslation());
}
} else {
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
_localTransform = Transform(meshState.clusterMatrices[0]);
}
}
_parentTransform = modelTransform;
_worldBound = _adjustedLocalBound;
_worldBound.transform(_parentTransform);
}
void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((_drawMesh->getVertexFormat()));
if (_meshBlendshapeBuffer) {
batch.setResourceBuffer(0, _meshBlendshapeBuffer);
}
batch.setInputStream(0, _drawMesh->getVertexStream());
}
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const {
if (_clusterBuffer) {
batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer);
}
batch.setModelTransform(transform);
}
void ModelMeshPartPayload::drawCall(gpu::Batch& batch) const {
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
}
// Note that this method is called for models but not for shapes
void ModelMeshPartPayload::updateKey(const render::ItemKey& key) {
ItemKey::Builder builder(key);
builder.withTypeShape();
@ -480,26 +285,25 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, PrimitiveMode pr
_shapeKey = builder.build();
}
ItemKey ModelMeshPartPayload::getKey() const {
return _itemKey;
}
Item::Bound ModelMeshPartPayload::getBound() const {
graphics::MaterialPointer material = _drawMaterials.empty() ? nullptr : _drawMaterials.top().material;
if (material && material->isProcedural() && material->isReady()) {
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(_drawMaterials.top().material);
if (procedural->hasVertexShader() && procedural->hasBoundOperator()) {
return procedural->getBound();
}
}
return _worldBound;
}
ShapeKey ModelMeshPartPayload::getShapeKey() const {
return _shapeKey;
}
void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((_drawMesh->getVertexFormat()));
if (_meshBlendshapeBuffer) {
batch.setResourceBuffer(0, _meshBlendshapeBuffer);
}
batch.setInputStream(0, _drawMesh->getVertexStream());
}
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
if (_clusterBuffer) {
batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer);
}
batch.setModelTransform(_transform);
}
void ModelMeshPartPayload::render(RenderArgs* args) {
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
@ -509,7 +313,12 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
gpu::Batch& batch = *(args->_batch);
bindTransform(batch, args->_renderMode);
Transform transform = _parentTransform;
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
Transform modelTransform = transform.worldTransform(_localTransform);
bindTransform(batch, modelTransform, args->_renderMode);
//Bind the index buffer and vertex buffer and Blend shapes if needed
bindMesh(batch);
@ -528,7 +337,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
auto& schema = _drawMaterials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
glm::vec4 outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
outColor = procedural->getColor(outColor);
procedural->prepare(batch, _drawTransform.getTranslation(), _drawTransform.getScale(), _drawTransform.getRotation(), _created,
procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created,
ProceduralProgramKey(outColor.a < 1.0f, _shapeKey.isDeformed(), _shapeKey.isDualQuatSkinned()));
batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
} else {
@ -548,36 +357,18 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
}
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices) {
_adjustedLocalBound = _localBound;
if (clusterMatrices.size() > 0) {
_adjustedLocalBound.transform(clusterMatrices.back());
for (int i = 0; i < (int)clusterMatrices.size() - 1; ++i) {
AABox clusterBound = _localBound;
clusterBound.transform(clusterMatrices[i]);
_adjustedLocalBound += clusterBound;
}
}
}
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
_adjustedLocalBound = _localBound;
if (clusterDualQuaternions.size() > 0) {
Transform rootTransform(clusterDualQuaternions.back().getRotation(),
clusterDualQuaternions.back().getScale(),
clusterDualQuaternions.back().getTranslation());
_adjustedLocalBound.transform(rootTransform);
for (int i = 0; i < (int)clusterDualQuaternions.size() - 1; ++i) {
AABox clusterBound = _localBound;
Transform transform(clusterDualQuaternions[i].getRotation(),
clusterDualQuaternions[i].getScale(),
clusterDualQuaternions[i].getTranslation());
clusterBound.transform(transform);
_adjustedLocalBound += clusterBound;
bool ModelMeshPartPayload::passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const {
if (!_renderWithZones.isEmpty()) {
if (!containingZones.empty()) {
for (auto renderWithZone : _renderWithZones) {
if (containingZones.find(renderWithZone) != containingZones.end()) {
return true;
}
}
}
return false;
}
return true;
}
void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& blendedMeshSizes) {
@ -596,3 +387,37 @@ void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map<int, gpu
}
}
}
namespace render {
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getKey();
}
return ItemKey::Builder::opaqueShape(); // for lack of a better idea
}
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getBound();
}
return Item::Bound();
}
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getShapeKey();
}
return ShapeKey::Builder::invalid();
}
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
return payload->render(args);
}
template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones) {
if (payload) {
return payload->passesZoneOcclusionTest(containingZones);
}
return false;
}
}

View file

@ -12,147 +12,94 @@
#ifndef hifi_MeshPartPayload_h
#define hifi_MeshPartPayload_h
#include <Interpolate.h>
#include <gpu/Batch.h>
#include <render/Scene.h>
#include <graphics/Geometry.h>
#include "Model.h"
class Model;
#include <gpu/Batch.h>
#include <render/Scene.h>
#include <graphics/Geometry.h>
class MeshPartPayload {
class ModelMeshPartPayload {
public:
MeshPartPayload() = default;
MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material, const uint64_t& created);
virtual ~MeshPartPayload() = default;
typedef render::Payload<MeshPartPayload> Payload;
typedef render::Payload<ModelMeshPartPayload> Payload;
typedef Payload::DataPointer Pointer;
virtual void updateKey(const render::ItemKey& key);
ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const uint64_t& created);
virtual void updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex);
virtual void notifyLocationChanged() {}
void updateTransform(const Transform& transform, const Transform& offsetTransform);
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices); // matrix palette skinning
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions); // dual quaternion skinning
// Render Item interface
virtual render::ItemKey getKey() const;
virtual render::Item::Bound getBound() const;
virtual render::ShapeKey getShapeKey() const;
virtual void render(RenderArgs* args);
void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices); // matrix palette skinning
void computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions); // dual quaternion skinning
void updateTransformForSkinnedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning);
// ModelMeshPartPayload functions to perform render
void bindMesh(gpu::Batch& batch);
virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const;
void drawCall(gpu::Batch& batch) const;
virtual void bindMesh(gpu::Batch& batch);
virtual void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const;
// Payload resource cached values
Transform _drawTransform;
Transform _transform;
int _partIndex = 0;
bool _hasColorAttrib { false };
void updateKey(const render::ItemKey& key);
void setShapeKey(bool invalidateShapeKey, PrimitiveMode primitiveMode, bool useDualQuaternionSkinning);
graphics::Box _localBound;
graphics::Box _adjustedLocalBound;
mutable graphics::Box _worldBound;
std::shared_ptr<const graphics::Mesh> _drawMesh;
graphics::MultiMaterial _drawMaterials;
graphics::Mesh::Part _drawPart;
// Render Item interface
render::ItemKey getKey() const;
render::Item::Bound getBound() const;
render::ShapeKey getShapeKey() const;
void render(RenderArgs* args);
size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; }
size_t getMaterialTextureSize() { return _drawMaterials.getTextureSize(); }
int getMaterialTextureCount() { return _drawMaterials.getTextureCount(); }
bool hasTextureInfo() const { return _drawMaterials.hasTextureInfo(); }
void addMaterial(graphics::MaterialLayer material);
void removeMaterial(graphics::MaterialPointer material);
void setCauterized(bool cauterized) { _cauterized = cauterized; }
void setCullWithParent(bool value) { _cullWithParent = value; }
void setRenderWithZones(const QVector<QUuid>& renderWithZones) { _renderWithZones = renderWithZones; }
void setBillboardMode(BillboardMode billboardMode) { _billboardMode = billboardMode; }
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const;
static bool enableMaterialProceduralShaders;
protected:
render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };
bool _cullWithParent { false };
QVector<QUuid> _renderWithZones;
uint64_t _created;
};
namespace render {
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload);
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload);
template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload);
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
template <> bool payloadPassesZoneOcclusionTest(const MeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones);
}
class ModelMeshPartPayload : public MeshPartPayload {
public:
ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform, const uint64_t& created);
typedef render::Payload<ModelMeshPartPayload> Payload;
typedef Payload::DataPointer Pointer;
void notifyLocationChanged() override;
void updateKey(const render::ItemKey& key) override;
// matrix palette skinning
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices);
// dual quaternion skinning
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
// Render Item interface
render::ShapeKey getShapeKey() const override;
void render(RenderArgs* args) override;
void setShapeKey(bool invalidateShapeKey, PrimitiveMode primitiveMode, bool useDualQuaternionSkinning);
void setCauterized(bool cauterized) { _cauterized = cauterized; }
// ModelMeshPartPayload functions to perform render
void bindMesh(gpu::Batch& batch) override;
void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override;
// matrix palette skinning
void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices);
// dual quaternion skinning
void computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
gpu::BufferPointer _clusterBuffer;
enum class ClusterBufferType { Matrices, DualQuaternions };
ClusterBufferType _clusterBufferType { ClusterBufferType::Matrices };
int _meshIndex;
int _shapeID;
bool _isSkinned{ false };
bool _isBlendShaped { false };
bool _hasTangents { false };
void addMaterial(graphics::MaterialLayer material) { _drawMaterials.push(material); }
void removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); }
void setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& blendedMeshSizes);
static bool enableMaterialProceduralShaders;
private:
void initCache(const ModelPointer& model);
void initCache(const ModelPointer& model, int shapeID);
int _meshIndex;
std::shared_ptr<const graphics::Mesh> _drawMesh;
graphics::Mesh::Part _drawPart;
graphics::MultiMaterial _drawMaterials;
gpu::BufferPointer _clusterBuffer;
enum class ClusterBufferType { Matrices, DualQuaternions };
ClusterBufferType _clusterBufferType { ClusterBufferType::Matrices };
gpu::BufferPointer _meshBlendshapeBuffer;
int _meshNumVertices;
render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() };
render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() };
bool _isSkinned { false };
bool _isBlendShaped { false };
bool _hasTangents { false };
bool _prevUseDualQuaternionSkinning { false };
bool _cauterized { false };
bool _cullWithParent { false };
QVector<QUuid> _renderWithZones;
BillboardMode _billboardMode;
uint64_t _created;
Transform _localTransform;
Transform _parentTransform;
graphics::Box _localBound;
graphics::Box _adjustedLocalBound;
mutable graphics::Box _worldBound;
};
namespace render {

View file

@ -226,6 +226,7 @@ void Model::updateRenderItems() {
modelTransform.setScale(glm::vec3(1.0f));
PrimitiveMode primitiveMode = self->getPrimitiveMode();
BillboardMode billboardMode = self->getBillboardMode();
auto renderWithZones = self->getRenderWithZones();
auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags();
bool cauterized = self->isCauterized();
@ -242,7 +243,7 @@ void Model::updateRenderItems() {
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning,
invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags,
invalidatePayloadShapeKey, primitiveMode, billboardMode, renderItemKeyGlobalFlags,
cauterized, renderWithZones](ModelMeshPartPayload& data) {
if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions);
@ -252,25 +253,11 @@ void Model::updateRenderItems() {
data.computeAdjustedLocalBound(meshState.clusterMatrices);
}
Transform renderTransform = modelTransform;
if (useDualQuaternionSkinning) {
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
const auto& dq = meshState.clusterDualQuaternions[0];
Transform transform(dq.getRotation(),
dq.getScale(),
dq.getTranslation());
renderTransform = modelTransform.worldTransform(Transform(transform));
}
} else {
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
}
}
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
data.updateTransformForSkinnedMesh(modelTransform, meshState, useDualQuaternionSkinning);
data.setCauterized(cauterized);
data.setRenderWithZones(renderWithZones);
data.setBillboardMode(billboardMode);
data.updateKey(renderItemKeyGlobalFlags);
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
});
@ -987,6 +974,31 @@ void Model::setPrimitiveMode(PrimitiveMode primitiveMode, const render::ScenePoi
}
}
void Model::setBillboardMode(BillboardMode billboardMode, const render::ScenePointer& scene) {
if (_billboardMode != billboardMode) {
_billboardMode = billboardMode;
if (!scene) {
_needsFixupInScene = true;
return;
}
bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
std::unordered_map<int, bool> shouldInvalidatePayloadShapeKeyMap;
for (auto& shape : _modelMeshRenderItemShapes) {
shouldInvalidatePayloadShapeKeyMap[shape.meshIndex] = shouldInvalidatePayloadShapeKey(shape.meshIndex);
}
render::Transaction transaction;
for (auto item : _modelMeshRenderItemIDs) {
transaction.updateItem<ModelMeshPartPayload>(item, [billboardMode](ModelMeshPartPayload& data) {
data.setBillboardMode(billboardMode);
});
}
scene->enqueueTransaction(transaction);
}
}
void Model::setCullWithParent(bool cullWithParent, const render::ScenePointer& scene) {
if (_cullWithParent != cullWithParent) {
_cullWithParent = cullWithParent;
@ -1017,9 +1029,8 @@ void Model::setRenderWithZones(const QVector<QUuid>& renderWithZones, const rend
}
render::Transaction transaction;
auto renderItemsKey = _renderItemKeyGlobalFlags;
for (auto item : _modelMeshRenderItemIDs) {
transaction.updateItem<ModelMeshPartPayload>(item, [renderWithZones, renderItemsKey](ModelMeshPartPayload& data) {
transaction.updateItem<ModelMeshPartPayload>(item, [renderWithZones](ModelMeshPartPayload& data) {
data.setRenderWithZones(renderWithZones);
});
}
@ -1545,10 +1556,6 @@ void Model::createRenderItemSet() {
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;
uint32_t numMeshes = (uint32_t)meshes.size();
@ -1561,7 +1568,7 @@ void Model::createRenderItemSet() {
// Create the render payloads
int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) {
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset, _created);
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, _created);
auto material = getGeometry()->getShapeMaterial(shapeID);
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });

View file

@ -38,6 +38,7 @@
#include "TextureCache.h"
#include "Rig.h"
#include "PrimitiveMode.h"
#include "BillboardMode.h"
// Use dual quaternion skinning!
// Must match define in Skinning.slh
@ -121,6 +122,9 @@ public:
void setPrimitiveMode(PrimitiveMode primitiveMode, const render::ScenePointer& scene = nullptr);
PrimitiveMode getPrimitiveMode() const { return _primitiveMode; }
void setBillboardMode(BillboardMode billboardMode, const render::ScenePointer& scene = nullptr);
BillboardMode getBillboardMode() const { return _billboardMode; }
void setCullWithParent(bool value, const render::ScenePointer& scene = nullptr);
void setRenderWithZones(const QVector<QUuid>& renderWithZones, const render::ScenePointer& scene = nullptr);
@ -447,6 +451,7 @@ protected:
virtual void createRenderItemSet();
PrimitiveMode _primitiveMode { PrimitiveMode::SOLID };
BillboardMode _billboardMode { BillboardMode::NONE };
bool _useDualQuaternionSkinning { false };
// debug rendering support

View file

@ -15,6 +15,8 @@ const char* billboardModeNames[] = {
};
static const size_t BILLBOARD_MODE_NAMES = (sizeof(billboardModeNames) / sizeof(billboardModeNames[0]));
std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode, const glm::vec3&, bool)> BillboardModeHelpers::_getBillboardRotationOperator = [](const glm::vec3&, const glm::quat& rotation, BillboardMode, const glm::vec3&, bool) { return rotation; };
std::function<glm::vec3()> BillboardModeHelpers::_getPrimaryViewFrustumPositionOperator = []() { return glm::vec3(0.0f); };
QString BillboardModeHelpers::getNameForBillboardMode(BillboardMode mode) {
if (((int)mode <= 0) || ((int)mode >= (int)BILLBOARD_MODE_NAMES)) {
@ -22,4 +24,4 @@ QString BillboardModeHelpers::getNameForBillboardMode(BillboardMode mode) {
}
return billboardModeNames[(int)mode];
}
}

View file

@ -9,8 +9,13 @@
#ifndef hifi_BillboardMode_h
#define hifi_BillboardMode_h
#include <functional>
#include "QString"
#include "glm/glm.hpp"
#include "glm/gtc/quaternion.hpp"
/**jsdoc
* <p>How an entity is billboarded.</p>
* <table>
@ -37,7 +42,15 @@ enum class BillboardMode {
class BillboardModeHelpers {
public:
static QString getNameForBillboardMode(BillboardMode mode);
static void setBillboardRotationOperator(std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode, const glm::vec3&, bool)> getBillboardRotationOperator) { _getBillboardRotationOperator = getBillboardRotationOperator; }
static glm::quat getBillboardRotation(const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos, bool rotate90x = false) { return _getBillboardRotationOperator(position, rotation, billboardMode, frustumPos, rotate90x); }
static void setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; }
static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); }
private:
static std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode, const glm::vec3&, bool)> _getBillboardRotationOperator;
static std::function<glm::vec3()> _getPrimaryViewFrustumPositionOperator;
};
#endif // hifi_BillboardMode_h