Merge branch 'master' into alignment

This commit is contained in:
HifiExperiments 2021-02-10 23:07:03 -08:00 committed by HifiExperiments
commit f46f1b2219
109 changed files with 1070 additions and 1383 deletions

View file

@ -4,7 +4,7 @@
Vircadia™ is a 3D social software project seeking to incrementally bring about a truly free and open metaverse, in desktop and XR.
### [Download](https://vircadia.com/download-vircadia/)
### [Website](https://vircadia.com/) | [Discord](https://discordapp.com/invite/Pvx2vke) | [Download](https://vircadia.com/download-vircadia/)
### Releases

View file

@ -505,7 +505,7 @@ function createDomainIDPrompt(callback) {
swal({
title: 'Finish Registering Domain',
type: 'input',
text: 'Enter a label for this machine.</br></br>This will help you identify which domain ID belongs to which machine.</br></br>This is a required step for registration.</br></br>',
text: 'Enter a label for this Domain Server.</br></br>This will help you identify which domain ID belongs to which server.</br></br>This is a required step for registration.</br></br>Acceptable characters are [A-Z][a-z0-9]+-_.</br',
showCancelButton: true,
confirmButtonText: "Create",
closeOnConfirm: false,

View file

@ -193,7 +193,11 @@ function promptToCreateDomainID() {
var formJSON = {
"metaverse": {
"automatic_networking": "full",
"id": domainID
},
"descriptors": {
"world_name": label
}
};

View file

@ -19,16 +19,17 @@ Item {
property string url: ""
property string scriptUrl: null
property bool useBackground: true
property string userAgent: ""
onUrlChanged: {
load(root.url, root.scriptUrl, root.useBackground);
load(root.url, root.scriptUrl, root.useBackground, root.userAgent);
}
onScriptUrlChanged: {
if (root.item) {
root.item.scriptUrl = root.scriptUrl;
} else {
load(root.url, root.scriptUrl, root.useBackground);
load(root.url, root.scriptUrl, root.useBackground, root.userAgent);
}
}
@ -36,13 +37,21 @@ Item {
if (root.item) {
root.item.useBackground = root.useBackground;
} else {
load(root.url, root.scriptUrl, root.useBackground);
load(root.url, root.scriptUrl, root.useBackground, root.userAgent);
}
}
onUserAgentChanged: {
if (root.item) {
root.item.userAgent = root.userAgent;
} else {
load(root.url, root.scriptUrl, root.useBackground, root.userAgent);
}
}
property var item: null
function load(url, scriptUrl, useBackground) {
function load(url, scriptUrl, useBackground, userAgent) {
// Ensure we reset any existing item to "about:blank" to ensure web audio stops: DEV-2375
if (root.item != null) {
root.item.url = "about:blank"
@ -54,11 +63,12 @@ Item {
root.item.url = url
root.item.scriptUrl = scriptUrl
root.item.useBackground = useBackground
root.item.userAgent = userAgent
})
}
Component.onCompleted: {
load(root.url, root.scriptUrl, root.useBackground);
load(root.url, root.scriptUrl, root.useBackground, root.userAgent);
}
signal sendToScript(var message);

View file

@ -13,10 +13,13 @@ Item {
property alias url: webViewCore.url
property alias canGoBack: webViewCore.canGoBack
property alias webViewCore: webViewCore
property alias webViewCoreProfile: webViewCore.profile
// FIXME - This was commented out to allow for manual setting of the userAgent.
//
// property alias webViewCoreProfile: webViewCore.profile
property string webViewCoreUserAgent
property bool useBackground: webViewCore.useBackground
property string userAgent: webViewCore.profile.httpUserAgent
property string userScriptUrl: ""
property string urlTag: "noDownload=false";
@ -34,6 +37,10 @@ Item {
permissionPopupBackground.visible = false;
}
onUserAgentChanged: {
webViewCore.profile.httpUserAgent = flick.userAgent;
}
StylesUIt.HifiConstants {
id: hifi
}
@ -74,7 +81,7 @@ Item {
function onLoadingChanged(loadRequest) {
if (WebEngineView.LoadStartedStatus === loadRequest.status) {
webViewCore.profile.httpUserAgent = flick.userAgent;
// Required to support clicking on "hifi://" links
var url = loadRequest.url.toString();
url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag;
@ -101,7 +108,6 @@ Item {
height: parent.height
backgroundColor: (flick.useBackground) ? "white" : "transparent"
profile: HFWebEngineProfile;
settings.pluginsEnabled: true
settings.touchIconsEnabled: true
settings.allowRunningInsecureContent: true
@ -136,8 +142,10 @@ Item {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
if (webViewCoreUserAgent !== undefined) {
webViewCore.profile.httpUserAgent = webViewCoreUserAgent
if (flick.userAgent !== undefined) {
webViewCore.profile.httpUserAgent = flick.userAgent;
webViewCore.profile.offTheRecord = false;
webViewCore.profile.storageName = "qmlWebEngine";
} else {
webViewCore.profile.httpUserAgent += " (VircadiaInterface)";
}

View file

@ -11,12 +11,14 @@ Item {
property alias url: webViewCore.url
property alias canGoBack: webViewCore.canGoBack
property alias webViewCore: webViewCore
property alias webViewCoreProfile: webViewCore.profile
property string webViewCoreUserAgent
// FIXME - This was commented out to allow for manual setting of the userAgent.
//
// property alias webViewCoreProfile: webViewCore.profile
property bool useBackground: webViewCore.useBackground
property alias useBackground: webViewCore.useBackground
property alias userAgent: webViewCore.userAgent
property string userScriptUrl: ""
property string urlTag: "noDownload=false";
property string urlTag: "noDownload=false"
signal newViewRequestedCallback(var request)
signal loadingChangedCallback(var loadRequest)

View file

@ -27,7 +27,11 @@ Item {
}
*/
property alias viewProfile: webroot.webViewCoreProfile
// FIXME - Reimplement profiles for... why? Was it so that new windows opened share the same profile?
// Are profiles written to by the webengine during the session?
// Removed in PR Feature/web entity user agent #988
//
// property alias viewProfile: webroot.webViewCoreProfile
FlickableWebViewCore {
id: webroot

View file

@ -25,7 +25,11 @@ Item {
property bool isDesktop: false
property alias url: web.url
property alias webView: web.webViewCore
property alias profile: web.webViewCoreProfile
// FIXME - Reimplement profiles for... why? Was it so that new windows opened share the same profile?
// Are profiles written to by the webengine during the session?
// Removed in PR Feature/web entity user agent #988
//
// property alias profile: web.webViewCoreProfile
property bool remove: false
property bool closeButtonVisible: true

View file

@ -24,6 +24,7 @@ Item {
property alias flickable: webroot.interactive
property alias blurOnCtrlShift: webroot.blurOnCtrlShift
property alias useBackground: webroot.useBackground
property alias userAgent: webroot.userAgent
function stop() {
webroot.stop();
@ -37,7 +38,11 @@ Item {
}
*/
property alias viewProfile: webroot.webViewCoreProfile
// FIXME - Reimplement profiles for... why? Was it so that new windows opened share the same profile?
// Are profiles written to by the webengine during the session?
// Removed in PR Feature/web entity user agent #988
//
// property alias viewProfile: webroot.webViewCoreProfile
FlickableWebViewCore {
id: webroot

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

@ -248,9 +248,9 @@ private: \
* <em>Read-only.</em>
* @property {string} lodStatus - Description of the current LOD.
* <em>Read-only.</em>
* @property {string} numEntityUpdates - The number of entity updates that happened last frame.
* @property {number} numEntityUpdates - The number of entity updates that happened last frame.
* <em>Read-only.</em>
* @property {string} numNeededEntityUpdates - The total number of entity updates scheduled for last frame.
* @property {number} numNeededEntityUpdates - The total number of entity updates scheduled for last frame.
* <em>Read-only.</em>
* @property {string} timingStats - Details of the average time (ms) spent in and number of calls made to different parts of
* the code. Provided only if <code>timingExpanded</code> is <code>true</code>. Only the top 10 items are provided if
@ -547,8 +547,8 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, lodAngle, 0)
STATS_PROPERTY(int, lodTargetFramerate, 0)
STATS_PROPERTY(QString, lodStatus, QString())
STATS_PROPERTY(int, numEntityUpdates, 0)
STATS_PROPERTY(int, numNeededEntityUpdates, 0)
STATS_PROPERTY(quint64, numEntityUpdates, 0)
STATS_PROPERTY(quint64, numNeededEntityUpdates, 0)
STATS_PROPERTY(QString, timingStats, QString())
STATS_PROPERTY(QString, gameUpdateStats, QString())
STATS_PROPERTY(int, serverElements, 0)

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

@ -33,6 +33,7 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
{
// SkeletonModels, and by extention Avatars, use Dual Quaternion skinning.
_useDualQuaternionSkinning = true;
_forceOffset = true;
// Avatars all cast shadow
setCanCastShadow(true);
@ -156,17 +157,13 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
updateAttitude(_owningAvatar->getWorldOrientation());
setBlendshapeCoefficients(_owningAvatar->getHead()->getSummedBlendshapeCoefficients());
Parent::simulate(deltaTime, fullUpdate);
if (fullUpdate) {
Parent::simulate(deltaTime, fullUpdate);
// let rig compute the model offset
glm::vec3 registrationPoint;
if (_rig.getModelRegistrationPoint(registrationPoint)) {
setOffset(registrationPoint);
}
} else {
Parent::simulate(deltaTime, fullUpdate);
}
// FIXME: This texture loading logic should probably live in Avatar, to mirror RenderableModelEntityItem,

View file

@ -136,8 +136,8 @@ public:
static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName);
static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName);
int getPrevNumEntityUpdates() const { return _prevNumEntityUpdates; }
int getPrevTotalNeededEntityUpdates() const { return _prevTotalNeededEntityUpdates; }
size_t getPrevNumEntityUpdates() const { return _prevNumEntityUpdates; }
size_t getPrevTotalNeededEntityUpdates() const { return _prevTotalNeededEntityUpdates; }
signals:
void enterEntity(const EntityItemID& entityItemID);
@ -253,8 +253,8 @@ private:
ReadWriteLockable _changedEntitiesGuard;
std::unordered_set<EntityItemID> _changedEntities;
int _prevNumEntityUpdates { 0 };
int _prevTotalNeededEntityUpdates { 0 };
size_t _prevNumEntityUpdates { 0 };
size_t _prevTotalNeededEntityUpdates { 0 };
std::unordered_set<EntityRendererPointer> _renderablesToUpdate;
std::unordered_map<EntityItemID, EntityRendererPointer> _entitiesInScene;

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

@ -149,10 +149,12 @@ void RenderableModelEntityItem::updateModelBounds() {
bool overridingModelTransform = model->isOverridingModelTransformAndOffset();
glm::vec3 scaledDimensions = getScaledDimensions();
glm::vec3 registrationPoint = getRegistrationPoint();
bool needsSimulate = false;
if (!overridingModelTransform &&
(model->getScaleToFitDimensions() != scaledDimensions ||
model->getRegistrationPoint() != registrationPoint ||
!model->getIsScaledToFit() || _needsToRescaleModel)) {
model->getRegistrationPoint() != registrationPoint ||
!model->getIsScaledToFit() || _needsToRescaleModel ||
_useOriginalPivot == model->getSnapModelToRegistrationPoint())) {
// The machinery for updateModelBounds will give existing models the opportunity to fix their
// translation/rotation/scale/registration. The first two are straightforward, but the latter two
// have guards to make sure they don't happen after they've already been set. Here we reset those guards.
@ -162,9 +164,9 @@ void RenderableModelEntityItem::updateModelBounds() {
// now recalculate the bounds and registration
model->setScaleToFit(true, scaledDimensions);
model->setSnapModelToRegistrationPoint(true, registrationPoint);
model->setSnapModelToRegistrationPoint(!_useOriginalPivot, registrationPoint);
updateRenderItems = true;
model->scaleToFit();
needsSimulate = true;
_needsToRescaleModel = false;
}
@ -176,10 +178,11 @@ void RenderableModelEntityItem::updateModelBounds() {
updateRenderItems = true;
}
if (_needsInitialSimulation || _needsJointSimulation || isAnimatingSomething()) {
if (_needsInitialSimulation || _needsJointSimulation || needsSimulate || isAnimatingSomething()) {
// NOTE: on isAnimatingSomething() we need to call Model::simulate() which calls Rig::updateRig()
// TODO: there is opportunity to further optimize the isAnimatingSomething() case.
model->simulate(0.0f);
locationChanged();
_needsInitialSimulation = false;
_needsJointSimulation = false;
updateRenderItems = true;
@ -219,31 +222,41 @@ EntityItemProperties RenderableModelEntityItem::getProperties(const EntityProper
return properties;
}
glm::vec3 RenderableModelEntityItem::getPivot() const {
auto model = getModel();
auto pivot = EntityItem::getPivot();
if (!model || !model->isLoaded() || !_useOriginalPivot) {
return pivot;
}
return pivot + model->getOriginalOffset();
}
bool RenderableModelEntityItem::supportsDetailedIntersection() const {
return true;
}
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);
}
@ -443,14 +456,15 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
// multiply each point by scale before handing the point-set off to the physics engine.
// also determine the extents of the collision model.
glm::vec3 registrationOffset = dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
glm::vec3 offset = model->getSnapModelToRegistrationPoint() ? model->getOffset() : glm::vec3(0.0f);
for (int32_t i = 0; i < pointCollection.size(); i++) {
for (int32_t j = 0; j < pointCollection[i].size(); j++) {
// back compensate for registration so we can apply that offset to the shapeInfo later
pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + model->getOffset()) - registrationOffset;
pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + offset) - registrationOffset;
}
}
shapeInfo.setParams(type, 0.5f * extents, getCompoundShapeURL());
adjustShapeInfoByRegistration(shapeInfo);
shapeInfo.setParams(type, 0.5f * extents, getCompoundShapeURL() + model->getSnapModelToRegistrationPoint());
adjustShapeInfoByRegistration(shapeInfo, model->getSnapModelToRegistrationPoint());
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
updateModelBounds();
model->updateGeometry();
@ -682,8 +696,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
}
}
shapeInfo.setParams(type, 0.5f * extents.size(), getModelURL());
adjustShapeInfoByRegistration(shapeInfo);
shapeInfo.setParams(type, 0.5f * extents.size(), getModelURL() + model->getSnapModelToRegistrationPoint());
adjustShapeInfoByRegistration(shapeInfo, model->getSnapModelToRegistrationPoint());
} else {
EntityItem::computeShapeInfo(shapeInfo);
}
@ -1254,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);
});
@ -1332,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

@ -42,7 +42,7 @@ protected:
void setModel(const ModelPointer& model);
ModelPointer getModel() const;
bool _needsInitialSimulation{ true };
bool _needsInitialSimulation { true };
private:
ModelPointer _model;
};
@ -63,14 +63,15 @@ public:
virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
void updateModelBounds();
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);
@ -723,8 +676,10 @@ ShapeType RenderablePolyVoxEntityItem::getShapeType() const {
}
void RenderablePolyVoxEntityItem::setRegistrationPoint(const glm::vec3& value) {
if (value != _registrationPoint) {
_shapeReady = false;
if (value != getRegistrationPoint()) {
withWriteLock([&] {
_shapeReady = false;
});
EntityItem::setRegistrationPoint(value);
startUpdates();
}
@ -1803,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;
}
@ -1829,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;
@ -1862,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();
@ -131,13 +119,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);
@ -148,14 +132,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);
@ -243,12 +228,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();
@ -310,21 +295,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);
@ -332,7 +314,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));
@ -353,9 +336,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 { "" };
@ -91,7 +89,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;
@ -107,7 +105,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

@ -39,6 +39,7 @@ const char* WebEntityRenderer::URL_PROPERTY = "url";
const char* WebEntityRenderer::SCRIPT_URL_PROPERTY = "scriptURL";
const char* WebEntityRenderer::GLOBAL_POSITION_PROPERTY = "globalPosition";
const char* WebEntityRenderer::USE_BACKGROUND_PROPERTY = "useBackground";
const char* WebEntityRenderer::USER_AGENT_PROPERTY = "userAgent";
std::function<void(QString, bool, QSharedPointer<OffscreenQmlSurface>&, bool&)> WebEntityRenderer::_acquireWebSurfaceOperator = nullptr;
std::function<void(QSharedPointer<OffscreenQmlSurface>&, bool&, std::vector<QMetaObject::Connection>&)> WebEntityRenderer::_releaseWebSurfaceOperator = nullptr;
@ -167,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;
@ -194,6 +194,7 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
_webSurface->getRootItem()->setProperty(URL_PROPERTY, newSourceURL);
_webSurface->getRootItem()->setProperty(SCRIPT_URL_PROPERTY, _scriptURL);
_webSurface->getRootItem()->setProperty(USE_BACKGROUND_PROPERTY, _useBackground);
_webSurface->getRootItem()->setProperty(USER_AGENT_PROPERTY, _userAgent);
_webSurface->getSurfaceContext()->setContextProperty(GLOBAL_POSITION_PROPERTY, vec3toVariant(_contextPosition));
_webSurface->setMaxFps((QUrl(newSourceURL).host().endsWith("youtube.com", Qt::CaseInsensitive)) ? YOUTUBE_MAX_FPS : _maxFPS);
::hifi::scripting::setLocalAccessSafeThread(false);
@ -231,6 +232,14 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
_useBackground = useBackground;
}
}
{
auto userAgent = entity->getUserAgent();
if (_userAgent != userAgent) {
_webSurface->getRootItem()->setProperty(USER_AGENT_PROPERTY, userAgent);
_userAgent = userAgent;
}
}
{
auto contextPosition = entity->getWorldPosition();
@ -257,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([&] {
@ -297,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();
});
@ -312,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

@ -36,6 +36,7 @@ public:
static const char* SCRIPT_URL_PROPERTY;
static const char* GLOBAL_POSITION_PROPERTY;
static const char* USE_BACKGROUND_PROPERTY;
static const char* USER_AGENT_PROPERTY;
static void setAcquireWebSurfaceOperator(std::function<void(const QString&, bool, QSharedPointer<OffscreenQmlSurface>&, bool&)> acquireWebSurfaceOperator) { _acquireWebSurfaceOperator = acquireWebSurfaceOperator; }
static void acquireWebSurface(const QString& url, bool htmlContent, QSharedPointer<OffscreenQmlSurface>& webSurface, bool& cachedWebSurface) {
@ -59,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; }
@ -90,13 +90,13 @@ private:
glm::u8vec3 _color;
float _alpha { 1.0f };
PulsePropertyGroup _pulseProperties;
BillboardMode _billboardMode;
QString _sourceURL;
uint16_t _dpi;
QString _scriptURL;
uint8_t _maxFPS;
bool _useBackground;
QString _userAgent;
WebInputMode _inputMode;
glm::vec3 _contextPosition;

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;
@ -1607,8 +1609,13 @@ void EntityItem::recordCreationTime() {
const Transform EntityItem::getTransformToCenter(bool& success) const {
Transform result = getTransform(success);
if (getRegistrationPoint() != ENTITY_ITEM_HALF_VEC3) { // If it is not already centered, translate to center
result.postTranslate((ENTITY_ITEM_HALF_VEC3 - getRegistrationPoint()) * getScaledDimensions()); // Position to center
glm::vec3 pivot = getPivot();
if (pivot != ENTITY_ITEM_ZERO_VEC3) {
result.postTranslate(pivot);
}
glm::vec3 registrationPoint = getRegistrationPoint();
if (registrationPoint != ENTITY_ITEM_HALF_VEC3) { // If it is not already centered, translate to center
result.postTranslate((ENTITY_ITEM_HALF_VEC3 - registrationPoint) * getScaledDimensions()); // Position to center
}
return result;
}
@ -1623,15 +1630,16 @@ AACube EntityItem::getMaximumAACube(bool& success) const {
_recalcMaxAACube = false;
// we want to compute the furthestExtent that an entity can extend out from its "position"
// to do this we compute the max of these two vec3s: registration and 1-registration
// and then scale by dimensions
glm::vec3 maxExtents = getScaledDimensions() * glm::max(_registrationPoint, glm::vec3(1.0f) - _registrationPoint);
// and then scale by dimensions and add the absolute value of the pivot
glm::vec3 registrationPoint = getRegistrationPoint();
glm::vec3 maxExtents = getScaledDimensions() * glm::max(registrationPoint, glm::vec3(1.0f) - registrationPoint);
// there exists a sphere that contains maxExtents for all rotations
float radius = glm::length(maxExtents);
// put a cube around the sphere
// TODO? replace _maxAACube with _boundingSphereRadius
glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius);
glm::vec3 minimumCorner = (centerOfRotation + getWorldOrientation() * getPivot()) - glm::vec3(radius, radius, radius);
_maxAACube = AACube(minimumCorner, radius * 2.0f);
}
} else {
@ -1650,9 +1658,12 @@ AACube EntityItem::getMinimumAACube(bool& success) const {
if (success) {
_recalcMinAACube = false;
glm::vec3 dimensions = getScaledDimensions();
glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint);
glm::vec3 registrationPoint = getRegistrationPoint();
glm::vec3 pivot = getPivot();
glm::vec3 unrotatedMinRelativeToEntity = -(dimensions * registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (ENTITY_ITEM_ONE_VEC3 - registrationPoint);
Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
extents.shiftBy(pivot);
extents.rotate(getWorldOrientation());
// shift the extents to be relative to the position/registration point
@ -1680,9 +1691,12 @@ AABox EntityItem::getAABox(bool& success) const {
if (success) {
_recalcAABox = false;
glm::vec3 dimensions = getScaledDimensions();
glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint);
glm::vec3 registrationPoint = getRegistrationPoint();
glm::vec3 pivot = getPivot();
glm::vec3 unrotatedMinRelativeToEntity = -(dimensions * registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (ENTITY_ITEM_ONE_VEC3 - registrationPoint);
Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
extents.shiftBy(pivot);
extents.rotate(getWorldOrientation());
// shift the extents to be relative to the position/registration point
@ -1722,12 +1736,22 @@ float EntityItem::getRadius() const {
return 0.5f * glm::length(getScaledDimensions());
}
void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info) const {
if (_registrationPoint != ENTITY_ITEM_DEFAULT_REGISTRATION_POINT) {
glm::mat4 scale = glm::scale(getScaledDimensions());
glm::mat4 registration = scale * glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
glm::vec3 regTransVec = glm::vec3(registration[3]); // extract position component from matrix
info.setOffset(regTransVec);
void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info, bool includePivot) const {
glm::vec3 offset;
glm::vec3 registrationPoint = getRegistrationPoint();
if (registrationPoint != ENTITY_ITEM_DEFAULT_REGISTRATION_POINT) {
offset += (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - registrationPoint) * getScaledDimensions();
}
if (includePivot) {
glm::vec3 pivot = getPivot();
if (pivot != ENTITY_ITEM_ZERO_VEC3) {
offset += pivot;
}
}
if (offset != ENTITY_ITEM_ZERO_VEC3) {
info.setOffset(offset);
}
}
@ -1739,7 +1763,7 @@ bool EntityItem::contains(const glm::vec3& point) const {
// anything with shapeType == SPHERE must collide as a bounding sphere in the world-frame regardless of dimensions
// therefore we must do math using an unscaled localPoint relative to sphere center
glm::vec3 dimensions = getScaledDimensions();
glm::vec3 localPoint = point - (getWorldPosition() + getWorldOrientation() * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())));
glm::vec3 localPoint = point - (getWorldPosition() + getWorldOrientation() * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()) + getPivot()));
const float HALF_SQUARED = 0.25f;
return glm::length2(localPoint) < HALF_SQUARED * glm::length2(dimensions);
}
@ -1797,11 +1821,16 @@ float EntityItem::getVolumeEstimate() const {
}
void EntityItem::setRegistrationPoint(const glm::vec3& value) {
if (value != _registrationPoint) {
withWriteLock([&] {
bool changed = false;
withWriteLock([&] {
if (value != _registrationPoint) {
_registrationPoint = glm::clamp(value, glm::vec3(ENTITY_ITEM_MIN_REGISTRATION_POINT),
glm::vec3(ENTITY_ITEM_MAX_REGISTRATION_POINT));
});
changed = true;
}
});
if (changed) {
dimensionsChanged(); // Registration Point affects the bounding box
markDirtyFlags(Simulation::DIRTY_SHAPE);
}
@ -2892,11 +2921,9 @@ QString EntityItem::getCollisionSoundURL() const {
}
glm::vec3 EntityItem::getRegistrationPoint() const {
glm::vec3 result;
withReadLock([&] {
result = _registrationPoint;
return resultWithReadLock<glm::vec3>([&] {
return _registrationPoint;
});
return result;
}
float EntityItem::getAngularDamping() const {
@ -3591,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,8 @@ 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;
virtual void setUnscaledDimensions(const glm::vec3& value);
@ -403,7 +404,7 @@ public:
// TODO: get rid of users of getRadius()...
float getRadius() const;
virtual void adjustShapeInfoByRegistration(ShapeInfo& info) const;
virtual void adjustShapeInfoByRegistration(ShapeInfo& info, bool includePivot = true) const;
virtual bool contains(const glm::vec3& point) const;
virtual bool isReadyToComputeShape() const { return !isDead(); }
@ -572,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; }
@ -587,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);
@ -778,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

@ -449,6 +449,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
@ -509,7 +510,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);
@ -554,6 +554,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_RELAY_PARENT_JOINTS, relayParentJoints);
CHECK_PROPERTY_CHANGE(PROP_GROUP_CULLED, groupCulled);
CHECK_PROPERTY_CHANGE(PROP_BLENDSHAPE_COEFFICIENTS, blendshapeCoefficients);
CHECK_PROPERTY_CHANGE(PROP_USE_ORIGINAL_PIVOT, useOriginalPivot);
changedProperties += _animation.getChangedProperties();
// Light
@ -620,6 +621,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_INPUT_MODE, inputMode);
CHECK_PROPERTY_CHANGE(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, showKeyboardFocusHighlight);
CHECK_PROPERTY_CHANGE(PROP_WEB_USE_BACKGROUND, useBackground);
CHECK_PROPERTY_CHANGE(PROP_USER_AGENT, userAgent);
// Polyline
CHECK_PROPERTY_CHANGE(PROP_LINE_POINTS, linePoints);
@ -828,6 +830,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.
*
@ -1019,6 +1023,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {string} blendshapeCoefficients - A JSON string of a map of blendshape names to values. Only stores set values.
* When editing this property, only coefficients that you are editing will change; it will not explicitly reset other
* coefficients.
* @property {boolean} useOriginalPivot=false - If <code>false</code>, the model will be centered based on its content,
* ignoring any offset in the model itself. If <code>true</code>, the model will respect its original offset. Currently,
* only pivots relative to <code>{x: 0, y: 0, z: 0}</code> are supported.
* @property {string} textures="" - A JSON string of texture name, URL pairs used when rendering the model in place of the
* model's original textures. Use a texture name from the <code>originalTextures</code> property to override that texture.
* Only the texture names and URLs to be overridden need be specified; original textures are used where there are no
@ -1350,7 +1357,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @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 {Entities.TextAlignment} alignment="left" - How the text is aligned against its background.
* @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>
@ -1386,7 +1392,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>
@ -1405,6 +1410,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {boolean} useBackground=true - <code>true</code> if the web entity should have a background,
* <code>false</code> if the web entity's background should be transparent. The webpage must have CSS properties for transparency set
* on the <code>background-color</code> for this property to have an effect.
* @property {string} userAgent - The user agent for the web entity to use when visiting web pages.
* Default value: <code>Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko)
* Chrome/69.0.3497.113 Mobile Safari/537.36</code>
* @example <caption>Create a Web entity displaying at 1920 x 1080 resolution.</caption>
* var METERS_TO_INCHES = 39.3701;
* var entity = Entities.addEntity({
@ -1505,7 +1513,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>
@ -1629,6 +1636,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
@ -1751,6 +1759,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RELAY_PARENT_JOINTS, relayParentJoints);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GROUP_CULLED, groupCulled);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_BLENDSHAPE_COEFFICIENTS, blendshapeCoefficients);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USE_ORIGINAL_PIVOT, useOriginalPivot);
if (!psuedoPropertyFlagsButDesiredEmpty) {
_animation.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
}
@ -1784,7 +1793,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);
@ -1835,7 +1843,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);
@ -1844,6 +1851,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_INPUT_MODE, inputMode, getInputModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, showKeyboardFocusHighlight);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_WEB_USE_BACKGROUND, useBackground);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_AGENT, userAgent);
}
// PolyVoxel only
@ -1903,7 +1911,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);
@ -2051,6 +2058,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
@ -2116,7 +2124,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);
@ -2161,6 +2168,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints);
COPY_PROPERTY_FROM_QSCRIPTVALUE(groupCulled, bool, setGroupCulled);
COPY_PROPERTY_FROM_QSCRIPTVALUE(blendshapeCoefficients, QString, setBlendshapeCoefficients);
COPY_PROPERTY_FROM_QSCRIPTVALUE(useOriginalPivot, bool, setUseOriginalPivot);
_animation.copyFromScriptValue(object, _defaultSettings);
// Light
@ -2227,6 +2235,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(inputMode, InputMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(showKeyboardFocusHighlight, bool, setShowKeyboardFocusHighlight);
COPY_PROPERTY_FROM_QSCRIPTVALUE(useBackground, bool, setUseBackground);
COPY_PROPERTY_FROM_QSCRIPTVALUE(userAgent, QString, setUserAgent);
// Polyline
COPY_PROPERTY_FROM_QSCRIPTVALUE(linePoints, qVectorVec3, setLinePoints);
@ -2349,6 +2358,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
@ -2409,7 +2419,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);
@ -2454,6 +2463,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(relayParentJoints);
COPY_PROPERTY_IF_CHANGED(groupCulled);
COPY_PROPERTY_IF_CHANGED(blendshapeCoefficients);
COPY_PROPERTY_IF_CHANGED(useOriginalPivot);
_animation.merge(other._animation);
// Light
@ -2520,6 +2530,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(inputMode);
COPY_PROPERTY_IF_CHANGED(showKeyboardFocusHighlight);
COPY_PROPERTY_IF_CHANGED(useBackground);
COPY_PROPERTY_IF_CHANGED(userAgent);
// Polyline
COPY_PROPERTY_IF_CHANGED(linePoints);
@ -2646,6 +2657,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);
@ -2742,7 +2754,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,
@ -2811,6 +2822,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_PROPERTY_TO_MAP(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool);
ADD_PROPERTY_TO_MAP(PROP_GROUP_CULLED, GroupCulled, groupCulled, bool);
ADD_PROPERTY_TO_MAP(PROP_BLENDSHAPE_COEFFICIENTS, BlendshapeCoefficients, blendshapeCoefficients, QString);
ADD_PROPERTY_TO_MAP(PROP_USE_ORIGINAL_PIVOT, UseOriginalPivot, useOriginalPivot, bool);
{ // Animation
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_URL, Animation, animation, URL, url);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation);
@ -2921,6 +2933,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_PROPERTY_TO_MAP(PROP_INPUT_MODE, InputMode, inputMode, WebInputMode);
ADD_PROPERTY_TO_MAP(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, ShowKeyboardFocusHighlight, showKeyboardFocusHighlight, bool);
ADD_PROPERTY_TO_MAP(PROP_WEB_USE_BACKGROUND, useBackground, useBackground, bool);
ADD_PROPERTY_TO_MAP(PROP_USER_AGENT, UserAgent, userAgent, QString);
// Polyline
ADD_PROPERTY_TO_MAP(PROP_LINE_POINTS, LinePoints, linePoints, QVector<vec3>);
@ -3139,6 +3152,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);
@ -3253,6 +3267,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, properties.getRelayParentJoints());
APPEND_ENTITY_PROPERTY(PROP_GROUP_CULLED, properties.getGroupCulled());
APPEND_ENTITY_PROPERTY(PROP_BLENDSHAPE_COEFFICIENTS, properties.getBlendshapeCoefficients());
APPEND_ENTITY_PROPERTY(PROP_USE_ORIGINAL_PIVOT, properties.getUseOriginalPivot());
_staticAnimation.setProperties(properties);
_staticAnimation.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
@ -3271,7 +3286,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());
@ -3344,7 +3358,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());
@ -3353,6 +3366,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_INPUT_MODE, (uint32_t)properties.getInputMode());
APPEND_ENTITY_PROPERTY(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, properties.getShowKeyboardFocusHighlight());
APPEND_ENTITY_PROPERTY(PROP_WEB_USE_BACKGROUND, properties.getUseBackground());
APPEND_ENTITY_PROPERTY(PROP_USER_AGENT, properties.getUserAgent());
}
if (properties.getType() == EntityTypes::Line) {
@ -3407,7 +3421,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());
@ -3633,6 +3646,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
@ -3743,6 +3757,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GROUP_CULLED, bool, setGroupCulled);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLENDSHAPE_COEFFICIENTS, QString, setBlendshapeCoefficients);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USE_ORIGINAL_PIVOT, bool, setUseOriginalPivot);
properties.getAnimation().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
}
@ -3759,7 +3774,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);
@ -3821,7 +3835,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);
@ -3830,6 +3843,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_INPUT_MODE, WebInputMode, setInputMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, bool, setShowKeyboardFocusHighlight);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_WEB_USE_BACKGROUND, bool, setUseBackground);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_AGENT, QString, setUserAgent);
}
if (properties.getType() == EntityTypes::Line) {
@ -3881,7 +3895,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);
@ -4055,6 +4068,7 @@ void EntityItemProperties::markAllChanged() {
_primitiveModeChanged = true;
_ignorePickIntersectionChanged = true;
_renderWithZonesChanged = true;
_billboardModeChanged = true;
_grab.markAllChanged();
// Physics
@ -4108,7 +4122,6 @@ void EntityItemProperties::markAllChanged() {
_alphaChanged = true;
_pulse.markAllChanged();
_texturesChanged = true;
_billboardModeChanged = true;
// Particles
_maxParticlesChanged = true;
@ -4153,6 +4166,7 @@ void EntityItemProperties::markAllChanged() {
_relayParentJointsChanged = true;
_groupCulledChanged = true;
_blendshapeCoefficientsChanged = true;
_useOriginalPivotChanged = true;
_animation.markAllChanged();
// Light
@ -4219,6 +4233,7 @@ void EntityItemProperties::markAllChanged() {
_inputModeChanged = true;
_showKeyboardFocusHighlightChanged = true;
_useBackgroundChanged = true;
_userAgentChanged = true;
// Polyline
_linePointsChanged = true;
@ -4464,6 +4479,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (renderWithZonesChanged()) {
out += "renderWithZones";
}
if (billboardModeChanged()) {
out += "billboardMode";
}
getGrab().listChangedProperties(out);
// Physics
@ -4599,9 +4617,6 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (texturesChanged()) {
out += "textures";
}
if (billboardModeChanged()) {
out += "billboardMode";
}
// Particles
if (maxParticlesChanged()) {
@ -4726,6 +4741,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (blendshapeCoefficientsChanged()) {
out += "blendshapeCoefficients";
}
if (useOriginalPivotChanged()) {
out += "useOriginalPivot";
}
getAnimation().listChangedProperties(out);
// Light
@ -4915,6 +4933,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (useBackgroundChanged()) {
out += "useBackground";
}
if (userAgentChanged()) {
out += "userAgent";
}
// Shape
if (shapeChanged()) {

View file

@ -198,6 +198,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
@ -258,7 +259,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);
@ -303,6 +303,7 @@ public:
DEFINE_PROPERTY(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool, ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS);
DEFINE_PROPERTY_REF(PROP_GROUP_CULLED, GroupCulled, groupCulled, bool, false);
DEFINE_PROPERTY_REF(PROP_BLENDSHAPE_COEFFICIENTS, BlendshapeCoefficients, blendshapeCoefficients, QString, "");
DEFINE_PROPERTY_REF(PROP_USE_ORIGINAL_PIVOT, UseOriginalPivot, useOriginalPivot, bool, false);
DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup);
// Light
@ -369,6 +370,7 @@ public:
DEFINE_PROPERTY_REF_ENUM(PROP_INPUT_MODE, InputMode, inputMode, WebInputMode, WebInputMode::TOUCH);
DEFINE_PROPERTY_REF(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, ShowKeyboardFocusHighlight, showKeyboardFocusHighlight, bool, true);
DEFINE_PROPERTY_REF(PROP_WEB_USE_BACKGROUND, UseBackground, useBackground, bool, true);
DEFINE_PROPERTY_REF(PROP_USER_AGENT, UserAgent, userAgent, QString, WebEntityItem::DEFAULT_USER_AGENT);
// Polyline
DEFINE_PROPERTY_REF(PROP_LINE_POINTS, LinePoints, linePoints, QVector<glm::vec3>, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC);

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
@ -218,16 +218,17 @@ enum EntityPropertyList {
PROP_RELAY_PARENT_JOINTS = PROP_DERIVED_6,
PROP_GROUP_CULLED = PROP_DERIVED_7,
PROP_BLENDSHAPE_COEFFICIENTS = PROP_DERIVED_8,
PROP_USE_ORIGINAL_PIVOT = PROP_DERIVED_9,
// Animation
PROP_ANIMATION_URL = PROP_DERIVED_9,
PROP_ANIMATION_ALLOW_TRANSLATION = PROP_DERIVED_10,
PROP_ANIMATION_FPS = PROP_DERIVED_11,
PROP_ANIMATION_FRAME_INDEX = PROP_DERIVED_12,
PROP_ANIMATION_PLAYING = PROP_DERIVED_13,
PROP_ANIMATION_LOOP = PROP_DERIVED_14,
PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_15,
PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_16,
PROP_ANIMATION_HOLD = PROP_DERIVED_17,
PROP_ANIMATION_URL = PROP_DERIVED_10,
PROP_ANIMATION_ALLOW_TRANSLATION = PROP_DERIVED_11,
PROP_ANIMATION_FPS = PROP_DERIVED_12,
PROP_ANIMATION_FRAME_INDEX = PROP_DERIVED_13,
PROP_ANIMATION_PLAYING = PROP_DERIVED_14,
PROP_ANIMATION_LOOP = PROP_DERIVED_15,
PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_16,
PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_17,
PROP_ANIMATION_HOLD = PROP_DERIVED_18,
// Light
PROP_IS_SPOTLIGHT = PROP_DERIVED_0,
@ -320,6 +321,7 @@ enum EntityPropertyList {
PROP_INPUT_MODE = PROP_DERIVED_4,
PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT = PROP_DERIVED_5,
PROP_WEB_USE_BACKGROUND = PROP_DERIVED_6,
PROP_USER_AGENT = PROP_DERIVED_7,
// Polyline
PROP_LINE_POINTS = PROP_DERIVED_0,

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) {
@ -205,10 +205,7 @@ EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& ori
// (this is faster and more likely to cull results than the filter check below so we do it first)
bool success;
AABox entityBox = entity->getAABox(success);
if (!success) {
return;
}
if (!entityBox.rayHitsBoundingSphere(origin, direction)) {
if (!success || !entityBox.rayHitsBoundingSphere(origin, direction)) {
return;
}
@ -219,14 +216,17 @@ 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);
glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
AABox entityFrameBox(corner, dimensions);
@ -244,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;
@ -277,11 +277,12 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad
bool result = false;
withReadLock([&] {
foreach(EntityItemPointer entity, _entityItems) {
glm::vec3 entityCenter = entity->getWorldPosition();
bool success;
glm::vec3 entityCenter = entity->getCenterPosition(success);
float entityRadius = entity->getRadius();
// don't penetrate yourself
if (entityCenter == center && entityRadius == radius) {
if (!success || (entityCenter == center && entityRadius == radius)) {
return;
}
@ -298,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) {
@ -321,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;
@ -334,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;
@ -349,15 +350,12 @@ EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3
// (this is faster and more likely to cull results than the filter check below so we do it first)
bool success;
AABox entityBox = entity->getAABox(success);
if (!success) {
return;
}
// Instead of checking parabolaInstersectsBoundingSphere here, we are just going to check if the plane
// defined by the parabola slices the sphere. The solution to parabolaIntersectsBoundingSphere is cubic,
// the solution to which is more computationally expensive than the quadratic AABox::findParabolaIntersection
// below
if (!entityBox.parabolaPlaneIntersectsBoundingSphere(origin, velocity, acceleration, normal)) {
if (!success || !entityBox.parabolaPlaneIntersectsBoundingSphere(origin, velocity, acceleration, normal)) {
return;
}
@ -368,14 +366,17 @@ 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);
glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
AABox entityFrameBox(corner, dimensions);
@ -394,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;
@ -445,12 +446,11 @@ void EntityTreeElement::evalEntitiesInSphere(const glm::vec3& position, float ra
bool success;
AABox entityBox = entity->getAABox(success);
// if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case
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
@ -464,21 +464,20 @@ void EntityTreeElement::evalEntitiesInSphere(const glm::vec3& position, float ra
float entityTrueRadius = dimensions.x / 2.0f;
bool success;
if (findSphereSpherePenetration(position, radius, entity->getCenterPosition(success), entityTrueRadius, penetration)) {
if (success) {
foundEntities.push_back(entity->getID());
}
glm::vec3 center = entity->getCenterPosition(success);
if (success && findSphereSpherePenetration(position, radius, center, entityTrueRadius, penetration)) {
foundEntities.push_back(entity->getID());
}
} 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);
glm::vec3 registrationPoint = entity->getRegistrationPoint();
glm::vec3 corner = -(dimensions * registrationPoint);
glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
AABox entityFrameBox(corner, dimensions);
@ -499,12 +498,11 @@ void EntityTreeElement::evalEntitiesInSphereWithType(const glm::vec3& position,
bool success;
AABox entityBox = entity->getAABox(success);
// if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case
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
@ -518,21 +516,20 @@ void EntityTreeElement::evalEntitiesInSphereWithType(const glm::vec3& position,
float entityTrueRadius = dimensions.x / 2.0f;
bool success;
if (findSphereSpherePenetration(position, radius, entity->getCenterPosition(success), entityTrueRadius, penetration)) {
if (success) {
foundEntities.push_back(entity->getID());
}
glm::vec3 center = entity->getCenterPosition(success);
if (success && findSphereSpherePenetration(position, radius, center, entityTrueRadius, penetration)) {
foundEntities.push_back(entity->getID());
}
} 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);
glm::vec3 registrationPoint = entity->getRegistrationPoint();
glm::vec3 corner = -(dimensions * registrationPoint);
glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
AABox entityFrameBox(corner, dimensions);
@ -563,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,23 +572,22 @@ void EntityTreeElement::evalEntitiesInSphereWithName(const glm::vec3& position,
// NOTE: entity->getRadius() doesn't return the true radius, it returns the radius of the
// maximum bounding sphere, which is actually larger than our actual radius
float entityTrueRadius = dimensions.x / 2.0f;
bool success;
if (findSphereSpherePenetration(position, radius, entity->getCenterPosition(success), entityTrueRadius, penetration)) {
if (success) {
foundEntities.push_back(entity->getID());
}
glm::vec3 center = entity->getCenterPosition(success);
if (success && findSphereSpherePenetration(position, radius, center, entityTrueRadius, penetration)) {
foundEntities.push_back(entity->getID());
}
} 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);
glm::vec3 registrationPoint = entity->getRegistrationPoint();
glm::vec3 corner = -(dimensions * registrationPoint);
glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot();
AABox entityFrameBox(corner, dimensions);
@ -612,6 +608,7 @@ void EntityTreeElement::evalEntitiesInCube(const AACube& cube, PickFilter search
bool success;
AABox entityBox = entity->getAABox(success);
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better
// FIXME - consider allowing the entity to determine penetration so that
// entities could presumably dull actuall hull testing if they wanted to
@ -642,6 +639,7 @@ void EntityTreeElement::evalEntitiesInBox(const AABox& box, PickFilter searchFil
bool success;
AABox entityBox = entity->getAABox(success);
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better
// FIXME - consider allowing the entity to determine penetration so that
// entities could presumably dull actuall hull testing if they wanted to
@ -680,7 +678,7 @@ void EntityTreeElement::evalEntitiesInFrustum(const ViewFrustum& frustum, PickFi
});
}
void EntityTreeElement::getEntities(EntityItemFilter& filter, QVector<EntityItemPointer>& foundEntities) {
void EntityTreeElement::getEntities(EntityItemFilter& filter, QVector<EntityItemPointer>& foundEntities) {
forEachEntity([&](EntityItemPointer entity) {
if (filter(entity)) {
foundEntities.push_back(entity);

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

@ -73,6 +73,7 @@ EntityItemProperties ModelEntityItem::getProperties(const EntityPropertyFlags& d
COPY_ENTITY_PROPERTY_TO_PROPERTIES(relayParentJoints, getRelayParentJoints);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(groupCulled, getGroupCulled);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendshapeCoefficients, getBlendshapeCoefficients);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(useOriginalPivot, getUseOriginalPivot);
withReadLock([&] {
_animationProperties.getProperties(properties);
});
@ -96,6 +97,7 @@ bool ModelEntityItem::setSubClassProperties(const EntityItemProperties& properti
SET_ENTITY_PROPERTY_FROM_PROPERTIES(relayParentJoints, setRelayParentJoints);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(groupCulled, setGroupCulled);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendshapeCoefficients, setBlendshapeCoefficients);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(useOriginalPivot, setUseOriginalPivot);
withWriteLock([&] {
AnimationPropertyGroup animationProperties = _animationProperties;
@ -130,6 +132,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints);
READ_ENTITY_PROPERTY(PROP_GROUP_CULLED, bool, setGroupCulled);
READ_ENTITY_PROPERTY(PROP_BLENDSHAPE_COEFFICIENTS, QString, setBlendshapeCoefficients);
READ_ENTITY_PROPERTY(PROP_USE_ORIGINAL_PIVOT, bool, setUseOriginalPivot);
// grab a local copy of _animationProperties to avoid multiple locks
int bytesFromAnimation;
@ -169,6 +172,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams&
requestedProperties += PROP_RELAY_PARENT_JOINTS;
requestedProperties += PROP_GROUP_CULLED;
requestedProperties += PROP_BLENDSHAPE_COEFFICIENTS;
requestedProperties += PROP_USE_ORIGINAL_PIVOT;
requestedProperties += _animationProperties.getEntityProperties(params);
return requestedProperties;
@ -198,6 +202,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, getRelayParentJoints());
APPEND_ENTITY_PROPERTY(PROP_GROUP_CULLED, getGroupCulled());
APPEND_ENTITY_PROPERTY(PROP_BLENDSHAPE_COEFFICIENTS, getBlendshapeCoefficients());
APPEND_ENTITY_PROPERTY(PROP_USE_ORIGINAL_PIVOT, getUseOriginalPivot());
withReadLock([&] {
_animationProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
@ -251,6 +256,7 @@ void ModelEntityItem::debugDump() const {
qCDebug(entities) << " model URL:" << getModelURL();
qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL();
qCDebug(entities) << " blendshapeCoefficients:" << getBlendshapeCoefficients();
qCDebug(entities) << " useOrigialPivot:" << getUseOriginalPivot();
}
void ModelEntityItem::setShapeType(ShapeType type) {
@ -713,3 +719,25 @@ QVector<float> ModelEntityItem::getBlendshapeCoefficientVector() {
return _blendshapeCoefficientsVector;
});
}
void ModelEntityItem::setUseOriginalPivot(bool value) {
bool changed = false;
withWriteLock([&] {
if (_useOriginalPivot != value) {
_needsRenderUpdate = true;
_useOriginalPivot = value;
changed = true;
}
});
if (changed) {
markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
locationChanged();
}
}
bool ModelEntityItem::getUseOriginalPivot() const {
return resultWithReadLock<bool>([&] {
return _useOriginalPivot;
});
}

View file

@ -119,6 +119,9 @@ public:
bool blendshapesChanged() const { return _blendshapesChanged; }
QVector<float> getBlendshapeCoefficientVector();
bool getUseOriginalPivot() const;
void setUseOriginalPivot(bool useOriginalPivot);
private:
void setAnimationSettings(const QString& value); // only called for old bitstream format
bool applyNewAnimationProperties(AnimationPropertyGroup newProperties);
@ -152,6 +155,7 @@ protected:
bool _relayParentJoints;
bool _groupCulled { false };
QVariantMap _blendshapeCoefficientsMap;
bool _useOriginalPivot { false };
ThreadSafeValueCache<QString> _compoundShapeURL;

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);
@ -82,7 +81,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);
@ -119,7 +117,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);
@ -145,7 +142,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;
@ -181,7 +177,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());
@ -201,69 +196,6 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
APPEND_ENTITY_PROPERTY(PROP_TEXT_ALIGNMENT, (uint32_t)getAlignment());
}
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;
@ -344,21 +276,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

@ -47,17 +47,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;
@ -81,9 +70,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);
@ -119,8 +105,6 @@ public:
PulsePropertyGroup getPulseProperties() const;
private:
BillboardMode _billboardMode;
QString _text;
float _lineHeight;
glm::u8vec3 _textColor;

View file

@ -25,6 +25,7 @@
#include "EntityTreeElement.h"
const QString WebEntityItem::DEFAULT_SOURCE_URL = NetworkingConstants::WEB_ENTITY_DEFAULT_SOURCE_URL;
const QString WebEntityItem::DEFAULT_USER_AGENT = NetworkingConstants::WEB_ENTITY_DEFAULT_USER_AGENT;
const uint8_t WebEntityItem::DEFAULT_MAX_FPS = 10;
EntityItemPointer WebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
@ -54,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);
@ -63,6 +63,7 @@ EntityItemProperties WebEntityItem::getProperties(const EntityPropertyFlags& des
COPY_ENTITY_PROPERTY_TO_PROPERTIES(inputMode, getInputMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(showKeyboardFocusHighlight, getShowKeyboardFocusHighlight);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(useBackground, getUseBackground);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(userAgent, getUserAgent);
return properties;
}
@ -76,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);
@ -85,6 +85,7 @@ bool WebEntityItem::setSubClassProperties(const EntityItemProperties& properties
SET_ENTITY_PROPERTY_FROM_PROPERTIES(inputMode, setInputMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(showKeyboardFocusHighlight, setShowKeyboardFocusHighlight);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(useBackground, setUseBackground);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(userAgent, setUserAgent);
return somethingChanged;
}
@ -106,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);
@ -115,6 +115,7 @@ int WebEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, i
READ_ENTITY_PROPERTY(PROP_INPUT_MODE, WebInputMode, setInputMode);
READ_ENTITY_PROPERTY(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, bool, setShowKeyboardFocusHighlight);
READ_ENTITY_PROPERTY(PROP_WEB_USE_BACKGROUND, bool, setUseBackground);
READ_ENTITY_PROPERTY(PROP_USER_AGENT, QString, setUserAgent);
return bytesRead;
}
@ -124,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;
@ -133,6 +133,7 @@ EntityPropertyFlags WebEntityItem::getEntityProperties(EncodeBitstreamParams& pa
requestedProperties += PROP_INPUT_MODE;
requestedProperties += PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT;
requestedProperties += PROP_WEB_USE_BACKGROUND;
requestedProperties += PROP_USER_AGENT;
return requestedProperties;
}
@ -151,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());
@ -160,71 +160,7 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
APPEND_ENTITY_PROPERTY(PROP_INPUT_MODE, (uint32_t)getInputMode());
APPEND_ENTITY_PROPERTY(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, getShowKeyboardFocusHighlight());
APPEND_ENTITY_PROPERTY(PROP_WEB_USE_BACKGROUND, getUseBackground());
}
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;
}
APPEND_ENTITY_PROPERTY(PROP_USER_AGENT, getUserAgent());
}
void WebEntityItem::setColor(const glm::u8vec3& value) {
@ -259,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;
@ -365,6 +288,17 @@ bool WebEntityItem::getUseBackground() const {
return resultWithReadLock<bool>([&] { return _useBackground; });
}
void WebEntityItem::setUserAgent(const QString& value) {
withWriteLock([&] {
_needsRenderUpdate |= _userAgent != value;
_userAgent = value;
});
}
QString WebEntityItem::getUserAgent() const {
return resultWithReadLock<QString>([&] { return _userAgent; });
}
PulsePropertyGroup WebEntityItem::getPulseProperties() const {
return resultWithReadLock<PulsePropertyGroup>([&] {
return _pulseProperties;

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;
@ -89,6 +75,10 @@ public:
bool getUseBackground() const;
void setUseBackground(bool value);
static const QString DEFAULT_USER_AGENT;
QString getUserAgent() const;
void setUserAgent(const QString& value);
PulsePropertyGroup getPulseProperties() const;
@ -96,7 +86,6 @@ protected:
glm::u8vec3 _color;
float _alpha { 1.0f };
PulsePropertyGroup _pulseProperties;
BillboardMode _billboardMode;
QString _sourceUrl;
uint16_t _dpi;
@ -105,6 +94,7 @@ protected:
WebInputMode _inputMode;
bool _showKeyboardFocusHighlight;
bool _useBackground;
QString _userAgent;
bool _localSafeContext { false };
};

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

@ -104,7 +104,7 @@ bool HFMModel::convexHullContains(const glm::vec3& point) const {
auto checkEachPrimitive = [=](HFMMesh& mesh, QVector<int> indices, int primitiveSize) -> bool {
// Check whether the point is "behind" all the primitives.
// But first must transform from model-frame into mesh-frame
glm::vec3 transformedPoint = glm::vec3(glm::inverse(mesh.modelTransform) * glm::vec4(point, 1.0f));
glm::vec3 transformedPoint = glm::vec3(glm::inverse(offset * mesh.modelTransform) * glm::vec4(point, 1.0f));
int verticesSize = mesh.vertices.size();
for (int j = 0;
j < indices.size() - 2; // -2 in case the vertices aren't the right size -- we access j + 2 below

View file

@ -25,6 +25,8 @@ namespace NetworkingConstants {
// You can avoid changing that and still effectively use a connected domain on staging
// if you manually generate a personal access token for the domains scope
// at https://staging.highfidelity.com/user/tokens/new?for_domain_server=true
const QString WEB_ENGINE_VERSION = "Chrome/69.0.3497.113";
// For now we only have one Metaverse server.
const QUrl METAVERSE_SERVER_URL_STABLE { "https://metaverse.vircadia.com/live" };
@ -37,15 +39,16 @@ namespace NetworkingConstants {
// Use a custom User-Agent to avoid ModSecurity filtering, e.g. by hosting providers.
const QByteArray VIRCADIA_USER_AGENT = "Mozilla/5.0 (VircadiaInterface)";
const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (VircadiaInterface)";
const QString METAVERSE_USER_AGENT = "Chrome/48.0 (VircadiaInterface)";
const QString MOBILE_USER_AGENT = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
const QUrl BUILDS_XML_URL("https://highfidelity.com/builds.xml");
const QUrl MASTER_BUILDS_XML_URL("https://highfidelity.com/dev-builds.xml");
const QString WEB_ENGINE_USER_AGENT = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) " + WEB_ENGINE_VERSION + " Mobile Safari/537.36";
const QString MOBILE_USER_AGENT = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) " + WEB_ENGINE_VERSION + " Mobile Safari/537.36";
// WebEntity Defaults
const QString WEB_ENTITY_DEFAULT_SOURCE_URL = "https://vircadia.com/";
const QString WEB_ENTITY_DEFAULT_USER_AGENT = WEB_ENGINE_USER_AGENT;
// Builds URLs
const QUrl BUILDS_XML_URL("https://highfidelity.com/builds.xml");
const QUrl MASTER_BUILDS_XML_URL("https://highfidelity.com/dev-builds.xml");
const QString DEFAULT_AVATAR_COLLISION_SOUND_URL = "https://hifi-public.s3.amazonaws.com/sounds/Collisions-otherorganic/Body_Hits_Impact.wav";

View file

@ -283,6 +283,9 @@ enum class EntityVersion : PacketVersion {
ZoneOcclusion,
ModelBlendshapes,
TransparentWeb,
UseOriginalPivot,
UserAgent,
AllBillboardMode,
TextAlignment,
// Add new versions above here

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,12 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
}
// extents is the entity relative, scaled, centered extents of the entity
glm::mat4 modelToWorldMatrix = 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());
}
glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix);
Extents modelExtents = getMeshExtents(); // NOTE: unrotated
@ -375,8 +367,12 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
calculateTriangleSets(hfmModel);
}
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
glm::mat4 meshToWorldMatrix = modelToWorldMatrix * meshToModelMatrix;
glm::mat4 meshToWorldMatrix = transRot;
if (_snapModelToRegistrationPoint || _forceOffset) {
meshToWorldMatrix = meshToWorldMatrix * (glm::scale(_scale) * glm::translate(_offset));
} else {
meshToWorldMatrix = meshToWorldMatrix * (glm::scale(_scale) * glm::translate(getNaturalDimensions() * (0.5f - _registrationPoint)));
}
glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix);
glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f));
@ -488,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...
@ -498,7 +494,12 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co
}
// extents is the entity relative, scaled, centered extents of the entity
glm::mat4 modelToWorldMatrix = 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());
}
glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix);
Extents modelExtents = getMeshExtents(); // NOTE: unrotated
@ -531,8 +532,12 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co
calculateTriangleSets(hfmModel);
}
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
glm::mat4 meshToWorldMatrix = modelToWorldMatrix * meshToModelMatrix;
glm::mat4 meshToWorldMatrix = transRot;
if (_snapModelToRegistrationPoint || _forceOffset) {
meshToWorldMatrix = meshToWorldMatrix * (glm::scale(_scale) * glm::translate(_offset));
} else {
meshToWorldMatrix = meshToWorldMatrix * (glm::scale(_scale) * glm::translate(getNaturalDimensions() * (0.5f - _registrationPoint)));
}
glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix);
glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f));
@ -987,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;
@ -1017,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);
});
}
@ -1182,17 +1204,8 @@ glm::vec3 Model::getNaturalDimensions() const {
}
Extents Model::getMeshExtents() const {
if (!isLoaded()) {
return Extents();
}
const Extents& extents = getHFMModel().meshExtents;
// even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which
// is captured in the offset matrix
glm::vec3 minimum = glm::vec3(getHFMModel().offset * glm::vec4(extents.minimum, 1.0f));
glm::vec3 maximum = glm::vec3(getHFMModel().offset * glm::vec4(extents.maximum, 1.0f));
Extents scaledExtents = { minimum * _scale, maximum * _scale };
return scaledExtents;
Extents extents = getUnscaledMeshExtents();
return { extents.minimum * _scale, extents.maximum * _scale };
}
Extents Model::getUnscaledMeshExtents() const {
@ -1417,6 +1430,15 @@ void Model::snapToRegistrationPoint() {
_snappedToRegistrationPoint = true;
}
glm::vec3 Model::getOriginalOffset() const {
Extents modelMeshExtents = getUnscaledMeshExtents();
glm::vec3 dimensions = (modelMeshExtents.maximum - modelMeshExtents.minimum);
glm::vec3 offset = modelMeshExtents.minimum + (0.5f * dimensions);
glm::mat4 transform = glm::scale(_scale) * glm::translate(offset);
return transform[3];
}
void Model::setUseDualQuaternionSkinning(bool value) {
_useDualQuaternionSkinning = value;
}
@ -1437,7 +1459,8 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
snapToRegistrationPoint();
}
// update the world space transforms for all joints
glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset);
glm::mat4 parentTransform = glm::scale(_scale) * ((_snapModelToRegistrationPoint || _forceOffset) ?
glm::translate(_offset) : glm::translate(getNaturalDimensions() * (0.5f - _registrationPoint)));
updateRig(deltaTime, parentTransform);
}
}
@ -1514,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;
}
@ -1545,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();
@ -1561,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);
@ -167,6 +171,7 @@ public:
void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint);
bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; }
bool getSnappedToRegistrationPoint() { return _snappedToRegistrationPoint; }
virtual void simulate(float deltaTime, bool fullUpdate = true);
virtual void updateClusterMatrices();
@ -194,15 +199,16 @@ 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);
const glm::vec3& getOffset() const { return _offset; }
glm::vec3 getOriginalOffset() const;
void setScaleToFit(bool scaleToFit, float largestDimension = 0.0f, bool forceRescale = false);
void setScaleToFit(bool scaleToFit, const glm::vec3& dimensions, bool forceRescale = false);
@ -348,6 +354,7 @@ public:
virtual bool replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointer model, int meshIndex, int partIndex) override;
void scaleToFit();
void snapToRegistrationPoint();
bool getUseDualQuaternionSkinning() const { return _useDualQuaternionSkinning; }
void setUseDualQuaternionSkinning(bool value);
@ -409,14 +416,14 @@ protected:
bool _snapModelToRegistrationPoint; /// is the model's offset automatically adjusted to a registration point in model space
bool _snappedToRegistrationPoint; /// are we currently snapped to a registration point
glm::vec3 _registrationPoint = glm::vec3(0.5f); /// the point in model space our center is snapped to
glm::vec3 _registrationPoint { glm::vec3(0.5f) }; /// the point in model space our center is snapped to
bool _forceOffset { false };
std::vector<MeshState> _meshStates;
virtual void initJointStates();
void setScaleInternal(const glm::vec3& scale);
void snapToRegistrationPoint();
virtual void updateRig(float deltaTime, glm::mat4 parentTransform);
@ -447,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);

Some files were not shown because too many files have changed in this diff Show more