Merge pull request #961 from HifiExperiments/billboard

Implement billboardMode for all Entity types
This commit is contained in:
Kalila 2021-02-10 02:41:40 -05:00 committed by GitHub
commit fd6973bd0b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
90 changed files with 715 additions and 1239 deletions

View file

@ -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();

View file

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

View file

@ -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();

View file

@ -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");

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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) {

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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();

View file

@ -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);
}

View file

@ -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>();

View file

@ -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;

View file

@ -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

View file

@ -23,7 +23,7 @@ public:
~GizmoEntityRenderer();
protected:
Item::Bound getBound() override;
Item::Bound getBound(RenderArgs* args) override;
ShapeKey getShapeKey() override;
bool isTransparent() const override;

View file

@ -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);

View file

@ -23,7 +23,7 @@ public:
~GridEntityRenderer();
protected:
Item::Bound getBound() override;
Item::Bound getBound(RenderArgs* args) override;
ShapeKey getShapeKey() override;
bool isTransparent() const override;

View file

@ -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());

View file

@ -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 };
};

View file

@ -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) {

View file

@ -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:

View file

@ -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,

View file

@ -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());
}

View file

@ -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);
});

View file

@ -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;

View file

@ -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));

View file

@ -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:

View file

@ -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);
}

View file

@ -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,

View file

@ -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;
};

View file

@ -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);

View file

@ -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;

View file

@ -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();
}

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -51,9 +51,6 @@ int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
QString EntityItem::_marketplacePublicKey;
std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode, const glm::vec3&)> 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;
});
}

View file

@ -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

View file

@ -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> &ndash; <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()) {

View file

@ -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);

View file

@ -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

View file

@ -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();

View file

@ -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);

View file

@ -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>

View file

@ -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);

View file

@ -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);

View file

@ -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([&] {

View file

@ -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 };

View file

@ -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

View file

@ -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:

View file

@ -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; }

View file

@ -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;

View file

@ -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 {

View file

@ -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;

View file

@ -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: {

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -285,6 +285,7 @@ enum class EntityVersion : PacketVersion {
TransparentWeb,
UseOriginalPivot,
UserAgent,
AllBillboardMode,
// Add new versions above here
NUM_PACKET_TYPE,

View file

@ -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)

View file

@ -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;

View file

@ -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);
}

View file

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

View file

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

View file

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

View file

@ -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();

View file

@ -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);
};

View file

@ -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();
}

View file

@ -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);
}

View file

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

View file

@ -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);

View file

@ -226,6 +226,7 @@ void Model::updateRenderItems() {
modelTransform.setScale(glm::vec3(1.0f));
PrimitiveMode primitiveMode = self->getPrimitiveMode();
BillboardMode billboardMode = self->getBillboardMode();
auto renderWithZones = self->getRenderWithZones();
auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags();
bool cauterized = self->isCauterized();
@ -242,7 +243,7 @@ void Model::updateRenderItems() {
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning,
invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags,
invalidatePayloadShapeKey, primitiveMode, billboardMode, renderItemKeyGlobalFlags,
cauterized, renderWithZones](ModelMeshPartPayload& data) {
if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions);
@ -252,25 +253,11 @@ void Model::updateRenderItems() {
data.computeAdjustedLocalBound(meshState.clusterMatrices);
}
Transform renderTransform = modelTransform;
if (useDualQuaternionSkinning) {
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
const auto& dq = meshState.clusterDualQuaternions[0];
Transform transform(dq.getRotation(),
dq.getScale(),
dq.getTranslation());
renderTransform = modelTransform.worldTransform(Transform(transform));
}
} else {
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
}
}
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
data.updateTransformForSkinnedMesh(modelTransform, meshState, useDualQuaternionSkinning);
data.setCauterized(cauterized);
data.setRenderWithZones(renderWithZones);
data.setBillboardMode(billboardMode);
data.updateKey(renderItemKeyGlobalFlags);
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
});
@ -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 });

View file

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

View file

@ -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);
}
}
}

View file

@ -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);
}

View file

@ -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 {

View file

@ -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) {

View file

@ -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);

View file

@ -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);

View file

@ -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));

View file

@ -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];
}
}

View file

@ -9,8 +9,13 @@
#ifndef hifi_BillboardMode_h
#define hifi_BillboardMode_h
#include <functional>
#include "QString"
#include "glm/glm.hpp"
#include "glm/gtc/quaternion.hpp"
/**jsdoc
* <p>How an entity is billboarded.</p>
* <table>
@ -37,7 +42,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

View file

@ -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."
},

View file

@ -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",