mirror of
https://github.com/overte-org/overte.git
synced 2025-04-09 05:53:25 +02:00
billboarding for model entities
This commit is contained in:
parent
6d1667df5a
commit
2a27fc4de2
32 changed files with 328 additions and 558 deletions
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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()}]);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue