mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-07 03:22:27 +02:00
Merge pull request #961 from HifiExperiments/billboard
Implement billboardMode for all Entity types
This commit is contained in:
commit
fd6973bd0b
90 changed files with 715 additions and 1239 deletions
|
@ -2455,13 +2455,19 @@ 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) {
|
||||
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
|
||||
glm::vec3 dPosition = frustumPos - position;
|
||||
// If x and z are 0, atan(x, z) is undefined, so default to 0 degrees
|
||||
float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z);
|
||||
return glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
|
||||
glm::quat result = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)) * rotation;
|
||||
if (rotate90x) {
|
||||
result *= ROTATE_90X;
|
||||
}
|
||||
return result;
|
||||
} else if (billboardMode == BillboardMode::FULL) {
|
||||
// use the referencial from the avatar, y isn't always up
|
||||
glm::vec3 avatarUP = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * Vectors::UP;
|
||||
|
@ -2470,12 +2476,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
|
||||
// make sure s is not NaN for any component
|
||||
if (glm::length2(s) > 0.0f) {
|
||||
return glm::conjugate(glm::toQuat(glm::lookAt(frustumPos, position, avatarUP)));
|
||||
glm::quat result = glm::conjugate(glm::toQuat(glm::lookAt(frustumPos, position, avatarUP))) * rotation;
|
||||
if (rotate90x) {
|
||||
result *= ROTATE_90X;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
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();
|
||||
});
|
||||
|
||||
{
|
||||
|
|
|
@ -767,6 +767,7 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
|
|||
glm::vec3 rayDirectionInv = { rayDirection.x != 0.0f ? 1.0f / rayDirection.x : INFINITY,
|
||||
rayDirection.y != 0.0f ? 1.0f / rayDirection.y : INFINITY,
|
||||
rayDirection.z != 0.0f ? 1.0f / rayDirection.z : INFINITY };
|
||||
glm::vec3 viewFrustumPos = BillboardModeHelpers::getPrimaryViewFrustumPosition();
|
||||
|
||||
for (auto &hit : physicsResults) {
|
||||
auto avatarID = hit._intersectWithAvatar;
|
||||
|
@ -842,7 +843,8 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
|
|||
BoxFace subMeshFace = BoxFace::UNKNOWN_FACE;
|
||||
glm::vec3 subMeshSurfaceNormal;
|
||||
QVariantMap subMeshExtraInfo;
|
||||
if (avatar->getSkeletonModel()->findRayIntersectionAgainstSubMeshes(defaultFrameRayOrigin, defaultFrameRayDirection, subMeshDistance, subMeshFace, subMeshSurfaceNormal, subMeshExtraInfo, true, false)) {
|
||||
if (avatar->getSkeletonModel()->findRayIntersectionAgainstSubMeshes(defaultFrameRayOrigin, defaultFrameRayDirection, viewFrustumPos, subMeshDistance,
|
||||
subMeshFace, subMeshSurfaceNormal, subMeshExtraInfo, true, false)) {
|
||||
rayAvatarResult._distance = subMeshDistance;
|
||||
rayAvatarResult._intersectionPoint = ray.origin + subMeshDistance * rayDirection;
|
||||
rayAvatarResult._intersectionNormal = subMeshSurfaceNormal;
|
||||
|
@ -932,6 +934,7 @@ ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector
|
|||
std::sort(sortedAvatars.begin(), sortedAvatars.end(), comparator);
|
||||
}
|
||||
|
||||
glm::vec3 viewFrustumPos = BillboardModeHelpers::getPrimaryViewFrustumPosition();
|
||||
for (auto it = sortedAvatars.begin(); it != sortedAvatars.end(); ++it) {
|
||||
const SortedAvatar& sortedAvatar = *it;
|
||||
// We can exit once avatarCapsuleDistance > bestDistance
|
||||
|
@ -944,7 +947,7 @@ ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector
|
|||
glm::vec3 surfaceNormal;
|
||||
QVariantMap extraInfo;
|
||||
SkeletonModelPointer avatarModel = sortedAvatar.second->getSkeletonModel();
|
||||
if (avatarModel->findParabolaIntersectionAgainstSubMeshes(pick.origin, pick.velocity, pick.acceleration, parabolicDistance, face, surfaceNormal, extraInfo, true)) {
|
||||
if (avatarModel->findParabolaIntersectionAgainstSubMeshes(pick.origin, pick.velocity, pick.acceleration, viewFrustumPos, parabolicDistance, face, surfaceNormal, extraInfo, true)) {
|
||||
if (parabolicDistance < result.parabolicDistance) {
|
||||
result.intersects = true;
|
||||
result.avatarID = sortedAvatar.second->getID();
|
||||
|
|
|
@ -16,7 +16,7 @@ render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) { return Item::Bound(); }
|
||||
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
||||
PerformanceTimer perfTimer("worldBox");
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff);
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff);
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args);
|
||||
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args);
|
||||
}
|
||||
|
||||
|
|
|
@ -462,9 +462,9 @@ namespace render {
|
|||
template <> const ItemKey payloadGetKey(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload) {
|
||||
return payload->getKey();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload) {
|
||||
template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload, RenderArgs* args) {
|
||||
if (payload) {
|
||||
return payload->getBound();
|
||||
return payload->getBound(args);
|
||||
}
|
||||
return Item::Bound();
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
|
||||
void render(RenderArgs* args);
|
||||
render::Item::Bound& editBound() { return _bound; }
|
||||
const render::Item::Bound& getBound() { return _bound; }
|
||||
const render::Item::Bound& getBound(RenderArgs* args) { return _bound; }
|
||||
render::ItemKey getKey() const { return _key; }
|
||||
|
||||
void setVisible(bool visible);
|
||||
|
@ -128,7 +128,7 @@ private:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload, RenderArgs* args);
|
||||
template <> void payloadRender(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload);
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ private:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay);
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay);
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay, RenderArgs* args);
|
||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay);
|
||||
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems);
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace render {
|
|||
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay) {
|
||||
return overlay->getKey();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||
return overlay->getBounds();
|
||||
}
|
||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||
|
|
|
@ -82,9 +82,9 @@ namespace render {
|
|||
template <> const ItemKey payloadGetKey(const GameWorkloadRenderItem::Pointer& payload) {
|
||||
return payload->getKey();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload) {
|
||||
template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args) {
|
||||
if (payload) {
|
||||
return payload->getBound();
|
||||
return payload->getBound(args);
|
||||
}
|
||||
return Item::Bound();
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public:
|
|||
void render(RenderArgs* args);
|
||||
|
||||
render::Item::Bound& editBound() { return _bound; }
|
||||
const render::Item::Bound& getBound() { return _bound; }
|
||||
const render::Item::Bound& getBound(RenderArgs* args) { return _bound; }
|
||||
|
||||
void setVisible(bool visible);
|
||||
void showProxies(bool show);
|
||||
|
@ -96,7 +96,7 @@ protected:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const GameWorkloadRenderItem::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args);
|
||||
template <> void payloadRender(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const GameWorkloadRenderItem::Pointer& payload);
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace render {
|
|||
}
|
||||
return keyBuilder.build();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
|
||||
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar, RenderArgs* args) {
|
||||
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
|
||||
if (avatarPtr) {
|
||||
return avatarPtr->getRenderBounds();
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar);
|
||||
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar);
|
||||
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar, RenderArgs* args);
|
||||
template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args);
|
||||
template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems);
|
||||
}
|
||||
|
|
|
@ -137,8 +137,15 @@ EntityRenderer::~EntityRenderer() {}
|
|||
// Smart payload proxy members, implementing the payload interface
|
||||
//
|
||||
|
||||
Item::Bound EntityRenderer::getBound() {
|
||||
return _bound;
|
||||
Item::Bound EntityRenderer::getBound(RenderArgs* args) {
|
||||
auto bound = _bound;
|
||||
if (_billboardMode != BillboardMode::NONE) {
|
||||
glm::vec3 dimensions = bound.getScale();
|
||||
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
|
||||
const float SQRT_2 = 1.41421356237f;
|
||||
bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
|
||||
}
|
||||
return bound;
|
||||
}
|
||||
|
||||
ShapeKey EntityRenderer::getShapeKey() {
|
||||
|
@ -198,12 +205,9 @@ uint32_t EntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
|
|||
}
|
||||
|
||||
bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const {
|
||||
auto renderWithZones = resultWithReadLock<QVector<QUuid>>([&] {
|
||||
return _renderWithZones;
|
||||
});
|
||||
if (!renderWithZones.isEmpty()) {
|
||||
if (!_renderWithZones.isEmpty()) {
|
||||
if (!containingZones.empty()) {
|
||||
for (auto renderWithZone : renderWithZones) {
|
||||
for (auto renderWithZone : _renderWithZones) {
|
||||
if (containingZones.find(renderWithZone) != containingZones.end()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -429,20 +433,24 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
|
|||
|
||||
_moving = entity->isMovingRelativeToParent();
|
||||
_visible = entity->getVisible();
|
||||
setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera());
|
||||
setRenderLayer(entity->getRenderLayer());
|
||||
_primitiveMode = entity->getPrimitiveMode();
|
||||
_canCastShadow = entity->getCanCastShadow();
|
||||
setCullWithParent(entity->getCullWithParent());
|
||||
_cauterized = entity->getCauterized();
|
||||
if (entity->needsZoneOcclusionUpdate()) {
|
||||
entity->resetNeedsZoneOcclusionUpdate();
|
||||
_renderWithZones = entity->getRenderWithZones();
|
||||
}
|
||||
entity->setNeedsRenderUpdate(false);
|
||||
});
|
||||
}
|
||||
|
||||
void EntityRenderer::doRenderUpdateAsynchronous(const EntityItemPointer& entity) {
|
||||
setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera());
|
||||
setRenderLayer(entity->getRenderLayer());
|
||||
_billboardMode = entity->getBillboardMode();
|
||||
_primitiveMode = entity->getPrimitiveMode();
|
||||
_canCastShadow = entity->getCanCastShadow();
|
||||
setCullWithParent(entity->getCullWithParent());
|
||||
_cauterized = entity->getCauterized();
|
||||
if (entity->needsZoneOcclusionUpdate()) {
|
||||
entity->resetNeedsZoneOcclusionUpdate();
|
||||
_renderWithZones = entity->getRenderWithZones();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityRenderer::onAddToScene(const EntityItemPointer& entity) {
|
||||
QObject::connect(this, &EntityRenderer::requestRenderUpdate, this, [this] {
|
||||
auto renderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
|
|
|
@ -64,7 +64,7 @@ public:
|
|||
static glm::vec3 calculatePulseColor(const glm::vec3& color, const PulsePropertyGroup& pulseProperties, quint64 start);
|
||||
|
||||
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
|
||||
virtual Item::Bound getBound() override;
|
||||
virtual Item::Bound getBound(RenderArgs* args) override;
|
||||
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const override;
|
||||
|
||||
protected:
|
||||
|
@ -95,8 +95,7 @@ protected:
|
|||
// Will be called by the lambda posted to the scene in updateInScene.
|
||||
// This function will execute on the rendering thread, so you cannot use network caches to fetch
|
||||
// data in this method if using multi-threaded rendering
|
||||
|
||||
virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity) { }
|
||||
virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity);
|
||||
|
||||
// Called by the `render` method after `needsRenderUpdate`
|
||||
virtual void doRender(RenderArgs* args) = 0;
|
||||
|
@ -135,6 +134,7 @@ protected:
|
|||
RenderLayer _renderLayer { RenderLayer::WORLD };
|
||||
PrimitiveMode _primitiveMode { PrimitiveMode::SOLID };
|
||||
QVector<QUuid> _renderWithZones;
|
||||
BillboardMode _billboardMode;
|
||||
bool _cauterized { false };
|
||||
bool _moving { false };
|
||||
Transform _renderTransform;
|
||||
|
|
|
@ -195,8 +195,8 @@ void GizmoEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
|||
}
|
||||
}
|
||||
|
||||
Item::Bound GizmoEntityRenderer::getBound() {
|
||||
auto bound = Parent::getBound();
|
||||
Item::Bound GizmoEntityRenderer::getBound(RenderArgs* args) {
|
||||
auto bound = Parent::getBound(args);
|
||||
if (_ringProperties.getHasTickMarks()) {
|
||||
glm::vec3 scale = bound.getScale();
|
||||
for (int i = 0; i < 3; i += 2) {
|
||||
|
@ -242,18 +242,20 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) {
|
|||
bool hasTickMarks = _ringProperties.getHasTickMarks();
|
||||
glm::vec4 tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(),
|
||||
_ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength());
|
||||
bool forward;
|
||||
bool wireframe;
|
||||
|
||||
bool transparent;
|
||||
withReadLock([&] {
|
||||
transform = _renderTransform;
|
||||
transparent = isTransparent();
|
||||
wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
|
||||
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
|
||||
});
|
||||
|
||||
bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
|
||||
bool forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
|
||||
|
||||
geometryCache->bindSimpleProgram(batch, false, transparent, wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
|
||||
|
||||
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
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
~GizmoEntityRenderer();
|
||||
|
||||
protected:
|
||||
Item::Bound getBound() override;
|
||||
Item::Bound getBound(RenderArgs* args) override;
|
||||
ShapeKey getShapeKey() override;
|
||||
|
||||
bool isTransparent() const override;
|
||||
|
|
|
@ -49,13 +49,13 @@ void GridEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
|
|||
_minorGridEvery = entity->getMinorGridEvery();
|
||||
}
|
||||
|
||||
Item::Bound GridEntityRenderer::getBound() {
|
||||
Item::Bound GridEntityRenderer::getBound(RenderArgs* args) {
|
||||
if (_followCamera) {
|
||||
// This is a UI element that should always be in view, lie to the octree to avoid culling
|
||||
const AABox DOMAIN_BOX = AABox(glm::vec3(-TREE_SCALE / 2), TREE_SCALE);
|
||||
return DOMAIN_BOX;
|
||||
}
|
||||
return Parent::getBound();
|
||||
return Parent::getBound(args);
|
||||
}
|
||||
|
||||
ShapeKey GridEntityRenderer::getShapeKey() {
|
||||
|
@ -77,17 +77,17 @@ void GridEntityRenderer::doRender(RenderArgs* args) {
|
|||
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
|
||||
glm::vec3 dimensions;
|
||||
Transform renderTransform;
|
||||
bool forward;
|
||||
withReadLock([&] {
|
||||
dimensions = _dimensions;
|
||||
renderTransform = _renderTransform;
|
||||
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
|
||||
});
|
||||
|
||||
if (!_visible || color.a == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
|
||||
|
||||
auto batch = args->_batch;
|
||||
|
||||
Transform transform;
|
||||
|
@ -103,6 +103,8 @@ void GridEntityRenderer::doRender(RenderArgs* args) {
|
|||
} else {
|
||||
transform.setTranslation(renderTransform.getTranslation());
|
||||
}
|
||||
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);
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
~GridEntityRenderer();
|
||||
|
||||
protected:
|
||||
Item::Bound getBound() override;
|
||||
Item::Bound getBound(RenderArgs* args) override;
|
||||
ShapeKey getShapeKey() override;
|
||||
|
||||
bool isTransparent() const override;
|
||||
|
|
|
@ -58,7 +58,6 @@ void ImageEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
|||
_color = entity->getColor();
|
||||
_alpha = entity->getAlpha();
|
||||
_pulseProperties = entity->getPulseProperties();
|
||||
_billboardMode = entity->getBillboardMode();
|
||||
|
||||
if (!_textureIsLoaded) {
|
||||
emit requestRenderUpdate();
|
||||
|
@ -66,17 +65,6 @@ void ImageEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
|||
_textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
|
||||
}
|
||||
|
||||
Item::Bound ImageEntityRenderer::getBound() {
|
||||
auto bound = Parent::getBound();
|
||||
if (_billboardMode != BillboardMode::NONE) {
|
||||
glm::vec3 dimensions = bound.getScale();
|
||||
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
|
||||
const float SQRT_2 = 1.41421356237f;
|
||||
bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
|
||||
}
|
||||
return bound;
|
||||
}
|
||||
|
||||
ShapeKey ImageEntityRenderer::getShapeKey() {
|
||||
auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias();
|
||||
if (isTransparent()) {
|
||||
|
@ -109,7 +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->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());
|
||||
|
|
|
@ -23,7 +23,6 @@ public:
|
|||
~ImageEntityRenderer();
|
||||
|
||||
protected:
|
||||
Item::Bound getBound() override;
|
||||
ShapeKey getShapeKey() override;
|
||||
|
||||
bool isTransparent() const override;
|
||||
|
@ -44,7 +43,6 @@ private:
|
|||
glm::u8vec3 _color;
|
||||
float _alpha;
|
||||
PulsePropertyGroup _pulseProperties;
|
||||
BillboardMode _billboardMode;
|
||||
|
||||
int _geometryId { 0 };
|
||||
};
|
||||
|
|
|
@ -60,8 +60,8 @@ ItemKey LightEntityRenderer::getKey() {
|
|||
return payloadGetKey(_lightPayload);
|
||||
}
|
||||
|
||||
Item::Bound LightEntityRenderer::getBound() {
|
||||
return payloadGetBound(_lightPayload);
|
||||
Item::Bound LightEntityRenderer::getBound(RenderArgs* args) {
|
||||
return payloadGetBound(_lightPayload, args);
|
||||
}
|
||||
|
||||
void LightEntityRenderer::doRender(RenderArgs* args) {
|
||||
|
|
|
@ -29,7 +29,7 @@ protected:
|
|||
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
|
||||
|
||||
virtual ItemKey getKey() override;
|
||||
virtual Item::Bound getBound() override;
|
||||
virtual Item::Bound getBound(RenderArgs* args) override;
|
||||
virtual void doRender(RenderArgs* args) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -47,7 +47,8 @@ void LineEntityRenderer::doRender(RenderArgs* args) {
|
|||
const auto& modelTransform = getModelTransform();
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(modelTransform.getTranslation());
|
||||
transform.setRotation(modelTransform.getRotation());
|
||||
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,
|
||||
|
|
|
@ -259,9 +259,9 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
|
||||
textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
|
||||
|
||||
Transform renderTransform;
|
||||
Transform transform;
|
||||
withReadLock([&] {
|
||||
renderTransform = _renderTransform;
|
||||
transform = _renderTransform;
|
||||
});
|
||||
|
||||
if (!drawMaterial) {
|
||||
|
@ -272,7 +272,9 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
proceduralRender = true;
|
||||
}
|
||||
|
||||
batch.setModelTransform(renderTransform);
|
||||
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) {
|
||||
drawMaterial->setTextureTransforms(textureTransform, MaterialMappingMode::UV, true);
|
||||
|
@ -287,8 +289,8 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
auto proceduralDrawMaterial = std::static_pointer_cast<graphics::ProceduralMaterial>(drawMaterial);
|
||||
glm::vec4 outColor = glm::vec4(drawMaterial->getAlbedo(), drawMaterial->getOpacity());
|
||||
outColor = proceduralDrawMaterial->getColor(outColor);
|
||||
proceduralDrawMaterial->prepare(batch, renderTransform.getTranslation(), renderTransform.getScale(),
|
||||
renderTransform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
proceduralDrawMaterial->prepare(batch, transform.getTranslation(), transform.getScale(),
|
||||
transform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
|
||||
DependencyManager::get<GeometryCache>()->renderWireSphere(batch, outColor);
|
||||
} else {
|
||||
|
@ -374,7 +376,7 @@ void MaterialEntityRenderer::applyMaterial(const TypedEntityPointer& entity) {
|
|||
|
||||
if (material->isProcedural()) {
|
||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(material);
|
||||
procedural->setBoundOperator([this] { return getBound(); });
|
||||
procedural->setBoundOperator([this](RenderArgs* args) { return getBound(args); });
|
||||
entity->setHasVertexShader(procedural->hasVertexShader());
|
||||
}
|
||||
|
||||
|
|
|
@ -237,26 +237,26 @@ bool RenderableModelEntityItem::supportsDetailedIntersection() const {
|
|||
}
|
||||
|
||||
bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
auto model = getModel();
|
||||
if (!model || !model->isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
|
||||
return model->findRayIntersectionAgainstSubMeshes(origin, direction, viewFrustumPos, distance,
|
||||
face, surfaceNormal, extraInfo, precisionPicking, false);
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance, BoxFace& face,
|
||||
glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
auto model = getModel();
|
||||
if (!model || !model->isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return model->findParabolaIntersectionAgainstSubMeshes(origin, velocity, acceleration, parabolicDistance,
|
||||
return model->findParabolaIntersectionAgainstSubMeshes(origin, velocity, acceleration, viewFrustumPos, parabolicDistance,
|
||||
face, surfaceNormal, extraInfo, precisionPicking, false);
|
||||
}
|
||||
|
||||
|
@ -1268,6 +1268,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);
|
||||
});
|
||||
|
@ -1346,6 +1347,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);
|
||||
});
|
||||
|
|
|
@ -66,12 +66,12 @@ public:
|
|||
glm::vec3 getPivot() const override;
|
||||
virtual bool supportsDetailedIntersection() const override;
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
virtual void setShapeType(ShapeType type) override;
|
||||
|
|
|
@ -161,7 +161,7 @@ ShapeKey ParticleEffectEntityRenderer::getShapeKey() {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
Item::Bound ParticleEffectEntityRenderer::getBound() {
|
||||
Item::Bound ParticleEffectEntityRenderer::getBound(RenderArgs* args) {
|
||||
return _bound;
|
||||
}
|
||||
|
||||
|
@ -456,6 +456,7 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) {
|
|||
color.spread = EntityRenderer::calculatePulseColor(_particleProperties.getColorSpread(), _pulseProperties, _created);
|
||||
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
batch.setUniformBuffer(0, _uniformBuffer);
|
||||
batch.setInputFormat(_vertexFormat);
|
||||
batch.setInputBuffer(0, _particleBuffer, 0, sizeof(GpuParticle));
|
||||
|
|
|
@ -30,7 +30,7 @@ protected:
|
|||
|
||||
virtual ItemKey getKey() override;
|
||||
virtual ShapeKey getShapeKey() override;
|
||||
virtual Item::Bound getBound() override;
|
||||
virtual Item::Bound getBound(RenderArgs* args) override;
|
||||
virtual void doRender(RenderArgs* args) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -325,8 +325,11 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
|
|||
buildPipelines();
|
||||
}
|
||||
|
||||
batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]);
|
||||
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()}]);
|
||||
batch.setResourceTexture(0, texture);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * _numVertices), 0);
|
||||
}
|
||||
|
|
|
@ -238,53 +238,6 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel
|
|||
startUpdates();
|
||||
}
|
||||
|
||||
glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
|
||||
glm::vec3 result;
|
||||
withReadLock([&] {
|
||||
glm::vec3 scale = getScaledDimensions() / _voxelVolumeSize; // meters / voxel-units
|
||||
if (isEdged(_voxelSurfaceStyle)) {
|
||||
result = scale / -2.0f;
|
||||
}
|
||||
return scale / 2.0f;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
|
||||
glm::vec3 voxelVolumeSize;
|
||||
withReadLock([&] {
|
||||
voxelVolumeSize = _voxelVolumeSize;
|
||||
});
|
||||
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec3 scale = dimensions / voxelVolumeSize; // meters / voxel-units
|
||||
bool success; // TODO -- Does this actually have to happen in world space?
|
||||
glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes
|
||||
glm::vec3 position = getWorldPosition(success);
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
|
||||
positionToCenter -= dimensions * Vectors::HALF - getSurfacePositionAdjustment();
|
||||
glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter);
|
||||
glm::mat4 scaled = glm::scale(centerToCorner, scale);
|
||||
return scaled;
|
||||
}
|
||||
|
||||
glm::mat4 RenderablePolyVoxEntityItem::localToVoxelMatrix() const {
|
||||
glm::mat4 localToModelMatrix = glm::inverse(voxelToLocalMatrix());
|
||||
return localToModelMatrix;
|
||||
}
|
||||
|
||||
glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const {
|
||||
glm::mat4 rotation = glm::mat4_cast(getWorldOrientation());
|
||||
glm::mat4 translation = glm::translate(getWorldPosition());
|
||||
return translation * rotation * voxelToLocalMatrix();
|
||||
}
|
||||
|
||||
glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const {
|
||||
glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix());
|
||||
return worldToModelMatrix;
|
||||
}
|
||||
|
||||
bool RenderablePolyVoxEntityItem::setVoxel(const ivec3& v, uint8_t toValue) {
|
||||
if (_locked) {
|
||||
return false;
|
||||
|
@ -573,7 +526,7 @@ public:
|
|||
#endif
|
||||
|
||||
bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
// TODO -- correctly pick against marching-cube generated meshes
|
||||
|
@ -582,7 +535,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
|
|||
return true;
|
||||
}
|
||||
|
||||
glm::mat4 wtvMatrix = worldToVoxelMatrix();
|
||||
glm::mat4 wtvMatrix = worldToVoxelMatrix(true);
|
||||
glm::vec3 normDirection = glm::normalize(direction);
|
||||
|
||||
// the PolyVox ray intersection code requires a near and far point.
|
||||
|
@ -614,7 +567,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
|
|||
}
|
||||
|
||||
bool RenderablePolyVoxEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
// TODO -- correctly pick against marching-cube generated meshes
|
||||
|
@ -623,7 +576,7 @@ bool RenderablePolyVoxEntityItem::findDetailedParabolaIntersection(const glm::ve
|
|||
return true;
|
||||
}
|
||||
|
||||
glm::mat4 wtvMatrix = worldToVoxelMatrix();
|
||||
glm::mat4 wtvMatrix = worldToVoxelMatrix(true);
|
||||
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
|
||||
glm::vec4 velocityInVoxel = wtvMatrix * glm::vec4(velocity, 0.0f);
|
||||
glm::vec4 accelerationInVoxel = wtvMatrix * glm::vec4(acceleration, 0.0f);
|
||||
|
@ -1805,7 +1758,7 @@ ShapeKey PolyVoxEntityRenderer::getShapeKey() {
|
|||
|
||||
bool PolyVoxEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
||||
if (resultWithReadLock<bool>([&] {
|
||||
if (entity->voxelToWorldMatrix() != _lastVoxelToWorldMatrix) {
|
||||
if (entity->voxelToLocalMatrix() != _lastVoxelToLocalMatrix) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1831,7 +1784,9 @@ void PolyVoxEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& s
|
|||
}
|
||||
|
||||
void PolyVoxEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
|
||||
_lastVoxelToWorldMatrix = entity->voxelToWorldMatrix();
|
||||
_lastVoxelToLocalMatrix = entity->voxelToLocalMatrix();
|
||||
_position = entity->getWorldPosition();
|
||||
_orientation = entity->getWorldOrientation();
|
||||
_lastVoxelVolumeSize = entity->getVoxelVolumeSize();
|
||||
_params->setSubData(0, vec4(_lastVoxelVolumeSize, 0.0));
|
||||
graphics::MeshPointer newMesh;
|
||||
|
@ -1864,17 +1819,18 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render");
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
Transform transform(_lastVoxelToWorldMatrix);
|
||||
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);
|
||||
|
||||
batch.setInputFormat(_vertexFormat);
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, _mesh->getVertexBuffer()._buffer, 0,
|
||||
sizeof(PolyVox::PositionMaterialNormal));
|
||||
|
||||
|
||||
// TODO -- should we be setting this?
|
||||
// batch.setInputBuffer(gpu::Stream::NORMAL, mesh->getVertexBuffer()._buffer,
|
||||
// 12,
|
||||
|
|
|
@ -71,24 +71,18 @@ public:
|
|||
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const vec3& accleration,
|
||||
OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
virtual void setVoxelData(const QByteArray& voxelData) override;
|
||||
virtual void setVoxelVolumeSize(const glm::vec3& voxelVolumeSize) override;
|
||||
virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) override;
|
||||
|
||||
glm::vec3 getSurfacePositionAdjustment() const;
|
||||
glm::mat4 voxelToWorldMatrix() const;
|
||||
glm::mat4 worldToVoxelMatrix() const;
|
||||
glm::mat4 voxelToLocalMatrix() const;
|
||||
glm::mat4 localToVoxelMatrix() const;
|
||||
|
||||
virtual ShapeType getShapeType() const override;
|
||||
virtual bool isReadyToComputeShape() const override;
|
||||
virtual void computeShapeInfo(ShapeInfo& info) override;
|
||||
|
@ -226,7 +220,9 @@ private:
|
|||
gpu::BufferPointer _params;
|
||||
std::array<NetworkTexturePointer, 3> _xyzTextures;
|
||||
glm::vec3 _lastVoxelVolumeSize;
|
||||
glm::mat4 _lastVoxelToWorldMatrix;
|
||||
glm::mat4 _lastVoxelToLocalMatrix;
|
||||
glm::vec3 _position;
|
||||
glm::quat _orientation;
|
||||
PolyVoxEntityItem::PolyVoxSurfaceStyle _lastSurfaceStyle { PolyVoxEntityItem::SURFACE_MARCHING_CUBES };
|
||||
std::array<QString, 3> _xyzTextureUrls;
|
||||
};
|
||||
|
|
|
@ -55,6 +55,7 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
void* key = (void*)this;
|
||||
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
|
||||
withWriteLock([&] {
|
||||
_shape = entity->getShape();
|
||||
_position = entity->getWorldPosition();
|
||||
_dimensions = entity->getUnscaledDimensions(); // get unscaled to avoid scaling twice
|
||||
_orientation = entity->getWorldOrientation();
|
||||
|
@ -69,7 +70,6 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
}
|
||||
|
||||
void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
|
||||
_shape = entity->getShape();
|
||||
_pulseProperties = entity->getPulseProperties();
|
||||
|
||||
bool materialChanged = false;
|
||||
|
@ -200,16 +200,16 @@ ShapeKey ShapeEntityRenderer::getShapeKey() {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
Item::Bound ShapeEntityRenderer::getBound() {
|
||||
Item::Bound ShapeEntityRenderer::getBound(RenderArgs* args) {
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end() && mat->second.top().material && mat->second.top().material->isProcedural() &&
|
||||
mat->second.top().material->isReady()) {
|
||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(mat->second.top().material);
|
||||
if (procedural->hasVertexShader() && procedural->hasBoundOperator()) {
|
||||
return procedural->getBound();
|
||||
return procedural->getBound(args);
|
||||
}
|
||||
}
|
||||
return Parent::getBound();
|
||||
return Parent::getBound(args);
|
||||
}
|
||||
|
||||
void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
||||
|
@ -221,14 +221,11 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
graphics::MultiMaterial materials;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
GeometryCache::Shape geometryShape = geometryCache->getShapeForEntityShape(_shape);
|
||||
PrimitiveMode primitiveMode;
|
||||
RenderLayer renderLayer;
|
||||
glm::vec4 outColor;
|
||||
Pipeline pipelineType;
|
||||
Transform transform;
|
||||
withReadLock([&] {
|
||||
primitiveMode = _primitiveMode;
|
||||
renderLayer = _renderLayer;
|
||||
batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
|
||||
transform = _renderTransform;
|
||||
materials = _materials["0"];
|
||||
pipelineType = getPipelineType(materials);
|
||||
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
|
||||
|
@ -241,6 +238,11 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (pipelineType == Pipeline::PROCEDURAL) {
|
||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials.top().material);
|
||||
outColor = procedural->getColor(outColor);
|
||||
|
@ -249,7 +251,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
procedural->prepare(batch, _position, _dimensions, _orientation, _created, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
});
|
||||
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
|
||||
geometryCache->renderWireShape(batch, geometryShape, outColor);
|
||||
} else {
|
||||
geometryCache->renderShape(batch, geometryShape, outColor);
|
||||
|
@ -258,8 +260,8 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
||||
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
render::ShapePipelinePointer pipeline = geometryCache->getShapePipelinePointer(outColor.a < 1.0f, false,
|
||||
renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD, materials.top().material->getCullFaceMode());
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
|
||||
_renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD, materials.top().material->getCullFaceMode());
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
|
||||
geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
||||
} else {
|
||||
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
|
||||
protected:
|
||||
ShapeKey getShapeKey() override;
|
||||
Item::Bound getBound() override;
|
||||
Item::Bound getBound(RenderArgs* args) override;
|
||||
|
||||
private:
|
||||
virtual bool needsRenderUpdate() const override;
|
||||
|
|
|
@ -54,17 +54,6 @@ bool TextEntityRenderer::isTextTransparent() const {
|
|||
});
|
||||
}
|
||||
|
||||
Item::Bound TextEntityRenderer::getBound() {
|
||||
auto bound = Parent::getBound();
|
||||
if (_billboardMode != BillboardMode::NONE) {
|
||||
glm::vec3 dimensions = bound.getScale();
|
||||
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
|
||||
const float SQRT_2 = 1.41421356237f;
|
||||
bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
|
||||
}
|
||||
return bound;
|
||||
}
|
||||
|
||||
ItemKey TextEntityRenderer::getKey() {
|
||||
return ItemKey::Builder(Parent::getKey()).withMetaCullGroup();
|
||||
}
|
||||
|
@ -111,7 +100,6 @@ void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
|
|||
_textAlpha = entity->getTextAlpha();
|
||||
_backgroundColor = toGlm(entity->getBackgroundColor());
|
||||
_backgroundAlpha = entity->getBackgroundAlpha();
|
||||
_billboardMode = entity->getBillboardMode();
|
||||
_leftMargin = entity->getLeftMargin();
|
||||
_rightMargin = entity->getRightMargin();
|
||||
_topMargin = entity->getTopMargin();
|
||||
|
@ -130,13 +118,9 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
|
|||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
glm::vec4 backgroundColor;
|
||||
Transform modelTransform;
|
||||
PrimitiveMode primitiveMode;
|
||||
RenderLayer renderLayer;
|
||||
Transform transform;
|
||||
withReadLock([&] {
|
||||
modelTransform = _renderTransform;
|
||||
primitiveMode = _primitiveMode;
|
||||
renderLayer = _renderLayer;
|
||||
transform = _renderTransform;
|
||||
|
||||
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
backgroundColor = glm::vec4(_backgroundColor, fadeRatio * _backgroundAlpha);
|
||||
|
@ -147,14 +131,15 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
|
|||
return;
|
||||
}
|
||||
|
||||
modelTransform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
|
||||
batch.setModelTransform(modelTransform);
|
||||
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>();
|
||||
// FIXME: we want to use instanced rendering here, but if textAlpha < 1 and backgroundAlpha < 1, the transparency sorting will be wrong
|
||||
//render::ShapePipelinePointer pipeline = geometryCache->getShapePipelinePointer(backgroundColor.a < 1.0f, _unlit,
|
||||
// renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD);
|
||||
//if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
|
||||
// _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD);
|
||||
//if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
|
||||
// geometryCache->renderWireShapeInstance(args, batch, GeometryCache::Quad, backgroundColor, pipeline);
|
||||
//} else {
|
||||
// geometryCache->renderSolidShapeInstance(args, batch, GeometryCache::Quad, backgroundColor, pipeline);
|
||||
|
@ -242,12 +227,12 @@ ItemKey entities::TextPayload::getKey() const {
|
|||
return ItemKey::Builder::opaqueShape();
|
||||
}
|
||||
|
||||
Item::Bound entities::TextPayload::getBound() const {
|
||||
Item::Bound entities::TextPayload::getBound(RenderArgs* args) const {
|
||||
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
if (entityTreeRenderer) {
|
||||
auto renderable = entityTreeRenderer->renderableForEntityId(_entityID);
|
||||
if (renderable) {
|
||||
return std::static_pointer_cast<TextEntityRenderer>(renderable)->getBound();
|
||||
return std::static_pointer_cast<TextEntityRenderer>(renderable)->getBound(args);
|
||||
}
|
||||
}
|
||||
return Item::Bound();
|
||||
|
@ -309,21 +294,18 @@ void entities::TextPayload::render(RenderArgs* args) {
|
|||
|
||||
Transform modelTransform;
|
||||
glm::vec3 dimensions;
|
||||
BillboardMode billboardMode;
|
||||
|
||||
glm::vec4 textColor;
|
||||
bool forward;
|
||||
textRenderable->withReadLock([&] {
|
||||
modelTransform = textRenderable->_renderTransform;
|
||||
dimensions = textRenderable->_dimensions;
|
||||
billboardMode = textRenderable->_billboardMode;
|
||||
|
||||
float fadeRatio = textRenderable->_isFading ? Interpolate::calculateFadeRatio(textRenderable->_fadeStartTime) : 1.0f;
|
||||
textColor = glm::vec4(textRenderable->_textColor, fadeRatio * textRenderable->_textAlpha);
|
||||
|
||||
forward = textRenderable->_renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
|
||||
});
|
||||
|
||||
bool forward = textRenderable->_renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
|
||||
|
||||
textColor = EntityRenderer::calculatePulseColor(textColor, textRenderable->_pulseProperties, textRenderable->_created);
|
||||
glm::vec3 effectColor = EntityRenderer::calculatePulseColor(textRenderable->_effectColor, textRenderable->_pulseProperties, textRenderable->_created);
|
||||
|
||||
|
@ -331,7 +313,8 @@ void entities::TextPayload::render(RenderArgs* args) {
|
|||
return;
|
||||
}
|
||||
|
||||
modelTransform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), billboardMode, 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));
|
||||
|
@ -352,9 +335,9 @@ template <> const ItemKey payloadGetKey(const TextPayload::Pointer& payload) {
|
|||
return ItemKey::Builder::opaqueShape();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const TextPayload::Pointer& payload) {
|
||||
template <> const Item::Bound payloadGetBound(const TextPayload::Pointer& payload, RenderArgs* args) {
|
||||
if (payload) {
|
||||
return payload->getBound();
|
||||
return payload->getBound(args);
|
||||
}
|
||||
return Item::Bound();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ public:
|
|||
protected:
|
||||
bool isTransparent() const override;
|
||||
bool isTextTransparent() const;
|
||||
Item::Bound getBound() override;
|
||||
ShapeKey getShapeKey() override;
|
||||
ItemKey getKey() override;
|
||||
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
|
||||
|
@ -63,7 +62,6 @@ private:
|
|||
float _topMargin;
|
||||
float _bottomMargin;
|
||||
|
||||
BillboardMode _billboardMode;
|
||||
glm::vec3 _dimensions;
|
||||
|
||||
QString _font { "" };
|
||||
|
@ -90,7 +88,7 @@ public:
|
|||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
ItemKey getKey() const;
|
||||
Item::Bound getBound() const;
|
||||
Item::Bound getBound(RenderArgs* args) const;
|
||||
ShapeKey getShapeKey() const;
|
||||
void render(RenderArgs* args);
|
||||
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const;
|
||||
|
@ -106,7 +104,7 @@ protected:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const entities::TextPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const entities::TextPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const entities::TextPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const entities::TextPayload::Pointer& payload);
|
||||
template <> void payloadRender(const entities::TextPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones);
|
||||
|
|
|
@ -168,7 +168,6 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
|
|||
_color = entity->getColor();
|
||||
_alpha = entity->getAlpha();
|
||||
_pulseProperties = entity->getPulseProperties();
|
||||
_billboardMode = entity->getBillboardMode();
|
||||
|
||||
if (_contentType == ContentType::NoContent) {
|
||||
_tryingToBuildURL = newSourceURL;
|
||||
|
@ -267,17 +266,6 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
|
|||
});
|
||||
}
|
||||
|
||||
Item::Bound WebEntityRenderer::getBound() {
|
||||
auto bound = Parent::getBound();
|
||||
if (_billboardMode != BillboardMode::NONE) {
|
||||
glm::vec3 dimensions = bound.getScale();
|
||||
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
|
||||
const float SQRT_2 = 1.41421356237f;
|
||||
bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
|
||||
}
|
||||
return bound;
|
||||
}
|
||||
|
||||
void WebEntityRenderer::doRender(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("WebEntityRenderer::render");
|
||||
withWriteLock([&] {
|
||||
|
@ -307,14 +295,12 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
|
|||
gpu::Batch& batch = *args->_batch;
|
||||
glm::vec4 color;
|
||||
Transform transform;
|
||||
bool forward;
|
||||
bool transparent;
|
||||
withReadLock([&] {
|
||||
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
color = glm::vec4(toGlm(_color), _alpha * fadeRatio);
|
||||
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
|
||||
transform = _renderTransform;
|
||||
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
|
||||
transparent = isTransparent();
|
||||
});
|
||||
|
||||
|
@ -322,9 +308,12 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
|
||||
|
||||
batch.setResourceTexture(0, _texture);
|
||||
|
||||
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, 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
|
||||
|
|
|
@ -60,7 +60,6 @@ protected:
|
|||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||
virtual void doRender(RenderArgs* args) override;
|
||||
virtual bool isTransparent() const override;
|
||||
Item::Bound getBound() override;
|
||||
|
||||
virtual bool wantsHandControllerPointerEvents() const override { return true; }
|
||||
virtual bool wantsKeyboardFocus() const override { return true; }
|
||||
|
@ -91,7 +90,6 @@ private:
|
|||
glm::u8vec3 _color;
|
||||
float _alpha { 1.0f };
|
||||
PulsePropertyGroup _pulseProperties;
|
||||
BillboardMode _billboardMode;
|
||||
|
||||
QString _sourceURL;
|
||||
uint16_t _dpi;
|
||||
|
|
|
@ -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&)> EntityItem::_getBillboardRotationOperator = [](const glm::vec3&, const glm::quat& rotation, BillboardMode, const glm::vec3&) { return rotation; };
|
||||
std::function<glm::vec3()> EntityItem::_getPrimaryViewFrustumPositionOperator = []() { return glm::vec3(0.0f); };
|
||||
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
||||
SpatiallyNestable(NestableType::Entity, entityItemID)
|
||||
{
|
||||
|
@ -107,6 +104,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
|
|||
requestedProperties += PROP_PRIMITIVE_MODE;
|
||||
requestedProperties += PROP_IGNORE_PICK_INTERSECTION;
|
||||
requestedProperties += PROP_RENDER_WITH_ZONES;
|
||||
requestedProperties += PROP_BILLBOARD_MODE;
|
||||
requestedProperties += _grabProperties.getEntityProperties(params);
|
||||
|
||||
// Physics
|
||||
|
@ -303,6 +301,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
|||
APPEND_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, (uint32_t)getPrimitiveMode());
|
||||
APPEND_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, getIgnorePickIntersection());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, getRenderWithZones());
|
||||
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
|
||||
withReadLock([&] {
|
||||
_grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
|
@ -875,6 +874,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
READ_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, PrimitiveMode, setPrimitiveMode);
|
||||
READ_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, bool, setIgnorePickIntersection);
|
||||
READ_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, QVector<QUuid>, setRenderWithZones);
|
||||
READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
|
||||
withWriteLock([&] {
|
||||
int bytesFromGrab = _grabProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData,
|
||||
|
@ -1358,6 +1358,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(primitiveMode, getPrimitiveMode);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignorePickIntersection, getIgnorePickIntersection);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(renderWithZones, getRenderWithZones);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
|
||||
withReadLock([&] {
|
||||
_grabProperties.getProperties(properties);
|
||||
});
|
||||
|
@ -1508,6 +1509,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(primitiveMode, setPrimitiveMode);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignorePickIntersection, setIgnorePickIntersection);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(renderWithZones, setRenderWithZones);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
|
||||
withWriteLock([&] {
|
||||
bool grabPropertiesChanged = _grabProperties.setProperties(properties);
|
||||
somethingChanged |= grabPropertiesChanged;
|
||||
|
@ -3616,4 +3618,17 @@ QVector<QUuid> EntityItem::getRenderWithZones() const {
|
|||
return resultWithReadLock<QVector<QUuid>>([&] {
|
||||
return _renderWithZones;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
BillboardMode EntityItem::getBillboardMode() const {
|
||||
return resultWithReadLock<BillboardMode>([&] {
|
||||
return _billboardMode;
|
||||
});
|
||||
}
|
||||
|
||||
void EntityItem::setBillboardMode(BillboardMode value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _billboardMode != value;
|
||||
_billboardMode = value;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -175,12 +175,12 @@ public:
|
|||
|
||||
virtual bool supportsDetailedIntersection() const { return false; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const { return true; }
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const { return true; }
|
||||
|
||||
// attributes applicable to all entity types
|
||||
|
@ -203,7 +203,7 @@ public:
|
|||
/// Dimensions in meters (0.0 - TREE_SCALE)
|
||||
virtual glm::vec3 getScaledDimensions() const;
|
||||
virtual void setScaledDimensions(const glm::vec3& value);
|
||||
virtual glm::vec3 getRaycastDimensions() const { return getScaledDimensions(); }
|
||||
|
||||
virtual glm::vec3 getPivot() const { return glm::vec3(0.0f); } // pivot offset for positioning, mainly for model entities
|
||||
|
||||
glm::vec3 getUnscaledDimensions() const;
|
||||
|
@ -573,11 +573,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&)> getBillboardRotationOperator) { _getBillboardRotationOperator = getBillboardRotationOperator; }
|
||||
static glm::quat getBillboardRotation(const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos) { return _getBillboardRotationOperator(position, rotation, billboardMode, frustumPos); }
|
||||
static void setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; }
|
||||
static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); }
|
||||
|
||||
bool stillHasMyGrab() const;
|
||||
|
||||
bool needsRenderUpdate() const { return _needsRenderUpdate; }
|
||||
|
@ -588,6 +583,10 @@ public:
|
|||
bool needsZoneOcclusionUpdate() const { return _needsZoneOcclusionUpdate; }
|
||||
void resetNeedsZoneOcclusionUpdate() { withWriteLock([&] { _needsZoneOcclusionUpdate = false; }); }
|
||||
|
||||
void setBillboardMode(BillboardMode value);
|
||||
BillboardMode getBillboardMode() const;
|
||||
virtual bool getRotateForPicking() const { return false; }
|
||||
|
||||
signals:
|
||||
void spaceUpdate(std::pair<int32_t, glm::vec4> data);
|
||||
|
||||
|
@ -779,13 +778,11 @@ protected:
|
|||
QVector<QUuid> _renderWithZones;
|
||||
mutable bool _needsZoneOcclusionUpdate { false };
|
||||
|
||||
BillboardMode _billboardMode { BillboardMode::NONE };
|
||||
|
||||
bool _cullWithParent { false };
|
||||
|
||||
mutable bool _needsRenderUpdate { false };
|
||||
|
||||
private:
|
||||
static std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode, const glm::vec3&)> _getBillboardRotationOperator;
|
||||
static std::function<glm::vec3()> _getPrimaryViewFrustumPositionOperator;
|
||||
};
|
||||
|
||||
#endif // hifi_EntityItem_h
|
||||
|
|
|
@ -433,6 +433,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_PRIMITIVE_MODE, primitiveMode);
|
||||
CHECK_PROPERTY_CHANGE(PROP_IGNORE_PICK_INTERSECTION, ignorePickIntersection);
|
||||
CHECK_PROPERTY_CHANGE(PROP_RENDER_WITH_ZONES, renderWithZones);
|
||||
CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode);
|
||||
changedProperties += _grab.getChangedProperties();
|
||||
|
||||
// Physics
|
||||
|
@ -493,7 +494,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha);
|
||||
changedProperties += _pulse.getChangedProperties();
|
||||
CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures);
|
||||
CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode);
|
||||
|
||||
// Particles
|
||||
CHECK_PROPERTY_CHANGE(PROP_MAX_PARTICLES, maxParticles);
|
||||
|
@ -813,6 +813,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {Uuid[]} renderWithZones=[]] - A list of entity IDs representing with which zones this entity should render.
|
||||
* If it is empty, this entity will render normally. Otherwise, this entity will only render if your avatar is within
|
||||
* one of the zones in this list.
|
||||
* @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera. Use the rotation
|
||||
* property to control which axis is facing you.
|
||||
*
|
||||
* @property {Entities.Grab} grab - The entity's grab-related properties.
|
||||
*
|
||||
|
@ -1337,7 +1339,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {Entities.TextEffect} textEffect="none" - The effect that is applied to the text.
|
||||
* @property {Color} textEffectColor=255,255,255 - The color of the effect.
|
||||
* @property {number} textEffectThickness=0.2 - The magnitude of the text effect, range <code>0.0</code> – <code>0.5</code>.
|
||||
* @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera.
|
||||
* @property {boolean} faceCamera - <code>true</code> if <code>billboardMode</code> is <code>"yaw"</code>, <code>false</code>
|
||||
* if it isn't. Setting this property to <code>false</code> sets the <code>billboardMode</code> to <code>"none"</code>.
|
||||
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
|
||||
|
@ -1373,7 +1374,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {number} alpha=1 - The opacity of the web surface.
|
||||
* @property {Entities.Pulse} pulse - Color and alpha pulse.
|
||||
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
|
||||
* @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera.
|
||||
* @property {boolean} faceCamera - <code>true</code> if <code>billboardMode</code> is <code>"yaw"</code>, <code>false</code>
|
||||
* if it isn't. Setting this property to <code>false</code> sets the <code>billboardMode</code> to <code>"none"</code>.
|
||||
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
|
||||
|
@ -1495,7 +1495,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* @property {number} alpha=1 - The opacity of the image.
|
||||
* @property {Entities.Pulse} pulse - Color and alpha pulse.
|
||||
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
|
||||
* @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera.
|
||||
* @property {boolean} faceCamera - <code>true</code> if <code>billboardMode</code> is <code>"yaw"</code>, <code>false</code>
|
||||
* if it isn't. Setting this property to <code>false</code> sets the <code>billboardMode</code> to <code>"none"</code>.
|
||||
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
|
||||
|
@ -1619,6 +1618,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_PRIMITIVE_MODE, primitiveMode, getPrimitiveModeAsString());
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_PICK_INTERSECTION, ignorePickIntersection);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RENDER_WITH_ZONES, renderWithZones);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
|
||||
_grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
|
||||
|
||||
// Physics
|
||||
|
@ -1775,7 +1775,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
// Text only
|
||||
if (_type == EntityTypes::Text) {
|
||||
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT, text);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_HEIGHT, lineHeight);
|
||||
|
@ -1825,7 +1824,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
|
||||
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SOURCE_URL, sourceUrl);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DPI, dpi);
|
||||
|
@ -1894,7 +1892,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha);
|
||||
_pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString());
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IMAGE_URL, imageURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMISSIVE, emissive);
|
||||
|
@ -2042,6 +2039,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(primitiveMode, PrimitiveMode);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(ignorePickIntersection, bool, setIgnorePickIntersection);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(renderWithZones, qVectorQUuid, setRenderWithZones);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode);
|
||||
_grab.copyFromScriptValue(object, _defaultSettings);
|
||||
|
||||
// Physics
|
||||
|
@ -2107,7 +2105,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha);
|
||||
_pulse.copyFromScriptValue(object, _defaultSettings);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(textures, QString, setTextures);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode);
|
||||
|
||||
// Particles
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(maxParticles, quint32, setMaxParticles);
|
||||
|
@ -2341,6 +2338,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
|
|||
COPY_PROPERTY_IF_CHANGED(primitiveMode);
|
||||
COPY_PROPERTY_IF_CHANGED(ignorePickIntersection);
|
||||
COPY_PROPERTY_IF_CHANGED(renderWithZones);
|
||||
COPY_PROPERTY_IF_CHANGED(billboardMode);
|
||||
_grab.merge(other._grab);
|
||||
|
||||
// Physics
|
||||
|
@ -2401,7 +2399,6 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
|
|||
COPY_PROPERTY_IF_CHANGED(alpha);
|
||||
_pulse.merge(other._pulse);
|
||||
COPY_PROPERTY_IF_CHANGED(textures);
|
||||
COPY_PROPERTY_IF_CHANGED(billboardMode);
|
||||
|
||||
// Particles
|
||||
COPY_PROPERTY_IF_CHANGED(maxParticles);
|
||||
|
@ -2639,6 +2636,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
|
|||
ADD_PROPERTY_TO_MAP(PROP_PRIMITIVE_MODE, PrimitiveMode, primitiveMode, PrimitiveMode);
|
||||
ADD_PROPERTY_TO_MAP(PROP_IGNORE_PICK_INTERSECTION, IgnorePickIntersection, ignorePickIntersection, bool);
|
||||
ADD_PROPERTY_TO_MAP(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector<QUuid>);
|
||||
ADD_PROPERTY_TO_MAP(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode);
|
||||
{ // Grab
|
||||
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable);
|
||||
ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic);
|
||||
|
@ -2735,7 +2733,6 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
|
|||
ADD_GROUP_PROPERTY_TO_MAP(PROP_PULSE_ALPHA_MODE, Pulse, pulse, AlphaMode, alphaMode);
|
||||
}
|
||||
ADD_PROPERTY_TO_MAP(PROP_TEXTURES, Textures, textures, QString);
|
||||
ADD_PROPERTY_TO_MAP(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode);
|
||||
|
||||
// Particles
|
||||
ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32,
|
||||
|
@ -3133,6 +3130,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
APPEND_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, (uint32_t)properties.getPrimitiveMode());
|
||||
APPEND_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, properties.getIgnorePickIntersection());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, properties.getRenderWithZones());
|
||||
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
|
||||
_staticGrab.setProperties(properties);
|
||||
_staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags,
|
||||
propertiesDidntFit, propertyCount, appendState);
|
||||
|
@ -3266,7 +3264,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
_staticPulse.setProperties(properties);
|
||||
_staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags,
|
||||
propertiesDidntFit, propertyCount, appendState);
|
||||
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText());
|
||||
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight());
|
||||
|
@ -3338,7 +3335,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
_staticPulse.setProperties(properties);
|
||||
_staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags,
|
||||
propertiesDidntFit, propertyCount, appendState);
|
||||
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl());
|
||||
APPEND_ENTITY_PROPERTY(PROP_DPI, properties.getDPI());
|
||||
|
@ -3402,7 +3398,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
_staticPulse.setProperties(properties);
|
||||
_staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags,
|
||||
propertiesDidntFit, propertyCount, appendState);
|
||||
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, properties.getImageURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, properties.getEmissive());
|
||||
|
@ -3628,6 +3623,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PRIMITIVE_MODE, PrimitiveMode, setPrimitiveMode);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_PICK_INTERSECTION, bool, setIgnorePickIntersection);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_WITH_ZONES, QVector<QUuid>, setRenderWithZones);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
|
||||
properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
|
||||
|
||||
// Physics
|
||||
|
@ -3755,7 +3751,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
|
||||
if (properties.getType() == EntityTypes::Text) {
|
||||
properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
|
||||
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight);
|
||||
|
@ -3816,7 +3811,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
|
||||
properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
|
||||
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DPI, uint16_t, setDPI);
|
||||
|
@ -3877,7 +3871,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
|
||||
properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
|
||||
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IMAGE_URL, QString, setImageURL);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMISSIVE, bool, setEmissive);
|
||||
|
@ -4051,6 +4044,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_primitiveModeChanged = true;
|
||||
_ignorePickIntersectionChanged = true;
|
||||
_renderWithZonesChanged = true;
|
||||
_billboardModeChanged = true;
|
||||
_grab.markAllChanged();
|
||||
|
||||
// Physics
|
||||
|
@ -4104,7 +4098,6 @@ void EntityItemProperties::markAllChanged() {
|
|||
_alphaChanged = true;
|
||||
_pulse.markAllChanged();
|
||||
_texturesChanged = true;
|
||||
_billboardModeChanged = true;
|
||||
|
||||
// Particles
|
||||
_maxParticlesChanged = true;
|
||||
|
@ -4461,6 +4454,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
if (renderWithZonesChanged()) {
|
||||
out += "renderWithZones";
|
||||
}
|
||||
if (billboardModeChanged()) {
|
||||
out += "billboardMode";
|
||||
}
|
||||
getGrab().listChangedProperties(out);
|
||||
|
||||
// Physics
|
||||
|
@ -4596,9 +4592,6 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
if (texturesChanged()) {
|
||||
out += "textures";
|
||||
}
|
||||
if (billboardModeChanged()) {
|
||||
out += "billboardMode";
|
||||
}
|
||||
|
||||
// Particles
|
||||
if (maxParticlesChanged()) {
|
||||
|
|
|
@ -197,6 +197,7 @@ public:
|
|||
DEFINE_PROPERTY_REF_ENUM(PROP_PRIMITIVE_MODE, PrimitiveMode, primitiveMode, PrimitiveMode, PrimitiveMode::SOLID);
|
||||
DEFINE_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, IgnorePickIntersection, ignorePickIntersection, bool, false);
|
||||
DEFINE_PROPERTY_REF(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector<QUuid>, QVector<QUuid>());
|
||||
DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE);
|
||||
DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup);
|
||||
|
||||
// Physics
|
||||
|
@ -257,7 +258,6 @@ public:
|
|||
DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float, ENTITY_ITEM_DEFAULT_ALPHA);
|
||||
DEFINE_PROPERTY_GROUP(Pulse, pulse, PulsePropertyGroup);
|
||||
DEFINE_PROPERTY_REF(PROP_TEXTURES, Textures, textures, QString, "");
|
||||
DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE);
|
||||
|
||||
// Particles
|
||||
DEFINE_PROPERTY(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32, particle::DEFAULT_MAX_PARTICLES);
|
||||
|
|
|
@ -45,6 +45,7 @@ enum EntityPropertyList {
|
|||
PROP_PRIMITIVE_MODE,
|
||||
PROP_IGNORE_PICK_INTERSECTION,
|
||||
PROP_RENDER_WITH_ZONES,
|
||||
PROP_BILLBOARD_MODE,
|
||||
// Grab
|
||||
PROP_GRAB_GRABBABLE,
|
||||
PROP_GRAB_KINEMATIC,
|
||||
|
@ -122,7 +123,6 @@ enum EntityPropertyList {
|
|||
PROP_PULSE_COLOR_MODE,
|
||||
PROP_PULSE_ALPHA_MODE,
|
||||
PROP_TEXTURES,
|
||||
PROP_BILLBOARD_MODE,
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ATTENTION: add new shared EntityItem properties to the list ABOVE this line
|
||||
|
|
|
@ -798,6 +798,7 @@ public:
|
|||
glm::vec3 origin;
|
||||
glm::vec3 direction;
|
||||
glm::vec3 invDirection;
|
||||
glm::vec3 viewFrustumPos;
|
||||
const QVector<EntityItemID>& entityIdsToInclude;
|
||||
const QVector<EntityItemID>& entityIdsToDiscard;
|
||||
PickFilter searchFilter;
|
||||
|
@ -815,7 +816,7 @@ bool evalRayIntersectionOp(const OctreeElementPointer& element, void* extraData)
|
|||
RayArgs* args = static_cast<RayArgs*>(extraData);
|
||||
bool keepSearching = true;
|
||||
EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
EntityItemID entityID = entityTreeElementPointer->evalRayIntersection(args->origin, args->direction,
|
||||
EntityItemID entityID = entityTreeElementPointer->evalRayIntersection(args->origin, args->direction, args->viewFrustumPos,
|
||||
args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude,
|
||||
args->entityIdsToDiscard, args->searchFilter, args->extraInfo);
|
||||
if (!entityID.isNull()) {
|
||||
|
@ -837,7 +838,8 @@ float evalRayIntersectionSortingOp(const OctreeElementPointer& element, void* ex
|
|||
float boundDistance = FLT_MAX;
|
||||
BoxFace face;
|
||||
glm::vec3 surfaceNormal;
|
||||
if (entityTreeElementPointer->getAACube().findRayIntersection(args->origin, args->direction, args->invDirection, boundDistance, face, surfaceNormal)) {
|
||||
if (entityTreeElementPointer->getAACube().findRayIntersection(args->origin, args->direction, args->invDirection,
|
||||
boundDistance, face, surfaceNormal)) {
|
||||
// Don't add this cell if it's already farther than our best distance so far
|
||||
if (boundDistance < args->distance) {
|
||||
distance = boundDistance;
|
||||
|
@ -857,7 +859,7 @@ EntityItemID EntityTree::evalRayIntersection(const glm::vec3& origin, const glm:
|
|||
vec3 dirReciprocal = glm::vec3(direction.x == 0.0f ? 0.0f : 1.0f / direction.x,
|
||||
direction.y == 0.0f ? 0.0f : 1.0f / direction.y,
|
||||
direction.z == 0.0f ? 0.0f : 1.0f / direction.z);
|
||||
RayArgs args = { origin, direction, dirReciprocal, entityIdsToInclude, entityIdsToDiscard,
|
||||
RayArgs args = { origin, direction, dirReciprocal, BillboardModeHelpers::getPrimaryViewFrustumPosition(), entityIdsToInclude, entityIdsToDiscard,
|
||||
searchFilter, element, distance, face, surfaceNormal, extraInfo, EntityItemID() };
|
||||
distance = FLT_MAX;
|
||||
|
||||
|
@ -879,6 +881,7 @@ public:
|
|||
glm::vec3 origin;
|
||||
glm::vec3 velocity;
|
||||
glm::vec3 acceleration;
|
||||
glm::vec3 viewFrustumPos;
|
||||
const QVector<EntityItemID>& entityIdsToInclude;
|
||||
const QVector<EntityItemID>& entityIdsToDiscard;
|
||||
PickFilter searchFilter;
|
||||
|
@ -896,7 +899,7 @@ bool evalParabolaIntersectionOp(const OctreeElementPointer& element, void* extra
|
|||
ParabolaArgs* args = static_cast<ParabolaArgs*>(extraData);
|
||||
bool keepSearching = true;
|
||||
EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
EntityItemID entityID = entityTreeElementPointer->evalParabolaIntersection(args->origin, args->velocity, args->acceleration,
|
||||
EntityItemID entityID = entityTreeElementPointer->evalParabolaIntersection(args->origin, args->velocity, args->acceleration, args->viewFrustumPos,
|
||||
args->element, args->parabolicDistance, args->face, args->surfaceNormal, args->entityIdsToInclude,
|
||||
args->entityIdsToDiscard, args->searchFilter, args->extraInfo);
|
||||
if (!entityID.isNull()) {
|
||||
|
@ -918,7 +921,8 @@ float evalParabolaIntersectionSortingOp(const OctreeElementPointer& element, voi
|
|||
float boundDistance = FLT_MAX;
|
||||
BoxFace face;
|
||||
glm::vec3 surfaceNormal;
|
||||
if (entityTreeElementPointer->getAACube().findParabolaIntersection(args->origin, args->velocity, args->acceleration, boundDistance, face, surfaceNormal)) {
|
||||
if (entityTreeElementPointer->getAACube().findParabolaIntersection(args->origin, args->velocity, args->acceleration,
|
||||
boundDistance, face, surfaceNormal)) {
|
||||
// Don't add this cell if it's already farther than our best distance so far
|
||||
if (boundDistance < args->parabolicDistance) {
|
||||
distance = boundDistance;
|
||||
|
@ -934,8 +938,8 @@ EntityItemID EntityTree::evalParabolaIntersection(const PickParabola& parabola,
|
|||
OctreeElementPointer& element, glm::vec3& intersection, float& distance, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
|
||||
Octree::lockType lockType, bool* accurateResult) {
|
||||
ParabolaArgs args = { parabola.origin, parabola.velocity, parabola.acceleration, entityIdsToInclude, entityIdsToDiscard,
|
||||
searchFilter, element, parabolicDistance, face, surfaceNormal, extraInfo, EntityItemID() };
|
||||
ParabolaArgs args = { parabola.origin, parabola.velocity, parabola.acceleration, BillboardModeHelpers::getPrimaryViewFrustumPosition(),
|
||||
entityIdsToInclude, entityIdsToDiscard, searchFilter, element, parabolicDistance, face, surfaceNormal, extraInfo, EntityItemID() };
|
||||
parabolicDistance = FLT_MAX;
|
||||
distance = FLT_MAX;
|
||||
|
||||
|
@ -3137,6 +3141,13 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) {
|
|||
}
|
||||
}
|
||||
|
||||
// Before, billboarded entities ignored rotation. Now, they use it to determine which axis is facing you.
|
||||
if (contentVersion < (int)EntityVersion::AllBillboardMode) {
|
||||
if (properties.getBillboardMode() != BillboardMode::NONE) {
|
||||
properties.setRotation(glm::quat());
|
||||
}
|
||||
}
|
||||
|
||||
EntityItemPointer entity = addEntity(entityItemID, properties, isImport);
|
||||
if (!entity) {
|
||||
qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType();
|
||||
|
|
|
@ -162,7 +162,7 @@ bool EntityTreeElement::checkFilterSettings(const EntityItemPointer& entity, Pic
|
|||
return true;
|
||||
}
|
||||
|
||||
EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
|
||||
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIdsToDiscard,
|
||||
PickFilter searchFilter, QVariantMap& extraInfo) {
|
||||
|
@ -177,7 +177,7 @@ EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, con
|
|||
|
||||
QVariantMap localExtraInfo;
|
||||
float distanceToElementDetails = distance;
|
||||
EntityItemID entityID = evalDetailedRayIntersection(origin, direction, element, distanceToElementDetails,
|
||||
EntityItemID entityID = evalDetailedRayIntersection(origin, direction, viewFrustumPos, element, distanceToElementDetails,
|
||||
localFace, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, searchFilter, localExtraInfo);
|
||||
if (!entityID.isNull() && distanceToElementDetails < distance) {
|
||||
distance = distanceToElementDetails;
|
||||
|
@ -189,7 +189,7 @@ EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, con
|
|||
return result;
|
||||
}
|
||||
|
||||
EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
|
||||
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIDsToDiscard,
|
||||
PickFilter searchFilter, QVariantMap& extraInfo) {
|
||||
|
@ -216,12 +216,15 @@ EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& ori
|
|||
}
|
||||
|
||||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
|
||||
glm::mat4 translation = glm::translate(entity->getWorldPosition());
|
||||
glm::vec3 position = entity->getWorldPosition();
|
||||
glm::mat4 translation = glm::translate(position);
|
||||
glm::quat orientation = entity->getWorldOrientation();
|
||||
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, entity->getBillboardMode(),
|
||||
viewFrustumPos, entity->getRotateForPicking()));
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
||||
glm::vec3 dimensions = entity->getRaycastDimensions();
|
||||
glm::vec3 dimensions = entity->getScaledDimensions();
|
||||
glm::vec3 registrationPoint = entity->getRegistrationPoint();
|
||||
glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
|
||||
|
||||
|
@ -241,7 +244,7 @@ EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& ori
|
|||
// now ask the entity if we actually intersect
|
||||
if (entity->supportsDetailedIntersection()) {
|
||||
QVariantMap localExtraInfo;
|
||||
if (entity->findDetailedRayIntersection(origin, direction, element, localDistance,
|
||||
if (entity->findDetailedRayIntersection(origin, direction, viewFrustumPos, element, localDistance,
|
||||
localFace, localSurfaceNormal, localExtraInfo, searchFilter.isPrecise())) {
|
||||
if (localDistance < distance) {
|
||||
distance = localDistance;
|
||||
|
@ -296,7 +299,7 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad
|
|||
}
|
||||
|
||||
EntityItemID EntityTreeElement::evalParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo) {
|
||||
|
||||
|
@ -319,7 +322,7 @@ EntityItemID EntityTreeElement::evalParabolaIntersection(const glm::vec3& origin
|
|||
}
|
||||
// Get the normal of the plane, the cross product of two vectors on the plane
|
||||
glm::vec3 normal = glm::normalize(glm::cross(vectorOnPlane, acceleration));
|
||||
EntityItemID entityID = evalDetailedParabolaIntersection(origin, velocity, acceleration, normal, element, distanceToElementDetails,
|
||||
EntityItemID entityID = evalDetailedParabolaIntersection(origin, velocity, acceleration, viewFrustumPos, normal, element, distanceToElementDetails,
|
||||
localFace, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, searchFilter, localExtraInfo);
|
||||
if (!entityID.isNull() && distanceToElementDetails < parabolicDistance) {
|
||||
parabolicDistance = distanceToElementDetails;
|
||||
|
@ -332,9 +335,9 @@ EntityItemID EntityTreeElement::evalParabolaIntersection(const glm::vec3& origin
|
|||
}
|
||||
|
||||
EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
const glm::vec3& normal, OctreeElementPointer& element, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIDsToDiscard,
|
||||
PickFilter searchFilter, QVariantMap& extraInfo) {
|
||||
const glm::vec3& viewFrustumPos,const glm::vec3& normal, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIDsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo) {
|
||||
|
||||
// only called if we do intersect our bounding cube, but find if we actually intersect with entities...
|
||||
EntityItemID entityID;
|
||||
|
@ -363,12 +366,15 @@ EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3
|
|||
}
|
||||
|
||||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
|
||||
glm::mat4 translation = glm::translate(entity->getWorldPosition());
|
||||
glm::vec3 position = entity->getWorldPosition();
|
||||
glm::mat4 translation = glm::translate(position);
|
||||
glm::quat orientation = entity->getWorldOrientation();
|
||||
glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, entity->getBillboardMode(),
|
||||
viewFrustumPos, entity->getRotateForPicking()));
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
||||
glm::vec3 dimensions = entity->getRaycastDimensions();
|
||||
glm::vec3 dimensions = entity->getScaledDimensions();
|
||||
glm::vec3 registrationPoint = entity->getRegistrationPoint();
|
||||
glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
|
||||
|
||||
|
@ -389,7 +395,7 @@ EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3
|
|||
// now ask the entity if we actually intersect
|
||||
if (entity->supportsDetailedIntersection()) {
|
||||
QVariantMap localExtraInfo;
|
||||
if (entity->findDetailedParabolaIntersection(origin, velocity, acceleration, element, localDistance,
|
||||
if (entity->findDetailedParabolaIntersection(origin, velocity, acceleration, viewFrustumPos, element, localDistance,
|
||||
localFace, localSurfaceNormal, localExtraInfo, searchFilter.isPrecise())) {
|
||||
if (localDistance < parabolicDistance) {
|
||||
parabolicDistance = localDistance;
|
||||
|
@ -444,7 +450,7 @@ void EntityTreeElement::evalEntitiesInSphere(const glm::vec3& position, float ra
|
|||
glm::vec3 penetration;
|
||||
if (success && entityBox.findSpherePenetration(position, radius, penetration)) {
|
||||
|
||||
glm::vec3 dimensions = entity->getRaycastDimensions();
|
||||
glm::vec3 dimensions = entity->getScaledDimensions();
|
||||
|
||||
// FIXME - consider allowing the entity to determine penetration so that
|
||||
// entities could presumably do actual hull testing if they wanted to
|
||||
|
@ -465,8 +471,8 @@ void EntityTreeElement::evalEntitiesInSphere(const glm::vec3& position, float ra
|
|||
} else {
|
||||
// determine the worldToEntityMatrix that doesn't include scale because
|
||||
// we're going to use the registration aware aa box in the entity frame
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
|
||||
glm::mat4 translation = glm::translate(entity->getWorldPosition());
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
||||
|
@ -496,7 +502,7 @@ void EntityTreeElement::evalEntitiesInSphereWithType(const glm::vec3& position,
|
|||
glm::vec3 penetration;
|
||||
if (success && entityBox.findSpherePenetration(position, radius, penetration)) {
|
||||
|
||||
glm::vec3 dimensions = entity->getRaycastDimensions();
|
||||
glm::vec3 dimensions = entity->getScaledDimensions();
|
||||
|
||||
// FIXME - consider allowing the entity to determine penetration so that
|
||||
// entities could presumably do actual hull testing if they wanted to
|
||||
|
@ -517,8 +523,8 @@ void EntityTreeElement::evalEntitiesInSphereWithType(const glm::vec3& position,
|
|||
} else {
|
||||
// determine the worldToEntityMatrix that doesn't include scale because
|
||||
// we're going to use the registration aware aa box in the entity frame
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
|
||||
glm::mat4 translation = glm::translate(entity->getWorldPosition());
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
||||
|
@ -554,7 +560,7 @@ void EntityTreeElement::evalEntitiesInSphereWithName(const glm::vec3& position,
|
|||
glm::vec3 penetration;
|
||||
if (success && entityBox.findSpherePenetration(position, radius, penetration)) {
|
||||
|
||||
glm::vec3 dimensions = entity->getRaycastDimensions();
|
||||
glm::vec3 dimensions = entity->getScaledDimensions();
|
||||
|
||||
// FIXME - consider allowing the entity to determine penetration so that
|
||||
// entities could presumably do actual hull testing if they wanted to
|
||||
|
@ -575,8 +581,8 @@ void EntityTreeElement::evalEntitiesInSphereWithName(const glm::vec3& position,
|
|||
} else {
|
||||
// determine the worldToEntityMatrix that doesn't include scale because
|
||||
// we're going to use the registration aware aa box in the entity frame
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
|
||||
glm::mat4 translation = glm::translate(entity->getWorldPosition());
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation());
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
||||
|
|
|
@ -136,24 +136,24 @@ public:
|
|||
|
||||
static bool checkFilterSettings(const EntityItemPointer& entity, PickFilter searchFilter);
|
||||
virtual bool canPickIntersect() const override { return hasEntities(); }
|
||||
virtual EntityItemID evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
virtual EntityItemID evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
|
||||
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIdsToDiscard,
|
||||
PickFilter searchFilter, QVariantMap& extraInfo);
|
||||
virtual EntityItemID evalDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
|
||||
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
||||
glm::vec3& penetration, void** penetratedObject) const override;
|
||||
|
||||
virtual EntityItemID evalParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
|
||||
virtual EntityItemID evalDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& normal, const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const glm::vec3& normal, const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
|
||||
|
||||
template <typename F>
|
||||
|
|
|
@ -103,14 +103,15 @@ bool GizmoEntityItem::supportsDetailedIntersection() const {
|
|||
}
|
||||
|
||||
bool GizmoEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.z);
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
rotation = glm::angleAxis(-(float)M_PI_2, rotation * Vectors::RIGHT) * rotation;
|
||||
rotation *= glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
|
||||
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
|
||||
glm::vec3 hitPosition = origin + (distance * direction);
|
||||
|
@ -136,15 +137,16 @@ bool GizmoEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
|
|||
}
|
||||
|
||||
bool GizmoEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
OctreeElementPointer& element, float& parabolicDistance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
//// Scale the dimensions by the diameter
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.z);
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
rotation = glm::angleAxis(-(float)M_PI_2, rotation * Vectors::RIGHT) * rotation;
|
||||
rotation *= glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
|
||||
glm::vec3 position = getWorldPosition();
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
|
||||
glm::quat inverseRot = glm::inverse(rotation);
|
||||
glm::vec3 localOrigin = inverseRot * (origin - position);
|
||||
|
|
|
@ -45,13 +45,14 @@ public:
|
|||
|
||||
bool supportsDetailedIntersection() const override;
|
||||
bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
bool getRotateForPicking() const override { return getBillboardMode() != BillboardMode::NONE; }
|
||||
|
||||
GizmoType getGizmoType() const;
|
||||
void setGizmoType(GizmoType value);
|
||||
|
|
|
@ -35,7 +35,6 @@ EntityItemProperties ImageEntityItem::getProperties(const EntityPropertyFlags& d
|
|||
withReadLock([&] {
|
||||
_pulseProperties.getProperties(properties);
|
||||
});
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getImageURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emissive, getEmissive);
|
||||
|
@ -55,7 +54,6 @@ bool ImageEntityItem::setSubClassProperties(const EntityItemProperties& properti
|
|||
somethingChanged |= pulsePropertiesChanged;
|
||||
_needsRenderUpdate |= pulsePropertiesChanged;
|
||||
});
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setImageURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emissive, setEmissive);
|
||||
|
@ -82,7 +80,6 @@ int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
bytesRead += bytesFromPulse;
|
||||
dataAt += bytesFromPulse;
|
||||
});
|
||||
READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_IMAGE_URL, QString, setImageURL);
|
||||
READ_ENTITY_PROPERTY(PROP_EMISSIVE, bool, setEmissive);
|
||||
|
@ -98,7 +95,6 @@ EntityPropertyFlags ImageEntityItem::getEntityProperties(EncodeBitstreamParams&
|
|||
requestedProperties += PROP_COLOR;
|
||||
requestedProperties += PROP_ALPHA;
|
||||
requestedProperties += _pulseProperties.getEntityProperties(params);
|
||||
requestedProperties += PROP_BILLBOARD_MODE;
|
||||
|
||||
requestedProperties += PROP_IMAGE_URL;
|
||||
requestedProperties += PROP_EMISSIVE;
|
||||
|
@ -124,7 +120,6 @@ void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
_pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
});
|
||||
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, getImageURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, getEmissive());
|
||||
|
@ -132,69 +127,6 @@ void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
APPEND_ENTITY_PROPERTY(PROP_SUB_IMAGE, getSubImage());
|
||||
}
|
||||
|
||||
glm::vec3 ImageEntityItem::getRaycastDimensions() const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
if (getBillboardMode() != BillboardMode::NONE) {
|
||||
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
|
||||
const float SQRT_2 = 1.41421356237f;
|
||||
return glm::vec3(SQRT_2 * max);
|
||||
}
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
bool ImageEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
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, _billboardMode, EntityItem::getPrimaryViewFrustumPosition());
|
||||
|
||||
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
|
||||
glm::vec3 forward = rotation * Vectors::FRONT;
|
||||
if (glm::dot(forward, direction) > 0.0f) {
|
||||
face = MAX_Z_FACE;
|
||||
surfaceNormal = -forward;
|
||||
} else {
|
||||
face = MIN_Z_FACE;
|
||||
surfaceNormal = forward;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ImageEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
|
||||
glm::quat inverseRot = glm::inverse(rotation);
|
||||
glm::vec3 localOrigin = inverseRot * (origin - position);
|
||||
glm::vec3 localVelocity = inverseRot * velocity;
|
||||
glm::vec3 localAcceleration = inverseRot * acceleration;
|
||||
|
||||
if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, xyDimensions, parabolicDistance)) {
|
||||
float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance;
|
||||
glm::vec3 forward = rotation * Vectors::FRONT;
|
||||
if (localIntersectionVelocityZ > 0.0f) {
|
||||
face = MIN_Z_FACE;
|
||||
surfaceNormal = forward;
|
||||
} else {
|
||||
face = MAX_Z_FACE;
|
||||
surfaceNormal = -forward;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QString ImageEntityItem::getImageURL() const {
|
||||
QString result;
|
||||
withReadLock([&] {
|
||||
|
@ -240,21 +172,6 @@ void ImageEntityItem::setKeepAspectRatio(bool keepAspectRatio) {
|
|||
});
|
||||
}
|
||||
|
||||
BillboardMode ImageEntityItem::getBillboardMode() const {
|
||||
BillboardMode result;
|
||||
withReadLock([&] {
|
||||
result = _billboardMode;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void ImageEntityItem::setBillboardMode(BillboardMode value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _billboardMode != value;
|
||||
_billboardMode = value;
|
||||
});
|
||||
}
|
||||
|
||||
QRect ImageEntityItem::getSubImage() const {
|
||||
QRect result;
|
||||
withReadLock([&] {
|
||||
|
|
|
@ -43,17 +43,6 @@ public:
|
|||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
bool& somethingChanged) override;
|
||||
|
||||
glm::vec3 getRaycastDimensions() const override;
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
void setImageURL(const QString& imageUrl);
|
||||
QString getImageURL() const;
|
||||
|
||||
|
@ -63,9 +52,6 @@ public:
|
|||
void setKeepAspectRatio(bool keepAspectRatio);
|
||||
bool getKeepAspectRatio() const;
|
||||
|
||||
void setBillboardMode(BillboardMode value);
|
||||
BillboardMode getBillboardMode() const;
|
||||
|
||||
void setSubImage(const QRect& subImage);
|
||||
QRect getSubImage() const;
|
||||
|
||||
|
@ -81,7 +67,6 @@ protected:
|
|||
glm::u8vec3 _color;
|
||||
float _alpha;
|
||||
PulsePropertyGroup _pulseProperties;
|
||||
BillboardMode _billboardMode;
|
||||
|
||||
QString _imageURL;
|
||||
bool _emissive { false };
|
||||
|
|
|
@ -254,7 +254,7 @@ float LightEntityItem::getCutoff() const {
|
|||
}
|
||||
|
||||
bool LightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
|
||||
|
@ -267,8 +267,8 @@ bool LightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
|
|||
}
|
||||
|
||||
bool LightEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
// TODO: consider if this is really what we want to do. We've made it so that "lights are pickable" is a global state
|
||||
// this is probably reasonable since there's typically only one tree you'd be picking on at a time. Technically we could
|
||||
|
|
|
@ -74,12 +74,12 @@ public:
|
|||
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -52,13 +52,13 @@ class LineEntityItem : public EntityItem {
|
|||
// never have a ray intersection pick a LineEntityItem.
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo,
|
||||
bool precisionPicking) const override { return false; }
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo,
|
||||
bool precisionPicking) const override { return false; }
|
||||
|
||||
|
|
|
@ -82,12 +82,12 @@ public:
|
|||
// never have a ray intersection pick a PolyLineEntityItem.
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
|
||||
|
||||
void computeTightLocalBoundingBox(AABox& box) const;
|
||||
|
|
|
@ -377,15 +377,21 @@ glm::mat4 PolyVoxEntityItem::localToVoxelMatrix() const {
|
|||
return localToModelMatrix;
|
||||
}
|
||||
|
||||
glm::mat4 PolyVoxEntityItem::voxelToWorldMatrix() const {
|
||||
glm::mat4 rotation = glm::mat4_cast(getWorldOrientation());
|
||||
glm::mat4 translation = glm::translate(getWorldPosition());
|
||||
glm::mat4 PolyVoxEntityItem::voxelToWorldMatrix(bool includeBillboard) const {
|
||||
glm::quat orientation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition();
|
||||
glm::mat4 translation = glm::translate(position);
|
||||
glm::mat4 rotation;
|
||||
if (includeBillboard) {
|
||||
rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition()));
|
||||
} else {
|
||||
rotation = glm::mat4_cast(orientation);
|
||||
}
|
||||
return translation * rotation * voxelToLocalMatrix();
|
||||
}
|
||||
|
||||
glm::mat4 PolyVoxEntityItem::worldToVoxelMatrix() const {
|
||||
glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix());
|
||||
return worldToModelMatrix;
|
||||
glm::mat4 PolyVoxEntityItem::worldToVoxelMatrix(bool includeBillboard) const {
|
||||
return glm::inverse(voxelToWorldMatrix(includeBillboard));
|
||||
}
|
||||
|
||||
glm::vec3 PolyVoxEntityItem::voxelCoordsToWorldCoords(const glm::vec3& voxelCoords) const {
|
||||
|
|
|
@ -44,12 +44,12 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
// never have a ray intersection pick a PolyVoxEntityItem.
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
|
||||
|
||||
virtual void debugDump() const override;
|
||||
|
@ -167,8 +167,8 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
|
||||
bool isEdged() const;
|
||||
|
||||
glm::mat4 voxelToWorldMatrix() const;
|
||||
glm::mat4 worldToVoxelMatrix() const;
|
||||
glm::mat4 voxelToWorldMatrix(bool includeBillboard = false) const;
|
||||
glm::mat4 worldToVoxelMatrix(bool includeBillboard = false) const;
|
||||
glm::mat4 voxelToLocalMatrix() const;
|
||||
glm::mat4 localToVoxelMatrix() const;
|
||||
|
||||
|
|
|
@ -257,7 +257,8 @@ float ShapeEntityItem::getAlpha() const {
|
|||
|
||||
void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
||||
const float MAX_FLAT_DIMENSION = 0.0001f;
|
||||
if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {
|
||||
const auto shape = getShape();
|
||||
if ((shape == entity::Shape::Circle || shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {
|
||||
// enforce flatness in Y
|
||||
glm::vec3 newDimensions = value;
|
||||
newDimensions.y = MAX_FLAT_DIMENSION;
|
||||
|
@ -268,15 +269,20 @@ void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
|||
}
|
||||
|
||||
bool ShapeEntityItem::supportsDetailedIntersection() const {
|
||||
return _shape == entity::Sphere;
|
||||
return getShape() == entity::Sphere;
|
||||
}
|
||||
|
||||
bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
|
||||
// determine the ray in the frame of the entity transformed from a unit sphere
|
||||
glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix();
|
||||
glm::mat4 entityToWorldMatrix = glm::translate(position) * glm::mat4_cast(rotation) * glm::scale(dimensions);
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
|
||||
|
@ -299,11 +305,16 @@ bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
|
|||
}
|
||||
|
||||
bool ShapeEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
OctreeElementPointer& element, float& parabolicDistance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
|
||||
// determine the parabola in the frame of the entity transformed from a unit sphere
|
||||
glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix();
|
||||
glm::mat4 entityToWorldMatrix = glm::translate(position) * glm::mat4_cast(rotation) * glm::scale(dimensions);
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 entityFrameVelocity = glm::vec3(worldToEntityMatrix * glm::vec4(velocity, 0.0f));
|
||||
|
@ -324,6 +335,11 @@ bool ShapeEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ShapeEntityItem::getRotateForPicking() const {
|
||||
auto shape = getShape();
|
||||
return getBillboardMode() != BillboardMode::NONE && (_shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron);
|
||||
}
|
||||
|
||||
void ShapeEntityItem::debugDump() const {
|
||||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
|
@ -343,8 +359,9 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
// is set.
|
||||
|
||||
const glm::vec3 entityDimensions = getScaledDimensions();
|
||||
const auto shape = getShape();
|
||||
|
||||
switch (_shape){
|
||||
switch (shape){
|
||||
case entity::Shape::Quad:
|
||||
// Quads collide like flat Cubes
|
||||
case entity::Shape::Cube: {
|
||||
|
|
|
@ -86,13 +86,14 @@ public:
|
|||
|
||||
bool supportsDetailedIntersection() const override;
|
||||
bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
bool getRotateForPicking() const override;
|
||||
|
||||
void debugDump() const override;
|
||||
|
||||
|
|
|
@ -53,7 +53,6 @@ EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& de
|
|||
withReadLock([&] {
|
||||
_pulseProperties.getProperties(properties);
|
||||
});
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(text, getText);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight);
|
||||
|
@ -81,7 +80,6 @@ bool TextEntityItem::setSubClassProperties(const EntityItemProperties& propertie
|
|||
somethingChanged |= pulsePropertiesChanged;
|
||||
_needsRenderUpdate |= pulsePropertiesChanged;
|
||||
});
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(text, setText);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineHeight, setLineHeight);
|
||||
|
@ -117,7 +115,6 @@ int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
bytesRead += bytesFromPulse;
|
||||
dataAt += bytesFromPulse;
|
||||
});
|
||||
READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_TEXT, QString, setText);
|
||||
READ_ENTITY_PROPERTY(PROP_LINE_HEIGHT, float, setLineHeight);
|
||||
|
@ -142,7 +139,6 @@ EntityPropertyFlags TextEntityItem::getEntityProperties(EncodeBitstreamParams& p
|
|||
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
||||
|
||||
requestedProperties += _pulseProperties.getEntityProperties(params);
|
||||
requestedProperties += PROP_BILLBOARD_MODE;
|
||||
|
||||
requestedProperties += PROP_TEXT;
|
||||
requestedProperties += PROP_LINE_HEIGHT;
|
||||
|
@ -177,7 +173,6 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
|
|||
_pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
});
|
||||
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXT, getText());
|
||||
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, getLineHeight());
|
||||
|
@ -196,69 +191,6 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
|
|||
APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT_THICKNESS, getTextEffectThickness());
|
||||
}
|
||||
|
||||
glm::vec3 TextEntityItem::getRaycastDimensions() const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
if (getBillboardMode() != BillboardMode::NONE) {
|
||||
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
|
||||
const float SQRT_2 = 1.41421356237f;
|
||||
return glm::vec3(SQRT_2 * max);
|
||||
}
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
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, _billboardMode, EntityItem::getPrimaryViewFrustumPosition());
|
||||
|
||||
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
|
||||
glm::vec3 forward = rotation * Vectors::FRONT;
|
||||
if (glm::dot(forward, direction) > 0.0f) {
|
||||
face = MAX_Z_FACE;
|
||||
surfaceNormal = -forward;
|
||||
} else {
|
||||
face = MIN_Z_FACE;
|
||||
surfaceNormal = forward;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TextEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
|
||||
glm::quat inverseRot = glm::inverse(rotation);
|
||||
glm::vec3 localOrigin = inverseRot * (origin - position);
|
||||
glm::vec3 localVelocity = inverseRot * velocity;
|
||||
glm::vec3 localAcceleration = inverseRot * acceleration;
|
||||
|
||||
if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, xyDimensions, parabolicDistance)) {
|
||||
float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance;
|
||||
glm::vec3 forward = rotation * Vectors::FRONT;
|
||||
if (localIntersectionVelocityZ > 0.0f) {
|
||||
face = MIN_Z_FACE;
|
||||
surfaceNormal = forward;
|
||||
} else {
|
||||
face = MAX_Z_FACE;
|
||||
surfaceNormal = -forward;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TextEntityItem::setText(const QString& value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _text != value;
|
||||
|
@ -339,21 +271,6 @@ float TextEntityItem::getBackgroundAlpha() const {
|
|||
});
|
||||
}
|
||||
|
||||
BillboardMode TextEntityItem::getBillboardMode() const {
|
||||
BillboardMode result;
|
||||
withReadLock([&] {
|
||||
result = _billboardMode;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void TextEntityItem::setBillboardMode(BillboardMode value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _billboardMode != value;
|
||||
_billboardMode = value;
|
||||
});
|
||||
}
|
||||
|
||||
void TextEntityItem::setLeftMargin(float value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _leftMargin != value;
|
||||
|
|
|
@ -48,17 +48,6 @@ public:
|
|||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
bool& somethingChanged) override;
|
||||
|
||||
glm::vec3 getRaycastDimensions() const override;
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
static const QString DEFAULT_TEXT;
|
||||
void setText(const QString& value);
|
||||
QString getText() const;
|
||||
|
@ -82,9 +71,6 @@ public:
|
|||
float getBackgroundAlpha() const;
|
||||
void setBackgroundAlpha(float value);
|
||||
|
||||
BillboardMode getBillboardMode() const;
|
||||
void setBillboardMode(BillboardMode value);
|
||||
|
||||
static const float DEFAULT_MARGIN;
|
||||
float getLeftMargin() const;
|
||||
void setLeftMargin(float value);
|
||||
|
@ -117,8 +103,6 @@ public:
|
|||
PulsePropertyGroup getPulseProperties() const;
|
||||
|
||||
private:
|
||||
BillboardMode _billboardMode;
|
||||
|
||||
QString _text;
|
||||
float _lineHeight;
|
||||
glm::u8vec3 _textColor;
|
||||
|
|
|
@ -55,7 +55,6 @@ EntityItemProperties WebEntityItem::getProperties(const EntityPropertyFlags& des
|
|||
withReadLock([&] {
|
||||
_pulseProperties.getProperties(properties);
|
||||
});
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(sourceUrl, getSourceUrl);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(dpi, getDPI);
|
||||
|
@ -78,7 +77,6 @@ bool WebEntityItem::setSubClassProperties(const EntityItemProperties& properties
|
|||
somethingChanged |= pulsePropertiesChanged;
|
||||
_needsRenderUpdate |= pulsePropertiesChanged;
|
||||
});
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(sourceUrl, setSourceUrl);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dpi, setDPI);
|
||||
|
@ -109,7 +107,6 @@ int WebEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, i
|
|||
bytesRead += bytesFromPulse;
|
||||
dataAt += bytesFromPulse;
|
||||
});
|
||||
READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_SOURCE_URL, QString, setSourceUrl);
|
||||
READ_ENTITY_PROPERTY(PROP_DPI, uint16_t, setDPI);
|
||||
|
@ -128,7 +125,6 @@ EntityPropertyFlags WebEntityItem::getEntityProperties(EncodeBitstreamParams& pa
|
|||
requestedProperties += PROP_COLOR;
|
||||
requestedProperties += PROP_ALPHA;
|
||||
requestedProperties += _pulseProperties.getEntityProperties(params);
|
||||
requestedProperties += PROP_BILLBOARD_MODE;
|
||||
|
||||
requestedProperties += PROP_SOURCE_URL;
|
||||
requestedProperties += PROP_DPI;
|
||||
|
@ -156,7 +152,6 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
|
|||
_pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
});
|
||||
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, getSourceUrl());
|
||||
APPEND_ENTITY_PROPERTY(PROP_DPI, getDPI());
|
||||
|
@ -168,71 +163,6 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
|
|||
APPEND_ENTITY_PROPERTY(PROP_USER_AGENT, getUserAgent());
|
||||
}
|
||||
|
||||
glm::vec3 WebEntityItem::getRaycastDimensions() const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
if (getBillboardMode() != BillboardMode::NONE) {
|
||||
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
|
||||
const float SQRT_2 = 1.41421356237f;
|
||||
return glm::vec3(SQRT_2 * max);
|
||||
}
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
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, _billboardMode, EntityItem::getPrimaryViewFrustumPosition());
|
||||
|
||||
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
|
||||
glm::vec3 forward = rotation * Vectors::FRONT;
|
||||
if (glm::dot(forward, direction) > 0.0f) {
|
||||
face = MAX_Z_FACE;
|
||||
surfaceNormal = -forward;
|
||||
} else {
|
||||
face = MIN_Z_FACE;
|
||||
surfaceNormal = forward;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool WebEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
|
||||
glm::quat inverseRot = glm::inverse(rotation);
|
||||
glm::vec3 localOrigin = inverseRot * (origin - position);
|
||||
glm::vec3 localVelocity = inverseRot * velocity;
|
||||
glm::vec3 localAcceleration = inverseRot * acceleration;
|
||||
|
||||
if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, xyDimensions, parabolicDistance)) {
|
||||
float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance;
|
||||
glm::vec3 forward = rotation * Vectors::FRONT;
|
||||
if (localIntersectionVelocityZ > 0.0f) {
|
||||
face = MIN_Z_FACE;
|
||||
surfaceNormal = forward;
|
||||
} else {
|
||||
face = MAX_Z_FACE;
|
||||
surfaceNormal = -forward;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void WebEntityItem::setColor(const glm::u8vec3& value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _color != value;
|
||||
|
@ -265,19 +195,6 @@ float WebEntityItem::getAlpha() const {
|
|||
});
|
||||
}
|
||||
|
||||
BillboardMode WebEntityItem::getBillboardMode() const {
|
||||
return resultWithReadLock<BillboardMode>([&] {
|
||||
return _billboardMode;
|
||||
});
|
||||
}
|
||||
|
||||
void WebEntityItem::setBillboardMode(BillboardMode value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _billboardMode != value;
|
||||
_billboardMode = value;
|
||||
});
|
||||
}
|
||||
|
||||
void WebEntityItem::setSourceUrl(const QString& value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _sourceUrl != value;
|
||||
|
|
|
@ -45,26 +45,12 @@ public:
|
|||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
bool& somethingChanged) override;
|
||||
|
||||
glm::vec3 getRaycastDimensions() const override;
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
glm::u8vec3 getColor() const;
|
||||
void setColor(const glm::u8vec3& value);
|
||||
|
||||
float getAlpha() const;
|
||||
void setAlpha(float alpha);
|
||||
|
||||
void setBillboardMode(BillboardMode value);
|
||||
BillboardMode getBillboardMode() const;
|
||||
|
||||
static const QString DEFAULT_SOURCE_URL;
|
||||
void setSourceUrl(const QString& value);
|
||||
QString getSourceUrl() const;
|
||||
|
@ -100,7 +86,6 @@ protected:
|
|||
glm::u8vec3 _color;
|
||||
float _alpha { 1.0f };
|
||||
PulsePropertyGroup _pulseProperties;
|
||||
BillboardMode _billboardMode;
|
||||
|
||||
QString _sourceUrl;
|
||||
uint16_t _dpi;
|
||||
|
|
|
@ -318,15 +318,15 @@ void ZoneEntityItem::setCompoundShapeURL(const QString& url) {
|
|||
}
|
||||
|
||||
bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
return _zonesArePickable;
|
||||
}
|
||||
|
||||
bool ZoneEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
return _zonesArePickable;
|
||||
}
|
||||
|
|
|
@ -116,12 +116,12 @@ public:
|
|||
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
bool contains(const glm::vec3& point) const override;
|
||||
|
|
|
@ -285,6 +285,7 @@ enum class EntityVersion : PacketVersion {
|
|||
TransparentWeb,
|
||||
UseOriginalPivot,
|
||||
UserAgent,
|
||||
AllBillboardMode,
|
||||
|
||||
// Add new versions above here
|
||||
NUM_PACKET_TYPE,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
set(TARGET_NAME procedural)
|
||||
setup_hifi_library()
|
||||
|
||||
link_hifi_libraries(shared gpu shaders networking graphics material-networking ktx image hfm)
|
||||
link_hifi_libraries(shared gpu shaders networking render graphics material-networking ktx image hfm)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QJsonArray>
|
||||
|
||||
#include <render/Args.h>
|
||||
#include <gpu/Shader.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
@ -113,9 +114,9 @@ public:
|
|||
void setDoesFade(bool doesFade) { _doesFade = doesFade; }
|
||||
|
||||
bool hasVertexShader() const;
|
||||
void setBoundOperator(const std::function<AABox()>& boundOperator) { _boundOperator = boundOperator; }
|
||||
void setBoundOperator(const std::function<AABox(RenderArgs*)>& boundOperator) { _boundOperator = boundOperator; }
|
||||
bool hasBoundOperator() const { return (bool)_boundOperator; }
|
||||
AABox getBound() { return _boundOperator(); }
|
||||
AABox getBound(RenderArgs* args) { return _boundOperator(args); }
|
||||
|
||||
gpu::Shader::Source _vertexSource;
|
||||
gpu::Shader::Source _vertexSourceSkinned;
|
||||
|
@ -199,7 +200,7 @@ private:
|
|||
bool _doesFade { true };
|
||||
ProceduralProgramKey _prevKey;
|
||||
|
||||
std::function<AABox()> _boundOperator { nullptr };
|
||||
std::function<AABox(RenderArgs*)> _boundOperator { nullptr };
|
||||
|
||||
mutable std::mutex _mutex;
|
||||
};
|
||||
|
@ -232,9 +233,9 @@ public:
|
|||
|
||||
void initializeProcedural();
|
||||
|
||||
void setBoundOperator(const std::function<AABox()>& boundOperator) { _procedural.setBoundOperator(boundOperator); }
|
||||
void setBoundOperator(const std::function<AABox(RenderArgs*)>& boundOperator) { _procedural.setBoundOperator(boundOperator); }
|
||||
bool hasBoundOperator() const { return _procedural.hasBoundOperator(); }
|
||||
AABox getBound() { return _procedural.getBound(); }
|
||||
AABox getBound(RenderArgs* args) { return _procedural.getBound(args); }
|
||||
|
||||
private:
|
||||
QString _proceduralString;
|
||||
|
|
|
@ -68,7 +68,7 @@ typedef render::Payload<AnimDebugDrawData> AnimDebugDrawPayload;
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::transparentShape() : ItemKey::Builder::transparentShape().withInvisible()).withTagBits(ItemKey::TAG_BITS_ALL); }
|
||||
template <> const Item::Bound payloadGetBound(const AnimDebugDrawData::Pointer& data) { return data->_bound; }
|
||||
template <> const Item::Bound payloadGetBound(const AnimDebugDrawData::Pointer& data, RenderArgs* args) { return data->_bound; }
|
||||
template <> void payloadRender(const AnimDebugDrawData::Pointer& data, RenderArgs* args) {
|
||||
data->render(args);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -575,7 +575,7 @@ void FadeJob::run(const render::RenderContextPointer& renderContext, FadeJob::Ou
|
|||
auto& item = scene->getItem(state.itemId);
|
||||
assert(item.getTransitionId() == transitionId);
|
||||
#endif
|
||||
if (update(*jobConfig, scene, transaction, state, deltaTime)) {
|
||||
if (update(renderContext->args, *jobConfig, scene, transaction, state, deltaTime)) {
|
||||
hasTransaction = true;
|
||||
}
|
||||
if (isFirstItem && (state.threshold != jobConfig->threshold)) {
|
||||
|
@ -599,7 +599,7 @@ const FadeCategory FadeJob::transitionToCategory[render::Transition::TYPE_COUNT]
|
|||
FADE_AVATAR_CHANGE
|
||||
};
|
||||
|
||||
bool FadeJob::update(const Config& config, const render::ScenePointer& scene, render::Transaction& transaction, render::Transition& transition, const double deltaTime) const {
|
||||
bool FadeJob::update(RenderArgs* args, const Config& config, const render::ScenePointer& scene, render::Transaction& transaction, render::Transition& transition, const double deltaTime) const {
|
||||
const auto fadeCategory = transitionToCategory[transition.eventType];
|
||||
auto& eventConfig = config.events[fadeCategory];
|
||||
auto item = scene->getItemSafe(transition.itemId);
|
||||
|
@ -607,11 +607,11 @@ bool FadeJob::update(const Config& config, const render::ScenePointer& scene, re
|
|||
const FadeConfig::Timing timing = (FadeConfig::Timing) eventConfig.timing;
|
||||
|
||||
if (item.exist()) {
|
||||
auto aabb = item.getBound();
|
||||
auto aabb = item.getBound(args);
|
||||
if (render::Item::isValidID(transition.boundItemId)) {
|
||||
auto boundItem = scene->getItemSafe(transition.boundItemId);
|
||||
if (boundItem.exist()) {
|
||||
aabb = boundItem.getBound();
|
||||
aabb = boundItem.getBound(args);
|
||||
}
|
||||
}
|
||||
auto& dimensions = aabb.getDimensions();
|
||||
|
|
|
@ -223,7 +223,7 @@ private:
|
|||
float _thresholdScale[FADE_CATEGORY_COUNT];
|
||||
uint64_t _previousTime{ 0 };
|
||||
|
||||
bool update(const Config& config, const render::ScenePointer& scene, render::Transaction& transaction, render::Transition& transition, const double deltaTime) const;
|
||||
bool update(RenderArgs* args, const Config& config, const render::ScenePointer& scene, render::Transaction& transaction, render::Transition& transition, const double deltaTime) const;
|
||||
static float computeElementEnterRatio(double time, const double period, FadeConfig::Timing timing);
|
||||
|
||||
};
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace render {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload) {
|
||||
template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload, RenderArgs* args) {
|
||||
if (payload) {
|
||||
return payload->editBound();
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ namespace render {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload) {
|
||||
template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload, RenderArgs* args) {
|
||||
if (payload) {
|
||||
return payload->editBound();
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ protected:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const LightPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> void payloadRender(const LightPayload::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ protected:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const KeyLightPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> void payloadRender(const KeyLightPayload::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,76 @@ 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;
|
||||
}
|
||||
|
||||
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 +283,33 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, PrimitiveMode pr
|
|||
_shapeKey = builder.build();
|
||||
}
|
||||
|
||||
ItemKey ModelMeshPartPayload::getKey() const {
|
||||
return _itemKey;
|
||||
}
|
||||
|
||||
Item::Bound ModelMeshPartPayload::getBound(RenderArgs* args) 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(args);
|
||||
}
|
||||
}
|
||||
|
||||
auto worldBound = _adjustedLocalBound;
|
||||
auto parentTransform = _parentTransform;
|
||||
if (args) {
|
||||
parentTransform.setRotation(BillboardModeHelpers::getBillboardRotation(parentTransform.getTranslation(), parentTransform.getRotation(), _billboardMode,
|
||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
||||
}
|
||||
worldBound.transform(parentTransform);
|
||||
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 +319,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 +343,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 +363,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 +393,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, RenderArgs* args) {
|
||||
if (payload) {
|
||||
return payload->getBound(args);
|
||||
}
|
||||
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,152 +12,98 @@
|
|||
#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(RenderArgs* args) 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;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
@ -332,8 +319,8 @@ void Model::initJointStates() {
|
|||
_rig.initJointStates(hfmModel, modelOffset);
|
||||
}
|
||||
|
||||
bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
|
||||
bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
|
||||
bool pickAgainstTriangles, bool allowBackface) {
|
||||
bool intersectedSomething = false;
|
||||
|
||||
|
@ -343,7 +330,8 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
}
|
||||
|
||||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::mat4 transRot = createMatFromQuatAndPos(_rotation, _translation);
|
||||
glm::quat rotation = BillboardModeHelpers::getBillboardRotation(_translation, _rotation, _billboardMode, viewFrustumPos);
|
||||
glm::mat4 transRot = createMatFromQuatAndPos(rotation, _translation);
|
||||
glm::mat4 modelToWorldMatrix = transRot;
|
||||
if (!_snapModelToRegistrationPoint) {
|
||||
modelToWorldMatrix = modelToWorldMatrix * glm::translate(getOriginalOffset());
|
||||
|
@ -496,8 +484,8 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
}
|
||||
|
||||
bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
|
||||
bool pickAgainstTriangles, bool allowBackface) {
|
||||
const glm::vec3& viewFrustumPos, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool pickAgainstTriangles, bool allowBackface) {
|
||||
bool intersectedSomething = false;
|
||||
|
||||
// if we aren't active, we can't pick yet...
|
||||
|
@ -506,7 +494,8 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co
|
|||
}
|
||||
|
||||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::mat4 transRot = createMatFromQuatAndPos(_rotation, _translation);
|
||||
glm::quat rotation = BillboardModeHelpers::getBillboardRotation(_translation, _rotation, _billboardMode, viewFrustumPos);
|
||||
glm::mat4 transRot = createMatFromQuatAndPos(rotation, _translation);
|
||||
glm::mat4 modelToWorldMatrix = transRot;
|
||||
if (!_snapModelToRegistrationPoint) {
|
||||
modelToWorldMatrix = modelToWorldMatrix * glm::translate(getOriginalOffset());
|
||||
|
@ -1003,6 +992,24 @@ 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -1033,9 +1040,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);
|
||||
});
|
||||
}
|
||||
|
@ -1531,7 +1537,7 @@ AABox Model::getRenderableMeshBound() const {
|
|||
// Build a bound using the last known bound from all the renderItems.
|
||||
AABox totalBound;
|
||||
for (auto& renderItem : _modelMeshRenderItems) {
|
||||
totalBound += renderItem->getBound();
|
||||
totalBound += renderItem->getBound(nullptr);
|
||||
}
|
||||
return totalBound;
|
||||
}
|
||||
|
@ -1562,10 +1568,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();
|
||||
|
@ -1578,7 +1580,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);
|
||||
|
@ -195,11 +199,11 @@ public:
|
|||
void setJointRotation(int index, bool valid, const glm::quat& rotation, float priority);
|
||||
void setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority);
|
||||
|
||||
bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool pickAgainstTriangles = false, bool allowBackface = false);
|
||||
bool findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& viewFrustumPos, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool pickAgainstTriangles = false, bool allowBackface = false);
|
||||
|
||||
void setOffset(const glm::vec3& offset);
|
||||
|
@ -450,6 +454,7 @@ protected:
|
|||
virtual void createRenderItemSet();
|
||||
|
||||
PrimitiveMode _primitiveMode { PrimitiveMode::SOLID };
|
||||
BillboardMode _billboardMode { BillboardMode::NONE };
|
||||
bool _useDualQuaternionSkinning { false };
|
||||
|
||||
// debug rendering support
|
||||
|
|
|
@ -83,7 +83,7 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const
|
|||
for (auto& id : items) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) {
|
||||
outItems.emplace_back(ItemBound(id, item.getBound()));
|
||||
outItems.emplace_back(ItemBound(id, item.getBound(renderContext->args)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,10 +188,10 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.insideItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -203,10 +203,10 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.insideSubcellItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -218,10 +218,10 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.partialItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -233,10 +233,10 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.partialSubcellItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -250,10 +250,10 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.insideItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -265,11 +265,11 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.insideSubcellItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
if (test.solidAngleTest(itemBound.bound)) {
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -282,11 +282,11 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.partialItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
if (test.frustumTest(itemBound.bound)) {
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -299,11 +299,11 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.partialSubcellItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
if (test.frustumTest(itemBound.bound) && test.solidAngleTest(itemBound.bound)) {
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ void DrawItemSelection::run(const RenderContextPointer& renderContext, const Ite
|
|||
render::ItemBounds itemBounds;
|
||||
for (const auto& itemID : itemIDs) {
|
||||
auto& item = scene->getItem(itemID);
|
||||
auto itemBound = item.getBound();
|
||||
auto itemBound = item.getBound(args);
|
||||
if (!itemBound.isInvalid()) {
|
||||
itemBounds.emplace_back(itemID, itemBound);
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ void IDsToBounds::run(const RenderContextPointer& renderContext, const ItemIDs&
|
|||
for (auto id : inItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (item.exist()) {
|
||||
outItems.emplace_back(ItemBound{ id, item.getBound() });
|
||||
outItems.emplace_back(ItemBound{ id, item.getBound(renderContext->args) });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -97,7 +97,7 @@ const ShapeKey Item::getShapeKey() const {
|
|||
return shapeKey;
|
||||
}
|
||||
|
||||
uint32_t Item::fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) const {
|
||||
uint32_t Item::fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene, RenderArgs* args) const {
|
||||
ItemIDs subItems;
|
||||
auto numSubs = fetchMetaSubItems(subItems);
|
||||
|
||||
|
@ -107,7 +107,7 @@ uint32_t Item::fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) c
|
|||
if (scene.isAllocatedID(id)) {
|
||||
auto& item = scene.getItem(id);
|
||||
if (item.exist()) {
|
||||
subItemBounds.emplace_back(id, item.getBound());
|
||||
subItemBounds.emplace_back(id, item.getBound(args));
|
||||
} else {
|
||||
numSubs--;
|
||||
}
|
||||
|
@ -133,11 +133,11 @@ namespace render {
|
|||
return payload->getShapeKey();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const PayloadProxyInterface::Pointer& payload) {
|
||||
template <> const Item::Bound payloadGetBound(const PayloadProxyInterface::Pointer& payload, RenderArgs* args) {
|
||||
if (!payload) {
|
||||
return render::Item::Bound();
|
||||
}
|
||||
return payload->getBound();
|
||||
return payload->getBound(args);
|
||||
}
|
||||
|
||||
template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, RenderArgs* args) {
|
||||
|
|
|
@ -431,7 +431,7 @@ public:
|
|||
class PayloadInterface {
|
||||
public:
|
||||
virtual const ItemKey getKey() const = 0;
|
||||
virtual const Bound getBound() const = 0;
|
||||
virtual const Bound getBound(RenderArgs* args) const = 0;
|
||||
virtual void render(RenderArgs* args) = 0;
|
||||
|
||||
virtual const ShapeKey getShapeKey() const = 0;
|
||||
|
@ -476,7 +476,7 @@ public:
|
|||
// Payload Interface
|
||||
|
||||
// Get the bound of the item expressed in world space (or eye space depending on the key.isWorldSpace())
|
||||
const Bound getBound() const { return _payload->getBound(); }
|
||||
const Bound getBound(RenderArgs* args) const { return _payload->getBound(args); }
|
||||
|
||||
// Get the layer where the item belongs, simply reflecting the key.
|
||||
int getLayer() const { return _key.getLayer(); }
|
||||
|
@ -489,7 +489,7 @@ public:
|
|||
|
||||
// Meta Type Interface
|
||||
uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return _payload->fetchMetaSubItems(subItems); }
|
||||
uint32_t fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) const;
|
||||
uint32_t fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene, RenderArgs* args) const;
|
||||
|
||||
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const { return _payload->passesZoneOcclusionTest(containingZones); }
|
||||
|
||||
|
@ -524,13 +524,13 @@ public:
|
|||
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const Item& item) {
|
||||
debug << "[Item: _key:" << item.getKey() << ", bounds:" << item.getBound() << "]";
|
||||
debug << "[Item: _key:" << item.getKey() << "]";
|
||||
return debug;
|
||||
}
|
||||
|
||||
// Item shared interface supported by the payload
|
||||
template <class T> const ItemKey payloadGetKey(const std::shared_ptr<T>& payloadData) { return ItemKey(); }
|
||||
template <class T> const Item::Bound payloadGetBound(const std::shared_ptr<T>& payloadData) { return Item::Bound(); }
|
||||
template <class T> const Item::Bound payloadGetBound(const std::shared_ptr<T>& payloadData, RenderArgs* args) { return Item::Bound(); }
|
||||
template <class T> void payloadRender(const std::shared_ptr<T>& payloadData, RenderArgs* args) { }
|
||||
|
||||
// Shape type interface
|
||||
|
@ -561,7 +561,7 @@ public:
|
|||
|
||||
// Payload general interface
|
||||
virtual const ItemKey getKey() const override { return payloadGetKey<T>(_data); }
|
||||
virtual const Item::Bound getBound() const override { return payloadGetBound<T>(_data); }
|
||||
virtual const Item::Bound getBound(RenderArgs* args) const override { return payloadGetBound<T>(_data, args); }
|
||||
|
||||
virtual void render(RenderArgs* args) override { payloadRender<T>(_data, args); }
|
||||
|
||||
|
@ -607,9 +607,9 @@ template <> const ItemKey payloadGetKey(const FooPointer& foo) {
|
|||
foo->makeMyKey();
|
||||
return foo->_myownKey;
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const FooPointer& foo) {
|
||||
template <> const Item::Bound payloadGetBound(const FooPointer& foo, RenderArgs* args) {
|
||||
// evaluate Foo's own bound
|
||||
return foo->evaluateMyBound();
|
||||
return foo->evaluateMyBound(args);
|
||||
}
|
||||
|
||||
// In this example, do not specialize the payloadRender call which means the compiler will use the default version which does nothing
|
||||
|
@ -624,7 +624,7 @@ public:
|
|||
|
||||
virtual ItemKey getKey() = 0;
|
||||
virtual ShapeKey getShapeKey() = 0;
|
||||
virtual Item::Bound getBound() = 0;
|
||||
virtual Item::Bound getBound(RenderArgs* args) = 0;
|
||||
virtual void render(RenderArgs* args) = 0;
|
||||
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const = 0;
|
||||
virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const = 0;
|
||||
|
@ -635,7 +635,7 @@ public:
|
|||
};
|
||||
|
||||
template <> const ItemKey payloadGetKey(const PayloadProxyInterface::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const PayloadProxyInterface::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const PayloadProxyInterface::Pointer& payload, RenderArgs* args);
|
||||
template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, RenderArgs* args);
|
||||
template <> uint32_t metaFetchMetaSubItems(const PayloadProxyInterface::Pointer& payload, ItemIDs& subItems);
|
||||
template <> const ShapeKey shapeGetShapeKey(const PayloadProxyInterface::Pointer& payload);
|
||||
|
|
|
@ -305,7 +305,7 @@ void Scene::resetItems(const Transaction::Resets& transactions) {
|
|||
// Update the item's container
|
||||
assert((oldKey.isSpatial() == newKey.isSpatial()) || oldKey._flags.none());
|
||||
if (newKey.isSpatial()) {
|
||||
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), itemId, newKey);
|
||||
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(nullptr), itemId, newKey);
|
||||
item.resetCell(newCell, newKey.isSmall());
|
||||
} else {
|
||||
_masterNonspatialSet.insert(itemId);
|
||||
|
@ -361,14 +361,14 @@ void Scene::updateItems(const Transaction::Updates& transactions) {
|
|||
// Update the item's container
|
||||
if (oldKey.isSpatial() == newKey.isSpatial()) {
|
||||
if (newKey.isSpatial()) {
|
||||
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), updateID, newKey);
|
||||
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(nullptr), updateID, newKey);
|
||||
item.resetCell(newCell, newKey.isSmall());
|
||||
}
|
||||
} else {
|
||||
if (newKey.isSpatial()) {
|
||||
_masterNonspatialSet.erase(updateID);
|
||||
|
||||
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), updateID, newKey);
|
||||
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(nullptr), updateID, newKey);
|
||||
item.resetCell(newCell, newKey.isSmall());
|
||||
} else {
|
||||
_masterSpatialTree.removeItem(oldCell, oldKey, updateID);
|
||||
|
|
|
@ -60,7 +60,7 @@ void render::depthSortItems(const RenderContextPointer& renderContext, bool fron
|
|||
|
||||
for (auto itemDetails : inItems) {
|
||||
auto item = scene->getItem(itemDetails.id);
|
||||
auto bound = itemDetails.bound; // item.getBound();
|
||||
auto bound = itemDetails.bound; // item.getBound(args);
|
||||
float distanceSquared = args->getViewFrustum().distanceToCameraSquared(bound.calcCenter());
|
||||
|
||||
itemBoundSorts.emplace_back(ItemBoundSort(distanceSquared, distanceSquared, distanceSquared, itemDetails.id, bound));
|
||||
|
|
|
@ -15,6 +15,23 @@ 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); };
|
||||
|
||||
void BillboardModeHelpers::setBillboardRotationOperator(std::function<glm::quat(const glm::vec3&, const glm::quat&,
|
||||
BillboardMode, const glm::vec3&, bool)> getBillboardRotationOperator) {
|
||||
_getBillboardRotationOperator = getBillboardRotationOperator;
|
||||
}
|
||||
|
||||
glm::quat BillboardModeHelpers::getBillboardRotation(const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode,
|
||||
const glm::vec3& frustumPos, bool rotate90x) {
|
||||
return _getBillboardRotationOperator(position, rotation, billboardMode, frustumPos, rotate90x);
|
||||
}
|
||||
|
||||
void BillboardModeHelpers::setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> getPrimaryViewFrustumPositionOperator) {
|
||||
_getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator;
|
||||
}
|
||||
|
||||
QString BillboardModeHelpers::getNameForBillboardMode(BillboardMode mode) {
|
||||
if (((int)mode <= 0) || ((int)mode >= (int)BILLBOARD_MODE_NAMES)) {
|
||||
|
@ -22,4 +39,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,17 @@ 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);
|
||||
static glm::quat getBillboardRotation(const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode,
|
||||
const glm::vec3& frustumPos, bool rotate90x = false);
|
||||
static void setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> 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
|
||||
|
||||
|
|
|
@ -38,10 +38,6 @@
|
|||
"textEffectThickness": {
|
||||
"tooltip": "The magnitude of the text effect."
|
||||
},
|
||||
"textBillboardMode": {
|
||||
"tooltip": "If enabled, determines how the entity will face the camera.",
|
||||
"jsPropertyName": "billboardMode"
|
||||
},
|
||||
"topMargin": {
|
||||
"tooltip": "The top margin, in meters."
|
||||
},
|
||||
|
@ -223,10 +219,6 @@
|
|||
"subImage": {
|
||||
"tooltip": "The area of the image that is displayed."
|
||||
},
|
||||
"imageBillboardMode": {
|
||||
"tooltip": "If enabled, determines how the entity will face the camera.",
|
||||
"jsPropertyName": "billboardMode"
|
||||
},
|
||||
"keepAspectRatio": {
|
||||
"tooltip": "If enabled, the image will maintain its original aspect ratio."
|
||||
},
|
||||
|
@ -236,10 +228,6 @@
|
|||
"dpi": {
|
||||
"tooltip": "The resolution to display the page at, in pixels per inch. Use this to resize your web source in the frame."
|
||||
},
|
||||
"webBillboardMode": {
|
||||
"tooltip": "If enabled, determines how the entity will face the camera.",
|
||||
"jsPropertyName": "billboardMode"
|
||||
},
|
||||
"inputMode": {
|
||||
"tooltip": "The user input mode to use."
|
||||
},
|
||||
|
@ -595,6 +583,9 @@
|
|||
"primitiveMode": {
|
||||
"tooltip": "The mode in which to draw an entity, either \"Solid\" or \"Wireframe\"."
|
||||
},
|
||||
"billboardMode": {
|
||||
"tooltip": "Determines if and how the entity will face the camera.",
|
||||
},
|
||||
"renderWithZones": {
|
||||
"tooltip": "If set, this entity will only render when your avatar is inside of a zone in this list."
|
||||
},
|
||||
|
|
|
@ -116,6 +116,16 @@ const GROUPS = [
|
|||
},
|
||||
propertyID: "primitiveMode",
|
||||
},
|
||||
{
|
||||
label: "Billboard Mode",
|
||||
type: "dropdown",
|
||||
options: {
|
||||
none: "None",
|
||||
yaw: "Yaw",
|
||||
full: "Full"
|
||||
},
|
||||
propertyID: "billboardMode",
|
||||
},
|
||||
{
|
||||
label: "Render With Zones",
|
||||
type: "multipleZonesSelection",
|
||||
|
@ -229,13 +239,6 @@ const GROUPS = [
|
|||
decimals: 2,
|
||||
propertyID: "textEffectThickness",
|
||||
},
|
||||
{
|
||||
label: "Billboard Mode",
|
||||
type: "dropdown",
|
||||
options: { none: "None", yaw: "Yaw", full: "Full"},
|
||||
propertyID: "textBillboardMode",
|
||||
propertyName: "billboardMode", // actual entity property name
|
||||
},
|
||||
{
|
||||
label: "Top Margin",
|
||||
type: "number-draggable",
|
||||
|
@ -723,13 +726,6 @@ const GROUPS = [
|
|||
subLabels: [ "x", "y", "w", "h" ],
|
||||
propertyID: "subImage",
|
||||
},
|
||||
{
|
||||
label: "Billboard Mode",
|
||||
type: "dropdown",
|
||||
options: { none: "None", yaw: "Yaw", full: "Full"},
|
||||
propertyID: "imageBillboardMode",
|
||||
propertyName: "billboardMode", // actual entity property name
|
||||
},
|
||||
{
|
||||
label: "Keep Aspect Ratio",
|
||||
type: "bool",
|
||||
|
@ -779,13 +775,6 @@ const GROUPS = [
|
|||
decimals: 0,
|
||||
propertyID: "maxFPS",
|
||||
},
|
||||
{
|
||||
label: "Billboard Mode",
|
||||
type: "dropdown",
|
||||
options: { none: "None", yaw: "Yaw", full: "Full"},
|
||||
propertyID: "webBillboardMode",
|
||||
propertyName: "billboardMode", // actual entity property name
|
||||
},
|
||||
{
|
||||
label: "Input Mode",
|
||||
type: "dropdown",
|
||||
|
|
Loading…
Reference in a new issue