mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-08 15:43:17 +02:00
Merge branch 'master' into alignment
This commit is contained in:
commit
f46f1b2219
109 changed files with 1070 additions and 1383 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -193,7 +193,11 @@ function promptToCreateDomainID() {
|
|||
|
||||
var formJSON = {
|
||||
"metaverse": {
|
||||
"automatic_networking": "full",
|
||||
"id": domainID
|
||||
},
|
||||
"descriptors": {
|
||||
"world_name": label
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)";
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2455,13 +2455,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value);
|
||||
});
|
||||
|
||||
EntityItem::setBillboardRotationOperator([](const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos) {
|
||||
BillboardModeHelpers::setBillboardRotationOperator([](const glm::vec3& position, const glm::quat& rotation,
|
||||
BillboardMode billboardMode, const glm::vec3& frustumPos, bool rotate90x) {
|
||||
const glm::quat ROTATE_90X = glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
|
||||
if (billboardMode == BillboardMode::YAW) {
|
||||
//rotate about vertical to face the camera
|
||||
glm::vec3 dPosition = frustumPos - position;
|
||||
// If x and z are 0, atan(x, z) is undefined, so default to 0 degrees
|
||||
float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z);
|
||||
return glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
|
||||
glm::quat result = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)) * rotation;
|
||||
if (rotate90x) {
|
||||
result *= ROTATE_90X;
|
||||
}
|
||||
return result;
|
||||
} else if (billboardMode == BillboardMode::FULL) {
|
||||
// use the referencial from the avatar, y isn't always up
|
||||
glm::vec3 avatarUP = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * Vectors::UP;
|
||||
|
@ -2470,12 +2476,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
|
||||
// make sure s is not NaN for any component
|
||||
if (glm::length2(s) > 0.0f) {
|
||||
return glm::conjugate(glm::toQuat(glm::lookAt(frustumPos, position, avatarUP)));
|
||||
glm::quat result = glm::conjugate(glm::toQuat(glm::lookAt(frustumPos, position, avatarUP))) * rotation;
|
||||
if (rotate90x) {
|
||||
result *= ROTATE_90X;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return rotation;
|
||||
});
|
||||
EntityItem::setPrimaryViewFrustumPositionOperator([this]() {
|
||||
BillboardModeHelpers::setPrimaryViewFrustumPositionOperator([this]() {
|
||||
ViewFrustum viewFrustum;
|
||||
copyViewFrustum(viewFrustum);
|
||||
return viewFrustum.getPosition();
|
||||
|
|
|
@ -509,7 +509,7 @@ Menu::Menu() {
|
|||
|
||||
action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::MaterialProceduralShaders, 0, false);
|
||||
connect(action, &QAction::triggered, [action] {
|
||||
MeshPartPayload::enableMaterialProceduralShaders = action->isChecked();
|
||||
ModelMeshPartPayload::enableMaterialProceduralShaders = action->isChecked();
|
||||
});
|
||||
|
||||
{
|
||||
|
|
|
@ -767,6 +767,7 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
|
|||
glm::vec3 rayDirectionInv = { rayDirection.x != 0.0f ? 1.0f / rayDirection.x : INFINITY,
|
||||
rayDirection.y != 0.0f ? 1.0f / rayDirection.y : INFINITY,
|
||||
rayDirection.z != 0.0f ? 1.0f / rayDirection.z : INFINITY };
|
||||
glm::vec3 viewFrustumPos = BillboardModeHelpers::getPrimaryViewFrustumPosition();
|
||||
|
||||
for (auto &hit : physicsResults) {
|
||||
auto avatarID = hit._intersectWithAvatar;
|
||||
|
@ -842,7 +843,8 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
|
|||
BoxFace subMeshFace = BoxFace::UNKNOWN_FACE;
|
||||
glm::vec3 subMeshSurfaceNormal;
|
||||
QVariantMap subMeshExtraInfo;
|
||||
if (avatar->getSkeletonModel()->findRayIntersectionAgainstSubMeshes(defaultFrameRayOrigin, defaultFrameRayDirection, subMeshDistance, subMeshFace, subMeshSurfaceNormal, subMeshExtraInfo, true, false)) {
|
||||
if (avatar->getSkeletonModel()->findRayIntersectionAgainstSubMeshes(defaultFrameRayOrigin, defaultFrameRayDirection, viewFrustumPos, subMeshDistance,
|
||||
subMeshFace, subMeshSurfaceNormal, subMeshExtraInfo, true, false)) {
|
||||
rayAvatarResult._distance = subMeshDistance;
|
||||
rayAvatarResult._intersectionPoint = ray.origin + subMeshDistance * rayDirection;
|
||||
rayAvatarResult._intersectionNormal = subMeshSurfaceNormal;
|
||||
|
@ -932,6 +934,7 @@ ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector
|
|||
std::sort(sortedAvatars.begin(), sortedAvatars.end(), comparator);
|
||||
}
|
||||
|
||||
glm::vec3 viewFrustumPos = BillboardModeHelpers::getPrimaryViewFrustumPosition();
|
||||
for (auto it = sortedAvatars.begin(); it != sortedAvatars.end(); ++it) {
|
||||
const SortedAvatar& sortedAvatar = *it;
|
||||
// We can exit once avatarCapsuleDistance > bestDistance
|
||||
|
@ -944,7 +947,7 @@ ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector
|
|||
glm::vec3 surfaceNormal;
|
||||
QVariantMap extraInfo;
|
||||
SkeletonModelPointer avatarModel = sortedAvatar.second->getSkeletonModel();
|
||||
if (avatarModel->findParabolaIntersectionAgainstSubMeshes(pick.origin, pick.velocity, pick.acceleration, parabolicDistance, face, surfaceNormal, extraInfo, true)) {
|
||||
if (avatarModel->findParabolaIntersectionAgainstSubMeshes(pick.origin, pick.velocity, pick.acceleration, viewFrustumPos, parabolicDistance, face, surfaceNormal, extraInfo, true)) {
|
||||
if (parabolicDistance < result.parabolicDistance) {
|
||||
result.intersects = true;
|
||||
result.avatarID = sortedAvatar.second->getID();
|
||||
|
|
|
@ -16,7 +16,7 @@ render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) { return Item::Bound(); }
|
||||
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
||||
PerformanceTimer perfTimer("worldBox");
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff);
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff);
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args);
|
||||
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args);
|
||||
}
|
||||
|
||||
|
|
|
@ -462,9 +462,9 @@ namespace render {
|
|||
template <> const ItemKey payloadGetKey(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload) {
|
||||
return payload->getKey();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload) {
|
||||
template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload, RenderArgs* args) {
|
||||
if (payload) {
|
||||
return payload->getBound();
|
||||
return payload->getBound(args);
|
||||
}
|
||||
return Item::Bound();
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
|
||||
void render(RenderArgs* args);
|
||||
render::Item::Bound& editBound() { return _bound; }
|
||||
const render::Item::Bound& getBound() { return _bound; }
|
||||
const render::Item::Bound& getBound(RenderArgs* args) { return _bound; }
|
||||
render::ItemKey getKey() const { return _key; }
|
||||
|
||||
void setVisible(bool visible);
|
||||
|
@ -128,7 +128,7 @@ private:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload, RenderArgs* args);
|
||||
template <> void payloadRender(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const ParabolaPointer::RenderState::ParabolaRenderItem::Pointer& payload);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -66,7 +66,7 @@ private:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay);
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay);
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay, RenderArgs* args);
|
||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay);
|
||||
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems);
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace render {
|
|||
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay) {
|
||||
return overlay->getKey();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||
return overlay->getBounds();
|
||||
}
|
||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||
|
|
|
@ -82,9 +82,9 @@ namespace render {
|
|||
template <> const ItemKey payloadGetKey(const GameWorkloadRenderItem::Pointer& payload) {
|
||||
return payload->getKey();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload) {
|
||||
template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args) {
|
||||
if (payload) {
|
||||
return payload->getBound();
|
||||
return payload->getBound(args);
|
||||
}
|
||||
return Item::Bound();
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public:
|
|||
void render(RenderArgs* args);
|
||||
|
||||
render::Item::Bound& editBound() { return _bound; }
|
||||
const render::Item::Bound& getBound() { return _bound; }
|
||||
const render::Item::Bound& getBound(RenderArgs* args) { return _bound; }
|
||||
|
||||
void setVisible(bool visible);
|
||||
void showProxies(bool show);
|
||||
|
@ -96,7 +96,7 @@ protected:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const GameWorkloadRenderItem::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args);
|
||||
template <> void payloadRender(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const GameWorkloadRenderItem::Pointer& payload);
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace render {
|
|||
}
|
||||
return keyBuilder.build();
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
|
||||
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar, RenderArgs* args) {
|
||||
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
|
||||
if (avatarPtr) {
|
||||
return avatarPtr->getRenderBounds();
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar);
|
||||
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar);
|
||||
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar, RenderArgs* args);
|
||||
template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args);
|
||||
template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -137,8 +137,15 @@ EntityRenderer::~EntityRenderer() {}
|
|||
// Smart payload proxy members, implementing the payload interface
|
||||
//
|
||||
|
||||
Item::Bound EntityRenderer::getBound() {
|
||||
return _bound;
|
||||
Item::Bound EntityRenderer::getBound(RenderArgs* args) {
|
||||
auto bound = _bound;
|
||||
if (_billboardMode != BillboardMode::NONE) {
|
||||
glm::vec3 dimensions = bound.getScale();
|
||||
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
|
||||
const float SQRT_2 = 1.41421356237f;
|
||||
bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
|
||||
}
|
||||
return bound;
|
||||
}
|
||||
|
||||
ShapeKey EntityRenderer::getShapeKey() {
|
||||
|
@ -198,12 +205,9 @@ uint32_t EntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
|
|||
}
|
||||
|
||||
bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const {
|
||||
auto renderWithZones = resultWithReadLock<QVector<QUuid>>([&] {
|
||||
return _renderWithZones;
|
||||
});
|
||||
if (!renderWithZones.isEmpty()) {
|
||||
if (!_renderWithZones.isEmpty()) {
|
||||
if (!containingZones.empty()) {
|
||||
for (auto renderWithZone : renderWithZones) {
|
||||
for (auto renderWithZone : _renderWithZones) {
|
||||
if (containingZones.find(renderWithZone) != containingZones.end()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -429,20 +433,24 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
|
|||
|
||||
_moving = entity->isMovingRelativeToParent();
|
||||
_visible = entity->getVisible();
|
||||
setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera());
|
||||
setRenderLayer(entity->getRenderLayer());
|
||||
_primitiveMode = entity->getPrimitiveMode();
|
||||
_canCastShadow = entity->getCanCastShadow();
|
||||
setCullWithParent(entity->getCullWithParent());
|
||||
_cauterized = entity->getCauterized();
|
||||
if (entity->needsZoneOcclusionUpdate()) {
|
||||
entity->resetNeedsZoneOcclusionUpdate();
|
||||
_renderWithZones = entity->getRenderWithZones();
|
||||
}
|
||||
entity->setNeedsRenderUpdate(false);
|
||||
});
|
||||
}
|
||||
|
||||
void EntityRenderer::doRenderUpdateAsynchronous(const EntityItemPointer& entity) {
|
||||
setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera());
|
||||
setRenderLayer(entity->getRenderLayer());
|
||||
_billboardMode = entity->getBillboardMode();
|
||||
_primitiveMode = entity->getPrimitiveMode();
|
||||
_canCastShadow = entity->getCanCastShadow();
|
||||
setCullWithParent(entity->getCullWithParent());
|
||||
_cauterized = entity->getCauterized();
|
||||
if (entity->needsZoneOcclusionUpdate()) {
|
||||
entity->resetNeedsZoneOcclusionUpdate();
|
||||
_renderWithZones = entity->getRenderWithZones();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityRenderer::onAddToScene(const EntityItemPointer& entity) {
|
||||
QObject::connect(this, &EntityRenderer::requestRenderUpdate, this, [this] {
|
||||
auto renderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
|
|
|
@ -64,7 +64,7 @@ public:
|
|||
static glm::vec3 calculatePulseColor(const glm::vec3& color, const PulsePropertyGroup& pulseProperties, quint64 start);
|
||||
|
||||
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
|
||||
virtual Item::Bound getBound() override;
|
||||
virtual Item::Bound getBound(RenderArgs* args) override;
|
||||
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const override;
|
||||
|
||||
protected:
|
||||
|
@ -95,8 +95,7 @@ protected:
|
|||
// Will be called by the lambda posted to the scene in updateInScene.
|
||||
// This function will execute on the rendering thread, so you cannot use network caches to fetch
|
||||
// data in this method if using multi-threaded rendering
|
||||
|
||||
virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity) { }
|
||||
virtual void doRenderUpdateAsynchronous(const EntityItemPointer& entity);
|
||||
|
||||
// Called by the `render` method after `needsRenderUpdate`
|
||||
virtual void doRender(RenderArgs* args) = 0;
|
||||
|
@ -135,6 +134,7 @@ protected:
|
|||
RenderLayer _renderLayer { RenderLayer::WORLD };
|
||||
PrimitiveMode _primitiveMode { PrimitiveMode::SOLID };
|
||||
QVector<QUuid> _renderWithZones;
|
||||
BillboardMode _billboardMode;
|
||||
bool _cauterized { false };
|
||||
bool _moving { false };
|
||||
Transform _renderTransform;
|
||||
|
|
|
@ -195,8 +195,8 @@ void GizmoEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
|||
}
|
||||
}
|
||||
|
||||
Item::Bound GizmoEntityRenderer::getBound() {
|
||||
auto bound = Parent::getBound();
|
||||
Item::Bound GizmoEntityRenderer::getBound(RenderArgs* args) {
|
||||
auto bound = Parent::getBound(args);
|
||||
if (_ringProperties.getHasTickMarks()) {
|
||||
glm::vec3 scale = bound.getScale();
|
||||
for (int i = 0; i < 3; i += 2) {
|
||||
|
@ -242,18 +242,20 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) {
|
|||
bool hasTickMarks = _ringProperties.getHasTickMarks();
|
||||
glm::vec4 tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(),
|
||||
_ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength());
|
||||
bool forward;
|
||||
bool wireframe;
|
||||
|
||||
bool transparent;
|
||||
withReadLock([&] {
|
||||
transform = _renderTransform;
|
||||
transparent = isTransparent();
|
||||
wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
|
||||
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
|
||||
});
|
||||
|
||||
bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
|
||||
bool forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
|
||||
|
||||
geometryCache->bindSimpleProgram(batch, false, transparent, wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
|
||||
|
||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true));
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
// Background circle
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
~GizmoEntityRenderer();
|
||||
|
||||
protected:
|
||||
Item::Bound getBound() override;
|
||||
Item::Bound getBound(RenderArgs* args) override;
|
||||
ShapeKey getShapeKey() override;
|
||||
|
||||
bool isTransparent() const override;
|
||||
|
|
|
@ -49,13 +49,13 @@ void GridEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
|
|||
_minorGridEvery = entity->getMinorGridEvery();
|
||||
}
|
||||
|
||||
Item::Bound GridEntityRenderer::getBound() {
|
||||
Item::Bound GridEntityRenderer::getBound(RenderArgs* args) {
|
||||
if (_followCamera) {
|
||||
// This is a UI element that should always be in view, lie to the octree to avoid culling
|
||||
const AABox DOMAIN_BOX = AABox(glm::vec3(-TREE_SCALE / 2), TREE_SCALE);
|
||||
return DOMAIN_BOX;
|
||||
}
|
||||
return Parent::getBound();
|
||||
return Parent::getBound(args);
|
||||
}
|
||||
|
||||
ShapeKey GridEntityRenderer::getShapeKey() {
|
||||
|
@ -77,17 +77,17 @@ void GridEntityRenderer::doRender(RenderArgs* args) {
|
|||
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
|
||||
glm::vec3 dimensions;
|
||||
Transform renderTransform;
|
||||
bool forward;
|
||||
withReadLock([&] {
|
||||
dimensions = _dimensions;
|
||||
renderTransform = _renderTransform;
|
||||
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
|
||||
});
|
||||
|
||||
if (!_visible || color.a == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
|
||||
|
||||
auto batch = args->_batch;
|
||||
|
||||
Transform transform;
|
||||
|
@ -103,6 +103,8 @@ void GridEntityRenderer::doRender(RenderArgs* args) {
|
|||
} else {
|
||||
transform.setTranslation(renderTransform.getTranslation());
|
||||
}
|
||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
||||
batch->setModelTransform(transform);
|
||||
|
||||
auto minCorner = glm::vec2(-0.5f, -0.5f);
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
~GridEntityRenderer();
|
||||
|
||||
protected:
|
||||
Item::Bound getBound() override;
|
||||
Item::Bound getBound(RenderArgs* args) override;
|
||||
ShapeKey getShapeKey() override;
|
||||
|
||||
bool isTransparent() const override;
|
||||
|
|
|
@ -58,7 +58,6 @@ void ImageEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
|||
_color = entity->getColor();
|
||||
_alpha = entity->getAlpha();
|
||||
_pulseProperties = entity->getPulseProperties();
|
||||
_billboardMode = entity->getBillboardMode();
|
||||
|
||||
if (!_textureIsLoaded) {
|
||||
emit requestRenderUpdate();
|
||||
|
@ -66,17 +65,6 @@ void ImageEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
|||
_textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
|
||||
}
|
||||
|
||||
Item::Bound ImageEntityRenderer::getBound() {
|
||||
auto bound = Parent::getBound();
|
||||
if (_billboardMode != BillboardMode::NONE) {
|
||||
glm::vec3 dimensions = bound.getScale();
|
||||
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
|
||||
const float SQRT_2 = 1.41421356237f;
|
||||
bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
|
||||
}
|
||||
return bound;
|
||||
}
|
||||
|
||||
ShapeKey ImageEntityRenderer::getShapeKey() {
|
||||
auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias();
|
||||
if (isTransparent()) {
|
||||
|
@ -109,7 +97,8 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
|
|||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch* batch = args->_batch;
|
||||
|
||||
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
|
||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
||||
|
||||
batch->setModelTransform(transform);
|
||||
batch->setResourceTexture(0, _texture->getGPUTexture());
|
||||
|
|
|
@ -23,7 +23,6 @@ public:
|
|||
~ImageEntityRenderer();
|
||||
|
||||
protected:
|
||||
Item::Bound getBound() override;
|
||||
ShapeKey getShapeKey() override;
|
||||
|
||||
bool isTransparent() const override;
|
||||
|
@ -44,7 +43,6 @@ private:
|
|||
glm::u8vec3 _color;
|
||||
float _alpha;
|
||||
PulsePropertyGroup _pulseProperties;
|
||||
BillboardMode _billboardMode;
|
||||
|
||||
int _geometryId { 0 };
|
||||
};
|
||||
|
|
|
@ -60,8 +60,8 @@ ItemKey LightEntityRenderer::getKey() {
|
|||
return payloadGetKey(_lightPayload);
|
||||
}
|
||||
|
||||
Item::Bound LightEntityRenderer::getBound() {
|
||||
return payloadGetBound(_lightPayload);
|
||||
Item::Bound LightEntityRenderer::getBound(RenderArgs* args) {
|
||||
return payloadGetBound(_lightPayload, args);
|
||||
}
|
||||
|
||||
void LightEntityRenderer::doRender(RenderArgs* args) {
|
||||
|
|
|
@ -29,7 +29,7 @@ protected:
|
|||
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
|
||||
|
||||
virtual ItemKey getKey() override;
|
||||
virtual Item::Bound getBound() override;
|
||||
virtual Item::Bound getBound(RenderArgs* args) override;
|
||||
virtual void doRender(RenderArgs* args) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -47,7 +47,8 @@ void LineEntityRenderer::doRender(RenderArgs* args) {
|
|||
const auto& modelTransform = getModelTransform();
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(modelTransform.getTranslation());
|
||||
transform.setRotation(modelTransform.getRotation());
|
||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode,
|
||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
||||
batch.setModelTransform(transform);
|
||||
if (_linePoints.size() > 1) {
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, false, false, true,
|
||||
|
|
|
@ -259,9 +259,9 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
|
||||
textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
|
||||
|
||||
Transform renderTransform;
|
||||
Transform transform;
|
||||
withReadLock([&] {
|
||||
renderTransform = _renderTransform;
|
||||
transform = _renderTransform;
|
||||
});
|
||||
|
||||
if (!drawMaterial) {
|
||||
|
@ -272,7 +272,9 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
proceduralRender = true;
|
||||
}
|
||||
|
||||
batch.setModelTransform(renderTransform);
|
||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
if (!proceduralRender) {
|
||||
drawMaterial->setTextureTransforms(textureTransform, MaterialMappingMode::UV, true);
|
||||
|
@ -287,8 +289,8 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
auto proceduralDrawMaterial = std::static_pointer_cast<graphics::ProceduralMaterial>(drawMaterial);
|
||||
glm::vec4 outColor = glm::vec4(drawMaterial->getAlbedo(), drawMaterial->getOpacity());
|
||||
outColor = proceduralDrawMaterial->getColor(outColor);
|
||||
proceduralDrawMaterial->prepare(batch, renderTransform.getTranslation(), renderTransform.getScale(),
|
||||
renderTransform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
proceduralDrawMaterial->prepare(batch, transform.getTranslation(), transform.getScale(),
|
||||
transform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
|
||||
DependencyManager::get<GeometryCache>()->renderWireSphere(batch, outColor);
|
||||
} else {
|
||||
|
@ -374,7 +376,7 @@ void MaterialEntityRenderer::applyMaterial(const TypedEntityPointer& entity) {
|
|||
|
||||
if (material->isProcedural()) {
|
||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(material);
|
||||
procedural->setBoundOperator([this] { return getBound(); });
|
||||
procedural->setBoundOperator([this](RenderArgs* args) { return getBound(args); });
|
||||
entity->setHasVertexShader(procedural->hasVertexShader());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -161,7 +161,7 @@ ShapeKey ParticleEffectEntityRenderer::getShapeKey() {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
Item::Bound ParticleEffectEntityRenderer::getBound() {
|
||||
Item::Bound ParticleEffectEntityRenderer::getBound(RenderArgs* args) {
|
||||
return _bound;
|
||||
}
|
||||
|
||||
|
@ -456,6 +456,7 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) {
|
|||
color.spread = EntityRenderer::calculatePulseColor(_particleProperties.getColorSpread(), _pulseProperties, _created);
|
||||
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
batch.setUniformBuffer(0, _uniformBuffer);
|
||||
batch.setInputFormat(_vertexFormat);
|
||||
batch.setInputBuffer(0, _particleBuffer, 0, sizeof(GpuParticle));
|
||||
|
|
|
@ -30,7 +30,7 @@ protected:
|
|||
|
||||
virtual ItemKey getKey() override;
|
||||
virtual ShapeKey getShapeKey() override;
|
||||
virtual Item::Bound getBound() override;
|
||||
virtual Item::Bound getBound(RenderArgs* args) override;
|
||||
virtual void doRender(RenderArgs* args) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -325,8 +325,11 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
|
|||
buildPipelines();
|
||||
}
|
||||
|
||||
batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]);
|
||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]);
|
||||
batch.setResourceTexture(0, texture);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * _numVertices), 0);
|
||||
}
|
||||
|
|
|
@ -238,53 +238,6 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel
|
|||
startUpdates();
|
||||
}
|
||||
|
||||
glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
|
||||
glm::vec3 result;
|
||||
withReadLock([&] {
|
||||
glm::vec3 scale = getScaledDimensions() / _voxelVolumeSize; // meters / voxel-units
|
||||
if (isEdged(_voxelSurfaceStyle)) {
|
||||
result = scale / -2.0f;
|
||||
}
|
||||
return scale / 2.0f;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
|
||||
glm::vec3 voxelVolumeSize;
|
||||
withReadLock([&] {
|
||||
voxelVolumeSize = _voxelVolumeSize;
|
||||
});
|
||||
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec3 scale = dimensions / voxelVolumeSize; // meters / voxel-units
|
||||
bool success; // TODO -- Does this actually have to happen in world space?
|
||||
glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes
|
||||
glm::vec3 position = getWorldPosition(success);
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
|
||||
positionToCenter -= dimensions * Vectors::HALF - getSurfacePositionAdjustment();
|
||||
glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter);
|
||||
glm::mat4 scaled = glm::scale(centerToCorner, scale);
|
||||
return scaled;
|
||||
}
|
||||
|
||||
glm::mat4 RenderablePolyVoxEntityItem::localToVoxelMatrix() const {
|
||||
glm::mat4 localToModelMatrix = glm::inverse(voxelToLocalMatrix());
|
||||
return localToModelMatrix;
|
||||
}
|
||||
|
||||
glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const {
|
||||
glm::mat4 rotation = glm::mat4_cast(getWorldOrientation());
|
||||
glm::mat4 translation = glm::translate(getWorldPosition());
|
||||
return translation * rotation * voxelToLocalMatrix();
|
||||
}
|
||||
|
||||
glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const {
|
||||
glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix());
|
||||
return worldToModelMatrix;
|
||||
}
|
||||
|
||||
bool RenderablePolyVoxEntityItem::setVoxel(const ivec3& v, uint8_t toValue) {
|
||||
if (_locked) {
|
||||
return false;
|
||||
|
@ -573,7 +526,7 @@ public:
|
|||
#endif
|
||||
|
||||
bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
// TODO -- correctly pick against marching-cube generated meshes
|
||||
|
@ -582,7 +535,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
|
|||
return true;
|
||||
}
|
||||
|
||||
glm::mat4 wtvMatrix = worldToVoxelMatrix();
|
||||
glm::mat4 wtvMatrix = worldToVoxelMatrix(true);
|
||||
glm::vec3 normDirection = glm::normalize(direction);
|
||||
|
||||
// the PolyVox ray intersection code requires a near and far point.
|
||||
|
@ -614,7 +567,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
|
|||
}
|
||||
|
||||
bool RenderablePolyVoxEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
// TODO -- correctly pick against marching-cube generated meshes
|
||||
|
@ -623,7 +576,7 @@ bool RenderablePolyVoxEntityItem::findDetailedParabolaIntersection(const glm::ve
|
|||
return true;
|
||||
}
|
||||
|
||||
glm::mat4 wtvMatrix = worldToVoxelMatrix();
|
||||
glm::mat4 wtvMatrix = worldToVoxelMatrix(true);
|
||||
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
|
||||
glm::vec4 velocityInVoxel = wtvMatrix * glm::vec4(velocity, 0.0f);
|
||||
glm::vec4 accelerationInVoxel = wtvMatrix * glm::vec4(acceleration, 0.0f);
|
||||
|
@ -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,
|
||||
|
|
|
@ -71,24 +71,18 @@ public:
|
|||
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const vec3& accleration,
|
||||
OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
virtual void setVoxelData(const QByteArray& voxelData) override;
|
||||
virtual void setVoxelVolumeSize(const glm::vec3& voxelVolumeSize) override;
|
||||
virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) override;
|
||||
|
||||
glm::vec3 getSurfacePositionAdjustment() const;
|
||||
glm::mat4 voxelToWorldMatrix() const;
|
||||
glm::mat4 worldToVoxelMatrix() const;
|
||||
glm::mat4 voxelToLocalMatrix() const;
|
||||
glm::mat4 localToVoxelMatrix() const;
|
||||
|
||||
virtual ShapeType getShapeType() const override;
|
||||
virtual bool isReadyToComputeShape() const override;
|
||||
virtual void computeShapeInfo(ShapeInfo& info) override;
|
||||
|
@ -226,7 +220,9 @@ private:
|
|||
gpu::BufferPointer _params;
|
||||
std::array<NetworkTexturePointer, 3> _xyzTextures;
|
||||
glm::vec3 _lastVoxelVolumeSize;
|
||||
glm::mat4 _lastVoxelToWorldMatrix;
|
||||
glm::mat4 _lastVoxelToLocalMatrix;
|
||||
glm::vec3 _position;
|
||||
glm::quat _orientation;
|
||||
PolyVoxEntityItem::PolyVoxSurfaceStyle _lastSurfaceStyle { PolyVoxEntityItem::SURFACE_MARCHING_CUBES };
|
||||
std::array<QString, 3> _xyzTextureUrls;
|
||||
};
|
||||
|
|
|
@ -55,6 +55,7 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
void* key = (void*)this;
|
||||
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
|
||||
withWriteLock([&] {
|
||||
_shape = entity->getShape();
|
||||
_position = entity->getWorldPosition();
|
||||
_dimensions = entity->getUnscaledDimensions(); // get unscaled to avoid scaling twice
|
||||
_orientation = entity->getWorldOrientation();
|
||||
|
@ -69,7 +70,6 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
}
|
||||
|
||||
void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
|
||||
_shape = entity->getShape();
|
||||
_pulseProperties = entity->getPulseProperties();
|
||||
|
||||
bool materialChanged = false;
|
||||
|
@ -200,16 +200,16 @@ ShapeKey ShapeEntityRenderer::getShapeKey() {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
Item::Bound ShapeEntityRenderer::getBound() {
|
||||
Item::Bound ShapeEntityRenderer::getBound(RenderArgs* args) {
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end() && mat->second.top().material && mat->second.top().material->isProcedural() &&
|
||||
mat->second.top().material->isReady()) {
|
||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(mat->second.top().material);
|
||||
if (procedural->hasVertexShader() && procedural->hasBoundOperator()) {
|
||||
return procedural->getBound();
|
||||
return procedural->getBound(args);
|
||||
}
|
||||
}
|
||||
return Parent::getBound();
|
||||
return Parent::getBound(args);
|
||||
}
|
||||
|
||||
void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
||||
|
@ -221,14 +221,11 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
graphics::MultiMaterial materials;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
GeometryCache::Shape geometryShape = geometryCache->getShapeForEntityShape(_shape);
|
||||
PrimitiveMode primitiveMode;
|
||||
RenderLayer renderLayer;
|
||||
glm::vec4 outColor;
|
||||
Pipeline pipelineType;
|
||||
Transform transform;
|
||||
withReadLock([&] {
|
||||
primitiveMode = _primitiveMode;
|
||||
renderLayer = _renderLayer;
|
||||
batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
|
||||
transform = _renderTransform;
|
||||
materials = _materials["0"];
|
||||
pipelineType = getPipelineType(materials);
|
||||
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
|
||||
|
@ -241,6 +238,11 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
return;
|
||||
}
|
||||
|
||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(),
|
||||
_shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron));
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
if (pipelineType == Pipeline::PROCEDURAL) {
|
||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials.top().material);
|
||||
outColor = procedural->getColor(outColor);
|
||||
|
@ -249,7 +251,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
procedural->prepare(batch, _position, _dimensions, _orientation, _created, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
});
|
||||
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
|
||||
geometryCache->renderWireShape(batch, geometryShape, outColor);
|
||||
} else {
|
||||
geometryCache->renderShape(batch, geometryShape, outColor);
|
||||
|
@ -258,8 +260,8 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
||||
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
render::ShapePipelinePointer pipeline = geometryCache->getShapePipelinePointer(outColor.a < 1.0f, false,
|
||||
renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD, materials.top().material->getCullFaceMode());
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
|
||||
_renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD, materials.top().material->getCullFaceMode());
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
|
||||
geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
||||
} else {
|
||||
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
|
||||
protected:
|
||||
ShapeKey getShapeKey() override;
|
||||
Item::Bound getBound() override;
|
||||
Item::Bound getBound(RenderArgs* args) override;
|
||||
|
||||
private:
|
||||
virtual bool needsRenderUpdate() const override;
|
||||
|
|
|
@ -54,17 +54,6 @@ bool TextEntityRenderer::isTextTransparent() const {
|
|||
});
|
||||
}
|
||||
|
||||
Item::Bound TextEntityRenderer::getBound() {
|
||||
auto bound = Parent::getBound();
|
||||
if (_billboardMode != BillboardMode::NONE) {
|
||||
glm::vec3 dimensions = bound.getScale();
|
||||
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
|
||||
const float SQRT_2 = 1.41421356237f;
|
||||
bound.setScaleStayCentered(glm::vec3(SQRT_2 * max));
|
||||
}
|
||||
return bound;
|
||||
}
|
||||
|
||||
ItemKey TextEntityRenderer::getKey() {
|
||||
return ItemKey::Builder(Parent::getKey()).withMetaCullGroup();
|
||||
}
|
||||
|
@ -111,7 +100,6 @@ void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
|
|||
_textAlpha = entity->getTextAlpha();
|
||||
_backgroundColor = toGlm(entity->getBackgroundColor());
|
||||
_backgroundAlpha = entity->getBackgroundAlpha();
|
||||
_billboardMode = entity->getBillboardMode();
|
||||
_leftMargin = entity->getLeftMargin();
|
||||
_rightMargin = entity->getRightMargin();
|
||||
_topMargin = entity->getTopMargin();
|
||||
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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> – <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()) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -798,6 +798,7 @@ public:
|
|||
glm::vec3 origin;
|
||||
glm::vec3 direction;
|
||||
glm::vec3 invDirection;
|
||||
glm::vec3 viewFrustumPos;
|
||||
const QVector<EntityItemID>& entityIdsToInclude;
|
||||
const QVector<EntityItemID>& entityIdsToDiscard;
|
||||
PickFilter searchFilter;
|
||||
|
@ -815,7 +816,7 @@ bool evalRayIntersectionOp(const OctreeElementPointer& element, void* extraData)
|
|||
RayArgs* args = static_cast<RayArgs*>(extraData);
|
||||
bool keepSearching = true;
|
||||
EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
EntityItemID entityID = entityTreeElementPointer->evalRayIntersection(args->origin, args->direction,
|
||||
EntityItemID entityID = entityTreeElementPointer->evalRayIntersection(args->origin, args->direction, args->viewFrustumPos,
|
||||
args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude,
|
||||
args->entityIdsToDiscard, args->searchFilter, args->extraInfo);
|
||||
if (!entityID.isNull()) {
|
||||
|
@ -837,7 +838,8 @@ float evalRayIntersectionSortingOp(const OctreeElementPointer& element, void* ex
|
|||
float boundDistance = FLT_MAX;
|
||||
BoxFace face;
|
||||
glm::vec3 surfaceNormal;
|
||||
if (entityTreeElementPointer->getAACube().findRayIntersection(args->origin, args->direction, args->invDirection, boundDistance, face, surfaceNormal)) {
|
||||
if (entityTreeElementPointer->getAACube().findRayIntersection(args->origin, args->direction, args->invDirection,
|
||||
boundDistance, face, surfaceNormal)) {
|
||||
// Don't add this cell if it's already farther than our best distance so far
|
||||
if (boundDistance < args->distance) {
|
||||
distance = boundDistance;
|
||||
|
@ -857,7 +859,7 @@ EntityItemID EntityTree::evalRayIntersection(const glm::vec3& origin, const glm:
|
|||
vec3 dirReciprocal = glm::vec3(direction.x == 0.0f ? 0.0f : 1.0f / direction.x,
|
||||
direction.y == 0.0f ? 0.0f : 1.0f / direction.y,
|
||||
direction.z == 0.0f ? 0.0f : 1.0f / direction.z);
|
||||
RayArgs args = { origin, direction, dirReciprocal, entityIdsToInclude, entityIdsToDiscard,
|
||||
RayArgs args = { origin, direction, dirReciprocal, BillboardModeHelpers::getPrimaryViewFrustumPosition(), entityIdsToInclude, entityIdsToDiscard,
|
||||
searchFilter, element, distance, face, surfaceNormal, extraInfo, EntityItemID() };
|
||||
distance = FLT_MAX;
|
||||
|
||||
|
@ -879,6 +881,7 @@ public:
|
|||
glm::vec3 origin;
|
||||
glm::vec3 velocity;
|
||||
glm::vec3 acceleration;
|
||||
glm::vec3 viewFrustumPos;
|
||||
const QVector<EntityItemID>& entityIdsToInclude;
|
||||
const QVector<EntityItemID>& entityIdsToDiscard;
|
||||
PickFilter searchFilter;
|
||||
|
@ -896,7 +899,7 @@ bool evalParabolaIntersectionOp(const OctreeElementPointer& element, void* extra
|
|||
ParabolaArgs* args = static_cast<ParabolaArgs*>(extraData);
|
||||
bool keepSearching = true;
|
||||
EntityTreeElementPointer entityTreeElementPointer = std::static_pointer_cast<EntityTreeElement>(element);
|
||||
EntityItemID entityID = entityTreeElementPointer->evalParabolaIntersection(args->origin, args->velocity, args->acceleration,
|
||||
EntityItemID entityID = entityTreeElementPointer->evalParabolaIntersection(args->origin, args->velocity, args->acceleration, args->viewFrustumPos,
|
||||
args->element, args->parabolicDistance, args->face, args->surfaceNormal, args->entityIdsToInclude,
|
||||
args->entityIdsToDiscard, args->searchFilter, args->extraInfo);
|
||||
if (!entityID.isNull()) {
|
||||
|
@ -918,7 +921,8 @@ float evalParabolaIntersectionSortingOp(const OctreeElementPointer& element, voi
|
|||
float boundDistance = FLT_MAX;
|
||||
BoxFace face;
|
||||
glm::vec3 surfaceNormal;
|
||||
if (entityTreeElementPointer->getAACube().findParabolaIntersection(args->origin, args->velocity, args->acceleration, boundDistance, face, surfaceNormal)) {
|
||||
if (entityTreeElementPointer->getAACube().findParabolaIntersection(args->origin, args->velocity, args->acceleration,
|
||||
boundDistance, face, surfaceNormal)) {
|
||||
// Don't add this cell if it's already farther than our best distance so far
|
||||
if (boundDistance < args->parabolicDistance) {
|
||||
distance = boundDistance;
|
||||
|
@ -934,8 +938,8 @@ EntityItemID EntityTree::evalParabolaIntersection(const PickParabola& parabola,
|
|||
OctreeElementPointer& element, glm::vec3& intersection, float& distance, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
|
||||
Octree::lockType lockType, bool* accurateResult) {
|
||||
ParabolaArgs args = { parabola.origin, parabola.velocity, parabola.acceleration, entityIdsToInclude, entityIdsToDiscard,
|
||||
searchFilter, element, parabolicDistance, face, surfaceNormal, extraInfo, EntityItemID() };
|
||||
ParabolaArgs args = { parabola.origin, parabola.velocity, parabola.acceleration, BillboardModeHelpers::getPrimaryViewFrustumPosition(),
|
||||
entityIdsToInclude, entityIdsToDiscard, searchFilter, element, parabolicDistance, face, surfaceNormal, extraInfo, EntityItemID() };
|
||||
parabolicDistance = FLT_MAX;
|
||||
distance = FLT_MAX;
|
||||
|
||||
|
@ -3137,6 +3141,13 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) {
|
|||
}
|
||||
}
|
||||
|
||||
// Before, billboarded entities ignored rotation. Now, they use it to determine which axis is facing you.
|
||||
if (contentVersion < (int)EntityVersion::AllBillboardMode) {
|
||||
if (properties.getBillboardMode() != BillboardMode::NONE) {
|
||||
properties.setRotation(glm::quat());
|
||||
}
|
||||
}
|
||||
|
||||
EntityItemPointer entity = addEntity(entityItemID, properties, isImport);
|
||||
if (!entity) {
|
||||
qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType();
|
||||
|
|
|
@ -162,7 +162,7 @@ bool EntityTreeElement::checkFilterSettings(const EntityItemPointer& entity, Pic
|
|||
return true;
|
||||
}
|
||||
|
||||
EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
|
||||
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIdsToDiscard,
|
||||
PickFilter searchFilter, QVariantMap& extraInfo) {
|
||||
|
@ -177,7 +177,7 @@ EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, con
|
|||
|
||||
QVariantMap localExtraInfo;
|
||||
float distanceToElementDetails = distance;
|
||||
EntityItemID entityID = evalDetailedRayIntersection(origin, direction, element, distanceToElementDetails,
|
||||
EntityItemID entityID = evalDetailedRayIntersection(origin, direction, viewFrustumPos, element, distanceToElementDetails,
|
||||
localFace, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, searchFilter, localExtraInfo);
|
||||
if (!entityID.isNull() && distanceToElementDetails < distance) {
|
||||
distance = distanceToElementDetails;
|
||||
|
@ -189,7 +189,7 @@ EntityItemID EntityTreeElement::evalRayIntersection(const glm::vec3& origin, con
|
|||
return result;
|
||||
}
|
||||
|
||||
EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
|
||||
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIDsToDiscard,
|
||||
PickFilter searchFilter, QVariantMap& extraInfo) {
|
||||
|
@ -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);
|
||||
|
|
|
@ -136,24 +136,24 @@ public:
|
|||
|
||||
static bool checkFilterSettings(const EntityItemPointer& entity, PickFilter searchFilter);
|
||||
virtual bool canPickIntersect() const override { return hasEntities(); }
|
||||
virtual EntityItemID evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
virtual EntityItemID evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
|
||||
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIdsToDiscard,
|
||||
PickFilter searchFilter, QVariantMap& extraInfo);
|
||||
virtual EntityItemID evalDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
|
||||
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
||||
glm::vec3& penetration, void** penetratedObject) const override;
|
||||
|
||||
virtual EntityItemID evalParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
|
||||
virtual EntityItemID evalDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& normal, const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const glm::vec3& normal, const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIdsToDiscard, PickFilter searchFilter, QVariantMap& extraInfo);
|
||||
|
||||
template <typename F>
|
||||
|
|
|
@ -103,14 +103,15 @@ bool GizmoEntityItem::supportsDetailedIntersection() const {
|
|||
}
|
||||
|
||||
bool GizmoEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.z);
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
rotation = glm::angleAxis(-(float)M_PI_2, rotation * Vectors::RIGHT) * rotation;
|
||||
rotation *= glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
|
||||
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
|
||||
glm::vec3 hitPosition = origin + (distance * direction);
|
||||
|
@ -136,15 +137,16 @@ bool GizmoEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
|
|||
}
|
||||
|
||||
bool GizmoEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
OctreeElementPointer& element, float& parabolicDistance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
//// Scale the dimensions by the diameter
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.z);
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
rotation = glm::angleAxis(-(float)M_PI_2, rotation * Vectors::RIGHT) * rotation;
|
||||
rotation *= glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
|
||||
glm::vec3 position = getWorldPosition();
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
|
||||
glm::quat inverseRot = glm::inverse(rotation);
|
||||
glm::vec3 localOrigin = inverseRot * (origin - position);
|
||||
|
|
|
@ -45,13 +45,14 @@ public:
|
|||
|
||||
bool supportsDetailedIntersection() const override;
|
||||
bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
bool getRotateForPicking() const override { return getBillboardMode() != BillboardMode::NONE; }
|
||||
|
||||
GizmoType getGizmoType() const;
|
||||
void setGizmoType(GizmoType value);
|
||||
|
|
|
@ -35,7 +35,6 @@ EntityItemProperties ImageEntityItem::getProperties(const EntityPropertyFlags& d
|
|||
withReadLock([&] {
|
||||
_pulseProperties.getProperties(properties);
|
||||
});
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getImageURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emissive, getEmissive);
|
||||
|
@ -55,7 +54,6 @@ bool ImageEntityItem::setSubClassProperties(const EntityItemProperties& properti
|
|||
somethingChanged |= pulsePropertiesChanged;
|
||||
_needsRenderUpdate |= pulsePropertiesChanged;
|
||||
});
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setImageURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emissive, setEmissive);
|
||||
|
@ -82,7 +80,6 @@ int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
bytesRead += bytesFromPulse;
|
||||
dataAt += bytesFromPulse;
|
||||
});
|
||||
READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_IMAGE_URL, QString, setImageURL);
|
||||
READ_ENTITY_PROPERTY(PROP_EMISSIVE, bool, setEmissive);
|
||||
|
@ -98,7 +95,6 @@ EntityPropertyFlags ImageEntityItem::getEntityProperties(EncodeBitstreamParams&
|
|||
requestedProperties += PROP_COLOR;
|
||||
requestedProperties += PROP_ALPHA;
|
||||
requestedProperties += _pulseProperties.getEntityProperties(params);
|
||||
requestedProperties += PROP_BILLBOARD_MODE;
|
||||
|
||||
requestedProperties += PROP_IMAGE_URL;
|
||||
requestedProperties += PROP_EMISSIVE;
|
||||
|
@ -124,7 +120,6 @@ void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
_pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
});
|
||||
APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, getImageURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, getEmissive());
|
||||
|
@ -132,69 +127,6 @@ void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
APPEND_ENTITY_PROPERTY(PROP_SUB_IMAGE, getSubImage());
|
||||
}
|
||||
|
||||
glm::vec3 ImageEntityItem::getRaycastDimensions() const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
if (getBillboardMode() != BillboardMode::NONE) {
|
||||
float max = glm::max(dimensions.x, glm::max(dimensions.y, dimensions.z));
|
||||
const float SQRT_2 = 1.41421356237f;
|
||||
return glm::vec3(SQRT_2 * max);
|
||||
}
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
bool ImageEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode, EntityItem::getPrimaryViewFrustumPosition());
|
||||
|
||||
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
|
||||
glm::vec3 forward = rotation * Vectors::FRONT;
|
||||
if (glm::dot(forward, direction) > 0.0f) {
|
||||
face = MAX_Z_FACE;
|
||||
surfaceNormal = -forward;
|
||||
} else {
|
||||
face = MIN_Z_FACE;
|
||||
surfaceNormal = forward;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ImageEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
|
||||
glm::quat inverseRot = glm::inverse(rotation);
|
||||
glm::vec3 localOrigin = inverseRot * (origin - position);
|
||||
glm::vec3 localVelocity = inverseRot * velocity;
|
||||
glm::vec3 localAcceleration = inverseRot * acceleration;
|
||||
|
||||
if (findParabolaRectangleIntersection(localOrigin, localVelocity, localAcceleration, xyDimensions, parabolicDistance)) {
|
||||
float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * parabolicDistance;
|
||||
glm::vec3 forward = rotation * Vectors::FRONT;
|
||||
if (localIntersectionVelocityZ > 0.0f) {
|
||||
face = MIN_Z_FACE;
|
||||
surfaceNormal = forward;
|
||||
} else {
|
||||
face = MAX_Z_FACE;
|
||||
surfaceNormal = -forward;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QString ImageEntityItem::getImageURL() const {
|
||||
QString result;
|
||||
withReadLock([&] {
|
||||
|
@ -240,21 +172,6 @@ void ImageEntityItem::setKeepAspectRatio(bool keepAspectRatio) {
|
|||
});
|
||||
}
|
||||
|
||||
BillboardMode ImageEntityItem::getBillboardMode() const {
|
||||
BillboardMode result;
|
||||
withReadLock([&] {
|
||||
result = _billboardMode;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void ImageEntityItem::setBillboardMode(BillboardMode value) {
|
||||
withWriteLock([&] {
|
||||
_needsRenderUpdate |= _billboardMode != value;
|
||||
_billboardMode = value;
|
||||
});
|
||||
}
|
||||
|
||||
QRect ImageEntityItem::getSubImage() const {
|
||||
QRect result;
|
||||
withReadLock([&] {
|
||||
|
|
|
@ -43,17 +43,6 @@ public:
|
|||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
bool& somethingChanged) override;
|
||||
|
||||
glm::vec3 getRaycastDimensions() const override;
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
void setImageURL(const QString& imageUrl);
|
||||
QString getImageURL() const;
|
||||
|
||||
|
@ -63,9 +52,6 @@ public:
|
|||
void setKeepAspectRatio(bool keepAspectRatio);
|
||||
bool getKeepAspectRatio() const;
|
||||
|
||||
void setBillboardMode(BillboardMode value);
|
||||
BillboardMode getBillboardMode() const;
|
||||
|
||||
void setSubImage(const QRect& subImage);
|
||||
QRect getSubImage() const;
|
||||
|
||||
|
@ -81,7 +67,6 @@ protected:
|
|||
glm::u8vec3 _color;
|
||||
float _alpha;
|
||||
PulsePropertyGroup _pulseProperties;
|
||||
BillboardMode _billboardMode;
|
||||
|
||||
QString _imageURL;
|
||||
bool _emissive { false };
|
||||
|
|
|
@ -254,7 +254,7 @@ float LightEntityItem::getCutoff() const {
|
|||
}
|
||||
|
||||
bool LightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
|
||||
|
@ -267,8 +267,8 @@ bool LightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
|
|||
}
|
||||
|
||||
bool LightEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
// TODO: consider if this is really what we want to do. We've made it so that "lights are pickable" is a global state
|
||||
// this is probably reasonable since there's typically only one tree you'd be picking on at a time. Technically we could
|
||||
|
|
|
@ -74,12 +74,12 @@ public:
|
|||
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -52,13 +52,13 @@ class LineEntityItem : public EntityItem {
|
|||
// never have a ray intersection pick a LineEntityItem.
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo,
|
||||
bool precisionPicking) const override { return false; }
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo,
|
||||
bool precisionPicking) const override { return false; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -82,12 +82,12 @@ public:
|
|||
// never have a ray intersection pick a PolyLineEntityItem.
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
|
||||
|
||||
void computeTightLocalBoundingBox(AABox& box) const;
|
||||
|
|
|
@ -377,15 +377,21 @@ glm::mat4 PolyVoxEntityItem::localToVoxelMatrix() const {
|
|||
return localToModelMatrix;
|
||||
}
|
||||
|
||||
glm::mat4 PolyVoxEntityItem::voxelToWorldMatrix() const {
|
||||
glm::mat4 rotation = glm::mat4_cast(getWorldOrientation());
|
||||
glm::mat4 translation = glm::translate(getWorldPosition());
|
||||
glm::mat4 PolyVoxEntityItem::voxelToWorldMatrix(bool includeBillboard) const {
|
||||
glm::quat orientation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition();
|
||||
glm::mat4 translation = glm::translate(position);
|
||||
glm::mat4 rotation;
|
||||
if (includeBillboard) {
|
||||
rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(position, orientation, getBillboardMode(), BillboardModeHelpers::getPrimaryViewFrustumPosition()));
|
||||
} else {
|
||||
rotation = glm::mat4_cast(orientation);
|
||||
}
|
||||
return translation * rotation * voxelToLocalMatrix();
|
||||
}
|
||||
|
||||
glm::mat4 PolyVoxEntityItem::worldToVoxelMatrix() const {
|
||||
glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix());
|
||||
return worldToModelMatrix;
|
||||
glm::mat4 PolyVoxEntityItem::worldToVoxelMatrix(bool includeBillboard) const {
|
||||
return glm::inverse(voxelToWorldMatrix(includeBillboard));
|
||||
}
|
||||
|
||||
glm::vec3 PolyVoxEntityItem::voxelCoordsToWorldCoords(const glm::vec3& voxelCoords) const {
|
||||
|
|
|
@ -44,12 +44,12 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
// never have a ray intersection pick a PolyVoxEntityItem.
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
|
||||
|
||||
virtual void debugDump() const override;
|
||||
|
@ -167,8 +167,8 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
|
||||
bool isEdged() const;
|
||||
|
||||
glm::mat4 voxelToWorldMatrix() const;
|
||||
glm::mat4 worldToVoxelMatrix() const;
|
||||
glm::mat4 voxelToWorldMatrix(bool includeBillboard = false) const;
|
||||
glm::mat4 worldToVoxelMatrix(bool includeBillboard = false) const;
|
||||
glm::mat4 voxelToLocalMatrix() const;
|
||||
glm::mat4 localToVoxelMatrix() const;
|
||||
|
||||
|
|
|
@ -257,7 +257,8 @@ float ShapeEntityItem::getAlpha() const {
|
|||
|
||||
void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
||||
const float MAX_FLAT_DIMENSION = 0.0001f;
|
||||
if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {
|
||||
const auto shape = getShape();
|
||||
if ((shape == entity::Shape::Circle || shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {
|
||||
// enforce flatness in Y
|
||||
glm::vec3 newDimensions = value;
|
||||
newDimensions.y = MAX_FLAT_DIMENSION;
|
||||
|
@ -268,15 +269,20 @@ void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
|||
}
|
||||
|
||||
bool ShapeEntityItem::supportsDetailedIntersection() const {
|
||||
return _shape == entity::Sphere;
|
||||
return getShape() == entity::Sphere;
|
||||
}
|
||||
|
||||
bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
|
||||
// determine the ray in the frame of the entity transformed from a unit sphere
|
||||
glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix();
|
||||
glm::mat4 entityToWorldMatrix = glm::translate(position) * glm::mat4_cast(rotation) * glm::scale(dimensions);
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
|
||||
|
@ -299,11 +305,16 @@ bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
|
|||
}
|
||||
|
||||
bool ShapeEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
OctreeElementPointer& element, float& parabolicDistance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getScaledDimensions();
|
||||
glm::quat rotation = getWorldOrientation();
|
||||
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
|
||||
rotation = BillboardModeHelpers::getBillboardRotation(position, rotation, getBillboardMode(), viewFrustumPos);
|
||||
|
||||
// determine the parabola in the frame of the entity transformed from a unit sphere
|
||||
glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix();
|
||||
glm::mat4 entityToWorldMatrix = glm::translate(position) * glm::mat4_cast(rotation) * glm::scale(dimensions);
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 entityFrameVelocity = glm::vec3(worldToEntityMatrix * glm::vec4(velocity, 0.0f));
|
||||
|
@ -324,6 +335,11 @@ bool ShapeEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ShapeEntityItem::getRotateForPicking() const {
|
||||
auto shape = getShape();
|
||||
return getBillboardMode() != BillboardMode::NONE && (_shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron);
|
||||
}
|
||||
|
||||
void ShapeEntityItem::debugDump() const {
|
||||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
|
@ -343,8 +359,9 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
// is set.
|
||||
|
||||
const glm::vec3 entityDimensions = getScaledDimensions();
|
||||
const auto shape = getShape();
|
||||
|
||||
switch (_shape){
|
||||
switch (shape){
|
||||
case entity::Shape::Quad:
|
||||
// Quads collide like flat Cubes
|
||||
case entity::Shape::Cube: {
|
||||
|
|
|
@ -86,13 +86,14 @@ public:
|
|||
|
||||
bool supportsDetailedIntersection() const override;
|
||||
bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
bool getRotateForPicking() const override;
|
||||
|
||||
void debugDump() const override;
|
||||
|
||||
|
|
|
@ -53,7 +53,6 @@ EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& de
|
|||
withReadLock([&] {
|
||||
_pulseProperties.getProperties(properties);
|
||||
});
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(text, getText);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight);
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
|
|
|
@ -318,15 +318,15 @@ void ZoneEntityItem::setCompoundShapeURL(const QString& url) {
|
|||
}
|
||||
|
||||
bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
return _zonesArePickable;
|
||||
}
|
||||
|
||||
bool ZoneEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
return _zonesArePickable;
|
||||
}
|
||||
|
|
|
@ -116,12 +116,12 @@ public:
|
|||
|
||||
virtual bool supportsDetailedIntersection() const override { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
bool contains(const glm::vec3& point) const override;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -283,6 +283,9 @@ enum class EntityVersion : PacketVersion {
|
|||
ZoneOcclusion,
|
||||
ModelBlendshapes,
|
||||
TransparentWeb,
|
||||
UseOriginalPivot,
|
||||
UserAgent,
|
||||
AllBillboardMode,
|
||||
TextAlignment,
|
||||
|
||||
// Add new versions above here
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
set(TARGET_NAME procedural)
|
||||
setup_hifi_library()
|
||||
|
||||
link_hifi_libraries(shared gpu shaders networking graphics material-networking ktx image hfm)
|
||||
link_hifi_libraries(shared gpu shaders networking render graphics material-networking ktx image hfm)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QJsonArray>
|
||||
|
||||
#include <render/Args.h>
|
||||
#include <gpu/Shader.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
@ -113,9 +114,9 @@ public:
|
|||
void setDoesFade(bool doesFade) { _doesFade = doesFade; }
|
||||
|
||||
bool hasVertexShader() const;
|
||||
void setBoundOperator(const std::function<AABox()>& boundOperator) { _boundOperator = boundOperator; }
|
||||
void setBoundOperator(const std::function<AABox(RenderArgs*)>& boundOperator) { _boundOperator = boundOperator; }
|
||||
bool hasBoundOperator() const { return (bool)_boundOperator; }
|
||||
AABox getBound() { return _boundOperator(); }
|
||||
AABox getBound(RenderArgs* args) { return _boundOperator(args); }
|
||||
|
||||
gpu::Shader::Source _vertexSource;
|
||||
gpu::Shader::Source _vertexSourceSkinned;
|
||||
|
@ -199,7 +200,7 @@ private:
|
|||
bool _doesFade { true };
|
||||
ProceduralProgramKey _prevKey;
|
||||
|
||||
std::function<AABox()> _boundOperator { nullptr };
|
||||
std::function<AABox(RenderArgs*)> _boundOperator { nullptr };
|
||||
|
||||
mutable std::mutex _mutex;
|
||||
};
|
||||
|
@ -232,9 +233,9 @@ public:
|
|||
|
||||
void initializeProcedural();
|
||||
|
||||
void setBoundOperator(const std::function<AABox()>& boundOperator) { _procedural.setBoundOperator(boundOperator); }
|
||||
void setBoundOperator(const std::function<AABox(RenderArgs*)>& boundOperator) { _procedural.setBoundOperator(boundOperator); }
|
||||
bool hasBoundOperator() const { return _procedural.hasBoundOperator(); }
|
||||
AABox getBound() { return _procedural.getBound(); }
|
||||
AABox getBound(RenderArgs* args) { return _procedural.getBound(args); }
|
||||
|
||||
private:
|
||||
QString _proceduralString;
|
||||
|
|
|
@ -68,7 +68,7 @@ typedef render::Payload<AnimDebugDrawData> AnimDebugDrawPayload;
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::transparentShape() : ItemKey::Builder::transparentShape().withInvisible()).withTagBits(ItemKey::TAG_BITS_ALL); }
|
||||
template <> const Item::Bound payloadGetBound(const AnimDebugDrawData::Pointer& data) { return data->_bound; }
|
||||
template <> const Item::Bound payloadGetBound(const AnimDebugDrawData::Pointer& data, RenderArgs* args) { return data->_bound; }
|
||||
template <> void payloadRender(const AnimDebugDrawData::Pointer& data, RenderArgs* args) {
|
||||
data->render(args);
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
using namespace render;
|
||||
|
||||
CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex,
|
||||
const Transform& transform, const Transform& offsetTransform, const uint64_t& created)
|
||||
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform, created) {}
|
||||
const Transform& transform, const uint64_t& created)
|
||||
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, created) {}
|
||||
|
||||
void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,
|
||||
const std::vector<glm::mat4>& cauterizedClusterMatrices) {
|
||||
|
@ -52,11 +52,26 @@ void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<Model::Tra
|
|||
}
|
||||
}
|
||||
|
||||
void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform& renderTransform) {
|
||||
void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning) {
|
||||
Transform renderTransform = modelTransform;
|
||||
if (useDualQuaternionSkinning) {
|
||||
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
|
||||
const auto& dq = meshState.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(Transform(transform));
|
||||
}
|
||||
} else {
|
||||
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
|
||||
}
|
||||
}
|
||||
|
||||
_cauterizedTransform = renderTransform;
|
||||
}
|
||||
|
||||
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
|
||||
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const {
|
||||
bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization;
|
||||
if (useCauterizedMesh) {
|
||||
if (_cauterizedClusterBuffer) {
|
||||
|
@ -64,7 +79,6 @@ void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::Ren
|
|||
}
|
||||
batch.setModelTransform(_cauterizedTransform);
|
||||
} else {
|
||||
ModelMeshPartPayload::bindTransform(batch, renderMode);
|
||||
ModelMeshPartPayload::bindTransform(batch, transform, renderMode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
class CauterizedMeshPartPayload : public ModelMeshPartPayload {
|
||||
public:
|
||||
CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform, const uint64_t& created);
|
||||
CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const uint64_t& created);
|
||||
|
||||
// matrix palette skinning
|
||||
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,
|
||||
|
@ -23,9 +23,9 @@ public:
|
|||
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions,
|
||||
const std::vector<Model::TransformDualQuaternion>& cauterizedClusterQuaternions);
|
||||
|
||||
void updateTransformForCauterizedMesh(const Transform& renderTransform);
|
||||
void updateTransformForCauterizedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning);
|
||||
|
||||
void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override;
|
||||
void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const override;
|
||||
|
||||
void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; }
|
||||
|
||||
|
|
|
@ -69,10 +69,6 @@ void CauterizedModel::createRenderItemSet() {
|
|||
transform.setTranslation(_translation);
|
||||
transform.setRotation(_rotation);
|
||||
|
||||
Transform offset;
|
||||
offset.setScale(_scale);
|
||||
offset.postTranslate(_offset);
|
||||
|
||||
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
||||
int shapeID = 0;
|
||||
uint32_t numMeshes = (uint32_t)meshes.size();
|
||||
|
@ -85,7 +81,7 @@ void CauterizedModel::createRenderItemSet() {
|
|||
// Create the render payloads
|
||||
int numParts = (int)mesh->getNumParts();
|
||||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset, _created);
|
||||
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, _created);
|
||||
_modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr);
|
||||
auto material = getGeometry()->getShapeMaterial(shapeID);
|
||||
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
|
||||
|
@ -235,37 +231,8 @@ void CauterizedModel::updateRenderItems() {
|
|||
data.computeAdjustedLocalBound(meshState.clusterMatrices);
|
||||
}
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
if (useDualQuaternionSkinning) {
|
||||
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
|
||||
const auto& dq = meshState.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(transform);
|
||||
}
|
||||
} else {
|
||||
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
|
||||
}
|
||||
}
|
||||
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
|
||||
|
||||
renderTransform = modelTransform;
|
||||
if (useDualQuaternionSkinning) {
|
||||
if (cauterizedMeshState.clusterDualQuaternions.size() == 1 || cauterizedMeshState.clusterDualQuaternions.size() == 2) {
|
||||
const auto& dq = cauterizedMeshState.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(Transform(transform));
|
||||
}
|
||||
} else {
|
||||
if (cauterizedMeshState.clusterMatrices.size() == 1 || cauterizedMeshState.clusterMatrices.size() == 2) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(cauterizedMeshState.clusterMatrices[0]));
|
||||
}
|
||||
}
|
||||
data.updateTransformForCauterizedMesh(renderTransform);
|
||||
data.updateTransformForSkinnedMesh(modelTransform, meshState, useDualQuaternionSkinning);
|
||||
data.updateTransformForCauterizedMesh(modelTransform, cauterizedMeshState, useDualQuaternionSkinning);
|
||||
|
||||
data.setEnableCauterization(enableCauterization);
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
|
|
|
@ -575,7 +575,7 @@ void FadeJob::run(const render::RenderContextPointer& renderContext, FadeJob::Ou
|
|||
auto& item = scene->getItem(state.itemId);
|
||||
assert(item.getTransitionId() == transitionId);
|
||||
#endif
|
||||
if (update(*jobConfig, scene, transaction, state, deltaTime)) {
|
||||
if (update(renderContext->args, *jobConfig, scene, transaction, state, deltaTime)) {
|
||||
hasTransaction = true;
|
||||
}
|
||||
if (isFirstItem && (state.threshold != jobConfig->threshold)) {
|
||||
|
@ -599,7 +599,7 @@ const FadeCategory FadeJob::transitionToCategory[render::Transition::TYPE_COUNT]
|
|||
FADE_AVATAR_CHANGE
|
||||
};
|
||||
|
||||
bool FadeJob::update(const Config& config, const render::ScenePointer& scene, render::Transaction& transaction, render::Transition& transition, const double deltaTime) const {
|
||||
bool FadeJob::update(RenderArgs* args, const Config& config, const render::ScenePointer& scene, render::Transaction& transaction, render::Transition& transition, const double deltaTime) const {
|
||||
const auto fadeCategory = transitionToCategory[transition.eventType];
|
||||
auto& eventConfig = config.events[fadeCategory];
|
||||
auto item = scene->getItemSafe(transition.itemId);
|
||||
|
@ -607,11 +607,11 @@ bool FadeJob::update(const Config& config, const render::ScenePointer& scene, re
|
|||
const FadeConfig::Timing timing = (FadeConfig::Timing) eventConfig.timing;
|
||||
|
||||
if (item.exist()) {
|
||||
auto aabb = item.getBound();
|
||||
auto aabb = item.getBound(args);
|
||||
if (render::Item::isValidID(transition.boundItemId)) {
|
||||
auto boundItem = scene->getItemSafe(transition.boundItemId);
|
||||
if (boundItem.exist()) {
|
||||
aabb = boundItem.getBound();
|
||||
aabb = boundItem.getBound(args);
|
||||
}
|
||||
}
|
||||
auto& dimensions = aabb.getDimensions();
|
||||
|
|
|
@ -223,7 +223,7 @@ private:
|
|||
float _thresholdScale[FADE_CATEGORY_COUNT];
|
||||
uint64_t _previousTime{ 0 };
|
||||
|
||||
bool update(const Config& config, const render::ScenePointer& scene, render::Transaction& transaction, render::Transition& transition, const double deltaTime) const;
|
||||
bool update(RenderArgs* args, const Config& config, const render::ScenePointer& scene, render::Transaction& transaction, render::Transition& transition, const double deltaTime) const;
|
||||
static float computeElementEnterRatio(double time, const double period, FadeConfig::Timing timing);
|
||||
|
||||
};
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace render {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload) {
|
||||
template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload, RenderArgs* args) {
|
||||
if (payload) {
|
||||
return payload->editBound();
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ namespace render {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload) {
|
||||
template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload, RenderArgs* args) {
|
||||
if (payload) {
|
||||
return payload->editBound();
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ protected:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const LightPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> void payloadRender(const LightPayload::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ protected:
|
|||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const KeyLightPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const KeyLightPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> void payloadRender(const KeyLightPayload::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
#include "MeshPartPayload.h"
|
||||
|
||||
#include <QProcess>
|
||||
|
||||
#include <BillboardMode.h>
|
||||
#include <PerfStat.h>
|
||||
#include <DualQuaternion.h>
|
||||
#include <graphics/ShaderConstants.h>
|
||||
|
@ -23,292 +22,33 @@
|
|||
|
||||
#include "RenderPipelines.h"
|
||||
|
||||
// static const QString ENABLE_MATERIAL_PROCEDURAL_SHADERS_STRING { "HIFI_ENABLE_MATERIAL_PROCEDURAL_SHADERS" };
|
||||
// static bool ENABLE_MATERIAL_PROCEDURAL_SHADERS = QProcessEnvironment::systemEnvironment().contains(ENABLE_MATERIAL_PROCEDURAL_SHADERS_STRING);
|
||||
|
||||
bool MeshPartPayload::enableMaterialProceduralShaders = false;
|
||||
|
||||
using namespace render;
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) {
|
||||
if (payload) {
|
||||
return payload->getKey();
|
||||
}
|
||||
return ItemKey::Builder::opaqueShape(); // for lack of a better idea
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) {
|
||||
if (payload) {
|
||||
return payload->getBound();
|
||||
}
|
||||
return Item::Bound();
|
||||
}
|
||||
|
||||
template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload) {
|
||||
if (payload) {
|
||||
return payload->getShapeKey();
|
||||
}
|
||||
return ShapeKey::Builder::invalid();
|
||||
}
|
||||
|
||||
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) {
|
||||
return payload->render(args);
|
||||
}
|
||||
|
||||
template <> bool payloadPassesZoneOcclusionTest(const MeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones) {
|
||||
if (payload) {
|
||||
return payload->passesZoneOcclusionTest(containingZones);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material, const uint64_t& created) :
|
||||
_created(created)
|
||||
{
|
||||
updateMeshPart(mesh, partIndex);
|
||||
addMaterial(graphics::MaterialLayer(material, 0));
|
||||
}
|
||||
|
||||
void MeshPartPayload::updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex) {
|
||||
_drawMesh = drawMesh;
|
||||
if (_drawMesh) {
|
||||
auto vertexFormat = _drawMesh->getVertexFormat();
|
||||
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
|
||||
_drawPart = _drawMesh->getPartBuffer().get<graphics::Mesh::Part>(partIndex);
|
||||
_localBound = _drawMesh->evalPartBound(partIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshPartPayload::updateTransform(const Transform& transform, const Transform& offsetTransform) {
|
||||
_transform = transform;
|
||||
Transform::mult(_drawTransform, _transform, offsetTransform);
|
||||
_worldBound = _localBound;
|
||||
_worldBound.transform(_drawTransform);
|
||||
}
|
||||
|
||||
void MeshPartPayload::addMaterial(graphics::MaterialLayer material) {
|
||||
_drawMaterials.push(material);
|
||||
}
|
||||
|
||||
void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) {
|
||||
_drawMaterials.remove(material);
|
||||
}
|
||||
|
||||
void MeshPartPayload::updateKey(const render::ItemKey& key) {
|
||||
ItemKey::Builder builder(key);
|
||||
builder.withTypeShape();
|
||||
|
||||
if (_drawMaterials.shouldUpdate()) {
|
||||
RenderPipelines::updateMultiMaterial(_drawMaterials);
|
||||
}
|
||||
|
||||
auto matKey = _drawMaterials.getMaterialKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
|
||||
if (_cullWithParent) {
|
||||
builder.withSubMetaCulled();
|
||||
}
|
||||
|
||||
_itemKey = builder.build();
|
||||
}
|
||||
|
||||
ItemKey MeshPartPayload::getKey() const {
|
||||
return _itemKey;
|
||||
}
|
||||
|
||||
Item::Bound MeshPartPayload::getBound() const {
|
||||
graphics::MaterialPointer material = _drawMaterials.empty() ? nullptr : _drawMaterials.top().material;
|
||||
if (material && material->isProcedural() && material->isReady()) {
|
||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(_drawMaterials.top().material);
|
||||
if (procedural->hasVertexShader() && procedural->hasBoundOperator()) {
|
||||
return procedural->getBound();
|
||||
}
|
||||
}
|
||||
return _worldBound;
|
||||
}
|
||||
|
||||
ShapeKey MeshPartPayload::getShapeKey() const {
|
||||
ShapeKey::Builder builder;
|
||||
graphics::MaterialPointer material = _drawMaterials.empty() ? nullptr : _drawMaterials.top().material;
|
||||
graphics::MaterialKey drawMaterialKey = _drawMaterials.getMaterialKey();
|
||||
|
||||
if (drawMaterialKey.isTranslucent()) {
|
||||
builder.withTranslucent();
|
||||
}
|
||||
|
||||
if (material && material->isProcedural() && material->isReady()) {
|
||||
builder.withOwnPipeline();
|
||||
} else {
|
||||
builder.withMaterial();
|
||||
|
||||
if (drawMaterialKey.isNormalMap()) {
|
||||
builder.withTangents();
|
||||
}
|
||||
if (drawMaterialKey.isLightMap()) {
|
||||
builder.withLightMap();
|
||||
}
|
||||
if (drawMaterialKey.isUnlit()) {
|
||||
builder.withUnlit();
|
||||
}
|
||||
if (material) {
|
||||
builder.withCullFaceMode(material->getCullFaceMode());
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
|
||||
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
|
||||
}
|
||||
|
||||
void MeshPartPayload::bindMesh(gpu::Batch& batch) {
|
||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||
|
||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||
|
||||
batch.setInputStream(0, _drawMesh->getVertexStream());
|
||||
}
|
||||
|
||||
void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
|
||||
batch.setModelTransform(_drawTransform);
|
||||
}
|
||||
|
||||
bool MeshPartPayload::passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const {
|
||||
if (!_renderWithZones.isEmpty()) {
|
||||
if (!containingZones.empty()) {
|
||||
for (auto renderWithZone : _renderWithZones) {
|
||||
if (containingZones.find(renderWithZone) != containingZones.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MeshPartPayload::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("MeshPartPayload::render");
|
||||
|
||||
if (!args) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpu::Batch& batch = *(args->_batch);
|
||||
|
||||
// Bind the model transform and the skinCLusterMatrices if needed
|
||||
bindTransform(batch, args->_renderMode);
|
||||
|
||||
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
||||
bindMesh(batch);
|
||||
|
||||
if (!_drawMaterials.empty() && _drawMaterials.top().material && _drawMaterials.top().material->isProcedural() &&
|
||||
_drawMaterials.top().material->isReady()) {
|
||||
if (!enableMaterialProceduralShaders) {
|
||||
return;
|
||||
}
|
||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(_drawMaterials.top().material);
|
||||
auto& schema = _drawMaterials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
|
||||
glm::vec4 outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
|
||||
outColor = procedural->getColor(outColor);
|
||||
procedural->prepare(batch, _drawTransform.getTranslation(), _drawTransform.getScale(), _drawTransform.getRotation(), _created,
|
||||
ProceduralProgramKey(outColor.a < 1.0f));
|
||||
batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
|
||||
} else {
|
||||
// apply material properties
|
||||
if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) {
|
||||
args->_details._materialSwitches++;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw!
|
||||
{
|
||||
PerformanceTimer perfTimer("batch.drawIndexed()");
|
||||
drawCall(batch);
|
||||
}
|
||||
|
||||
const int INDICES_PER_TRIANGLE = 3;
|
||||
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
|
||||
}
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) {
|
||||
if (payload) {
|
||||
return payload->getKey();
|
||||
}
|
||||
return ItemKey::Builder::opaqueShape(); // for lack of a better idea
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) {
|
||||
if (payload) {
|
||||
return payload->getBound();
|
||||
}
|
||||
return Item::Bound();
|
||||
}
|
||||
|
||||
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) {
|
||||
if (payload) {
|
||||
return payload->getShapeKey();
|
||||
}
|
||||
return ShapeKey::Builder::invalid();
|
||||
}
|
||||
|
||||
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
|
||||
return payload->render(args);
|
||||
}
|
||||
|
||||
template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones) {
|
||||
if (payload) {
|
||||
return payload->passesZoneOcclusionTest(containingZones);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ModelMeshPartPayload::enableMaterialProceduralShaders = false;
|
||||
|
||||
ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex,
|
||||
const Transform& transform, const Transform& offsetTransform, const uint64_t& created) :
|
||||
const Transform& transform, const uint64_t& created) :
|
||||
_meshIndex(meshIndex),
|
||||
_shapeID(shapeIndex) {
|
||||
_created(created) {
|
||||
|
||||
assert(model && model->isLoaded());
|
||||
|
||||
bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning();
|
||||
|
||||
auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex);
|
||||
_meshNumVertices = (int)modelMesh->getNumVertices();
|
||||
const Model::MeshState& state = model->getMeshState(_meshIndex);
|
||||
|
||||
updateMeshPart(modelMesh, partIndex);
|
||||
|
||||
bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning();
|
||||
if (useDualQuaternionSkinning) {
|
||||
computeAdjustedLocalBound(state.clusterDualQuaternions);
|
||||
} else {
|
||||
computeAdjustedLocalBound(state.clusterMatrices);
|
||||
}
|
||||
|
||||
updateTransform(transform, offsetTransform);
|
||||
Transform renderTransform = transform;
|
||||
if (useDualQuaternionSkinning) {
|
||||
if (state.clusterDualQuaternions.size() == 1) {
|
||||
const auto& dq = state.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = transform.worldTransform(Transform(transform));
|
||||
}
|
||||
} else {
|
||||
if (state.clusterMatrices.size() == 1) {
|
||||
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
|
||||
}
|
||||
}
|
||||
updateTransformForSkinnedMesh(renderTransform, transform);
|
||||
updateTransformForSkinnedMesh(transform, state, useDualQuaternionSkinning);
|
||||
|
||||
initCache(model);
|
||||
initCache(model, shapeIndex);
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_ANDROID)
|
||||
// On mac AMD, we specifically need to have a _meshBlendshapeBuffer bound when using a deformed mesh pipeline
|
||||
|
@ -322,14 +62,11 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
|
|||
_meshBlendshapeBuffer = std::make_shared<gpu::Buffer>(sizeof(BlendshapeOffset), reinterpret_cast<const gpu::Byte*>(&data), sizeof(BlendshapeOffset));
|
||||
}
|
||||
#endif
|
||||
|
||||
_created = created;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::initCache(const ModelPointer& model) {
|
||||
void ModelMeshPartPayload::initCache(const ModelPointer& model, int shapeID) {
|
||||
if (_drawMesh) {
|
||||
auto vertexFormat = _drawMesh->getVertexFormat();
|
||||
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
|
||||
_isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX);
|
||||
|
||||
const HFMModel& hfmModel = model->getHFMModel();
|
||||
|
@ -339,18 +76,22 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) {
|
|||
_hasTangents = !mesh.tangents.isEmpty();
|
||||
}
|
||||
|
||||
auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID);
|
||||
auto networkMaterial = model->getGeometry()->getShapeMaterial(shapeID);
|
||||
if (networkMaterial) {
|
||||
addMaterial(graphics::MaterialLayer(networkMaterial, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::notifyLocationChanged() {
|
||||
|
||||
void ModelMeshPartPayload::updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex) {
|
||||
_drawMesh = drawMesh;
|
||||
if (_drawMesh) {
|
||||
auto vertexFormat = _drawMesh->getVertexFormat();
|
||||
_drawPart = _drawMesh->getPartBuffer().get<graphics::Mesh::Part>(partIndex);
|
||||
_localBound = _drawMesh->evalPartBound(partIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices) {
|
||||
|
||||
// reset cluster buffer if we change the cluster buffer type
|
||||
if (_clusterBufferType != ClusterBufferType::Matrices) {
|
||||
_clusterBuffer.reset();
|
||||
|
@ -370,7 +111,6 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clu
|
|||
}
|
||||
|
||||
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
|
||||
|
||||
// reset cluster buffer if we change the cluster buffer type
|
||||
if (_clusterBufferType != ClusterBufferType::DualQuaternions) {
|
||||
_clusterBuffer.reset();
|
||||
|
@ -389,13 +129,76 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector<Model::Transfor
|
|||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform) {
|
||||
_transform = renderTransform;
|
||||
_worldBound = _adjustedLocalBound;
|
||||
_worldBound.transform(boundTransform);
|
||||
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices) {
|
||||
_adjustedLocalBound = _localBound;
|
||||
if (clusterMatrices.size() > 0) {
|
||||
_adjustedLocalBound.transform(clusterMatrices.back());
|
||||
|
||||
for (int i = 0; i < (int)clusterMatrices.size() - 1; ++i) {
|
||||
AABox clusterBound = _localBound;
|
||||
clusterBound.transform(clusterMatrices[i]);
|
||||
_adjustedLocalBound += clusterBound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
|
||||
_adjustedLocalBound = _localBound;
|
||||
if (clusterDualQuaternions.size() > 0) {
|
||||
Transform rootTransform(clusterDualQuaternions.back().getRotation(),
|
||||
clusterDualQuaternions.back().getScale(),
|
||||
clusterDualQuaternions.back().getTranslation());
|
||||
_adjustedLocalBound.transform(rootTransform);
|
||||
|
||||
for (int i = 0; i < (int)clusterDualQuaternions.size() - 1; ++i) {
|
||||
AABox clusterBound = _localBound;
|
||||
Transform transform(clusterDualQuaternions[i].getRotation(),
|
||||
clusterDualQuaternions[i].getScale(),
|
||||
clusterDualQuaternions[i].getTranslation());
|
||||
clusterBound.transform(transform);
|
||||
_adjustedLocalBound += clusterBound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning) {
|
||||
_localTransform = Transform();
|
||||
if (useDualQuaternionSkinning) {
|
||||
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
|
||||
const auto& dq = meshState.clusterDualQuaternions[0];
|
||||
_localTransform = Transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
}
|
||||
} else {
|
||||
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
|
||||
_localTransform = Transform(meshState.clusterMatrices[0]);
|
||||
}
|
||||
}
|
||||
|
||||
_parentTransform = modelTransform;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
|
||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||
if (_meshBlendshapeBuffer) {
|
||||
batch.setResourceBuffer(0, _meshBlendshapeBuffer);
|
||||
}
|
||||
batch.setInputStream(0, _drawMesh->getVertexStream());
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const {
|
||||
if (_clusterBuffer) {
|
||||
batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer);
|
||||
}
|
||||
batch.setModelTransform(transform);
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::drawCall(gpu::Batch& batch) const {
|
||||
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
|
||||
}
|
||||
|
||||
// Note that this method is called for models but not for shapes
|
||||
void ModelMeshPartPayload::updateKey(const render::ItemKey& key) {
|
||||
ItemKey::Builder builder(key);
|
||||
builder.withTypeShape();
|
||||
|
@ -480,26 +283,33 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, PrimitiveMode pr
|
|||
_shapeKey = builder.build();
|
||||
}
|
||||
|
||||
ItemKey ModelMeshPartPayload::getKey() const {
|
||||
return _itemKey;
|
||||
}
|
||||
|
||||
Item::Bound ModelMeshPartPayload::getBound(RenderArgs* args) const {
|
||||
graphics::MaterialPointer material = _drawMaterials.empty() ? nullptr : _drawMaterials.top().material;
|
||||
if (material && material->isProcedural() && material->isReady()) {
|
||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(_drawMaterials.top().material);
|
||||
if (procedural->hasVertexShader() && procedural->hasBoundOperator()) {
|
||||
return procedural->getBound(args);
|
||||
}
|
||||
}
|
||||
|
||||
auto worldBound = _adjustedLocalBound;
|
||||
auto parentTransform = _parentTransform;
|
||||
if (args) {
|
||||
parentTransform.setRotation(BillboardModeHelpers::getBillboardRotation(parentTransform.getTranslation(), parentTransform.getRotation(), _billboardMode,
|
||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
||||
}
|
||||
worldBound.transform(parentTransform);
|
||||
return worldBound;
|
||||
}
|
||||
|
||||
ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
||||
return _shapeKey;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
|
||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||
if (_meshBlendshapeBuffer) {
|
||||
batch.setResourceBuffer(0, _meshBlendshapeBuffer);
|
||||
}
|
||||
batch.setInputStream(0, _drawMesh->getVertexStream());
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
|
||||
if (_clusterBuffer) {
|
||||
batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer);
|
||||
}
|
||||
batch.setModelTransform(_transform);
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
|
||||
|
||||
|
@ -509,7 +319,12 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
|
|||
|
||||
gpu::Batch& batch = *(args->_batch);
|
||||
|
||||
bindTransform(batch, args->_renderMode);
|
||||
Transform transform = _parentTransform;
|
||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
||||
|
||||
Transform modelTransform = transform.worldTransform(_localTransform);
|
||||
bindTransform(batch, modelTransform, args->_renderMode);
|
||||
|
||||
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
||||
bindMesh(batch);
|
||||
|
@ -528,7 +343,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
|
|||
auto& schema = _drawMaterials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
|
||||
glm::vec4 outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
|
||||
outColor = procedural->getColor(outColor);
|
||||
procedural->prepare(batch, _drawTransform.getTranslation(), _drawTransform.getScale(), _drawTransform.getRotation(), _created,
|
||||
procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created,
|
||||
ProceduralProgramKey(outColor.a < 1.0f, _shapeKey.isDeformed(), _shapeKey.isDualQuatSkinned()));
|
||||
batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
|
||||
} else {
|
||||
|
@ -548,36 +363,18 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
|
|||
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices) {
|
||||
_adjustedLocalBound = _localBound;
|
||||
if (clusterMatrices.size() > 0) {
|
||||
_adjustedLocalBound.transform(clusterMatrices.back());
|
||||
|
||||
for (int i = 0; i < (int)clusterMatrices.size() - 1; ++i) {
|
||||
AABox clusterBound = _localBound;
|
||||
clusterBound.transform(clusterMatrices[i]);
|
||||
_adjustedLocalBound += clusterBound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
|
||||
_adjustedLocalBound = _localBound;
|
||||
if (clusterDualQuaternions.size() > 0) {
|
||||
Transform rootTransform(clusterDualQuaternions.back().getRotation(),
|
||||
clusterDualQuaternions.back().getScale(),
|
||||
clusterDualQuaternions.back().getTranslation());
|
||||
_adjustedLocalBound.transform(rootTransform);
|
||||
|
||||
for (int i = 0; i < (int)clusterDualQuaternions.size() - 1; ++i) {
|
||||
AABox clusterBound = _localBound;
|
||||
Transform transform(clusterDualQuaternions[i].getRotation(),
|
||||
clusterDualQuaternions[i].getScale(),
|
||||
clusterDualQuaternions[i].getTranslation());
|
||||
clusterBound.transform(transform);
|
||||
_adjustedLocalBound += clusterBound;
|
||||
bool ModelMeshPartPayload::passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const {
|
||||
if (!_renderWithZones.isEmpty()) {
|
||||
if (!containingZones.empty()) {
|
||||
for (auto renderWithZone : _renderWithZones) {
|
||||
if (containingZones.find(renderWithZone) != containingZones.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& blendedMeshSizes) {
|
||||
|
@ -596,3 +393,37 @@ void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map<int, gpu
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) {
|
||||
if (payload) {
|
||||
return payload->getKey();
|
||||
}
|
||||
return ItemKey::Builder::opaqueShape(); // for lack of a better idea
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
|
||||
if (payload) {
|
||||
return payload->getBound(args);
|
||||
}
|
||||
return Item::Bound();
|
||||
}
|
||||
|
||||
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) {
|
||||
if (payload) {
|
||||
return payload->getShapeKey();
|
||||
}
|
||||
return ShapeKey::Builder::invalid();
|
||||
}
|
||||
|
||||
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
|
||||
return payload->render(args);
|
||||
}
|
||||
|
||||
template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones) {
|
||||
if (payload) {
|
||||
return payload->passesZoneOcclusionTest(containingZones);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,152 +12,98 @@
|
|||
#ifndef hifi_MeshPartPayload_h
|
||||
#define hifi_MeshPartPayload_h
|
||||
|
||||
#include <Interpolate.h>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <render/Scene.h>
|
||||
|
||||
#include <graphics/Geometry.h>
|
||||
|
||||
#include "Model.h"
|
||||
|
||||
class Model;
|
||||
#include <gpu/Batch.h>
|
||||
#include <render/Scene.h>
|
||||
#include <graphics/Geometry.h>
|
||||
|
||||
class MeshPartPayload {
|
||||
class ModelMeshPartPayload {
|
||||
public:
|
||||
MeshPartPayload() = default;
|
||||
MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material, const uint64_t& created);
|
||||
virtual ~MeshPartPayload() = default;
|
||||
|
||||
typedef render::Payload<MeshPartPayload> Payload;
|
||||
typedef render::Payload<ModelMeshPartPayload> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
virtual void updateKey(const render::ItemKey& key);
|
||||
ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const uint64_t& created);
|
||||
|
||||
virtual void updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex);
|
||||
|
||||
virtual void notifyLocationChanged() {}
|
||||
void updateTransform(const Transform& transform, const Transform& offsetTransform);
|
||||
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices); // matrix palette skinning
|
||||
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions); // dual quaternion skinning
|
||||
|
||||
// Render Item interface
|
||||
virtual render::ItemKey getKey() const;
|
||||
virtual render::Item::Bound getBound() const;
|
||||
virtual render::ShapeKey getShapeKey() const;
|
||||
virtual void render(RenderArgs* args);
|
||||
void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices); // matrix palette skinning
|
||||
void computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions); // dual quaternion skinning
|
||||
|
||||
void updateTransformForSkinnedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning);
|
||||
|
||||
// ModelMeshPartPayload functions to perform render
|
||||
void bindMesh(gpu::Batch& batch);
|
||||
virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const;
|
||||
void drawCall(gpu::Batch& batch) const;
|
||||
virtual void bindMesh(gpu::Batch& batch);
|
||||
virtual void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const;
|
||||
|
||||
// Payload resource cached values
|
||||
Transform _drawTransform;
|
||||
Transform _transform;
|
||||
int _partIndex = 0;
|
||||
bool _hasColorAttrib { false };
|
||||
void updateKey(const render::ItemKey& key);
|
||||
void setShapeKey(bool invalidateShapeKey, PrimitiveMode primitiveMode, bool useDualQuaternionSkinning);
|
||||
|
||||
graphics::Box _localBound;
|
||||
graphics::Box _adjustedLocalBound;
|
||||
mutable graphics::Box _worldBound;
|
||||
std::shared_ptr<const graphics::Mesh> _drawMesh;
|
||||
|
||||
graphics::MultiMaterial _drawMaterials;
|
||||
graphics::Mesh::Part _drawPart;
|
||||
// Render Item interface
|
||||
render::ItemKey getKey() const;
|
||||
render::Item::Bound getBound(RenderArgs* args) const;
|
||||
render::ShapeKey getShapeKey() const;
|
||||
void render(RenderArgs* args);
|
||||
|
||||
size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; }
|
||||
size_t getMaterialTextureSize() { return _drawMaterials.getTextureSize(); }
|
||||
int getMaterialTextureCount() { return _drawMaterials.getTextureCount(); }
|
||||
bool hasTextureInfo() const { return _drawMaterials.hasTextureInfo(); }
|
||||
|
||||
void addMaterial(graphics::MaterialLayer material);
|
||||
void removeMaterial(graphics::MaterialPointer material);
|
||||
|
||||
void setCauterized(bool cauterized) { _cauterized = cauterized; }
|
||||
void setCullWithParent(bool value) { _cullWithParent = value; }
|
||||
|
||||
void setRenderWithZones(const QVector<QUuid>& renderWithZones) { _renderWithZones = renderWithZones; }
|
||||
void setBillboardMode(BillboardMode billboardMode) { _billboardMode = billboardMode; }
|
||||
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const;
|
||||
|
||||
static bool enableMaterialProceduralShaders;
|
||||
|
||||
protected:
|
||||
render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };
|
||||
bool _cullWithParent { false };
|
||||
QVector<QUuid> _renderWithZones;
|
||||
uint64_t _created;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload);
|
||||
template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload);
|
||||
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> bool payloadPassesZoneOcclusionTest(const MeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones);
|
||||
}
|
||||
|
||||
class ModelMeshPartPayload : public MeshPartPayload {
|
||||
public:
|
||||
ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform, const uint64_t& created);
|
||||
|
||||
typedef render::Payload<ModelMeshPartPayload> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
void notifyLocationChanged() override;
|
||||
|
||||
void updateKey(const render::ItemKey& key) override;
|
||||
|
||||
// matrix palette skinning
|
||||
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices);
|
||||
|
||||
// dual quaternion skinning
|
||||
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
|
||||
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
|
||||
|
||||
// Render Item interface
|
||||
render::ShapeKey getShapeKey() const override;
|
||||
void render(RenderArgs* args) override;
|
||||
|
||||
void setShapeKey(bool invalidateShapeKey, PrimitiveMode primitiveMode, bool useDualQuaternionSkinning);
|
||||
void setCauterized(bool cauterized) { _cauterized = cauterized; }
|
||||
|
||||
// ModelMeshPartPayload functions to perform render
|
||||
void bindMesh(gpu::Batch& batch) override;
|
||||
void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override;
|
||||
|
||||
// matrix palette skinning
|
||||
void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices);
|
||||
|
||||
// dual quaternion skinning
|
||||
void computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
|
||||
|
||||
gpu::BufferPointer _clusterBuffer;
|
||||
|
||||
enum class ClusterBufferType { Matrices, DualQuaternions };
|
||||
ClusterBufferType _clusterBufferType { ClusterBufferType::Matrices };
|
||||
|
||||
int _meshIndex;
|
||||
int _shapeID;
|
||||
|
||||
bool _isSkinned{ false };
|
||||
bool _isBlendShaped { false };
|
||||
bool _hasTangents { false };
|
||||
void addMaterial(graphics::MaterialLayer material) { _drawMaterials.push(material); }
|
||||
void removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); }
|
||||
|
||||
void setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& blendedMeshSizes);
|
||||
|
||||
static bool enableMaterialProceduralShaders;
|
||||
|
||||
private:
|
||||
void initCache(const ModelPointer& model);
|
||||
void initCache(const ModelPointer& model, int shapeID);
|
||||
|
||||
int _meshIndex;
|
||||
std::shared_ptr<const graphics::Mesh> _drawMesh;
|
||||
graphics::Mesh::Part _drawPart;
|
||||
graphics::MultiMaterial _drawMaterials;
|
||||
|
||||
gpu::BufferPointer _clusterBuffer;
|
||||
enum class ClusterBufferType { Matrices, DualQuaternions };
|
||||
ClusterBufferType _clusterBufferType { ClusterBufferType::Matrices };
|
||||
|
||||
gpu::BufferPointer _meshBlendshapeBuffer;
|
||||
int _meshNumVertices;
|
||||
|
||||
render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() };
|
||||
render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() };
|
||||
|
||||
bool _isSkinned { false };
|
||||
bool _isBlendShaped { false };
|
||||
bool _hasTangents { false };
|
||||
bool _prevUseDualQuaternionSkinning { false };
|
||||
bool _cauterized { false };
|
||||
bool _cullWithParent { false };
|
||||
QVector<QUuid> _renderWithZones;
|
||||
BillboardMode _billboardMode;
|
||||
uint64_t _created;
|
||||
|
||||
Transform _localTransform;
|
||||
Transform _parentTransform;
|
||||
graphics::Box _localBound;
|
||||
graphics::Box _adjustedLocalBound;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones);
|
||||
|
|
|
@ -226,6 +226,7 @@ void Model::updateRenderItems() {
|
|||
modelTransform.setScale(glm::vec3(1.0f));
|
||||
|
||||
PrimitiveMode primitiveMode = self->getPrimitiveMode();
|
||||
BillboardMode billboardMode = self->getBillboardMode();
|
||||
auto renderWithZones = self->getRenderWithZones();
|
||||
auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags();
|
||||
bool cauterized = self->isCauterized();
|
||||
|
@ -242,7 +243,7 @@ void Model::updateRenderItems() {
|
|||
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
|
||||
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning,
|
||||
invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags,
|
||||
invalidatePayloadShapeKey, primitiveMode, billboardMode, renderItemKeyGlobalFlags,
|
||||
cauterized, renderWithZones](ModelMeshPartPayload& data) {
|
||||
if (useDualQuaternionSkinning) {
|
||||
data.updateClusterBuffer(meshState.clusterDualQuaternions);
|
||||
|
@ -252,25 +253,11 @@ void Model::updateRenderItems() {
|
|||
data.computeAdjustedLocalBound(meshState.clusterMatrices);
|
||||
}
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
|
||||
if (useDualQuaternionSkinning) {
|
||||
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
|
||||
const auto& dq = meshState.clusterDualQuaternions[0];
|
||||
Transform transform(dq.getRotation(),
|
||||
dq.getScale(),
|
||||
dq.getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(Transform(transform));
|
||||
}
|
||||
} else {
|
||||
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0]));
|
||||
}
|
||||
}
|
||||
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
|
||||
data.updateTransformForSkinnedMesh(modelTransform, meshState, useDualQuaternionSkinning);
|
||||
|
||||
data.setCauterized(cauterized);
|
||||
data.setRenderWithZones(renderWithZones);
|
||||
data.setBillboardMode(billboardMode);
|
||||
data.updateKey(renderItemKeyGlobalFlags);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
|
||||
});
|
||||
|
@ -332,8 +319,8 @@ void Model::initJointStates() {
|
|||
_rig.initJointStates(hfmModel, modelOffset);
|
||||
}
|
||||
|
||||
bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
|
||||
bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
|
||||
bool pickAgainstTriangles, bool allowBackface) {
|
||||
bool intersectedSomething = false;
|
||||
|
||||
|
@ -343,7 +330,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 });
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -83,7 +83,7 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const
|
|||
for (auto& id : items) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) {
|
||||
outItems.emplace_back(ItemBound(id, item.getBound()));
|
||||
outItems.emplace_back(ItemBound(id, item.getBound(renderContext->args)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,10 +188,10 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.insideItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -203,10 +203,10 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.insideSubcellItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -218,10 +218,10 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.partialItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -233,10 +233,10 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.partialSubcellItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -250,10 +250,10 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.insideItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -265,11 +265,11 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.insideSubcellItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
if (test.solidAngleTest(itemBound.bound)) {
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -282,11 +282,11 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.partialItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
if (test.frustumTest(itemBound.bound)) {
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -299,11 +299,11 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
|||
for (auto id : inSelection.partialSubcellItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) {
|
||||
ItemBound itemBound(id, item.getBound());
|
||||
ItemBound itemBound(id, item.getBound(args));
|
||||
if (test.frustumTest(itemBound.bound) && test.solidAngleTest(itemBound.bound)) {
|
||||
outItems.emplace_back(itemBound);
|
||||
if (item.getKey().isMetaCullGroup()) {
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene));
|
||||
item.fetchMetaSubItemBounds(outItems, (*scene), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ void DrawItemSelection::run(const RenderContextPointer& renderContext, const Ite
|
|||
render::ItemBounds itemBounds;
|
||||
for (const auto& itemID : itemIDs) {
|
||||
auto& item = scene->getItem(itemID);
|
||||
auto itemBound = item.getBound();
|
||||
auto itemBound = item.getBound(args);
|
||||
if (!itemBound.isInvalid()) {
|
||||
itemBounds.emplace_back(itemID, itemBound);
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ void IDsToBounds::run(const RenderContextPointer& renderContext, const ItemIDs&
|
|||
for (auto id : inItems) {
|
||||
auto& item = scene->getItem(id);
|
||||
if (item.exist()) {
|
||||
outItems.emplace_back(ItemBound{ id, item.getBound() });
|
||||
outItems.emplace_back(ItemBound{ id, item.getBound(renderContext->args) });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -97,7 +97,7 @@ const ShapeKey Item::getShapeKey() const {
|
|||
return shapeKey;
|
||||
}
|
||||
|
||||
uint32_t Item::fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) const {
|
||||
uint32_t Item::fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene, RenderArgs* args) const {
|
||||
ItemIDs subItems;
|
||||
auto numSubs = fetchMetaSubItems(subItems);
|
||||
|
||||
|
@ -107,7 +107,7 @@ uint32_t Item::fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) c
|
|||
if (scene.isAllocatedID(id)) {
|
||||
auto& item = scene.getItem(id);
|
||||
if (item.exist()) {
|
||||
subItemBounds.emplace_back(id, item.getBound());
|
||||
subItemBounds.emplace_back(id, item.getBound(args));
|
||||
} else {
|
||||
numSubs--;
|
||||
}
|
||||
|
@ -133,11 +133,11 @@ namespace render {
|
|||
return payload->getShapeKey();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const PayloadProxyInterface::Pointer& payload) {
|
||||
template <> const Item::Bound payloadGetBound(const PayloadProxyInterface::Pointer& payload, RenderArgs* args) {
|
||||
if (!payload) {
|
||||
return render::Item::Bound();
|
||||
}
|
||||
return payload->getBound();
|
||||
return payload->getBound(args);
|
||||
}
|
||||
|
||||
template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, RenderArgs* args) {
|
||||
|
|
|
@ -431,7 +431,7 @@ public:
|
|||
class PayloadInterface {
|
||||
public:
|
||||
virtual const ItemKey getKey() const = 0;
|
||||
virtual const Bound getBound() const = 0;
|
||||
virtual const Bound getBound(RenderArgs* args) const = 0;
|
||||
virtual void render(RenderArgs* args) = 0;
|
||||
|
||||
virtual const ShapeKey getShapeKey() const = 0;
|
||||
|
@ -476,7 +476,7 @@ public:
|
|||
// Payload Interface
|
||||
|
||||
// Get the bound of the item expressed in world space (or eye space depending on the key.isWorldSpace())
|
||||
const Bound getBound() const { return _payload->getBound(); }
|
||||
const Bound getBound(RenderArgs* args) const { return _payload->getBound(args); }
|
||||
|
||||
// Get the layer where the item belongs, simply reflecting the key.
|
||||
int getLayer() const { return _key.getLayer(); }
|
||||
|
@ -489,7 +489,7 @@ public:
|
|||
|
||||
// Meta Type Interface
|
||||
uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return _payload->fetchMetaSubItems(subItems); }
|
||||
uint32_t fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) const;
|
||||
uint32_t fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene, RenderArgs* args) const;
|
||||
|
||||
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const { return _payload->passesZoneOcclusionTest(containingZones); }
|
||||
|
||||
|
@ -524,13 +524,13 @@ public:
|
|||
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const Item& item) {
|
||||
debug << "[Item: _key:" << item.getKey() << ", bounds:" << item.getBound() << "]";
|
||||
debug << "[Item: _key:" << item.getKey() << "]";
|
||||
return debug;
|
||||
}
|
||||
|
||||
// Item shared interface supported by the payload
|
||||
template <class T> const ItemKey payloadGetKey(const std::shared_ptr<T>& payloadData) { return ItemKey(); }
|
||||
template <class T> const Item::Bound payloadGetBound(const std::shared_ptr<T>& payloadData) { return Item::Bound(); }
|
||||
template <class T> const Item::Bound payloadGetBound(const std::shared_ptr<T>& payloadData, RenderArgs* args) { return Item::Bound(); }
|
||||
template <class T> void payloadRender(const std::shared_ptr<T>& payloadData, RenderArgs* args) { }
|
||||
|
||||
// Shape type interface
|
||||
|
@ -561,7 +561,7 @@ public:
|
|||
|
||||
// Payload general interface
|
||||
virtual const ItemKey getKey() const override { return payloadGetKey<T>(_data); }
|
||||
virtual const Item::Bound getBound() const override { return payloadGetBound<T>(_data); }
|
||||
virtual const Item::Bound getBound(RenderArgs* args) const override { return payloadGetBound<T>(_data, args); }
|
||||
|
||||
virtual void render(RenderArgs* args) override { payloadRender<T>(_data, args); }
|
||||
|
||||
|
@ -607,9 +607,9 @@ template <> const ItemKey payloadGetKey(const FooPointer& foo) {
|
|||
foo->makeMyKey();
|
||||
return foo->_myownKey;
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const FooPointer& foo) {
|
||||
template <> const Item::Bound payloadGetBound(const FooPointer& foo, RenderArgs* args) {
|
||||
// evaluate Foo's own bound
|
||||
return foo->evaluateMyBound();
|
||||
return foo->evaluateMyBound(args);
|
||||
}
|
||||
|
||||
// In this example, do not specialize the payloadRender call which means the compiler will use the default version which does nothing
|
||||
|
@ -624,7 +624,7 @@ public:
|
|||
|
||||
virtual ItemKey getKey() = 0;
|
||||
virtual ShapeKey getShapeKey() = 0;
|
||||
virtual Item::Bound getBound() = 0;
|
||||
virtual Item::Bound getBound(RenderArgs* args) = 0;
|
||||
virtual void render(RenderArgs* args) = 0;
|
||||
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const = 0;
|
||||
virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const = 0;
|
||||
|
@ -635,7 +635,7 @@ public:
|
|||
};
|
||||
|
||||
template <> const ItemKey payloadGetKey(const PayloadProxyInterface::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const PayloadProxyInterface::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const PayloadProxyInterface::Pointer& payload, RenderArgs* args);
|
||||
template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, RenderArgs* args);
|
||||
template <> uint32_t metaFetchMetaSubItems(const PayloadProxyInterface::Pointer& payload, ItemIDs& subItems);
|
||||
template <> const ShapeKey shapeGetShapeKey(const PayloadProxyInterface::Pointer& payload);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue