mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 01:24:03 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into set-model-entity-joints
This commit is contained in:
commit
afc1757adf
29 changed files with 598 additions and 309 deletions
|
@ -23,14 +23,14 @@ var WANT_DEBUG = false;
|
|||
// these tune time-averaging and "on" value for analog trigger
|
||||
//
|
||||
|
||||
var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing
|
||||
var TRIGGER_ON_VALUE = 0.4; // Squeezed just enough to activate search or near grab
|
||||
var TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab
|
||||
var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing
|
||||
var TRIGGER_ON_VALUE = 0.4; // Squeezed just enough to activate search or near grab
|
||||
var TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab
|
||||
var TRIGGER_OFF_VALUE = 0.15;
|
||||
|
||||
var BUMPER_ON_VALUE = 0.5;
|
||||
|
||||
var HAND_HEAD_MIX_RATIO = 0.0; // 0 = only use hands for search/move. 1 = only use head for search/move.
|
||||
var HAND_HEAD_MIX_RATIO = 0.0; // 0 = only use hands for search/move. 1 = only use head for search/move.
|
||||
|
||||
//
|
||||
// distant manipulation
|
||||
|
@ -421,7 +421,7 @@ function MyController(hand) {
|
|||
this.searchSphereOn = function(location, size, color) {
|
||||
if (this.searchSphere === null) {
|
||||
var sphereProperties = {
|
||||
position: location,
|
||||
position: location,
|
||||
size: size,
|
||||
color: color,
|
||||
alpha: SEARCH_SPHERE_ALPHA,
|
||||
|
@ -429,10 +429,15 @@ function MyController(hand) {
|
|||
visible: true
|
||||
}
|
||||
this.searchSphere = Overlays.addOverlay("sphere", sphereProperties);
|
||||
} else {
|
||||
Overlays.editOverlay(this.searchSphere, { position: location, size: size, color: color, visible: true });
|
||||
} else {
|
||||
Overlays.editOverlay(this.searchSphere, {
|
||||
position: location,
|
||||
size: size,
|
||||
color: color,
|
||||
visible: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.overlayLineOn = function(closePoint, farPoint, color) {
|
||||
if (this.overlayLine === null) {
|
||||
|
@ -765,7 +770,7 @@ function MyController(hand) {
|
|||
if (this.triggerSmoothedSqueezed() || this.bumperSqueezed()) {
|
||||
this.lastPickTime = 0;
|
||||
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
this.startingHandRotation = Controller.getPoseValue(controllerHandInput).rotation;
|
||||
this.startingHandRotation = Controller.getPoseValue(controllerHandInput).rotation;
|
||||
if (this.triggerSmoothedSqueezed()) {
|
||||
this.setState(STATE_SEARCHING);
|
||||
} else {
|
||||
|
@ -788,13 +793,19 @@ function MyController(hand) {
|
|||
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var currentHandRotation = Controller.getPoseValue(controllerHandInput).rotation;
|
||||
var handDeltaRotation = Quat.multiply(currentHandRotation, Quat.inverse(this.startingHandRotation));
|
||||
|
||||
|
||||
var distantPickRay = {
|
||||
origin: Camera.position,
|
||||
origin: Camera.position,
|
||||
direction: Vec3.mix(Quat.getUp(this.getHandRotation()), Quat.getFront(Camera.orientation), HAND_HEAD_MIX_RATIO),
|
||||
length: PICK_MAX_DISTANCE
|
||||
};
|
||||
|
||||
var searchVisualizationPickRay = {
|
||||
origin: handPosition,
|
||||
direction: Quat.getUp(this.getHandRotation()),
|
||||
length: PICK_MAX_DISTANCE
|
||||
};
|
||||
|
||||
// Pick at some maximum rate, not always
|
||||
var pickRays = [];
|
||||
var now = Date.now();
|
||||
|
@ -1015,6 +1026,11 @@ function MyController(hand) {
|
|||
if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) {
|
||||
this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR);
|
||||
}
|
||||
|
||||
if (USE_OVERLAY_LINES_FOR_SEARCHING === true) {
|
||||
this.overlayLineOn(searchVisualizationPickRay.origin, Vec3.sum(searchVisualizationPickRay.origin, Vec3.multiply(searchVisualizationPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR);
|
||||
}
|
||||
|
||||
if (this.intersectionDistance > 0) {
|
||||
var SPHERE_INTERSECTION_SIZE = 0.011;
|
||||
var SEARCH_SPHERE_FOLLOW_RATE = 0.50;
|
||||
|
|
|
@ -24,6 +24,9 @@ RaveStick = function(spawnPosition) {
|
|||
green: 10,
|
||||
blue: 40
|
||||
}];
|
||||
|
||||
|
||||
|
||||
var stick = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "raveStick",
|
||||
|
@ -40,23 +43,25 @@ RaveStick = function(spawnPosition) {
|
|||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
rightRelativePosition: {
|
||||
x: 0.02,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
leftRelativePosition: {
|
||||
x: -0.02,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0)
|
||||
rightRelativePosition: {
|
||||
x: 0.02,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
leftRelativePosition: {
|
||||
x: -0.02,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0)
|
||||
},
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
var glowEmitter = createGlowEmitter();
|
||||
|
||||
var light = Entities.addEntity({
|
||||
type: 'Light',
|
||||
name: "raveLight",
|
||||
|
@ -82,14 +87,76 @@ RaveStick = function(spawnPosition) {
|
|||
green: 200,
|
||||
blue: 40
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(stick);
|
||||
Entities.deleteEntity(light);
|
||||
Entities.deleteEntity(glowEmitter);
|
||||
}
|
||||
|
||||
this.cleanup = cleanup;
|
||||
}
|
||||
|
||||
function createGlowEmitter() {
|
||||
var props = Entities.getEntityProperties(stick, ["position", "rotation"]);
|
||||
var forwardVec = Quat.getFront(props.rotation);
|
||||
var forwardQuat = Quat.rotationBetween(Vec3.UNIT_Z, forwardVec);
|
||||
var position = props.position;
|
||||
var color = {
|
||||
red: 150,
|
||||
green: 20,
|
||||
blue: 100
|
||||
}
|
||||
var props = {
|
||||
type: "ParticleEffect",
|
||||
name: "Rave Stick Glow Emitter",
|
||||
position: position,
|
||||
parentID: stick,
|
||||
isEmitting: true,
|
||||
colorStart: color,
|
||||
color: {
|
||||
red: 200,
|
||||
green: 200,
|
||||
blue: 255
|
||||
},
|
||||
colorFinish: color,
|
||||
maxParticles: 100000,
|
||||
lifespan: 0.8,
|
||||
emitRate: 1000,
|
||||
emitOrientation: forwardQuat,
|
||||
emitSpeed: 0.2,
|
||||
speedSpread: 0.0,
|
||||
emitDimensions: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
polarStart: 0,
|
||||
polarFinish: 0,
|
||||
azimuthStart: 0.1,
|
||||
azimuthFinish: 0.01,
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
accelerationSpread: {
|
||||
x: 0.00,
|
||||
y: 0.00,
|
||||
z: 0.00
|
||||
},
|
||||
radiusStart: 0.01,
|
||||
radiusFinish: 0.005,
|
||||
alpha: 0.7,
|
||||
alphaSpread: 0.1,
|
||||
alphaStart: 0.1,
|
||||
alphaFinish: 0.1,
|
||||
textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png",
|
||||
emitterShouldTrail: false
|
||||
}
|
||||
var glowEmitter = Entities.addEntity(props);
|
||||
return glowEmitter;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,13 @@
|
|||
this.bulletForce = 10;
|
||||
this.showLaser = false;
|
||||
|
||||
this.laserOffsets = {
|
||||
y: 0.095
|
||||
};
|
||||
this.firingOffsets = {
|
||||
z: 0.16
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Pistol.prototype = {
|
||||
|
@ -272,46 +279,12 @@
|
|||
});
|
||||
}, 100);
|
||||
|
||||
Entities.editEntity(this.flash, {
|
||||
isEmitting: true
|
||||
});
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(_this.flash, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100)
|
||||
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
this.laser = Overlays.addOverlay("line3d", {
|
||||
start: ZERO_VECTOR,
|
||||
end: ZERO_VECTOR,
|
||||
color: COLORS.RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: 2
|
||||
});
|
||||
this.laserOffsets = {
|
||||
y: 0.095
|
||||
};
|
||||
this.firingOffsets = {
|
||||
z: 0.16
|
||||
}
|
||||
var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
|
||||
var position = gunProps.position;
|
||||
var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
||||
this.firingDirection = Quat.getFront(rotation);
|
||||
var upVec = Quat.getUp(rotation);
|
||||
this.barrelPoint = Vec3.sum(position, Vec3.multiply(upVec, this.laserOffsets.y));
|
||||
this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z))
|
||||
|
||||
this.flash = Entities.addEntity({
|
||||
var flash = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: this.barrelPoint,
|
||||
"name": "Muzzle Flash",
|
||||
isEmitting: false,
|
||||
lifetime: 4,
|
||||
parentID: this.entityID,
|
||||
"color": {
|
||||
red: 228,
|
||||
green: 128,
|
||||
|
@ -363,14 +336,27 @@
|
|||
"additiveBlending": true,
|
||||
"textures": "http://ericrius1.github.io/PartiArt/assets/star.png"
|
||||
});
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(flash, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100)
|
||||
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(_this.flash, {parentID: _this.entityID});
|
||||
}, 500)
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
this.laser = Overlays.addOverlay("line3d", {
|
||||
start: ZERO_VECTOR,
|
||||
end: ZERO_VECTOR,
|
||||
color: COLORS.RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: 2
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new Pistol();
|
||||
});
|
||||
});
|
|
@ -84,6 +84,7 @@ Hifi.AvatarInputs {
|
|||
Item {
|
||||
width: root.mirrorWidth
|
||||
height: 44
|
||||
visible: !root.isHMD
|
||||
|
||||
x: root.mirrorLeftPad
|
||||
y: root.mirrorVisible ? root.mirrorTopPad + root.mirrorHeight : 5
|
||||
|
|
|
@ -49,7 +49,7 @@ VrDialog {
|
|||
|
||||
onUrlChanged: {
|
||||
var currentUrl = url.toString();
|
||||
var newUrl = urlHandler.fixupUrl(currentUrl);
|
||||
var newUrl = urlHandler.fixupUrl(currentUrl).toString();
|
||||
if (newUrl != currentUrl) {
|
||||
url = newUrl;
|
||||
}
|
||||
|
|
|
@ -258,14 +258,14 @@ Item {
|
|||
Text {
|
||||
color: root.fontColor;
|
||||
font.pixelSize: root.fontSize
|
||||
visible: root.expanded
|
||||
visible: root.showAcuity
|
||||
text: "LOD: " + root.lodStatus;
|
||||
}
|
||||
Text {
|
||||
color: root.fontColor;
|
||||
font.pixelSize: root.fontSize
|
||||
visible: root.expanded
|
||||
text: "Renderable avatars: " + root.avatarRenderableCount + " w/in " + root.avatarRenderDistance + "m";
|
||||
text: root.lodStatsRenderText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import Hifi 1.0 as Hifi
|
||||
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
|
||||
import "controls"
|
||||
import "styles"
|
||||
|
||||
|
@ -21,15 +23,12 @@ Hifi.VrMenu {
|
|||
property var models: []
|
||||
property var columns: []
|
||||
|
||||
|
||||
onEnabledChanged: {
|
||||
if (enabled && columns.length == 0) {
|
||||
pushColumn(rootMenu.items);
|
||||
}
|
||||
opacity = enabled ? 1.0 : 0.0
|
||||
if (enabled) {
|
||||
forceActiveFocus()
|
||||
}
|
||||
offscreenFlags.navigationFocused = enabled;
|
||||
}
|
||||
|
||||
// The actual animator
|
||||
|
@ -49,13 +48,12 @@ Hifi.VrMenu {
|
|||
}
|
||||
|
||||
property var menuBuilder: Component {
|
||||
Border {
|
||||
HifiConstants { id: hifi }
|
||||
property int menuDepth
|
||||
VrMenuView {
|
||||
property int menuDepth: root.models.length - 1
|
||||
model: root.models[menuDepth]
|
||||
|
||||
Component.onCompleted: {
|
||||
menuDepth = root.models.length - 1
|
||||
if (menuDepth == 0) {
|
||||
if (menuDepth === 0) {
|
||||
x = lastMousePosition.x - 20
|
||||
y = lastMousePosition.y - 20
|
||||
} else {
|
||||
|
@ -65,48 +63,8 @@ Hifi.VrMenu {
|
|||
}
|
||||
}
|
||||
|
||||
border.color: hifi.colors.hifiBlue
|
||||
color: hifi.colors.window
|
||||
implicitHeight: listView.implicitHeight + 16
|
||||
implicitWidth: listView.implicitWidth + 16
|
||||
|
||||
Column {
|
||||
id: listView
|
||||
property real minWidth: 0
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: 8
|
||||
left: parent.left
|
||||
leftMargin: 8
|
||||
right: parent.right
|
||||
rightMargin: 8
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: root.models[menuDepth]
|
||||
delegate: Loader {
|
||||
id: loader
|
||||
source: "VrMenuItem.qml"
|
||||
Binding {
|
||||
target: loader.item
|
||||
property: "menuContainer"
|
||||
value: root
|
||||
when: loader.status == Loader.Ready
|
||||
}
|
||||
Binding {
|
||||
target: loader.item
|
||||
property: "source"
|
||||
value: modelData
|
||||
when: loader.status == Loader.Ready
|
||||
}
|
||||
Binding {
|
||||
target: loader.item
|
||||
property: "listView"
|
||||
value: listView
|
||||
when: loader.status == Loader.Ready
|
||||
}
|
||||
}
|
||||
}
|
||||
onSelected: {
|
||||
root.selectItem(menuDepth, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,14 +74,14 @@ Hifi.VrMenu {
|
|||
}
|
||||
|
||||
function pushColumn(items) {
|
||||
models.push(items)
|
||||
models.push(itemsToModel(items))
|
||||
if (columns.length) {
|
||||
var oldColumn = lastColumn();
|
||||
//oldColumn.enabled = false
|
||||
}
|
||||
var newColumn = menuBuilder.createObject(root);
|
||||
columns.push(newColumn);
|
||||
newColumn.forceActiveFocus();
|
||||
forceActiveFocus();
|
||||
}
|
||||
|
||||
function popColumn() {
|
||||
|
@ -145,13 +103,39 @@ Hifi.VrMenu {
|
|||
curColumn.forceActiveFocus();
|
||||
}
|
||||
|
||||
function selectItem(source) {
|
||||
function itemsToModel(items) {
|
||||
var newListModel = Qt.createQmlObject('import QtQuick 2.2; ListModel {}', root);
|
||||
for (var i = 0; i < items.length; ++i) {
|
||||
var item = items[i];
|
||||
switch (item.type) {
|
||||
case 2:
|
||||
newListModel.append({"type":item.type, "name": item.title, "item": item})
|
||||
break;
|
||||
case 1:
|
||||
newListModel.append({"type":item.type, "name": item.text, "item": item})
|
||||
break;
|
||||
case 0:
|
||||
newListModel.append({"type":item.type, "name": "-----", "item": item})
|
||||
break;
|
||||
}
|
||||
}
|
||||
return newListModel;
|
||||
}
|
||||
|
||||
function selectItem(depth, source) {
|
||||
var popped = false;
|
||||
while (depth + 1 < columns.length) {
|
||||
popColumn()
|
||||
popped = true
|
||||
}
|
||||
|
||||
switch (source.type) {
|
||||
case 2:
|
||||
lastColumn().enabled = false
|
||||
pushColumn(source.items)
|
||||
break;
|
||||
case 1:
|
||||
source.trigger()
|
||||
if (!popped) source.trigger()
|
||||
enabled = false
|
||||
break;
|
||||
case 0:
|
||||
|
@ -165,14 +149,6 @@ Hifi.VrMenu {
|
|||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
root.popColumn()
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
id: mouseArea
|
||||
|
@ -206,4 +182,36 @@ Hifi.VrMenu {
|
|||
function removeItem(menu, menuItem) {
|
||||
menu.removeItem(menuItem);
|
||||
}
|
||||
|
||||
function previousItem() {
|
||||
if (columns.length) {
|
||||
lastColumn().incrementCurrentIndex()
|
||||
}
|
||||
}
|
||||
|
||||
function nextItem() {
|
||||
if (columns.length) {
|
||||
lastColumn().decrementCurrentIndex()
|
||||
}
|
||||
}
|
||||
|
||||
function selectCurrentItem() {
|
||||
if (columns.length) {
|
||||
var depth = columns.length - 1;
|
||||
var index = lastColumn().currentIndex;
|
||||
if (index >= 0) {
|
||||
var model = models[depth];
|
||||
var item = model.get(index).item;
|
||||
selectItem(depth, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onDownPressed: previousItem();
|
||||
Keys.onUpPressed: nextItem();
|
||||
Keys.onSpacePressed: selectCurrentItem();
|
||||
Keys.onReturnPressed: selectCurrentItem();
|
||||
Keys.onRightPressed: selectCurrentItem();
|
||||
Keys.onLeftPressed: popColumn();
|
||||
Keys.onEscapePressed: popColumn();
|
||||
}
|
||||
|
|
|
@ -6,57 +6,18 @@ import "styles"
|
|||
|
||||
Item {
|
||||
id: root
|
||||
HifiConstants {
|
||||
id: hifi
|
||||
HifiConstants {
|
||||
id: hifi
|
||||
}
|
||||
|
||||
// The model object
|
||||
property alias text: label.text
|
||||
property var source
|
||||
property var menuContainer
|
||||
property var listView
|
||||
|
||||
MouseArea {
|
||||
anchors.left: parent.left
|
||||
anchors.right: tag.right
|
||||
anchors.rightMargin: -4
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: true
|
||||
|
||||
Rectangle {
|
||||
id: highlight
|
||||
visible: false
|
||||
anchors.fill: parent
|
||||
color: "#7f0e7077"
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
//if (source.type == 2 && enabled) {
|
||||
// timer.start()
|
||||
//}
|
||||
highlight.visible = source.enabled
|
||||
}
|
||||
|
||||
onExited: {
|
||||
timer.stop()
|
||||
highlight.visible = false
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
select()
|
||||
}
|
||||
}
|
||||
|
||||
implicitHeight: source.visible ? label.implicitHeight * 1.5 : 0
|
||||
implicitWidth: label.implicitWidth + label.height * 2.5
|
||||
implicitWidth: label.width + label.height * 2.5
|
||||
visible: source.visible
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
interval: 1000
|
||||
onTriggered: parent.select()
|
||||
}
|
||||
|
||||
width: parent.width
|
||||
|
||||
FontAwesome {
|
||||
clip: true
|
||||
|
@ -84,32 +45,18 @@ Item {
|
|||
|
||||
Text {
|
||||
id: label
|
||||
text: typedText()
|
||||
anchors.left: check.right
|
||||
anchors.leftMargin: 4
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: source.enabled ? hifi.colors.text : hifi.colors.disabledText
|
||||
enabled: source.enabled && source.visible
|
||||
enabled: source.visible && (source.type !== 0 ? source.enabled : false)
|
||||
visible: source.visible
|
||||
function typedText() {
|
||||
if (source) {
|
||||
switch (source.type) {
|
||||
case 2:
|
||||
return source.title
|
||||
case 1:
|
||||
return source.text
|
||||
case 0:
|
||||
return "-----"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
FontAwesome {
|
||||
id: tag
|
||||
x: listView.width - width - 4
|
||||
x: root.parent.width - width
|
||||
size: label.height
|
||||
width: implicitWidth
|
||||
visible: source.visible && (source.type == 2)
|
||||
|
@ -117,17 +64,4 @@ Item {
|
|||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: label.color
|
||||
}
|
||||
|
||||
function select() {
|
||||
//timer.stop();
|
||||
var popped = false
|
||||
while (columns.length - 1 > listView.parent.menuDepth) {
|
||||
popColumn()
|
||||
popped = true
|
||||
}
|
||||
|
||||
if (!popped || source.type != 1) {
|
||||
root.menuContainer.selectItem(source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
77
interface/resources/qml/VrMenuView.qml
Normal file
77
interface/resources/qml/VrMenuView.qml
Normal file
|
@ -0,0 +1,77 @@
|
|||
import QtQuick 2.4
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
|
||||
import "styles"
|
||||
|
||||
ListView {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
width: 128
|
||||
height: count * 32
|
||||
onEnabledChanged: recalcSize();
|
||||
onVisibleChanged: recalcSize();
|
||||
onCountChanged: recalcSize();
|
||||
|
||||
signal selected(var item)
|
||||
|
||||
highlight: Rectangle {
|
||||
width: root.currentItem ? root.currentItem.width : 0
|
||||
height: root.currentItem ? root.currentItem.height : 0
|
||||
color: "lightsteelblue"; radius: 3
|
||||
}
|
||||
|
||||
delegate: VrMenuItem {
|
||||
text: name
|
||||
source: item
|
||||
onImplicitHeightChanged: root.recalcSize()
|
||||
onImplicitWidthChanged: root.recalcSize()
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: root.currentIndex = index
|
||||
onClicked: root.selected(item)
|
||||
}
|
||||
}
|
||||
|
||||
function recalcSize() {
|
||||
if (model.count !== count || !visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
var originalIndex = currentIndex;
|
||||
var maxWidth = width;
|
||||
var newHeight = 0;
|
||||
for (var i = 0; i < count; ++i) {
|
||||
currentIndex = i;
|
||||
if (!currentItem) {
|
||||
continue;
|
||||
}
|
||||
if (currentItem && currentItem.implicitWidth > maxWidth) {
|
||||
maxWidth = currentItem.implicitWidth
|
||||
}
|
||||
if (currentItem.visible) {
|
||||
newHeight += currentItem.implicitHeight
|
||||
}
|
||||
}
|
||||
if (maxWidth > width) {
|
||||
width = maxWidth;
|
||||
}
|
||||
if (newHeight > height) {
|
||||
height = newHeight
|
||||
}
|
||||
currentIndex = originalIndex;
|
||||
}
|
||||
|
||||
Border {
|
||||
id: border
|
||||
anchors.fill: parent
|
||||
anchors.margins: -8
|
||||
z: parent.z - 1
|
||||
border.color: hifi.colors.hifiBlue
|
||||
color: hifi.colors.window
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2990,7 +2990,11 @@ void Application::update(float deltaTime) {
|
|||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::update()");
|
||||
|
||||
updateLOD();
|
||||
if (DependencyManager::get<LODManager>()->getUseAcuity()) {
|
||||
updateLOD();
|
||||
} else {
|
||||
DependencyManager::get<LODManager>()->updatePIDRenderDistance(getTargetFrameRate(), getLastInstanteousFps(), deltaTime, isThrottleRendering());
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("devices");
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <Util.h>
|
||||
|
||||
|
@ -20,9 +21,30 @@
|
|||
|
||||
Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS);
|
||||
Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS);
|
||||
// There are two different systems in use, based on lodPreference:
|
||||
// pid: renderDistance is adjusted by a PID such that frame rate targets are met.
|
||||
// acuity: a pseudo-acuity target is held, or adjusted to match minimum frame rates (and a PID controlls avatar rendering distance)
|
||||
// If unspecified, acuity is used only if user has specified non-default minumum frame rates.
|
||||
Setting::Handle<int> lodPreference("lodPreference", (int)LODManager::LODPreference::unspecified);
|
||||
const float SMALLEST_REASONABLE_HORIZON = 50.0f; // meters
|
||||
Setting::Handle<float> renderDistanceInverseHighLimit("renderDistanceInverseHighLimit", 1.0f / SMALLEST_REASONABLE_HORIZON);
|
||||
void LODManager::setRenderDistanceInverseHighLimit(float newValue) {
|
||||
renderDistanceInverseHighLimit.set(newValue); // persist it, and tell all the controllers that use it
|
||||
_renderDistanceController.setControlledValueHighLimit(newValue);
|
||||
}
|
||||
|
||||
LODManager::LODManager() {
|
||||
calculateAvatarLODDistanceMultiplier();
|
||||
|
||||
setRenderDistanceInverseHighLimit(renderDistanceInverseHighLimit.get());
|
||||
setRenderDistanceInverseLowLimit(1.0f / (float)TREE_SCALE);
|
||||
// Advice for tuning parameters:
|
||||
// See PIDController.h. There's a section on tuning in the reference.
|
||||
// Turn on logging with the following (or from js with LODManager.setRenderDistanceControllerHistory("render pid", 240))
|
||||
//setRenderDistanceControllerHistory("render pid", 60 * 4);
|
||||
// Note that extra logging/hysteresis is turned off in Avatar.cpp when the above logging is on.
|
||||
setRenderDistanceKP(0.000012f); // Usually about 0.6 of largest that doesn't oscillate when other parameters 0.
|
||||
setRenderDistanceKI(0.00002f); // Big enough to bring us to target with the above KP.
|
||||
}
|
||||
|
||||
float LODManager::getLODDecreaseFPS() {
|
||||
|
@ -39,7 +61,6 @@ float LODManager::getLODIncreaseFPS() {
|
|||
return getDesktopLODIncreaseFPS();
|
||||
}
|
||||
|
||||
|
||||
void LODManager::autoAdjustLOD(float currentFPS) {
|
||||
|
||||
// NOTE: our first ~100 samples at app startup are completely all over the place, and we don't
|
||||
|
@ -217,15 +238,58 @@ QString LODManager::getLODFeedbackText() {
|
|||
return result;
|
||||
}
|
||||
|
||||
static float renderDistance = (float)TREE_SCALE;
|
||||
static int renderedCount = 0;
|
||||
static int lastRenderedCount = 0;
|
||||
bool LODManager::getUseAcuity() { return lodPreference.get() == (int)LODManager::LODPreference::acuity; }
|
||||
void LODManager::setUseAcuity(bool newValue) { lodPreference.set(newValue ? (int)LODManager::LODPreference::acuity : (int)LODManager::LODPreference::pid); }
|
||||
float LODManager::getRenderDistance() {
|
||||
return renderDistance;
|
||||
}
|
||||
int LODManager::getRenderedCount() {
|
||||
return lastRenderedCount;
|
||||
}
|
||||
QString LODManager::getLODStatsRenderText() {
|
||||
QString label = getUseAcuity() ? "Renderable avatars: " : "Rendered objects: ";
|
||||
return label + QString::number(getRenderedCount()) + " w/in " + QString::number((int)getRenderDistance()) + "m";
|
||||
}
|
||||
// compare audoAdjustLOD()
|
||||
void LODManager::updatePIDRenderDistance(float targetFps, float measuredFps, float deltaTime, bool isThrottled) {
|
||||
float distance;
|
||||
if (!isThrottled) {
|
||||
_renderDistanceController.setMeasuredValueSetpoint(targetFps / 2.0f); // No problem updating in flight.
|
||||
// The PID controller raises the controlled value when the measured value goes up.
|
||||
// The measured value is frame rate. When the controlled value (1 / render cutoff distance)
|
||||
// goes up, the render cutoff distance gets closer, the number of rendered avatars is less, and frame rate
|
||||
// goes up.
|
||||
distance = 1.0f / _renderDistanceController.update(measuredFps, deltaTime);
|
||||
} else {
|
||||
// Here we choose to just use the maximum render cutoff distance if throttled.
|
||||
distance = 1.0f / _renderDistanceController.getControlledValueLowLimit();
|
||||
}
|
||||
_renderDistanceAverage.updateAverage(distance);
|
||||
renderDistance = _renderDistanceAverage.getAverage(); // average only once per cycle
|
||||
lastRenderedCount = renderedCount;
|
||||
renderedCount = 0;
|
||||
}
|
||||
|
||||
bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) {
|
||||
float distanceToCamera = glm::length(bounds.calcCenter() - args->_viewFrustum->getPosition());
|
||||
float largestDimension = bounds.getLargestDimension();
|
||||
if (!getUseAcuity()) {
|
||||
const float scenerySize = 300; // meters
|
||||
bool isRendered = (largestDimension > scenerySize) || // render scenery regardless of distance
|
||||
(fabsf(distanceToCamera - largestDimension) < renderDistance);
|
||||
renderedCount += isRendered ? 1 : 0;
|
||||
return isRendered;
|
||||
}
|
||||
|
||||
const float maxScale = (float)TREE_SCALE;
|
||||
const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it.
|
||||
float octreeSizeScale = args->_sizeScale;
|
||||
int boundaryLevelAdjust = args->_boundaryLevelAdjust;
|
||||
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio;
|
||||
float distanceToCamera = glm::length(bounds.calcCenter() - args->_viewFrustum->getPosition());
|
||||
float largestDimension = bounds.getLargestDimension();
|
||||
|
||||
|
||||
static bool shouldRenderTableNeedsBuilding = true;
|
||||
static QMap<float, float> shouldRenderTable;
|
||||
if (shouldRenderTableNeedsBuilding) {
|
||||
|
@ -315,6 +379,12 @@ void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) {
|
|||
void LODManager::loadSettings() {
|
||||
setDesktopLODDecreaseFPS(desktopLODDecreaseFPS.get());
|
||||
setHMDLODDecreaseFPS(hmdLODDecreaseFPS.get());
|
||||
|
||||
if (lodPreference.get() == (int)LODManager::LODPreference::unspecified) {
|
||||
setUseAcuity((getDesktopLODDecreaseFPS() != DEFAULT_DESKTOP_LOD_DOWN_FPS) || (getHMDLODDecreaseFPS() != DEFAULT_HMD_LOD_DOWN_FPS));
|
||||
}
|
||||
Menu::getInstance()->getActionForOption(MenuOption::LodTools)->setEnabled(getUseAcuity());
|
||||
Menu::getInstance()->getSubMenuFromName(MenuOption::RenderResolution, Menu::getInstance()->getSubMenuFromName("Render", Menu::getInstance()->getMenu("Developer")))->setEnabled(getUseAcuity());
|
||||
}
|
||||
|
||||
void LODManager::saveSettings() {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <DependencyManager.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <OctreeConstants.h>
|
||||
#include <PIDController.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
|
||||
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 15.0;
|
||||
|
@ -81,6 +82,27 @@ public:
|
|||
Q_INVOKABLE float getLODDecreaseFPS();
|
||||
Q_INVOKABLE float getLODIncreaseFPS();
|
||||
|
||||
enum class LODPreference {
|
||||
pid = 0,
|
||||
acuity,
|
||||
unspecified
|
||||
};
|
||||
static bool getUseAcuity();
|
||||
static void setUseAcuity(bool newValue);
|
||||
Q_INVOKABLE void setRenderDistanceKP(float newValue) { _renderDistanceController.setKP(newValue); }
|
||||
Q_INVOKABLE void setRenderDistanceKI(float newValue) { _renderDistanceController.setKI(newValue); }
|
||||
Q_INVOKABLE void setRenderDistanceKD(float newValue) { _renderDistanceController.setKD(newValue); }
|
||||
Q_INVOKABLE bool getRenderDistanceControllerIsLogging() { return _renderDistanceController.getIsLogging(); }
|
||||
Q_INVOKABLE void setRenderDistanceControllerHistory(QString label, int size) { return _renderDistanceController.setHistorySize(label, size); }
|
||||
Q_INVOKABLE float getRenderDistanceInverseLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); }
|
||||
Q_INVOKABLE void setRenderDistanceInverseLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); }
|
||||
Q_INVOKABLE float getRenderDistanceInverseHighLimit() { return _renderDistanceController.getControlledValueHighLimit(); }
|
||||
Q_INVOKABLE void setRenderDistanceInverseHighLimit(float newValue);
|
||||
void updatePIDRenderDistance(float targetFps, float measuredFps, float deltaTime, bool isThrottled);
|
||||
float getRenderDistance();
|
||||
int getRenderedCount();
|
||||
QString getLODStatsRenderText();
|
||||
|
||||
static bool shouldRender(const RenderArgs* args, const AABox& bounds);
|
||||
bool shouldRenderMesh(float largestDimension, float distanceToCamera);
|
||||
void autoAdjustLOD(float currentFPS);
|
||||
|
@ -116,6 +138,9 @@ private:
|
|||
|
||||
bool _shouldRenderTableNeedsRebuilding = true;
|
||||
QMap<float, float> _shouldRenderTable;
|
||||
|
||||
PIDController _renderDistanceController{};
|
||||
SimpleMovingAverage _renderDistanceAverage{ 10 };
|
||||
};
|
||||
|
||||
#endif // hifi_LODManager_h
|
||||
|
|
|
@ -64,6 +64,7 @@ public:
|
|||
void saveSettings();
|
||||
|
||||
MenuWrapper* getMenu(const QString& menuName);
|
||||
MenuWrapper* getSubMenuFromName(const QString& menuName, MenuWrapper* menu);
|
||||
|
||||
void triggerOption(const QString& menuOption);
|
||||
QAction* getActionForOption(const QString& menuOption);
|
||||
|
@ -130,7 +131,6 @@ private:
|
|||
const QString& grouping = QString());
|
||||
|
||||
QAction* getActionFromName(const QString& menuName, MenuWrapper* menu);
|
||||
MenuWrapper* getSubMenuFromName(const QString& menuName, MenuWrapper* menu);
|
||||
MenuWrapper* getMenuParent(const QString& menuName, QString& finalMenuPart);
|
||||
|
||||
QAction* getMenuAction(const QString& menuName);
|
||||
|
|
|
@ -184,26 +184,6 @@ void Avatar::simulate(float deltaTime) {
|
|||
qCDebug(interfaceapp) << "Billboarding" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for LOD" << getLODDistance();
|
||||
}
|
||||
|
||||
const bool isControllerLogging = DependencyManager::get<AvatarManager>()->getRenderDistanceControllerIsLogging();
|
||||
float renderDistance = DependencyManager::get<AvatarManager>()->getRenderDistance();
|
||||
const float SKIP_HYSTERESIS_PROPORTION = isControllerLogging ? 0.0f : BILLBOARD_HYSTERESIS_PROPORTION;
|
||||
float distance = glm::distance(qApp->getCamera()->getPosition(), getPosition());
|
||||
if (_shouldSkipRender) {
|
||||
if (distance < renderDistance * (1.0f - SKIP_HYSTERESIS_PROPORTION)) {
|
||||
_shouldSkipRender = false;
|
||||
_skeletonModel.setVisibleInScene(true, qApp->getMain3DScene());
|
||||
if (!isControllerLogging) { // Test for isMyAvatar is prophylactic. Never occurs in current code.
|
||||
qCDebug(interfaceapp) << "Rerendering" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for distance" << renderDistance;
|
||||
}
|
||||
}
|
||||
} else if (distance > renderDistance * (1.0f + SKIP_HYSTERESIS_PROPORTION)) {
|
||||
_shouldSkipRender = true;
|
||||
_skeletonModel.setVisibleInScene(false, qApp->getMain3DScene());
|
||||
if (!isControllerLogging) {
|
||||
qCDebug(interfaceapp) << "Unrendering" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for distance" << renderDistance;
|
||||
}
|
||||
}
|
||||
|
||||
// simple frustum check
|
||||
float boundingRadius = getBillboardSize();
|
||||
bool inViewFrustum = qApp->getViewFrustum()->sphereInFrustum(getPosition(), boundingRadius) !=
|
||||
|
|
|
@ -76,13 +76,6 @@ AvatarManager::AvatarManager(QObject* parent) :
|
|||
packetReceiver.registerListener(PacketType::AvatarBillboard, this, "processAvatarBillboardPacket");
|
||||
}
|
||||
|
||||
const float SMALLEST_REASONABLE_HORIZON = 5.0f; // meters
|
||||
Setting::Handle<float> avatarRenderDistanceInverseHighLimit("avatarRenderDistanceHighLimit", 1.0f / SMALLEST_REASONABLE_HORIZON);
|
||||
void AvatarManager::setRenderDistanceInverseHighLimit(float newValue) {
|
||||
avatarRenderDistanceInverseHighLimit.set(newValue);
|
||||
_renderDistanceController.setControlledValueHighLimit(newValue);
|
||||
}
|
||||
|
||||
void AvatarManager::init() {
|
||||
_myAvatar->init();
|
||||
{
|
||||
|
@ -98,19 +91,6 @@ void AvatarManager::init() {
|
|||
_myAvatar->addToScene(_myAvatar, scene, pendingChanges);
|
||||
}
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
|
||||
const float target_fps = qApp->getTargetFrameRate();
|
||||
_renderDistanceController.setMeasuredValueSetpoint(target_fps);
|
||||
_renderDistanceController.setControlledValueHighLimit(avatarRenderDistanceInverseHighLimit.get());
|
||||
_renderDistanceController.setControlledValueLowLimit(1.0f / (float) TREE_SCALE);
|
||||
// Advice for tuning parameters:
|
||||
// See PIDController.h. There's a section on tuning in the reference.
|
||||
// Turn on logging with the following (or from js with AvatarList.setRenderDistanceControllerHistory("avatar render", 300))
|
||||
//_renderDistanceController.setHistorySize("avatar render", target_fps * 4);
|
||||
// Note that extra logging/hysteresis is turned off in Avatar.cpp when the above logging is on.
|
||||
_renderDistanceController.setKP(0.0008f); // Usually about 0.6 of largest that doesn't oscillate when other parameters 0.
|
||||
_renderDistanceController.setKI(0.0006f); // Big enough to bring us to target with the above KP.
|
||||
_renderDistanceController.setKD(0.000001f); // A touch of kd increases the speed by which we get there.
|
||||
}
|
||||
|
||||
void AvatarManager::updateMyAvatar(float deltaTime) {
|
||||
|
@ -145,23 +125,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
|
||||
PerformanceTimer perfTimer("otherAvatars");
|
||||
|
||||
float distance;
|
||||
if (!qApp->isThrottleRendering()) {
|
||||
_renderDistanceController.setMeasuredValueSetpoint(qApp->getTargetFrameRate()); // No problem updating in flight.
|
||||
// The PID controller raises the controlled value when the measured value goes up.
|
||||
// The measured value is frame rate. When the controlled value (1 / render cutoff distance)
|
||||
// goes up, the render cutoff distance gets closer, the number of rendered avatars is less, and frame rate
|
||||
// goes up.
|
||||
const float deduced = qApp->getLastUnsynchronizedFps();
|
||||
distance = 1.0f / _renderDistanceController.update(deduced, deltaTime);
|
||||
} else {
|
||||
// Here we choose to just use the maximum render cutoff distance if throttled.
|
||||
distance = 1.0f / _renderDistanceController.getControlledValueLowLimit();
|
||||
}
|
||||
_renderDistanceAverage.updateAverage(distance);
|
||||
_renderDistance = _renderDistanceAverage.getAverage();
|
||||
int renderableCount = 0;
|
||||
|
||||
// simulate avatars
|
||||
auto hashCopy = getHashCopy();
|
||||
|
||||
|
@ -179,14 +142,10 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
} else {
|
||||
avatar->startUpdate();
|
||||
avatar->simulate(deltaTime);
|
||||
if (avatar->getShouldRender()) {
|
||||
renderableCount++;
|
||||
}
|
||||
avatar->endUpdate();
|
||||
++avatarIterator;
|
||||
}
|
||||
}
|
||||
_renderedAvatarCount = renderableCount;
|
||||
|
||||
// simulate avatar fades
|
||||
simulateAvatarFades(deltaTime);
|
||||
|
|
|
@ -45,7 +45,6 @@ public:
|
|||
void clearOtherAvatars();
|
||||
|
||||
bool shouldShowReceiveStats() const { return _shouldShowReceiveStats; }
|
||||
PIDController& getRenderDistanceController() { return _renderDistanceController; }
|
||||
|
||||
class LocalLight {
|
||||
public:
|
||||
|
@ -68,19 +67,6 @@ public:
|
|||
|
||||
void addAvatarToSimulation(Avatar* avatar);
|
||||
|
||||
// Expose results and parameter-tuning operations to other systems, such as stats and javascript.
|
||||
Q_INVOKABLE float getRenderDistance() { return _renderDistance; }
|
||||
Q_INVOKABLE float getRenderDistanceInverseLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); }
|
||||
Q_INVOKABLE float getRenderDistanceInverseHighLimit() { return _renderDistanceController.getControlledValueHighLimit(); }
|
||||
Q_INVOKABLE int getNumberInRenderRange() { return _renderedAvatarCount; }
|
||||
Q_INVOKABLE bool getRenderDistanceControllerIsLogging() { return _renderDistanceController.getIsLogging(); }
|
||||
Q_INVOKABLE void setRenderDistanceControllerHistory(QString label, int size) { return _renderDistanceController.setHistorySize(label, size); }
|
||||
Q_INVOKABLE void setRenderDistanceKP(float newValue) { _renderDistanceController.setKP(newValue); }
|
||||
Q_INVOKABLE void setRenderDistanceKI(float newValue) { _renderDistanceController.setKI(newValue); }
|
||||
Q_INVOKABLE void setRenderDistanceKD(float newValue) { _renderDistanceController.setKD(newValue); }
|
||||
Q_INVOKABLE void setRenderDistanceInverseLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); }
|
||||
Q_INVOKABLE void setRenderDistanceInverseHighLimit(float newValue);
|
||||
|
||||
public slots:
|
||||
void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; }
|
||||
void updateAvatarRenderStatus(bool shouldRenderAvatars);
|
||||
|
@ -106,10 +92,6 @@ private:
|
|||
QVector<AvatarManager::LocalLight> _localLights;
|
||||
|
||||
bool _shouldShowReceiveStats = false;
|
||||
float _renderDistance { (float) TREE_SCALE };
|
||||
int _renderedAvatarCount { 0 };
|
||||
PIDController _renderDistanceController { };
|
||||
SimpleMovingAverage _renderDistanceAverage { 10 };
|
||||
|
||||
SetOfAvatarMotionStates _avatarMotionStates;
|
||||
SetOfMotionStates _motionStatesToAdd;
|
||||
|
|
|
@ -86,7 +86,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
|||
|
||||
// Now render the overlay components together into a single texture
|
||||
renderDomainConnectionStatusBorder(renderArgs); // renders the connected domain line
|
||||
renderAudioScope(renderArgs); // audio scope in the very back
|
||||
renderAudioScope(renderArgs); // audio scope in the very back - NOTE: this is the debug audio scope, not the VU meter
|
||||
renderRearView(renderArgs); // renders the mirror view selfie
|
||||
renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture, and the text overlays from scripts
|
||||
renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope
|
||||
|
@ -158,7 +158,7 @@ void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) {
|
|||
}
|
||||
|
||||
void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
if (!qApp->isHMDMode() && Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
gpu::Batch& batch = *renderArgs->_batch;
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
|
|
@ -66,6 +66,7 @@ void AvatarInputs::update() {
|
|||
&& !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror));
|
||||
AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking));
|
||||
AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking));
|
||||
AI_UPDATE(isHMD, qApp->isHMDMode());
|
||||
|
||||
auto audioIO = DependencyManager::get<AudioClient>();
|
||||
const float AUDIO_METER_AVERAGING = 0.5;
|
||||
|
|
|
@ -30,6 +30,7 @@ class AvatarInputs : public QQuickItem {
|
|||
AI_PROPERTY(float, audioLevel, 0)
|
||||
AI_PROPERTY(bool, mirrorVisible, false)
|
||||
AI_PROPERTY(bool, mirrorZoomed, true)
|
||||
AI_PROPERTY(bool, isHMD, false)
|
||||
|
||||
public:
|
||||
static AvatarInputs* getInstance();
|
||||
|
@ -44,6 +45,7 @@ signals:
|
|||
void audioLevelChanged();
|
||||
void mirrorVisibleChanged();
|
||||
void mirrorZoomedChanged();
|
||||
void isHMDChanged();
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void resetSensors();
|
||||
|
|
|
@ -48,6 +48,7 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) :
|
|||
|
||||
connect(ui.buttonChangeAppearance, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser);
|
||||
connect(ui.appearanceDescription, &QLineEdit::editingFinished, this, &PreferencesDialog::changeFullAvatarURL);
|
||||
connect(ui.useAcuityCheckBox, &QCheckBox::clicked, this, &PreferencesDialog::changeUseAcuity);
|
||||
|
||||
connect(qApp, &Application::fullAvatarURLChanged, this, &PreferencesDialog::fullAvatarURLChanged);
|
||||
|
||||
|
@ -58,6 +59,16 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) :
|
|||
UIUtil::scaleWidgetFontSizes(this);
|
||||
}
|
||||
|
||||
void PreferencesDialog::changeUseAcuity() {
|
||||
bool useAcuity = ui.useAcuityCheckBox->isChecked();
|
||||
ui.label_desktopMinimumFPSSpin->setEnabled(useAcuity);
|
||||
ui.desktopMinimumFPSSpin->setEnabled(useAcuity);
|
||||
ui.label_hmdMinimumFPSSpin->setEnabled(useAcuity);
|
||||
ui.hmdMinimumFPSSpin->setEnabled(useAcuity);
|
||||
ui.label_smallestReasonableRenderHorizon->setText(useAcuity ? "Minimum Avatar Display Distance (@half speed)" : "Minimum Display Distance (@half speed)");
|
||||
Menu::getInstance()->getActionForOption(MenuOption::LodTools)->setEnabled(useAcuity);
|
||||
Menu::getInstance()->getSubMenuFromName(MenuOption::RenderResolution, Menu::getInstance()->getSubMenuFromName("Render", Menu::getInstance()->getMenu("Developer")))->setEnabled(useAcuity);
|
||||
}
|
||||
void PreferencesDialog::changeFullAvatarURL() {
|
||||
DependencyManager::get<AvatarManager>()->getMyAvatar()->useFullAvatarURL(ui.appearanceDescription->text(), "");
|
||||
this->fullAvatarURLChanged(ui.appearanceDescription->text(), "");
|
||||
|
@ -212,9 +223,11 @@ void PreferencesDialog::loadPreferences() {
|
|||
|
||||
// LOD items
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
ui.useAcuityCheckBox->setChecked(lodManager->getUseAcuity());
|
||||
ui.desktopMinimumFPSSpin->setValue(lodManager->getDesktopLODDecreaseFPS());
|
||||
ui.hmdMinimumFPSSpin->setValue(lodManager->getHMDLODDecreaseFPS());
|
||||
ui.avatarRenderSmallestReasonableHorizon->setValue(1.0f / DependencyManager::get<AvatarManager>()->getRenderDistanceInverseHighLimit());
|
||||
ui.smallestReasonableRenderHorizon->setValue(1.0f / lodManager->getRenderDistanceInverseHighLimit());
|
||||
changeUseAcuity();
|
||||
}
|
||||
|
||||
void PreferencesDialog::savePreferences() {
|
||||
|
@ -303,7 +316,8 @@ void PreferencesDialog::savePreferences() {
|
|||
|
||||
// LOD items
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
lodManager->setUseAcuity(ui.useAcuityCheckBox->isChecked());
|
||||
lodManager->setDesktopLODDecreaseFPS(ui.desktopMinimumFPSSpin->value());
|
||||
lodManager->setHMDLODDecreaseFPS(ui.hmdMinimumFPSSpin->value());
|
||||
DependencyManager::get<AvatarManager>()->setRenderDistanceInverseHighLimit(1.0f / ui.avatarRenderSmallestReasonableHorizon->value());
|
||||
lodManager->setRenderDistanceInverseHighLimit(1.0f / ui.smallestReasonableRenderHorizon->value());
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ private slots:
|
|||
void openScriptsLocationBrowser();
|
||||
void changeFullAvatarURL();
|
||||
void fullAvatarURLChanged(const QString& newValue, const QString& modelName);
|
||||
void changeUseAcuity();
|
||||
};
|
||||
|
||||
#endif // hifi_PreferencesDialog_h
|
||||
|
|
|
@ -116,8 +116,6 @@ void Stats::updateStats(bool force) {
|
|||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
// we need to take one avatar out so we don't include ourselves
|
||||
STAT_UPDATE(avatarCount, avatarManager->size() - 1);
|
||||
STAT_UPDATE(avatarRenderableCount, avatarManager->getNumberInRenderRange());
|
||||
STAT_UPDATE(avatarRenderDistance, (int) round(avatarManager->getRenderDistance())); // deliberately truncating
|
||||
STAT_UPDATE(serverCount, (int)nodeList->size());
|
||||
STAT_UPDATE(renderrate, (int)qApp->getFps());
|
||||
if (qApp->getActiveDisplayPlugin()) {
|
||||
|
@ -285,7 +283,9 @@ void Stats::updateStats(bool force) {
|
|||
STAT_UPDATE(localLeaves, (int)OctreeElement::getLeafNodeCount());
|
||||
// LOD Details
|
||||
STAT_UPDATE(lodStatus, "You can see " + DependencyManager::get<LODManager>()->getLODFeedbackText());
|
||||
STAT_UPDATE(lodStatsRenderText, DependencyManager::get<LODManager>()->getLODStatsRenderText());
|
||||
}
|
||||
STAT_UPDATE(showAcuity, (_expanded || force) && DependencyManager::get<LODManager>()->getUseAcuity());
|
||||
|
||||
bool performanceTimerIsActive = PerformanceTimer::isActive();
|
||||
bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails);
|
||||
|
|
|
@ -30,6 +30,7 @@ class Stats : public QQuickItem {
|
|||
Q_PROPERTY(QString monospaceFont READ monospaceFont CONSTANT)
|
||||
Q_PROPERTY(float audioPacketlossUpstream READ getAudioPacketLossUpstream)
|
||||
Q_PROPERTY(float audioPacketlossDownstream READ getAudioPacketLossDownstream)
|
||||
Q_PROPERTY(bool showAcuity READ getShowAcuity WRITE setShowAcuity NOTIFY showAcuityChanged)
|
||||
|
||||
STATS_PROPERTY(int, serverCount, 0)
|
||||
STATS_PROPERTY(int, renderrate, 0)
|
||||
|
@ -37,8 +38,6 @@ class Stats : public QQuickItem {
|
|||
STATS_PROPERTY(int, simrate, 0)
|
||||
STATS_PROPERTY(int, avatarSimrate, 0)
|
||||
STATS_PROPERTY(int, avatarCount, 0)
|
||||
STATS_PROPERTY(int, avatarRenderableCount, 0)
|
||||
STATS_PROPERTY(int, avatarRenderDistance, 0)
|
||||
STATS_PROPERTY(int, packetInCount, 0)
|
||||
STATS_PROPERTY(int, packetOutCount, 0)
|
||||
STATS_PROPERTY(float, mbpsIn, 0)
|
||||
|
@ -77,6 +76,7 @@ class Stats : public QQuickItem {
|
|||
STATS_PROPERTY(QString, packetStats, QString())
|
||||
STATS_PROPERTY(QString, lodStatus, QString())
|
||||
STATS_PROPERTY(QString, timingStats, QString())
|
||||
STATS_PROPERTY(QString, lodStatsRenderText, QString())
|
||||
STATS_PROPERTY(int, serverElements, 0)
|
||||
STATS_PROPERTY(int, serverInternal, 0)
|
||||
STATS_PROPERTY(int, serverLeaves, 0)
|
||||
|
@ -108,12 +108,15 @@ public:
|
|||
emit expandedChanged();
|
||||
}
|
||||
}
|
||||
bool getShowAcuity() { return _showAcuity; }
|
||||
void setShowAcuity(bool newValue) { _showAcuity = newValue; }
|
||||
|
||||
public slots:
|
||||
void forceUpdateStats() { updateStats(true); }
|
||||
|
||||
signals:
|
||||
void expandedChanged();
|
||||
void showAcuityChanged();
|
||||
void timingExpandedChanged();
|
||||
void serverCountChanged();
|
||||
void renderrateChanged();
|
||||
|
@ -121,8 +124,7 @@ signals:
|
|||
void simrateChanged();
|
||||
void avatarSimrateChanged();
|
||||
void avatarCountChanged();
|
||||
void avatarRenderableCountChanged();
|
||||
void avatarRenderDistanceChanged();
|
||||
void lodStatsRenderTextChanged();
|
||||
void packetInCountChanged();
|
||||
void packetOutCountChanged();
|
||||
void mbpsInChanged();
|
||||
|
@ -172,6 +174,7 @@ private:
|
|||
int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process
|
||||
bool _resetRecentMaxPacketsSoon{ true };
|
||||
bool _expanded{ false };
|
||||
bool _showAcuity{ false };
|
||||
bool _timingExpanded{ false };
|
||||
QString _monospaceFont;
|
||||
const AudioIOStats* _audioStats;
|
||||
|
|
|
@ -742,6 +742,43 @@
|
|||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QCheckBox" name="useAcuityCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Render based on visual acuity</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_111x">
|
||||
<property name="spacing">
|
||||
|
@ -757,7 +794,7 @@
|
|||
<number>7</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9x">
|
||||
<widget class="QLabel" name="label_desktopMinimumFPSSpin">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
|
@ -842,7 +879,7 @@
|
|||
<number>7</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9y">
|
||||
<widget class="QLabel" name="label_hmdMinimumFPSSpin">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
|
@ -927,7 +964,7 @@
|
|||
<number>7</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9yz">
|
||||
<widget class="QLabel" name="label_smallestReasonableRenderHorizon">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
|
@ -963,7 +1000,7 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="avatarRenderSmallestReasonableHorizon">
|
||||
<widget class="QSpinBox" name="smallestReasonableRenderHorizon">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
const gpu::Stream::FormatPointer getVertexFormat() const { return _vertexFormat; }
|
||||
|
||||
// BufferStream on the mesh vertices and attributes matching the vertex format
|
||||
const gpu::BufferStream getVertexStream() const { return _vertexStream; }
|
||||
const gpu::BufferStream& getVertexStream() const { return _vertexStream; }
|
||||
|
||||
// Index Buffer
|
||||
void setIndexBuffer(const BufferView& buffer);
|
||||
|
|
|
@ -819,8 +819,6 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() {
|
|||
//DEBUG: model::Mesh::Part part(0, indices, 0, model::Mesh::LINE_STRIP);
|
||||
|
||||
_spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(sizeof(part), (gpu::Byte*) &part), gpu::Element::PART_DRAWCALL));
|
||||
|
||||
_spotLightMesh->getVertexStream();
|
||||
}
|
||||
return _spotLightMesh;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
float update(float measuredValue, float dt, bool resetAccumulator = false); // returns the new computedValue
|
||||
void setHistorySize(QString label = QString(""), int size = 0) { _history.reserve(size); _history.resize(0); _label = label; } // non-empty does logging
|
||||
|
||||
bool getIsLogging() { return _history.capacity(); }
|
||||
bool getIsLogging() { return !_label.isEmpty(); }
|
||||
float getMeasuredValueSetpoint() const { return _measuredValueSetpoint; }
|
||||
// In normal operation (where we can easily reach setpoint), controlledValue is typcially pinned at max.
|
||||
// Defaults to [0, max float], but for 1/LODdistance, it might be, say, [0, 0.2 or 0.1]
|
||||
|
|
|
@ -170,10 +170,12 @@
|
|||
|
||||
function createRaveStick(position) {
|
||||
var modelURL = "http://hifi-content.s3.amazonaws.com/eric/models/raveStick.fbx";
|
||||
var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
||||
var stick = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "raveStick",
|
||||
modelURL: modelURL,
|
||||
rotation: rotation,
|
||||
position: position,
|
||||
shapeType: 'box',
|
||||
collisionsWillMove: true,
|
||||
|
@ -206,6 +208,66 @@
|
|||
})
|
||||
});
|
||||
|
||||
var forwardVec = Quat.getFront(rotation);
|
||||
var forwardQuat = Quat.rotationBetween(Vec3.UNIT_Z, forwardVec);
|
||||
var color = {
|
||||
red: 150,
|
||||
green: 20,
|
||||
blue: 100
|
||||
}
|
||||
var raveGlowEmitter = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
name: "Rave Stick Glow Emitter",
|
||||
position: position,
|
||||
parentID: stick,
|
||||
isEmitting: true,
|
||||
colorStart: color,
|
||||
color: {
|
||||
red: 200,
|
||||
green: 200,
|
||||
blue: 255
|
||||
},
|
||||
colorFinish: color,
|
||||
maxParticles: 100000,
|
||||
lifespan: 0.8,
|
||||
emitRate: 1000,
|
||||
emitOrientation: forwardQuat,
|
||||
emitSpeed: 0.2,
|
||||
speedSpread: 0.0,
|
||||
emitDimensions: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
polarStart: 0,
|
||||
polarFinish: 0,
|
||||
azimuthStart: 0.1,
|
||||
azimuthFinish: 0.01,
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
accelerationSpread: {
|
||||
x: 0.00,
|
||||
y: 0.00,
|
||||
z: 0.00
|
||||
},
|
||||
radiusStart: 0.01,
|
||||
radiusFinish: 0.005,
|
||||
alpha: 0.7,
|
||||
alphaSpread: 0.1,
|
||||
alphaStart: 0.1,
|
||||
alphaFinish: 0.1,
|
||||
textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png",
|
||||
emitterShouldTrail: false,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function createGun(position) {
|
||||
|
|
|
@ -149,10 +149,12 @@ MasterReset = function() {
|
|||
|
||||
function createRaveStick(position) {
|
||||
var modelURL = "http://hifi-content.s3.amazonaws.com/eric/models/raveStick.fbx";
|
||||
var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
||||
var stick = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "raveStick",
|
||||
modelURL: modelURL,
|
||||
rotation: rotation,
|
||||
position: position,
|
||||
shapeType: 'box',
|
||||
collisionsWillMove: true,
|
||||
|
@ -189,6 +191,66 @@ MasterReset = function() {
|
|||
}
|
||||
})
|
||||
});
|
||||
|
||||
var forwardVec = Quat.getFront(rotation);
|
||||
var forwardQuat = Quat.rotationBetween(Vec3.UNIT_Z, forwardVec);
|
||||
var color = {
|
||||
red: 150,
|
||||
green: 20,
|
||||
blue: 100
|
||||
}
|
||||
var raveGlowEmitter = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
name: "Rave Stick Glow Emitter",
|
||||
position: position,
|
||||
parentID: stick,
|
||||
isEmitting: true,
|
||||
colorStart: color,
|
||||
color: {
|
||||
red: 200,
|
||||
green: 200,
|
||||
blue: 255
|
||||
},
|
||||
colorFinish: color,
|
||||
maxParticles: 100000,
|
||||
lifespan: 0.8,
|
||||
emitRate: 1000,
|
||||
emitOrientation: forwardQuat,
|
||||
emitSpeed: 0.2,
|
||||
speedSpread: 0.0,
|
||||
emitDimensions: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
polarStart: 0,
|
||||
polarFinish: 0,
|
||||
azimuthStart: 0.1,
|
||||
azimuthFinish: 0.01,
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
accelerationSpread: {
|
||||
x: 0.00,
|
||||
y: 0.00,
|
||||
z: 0.00
|
||||
},
|
||||
radiusStart: 0.01,
|
||||
radiusFinish: 0.005,
|
||||
alpha: 0.7,
|
||||
alphaSpread: 0.1,
|
||||
alphaStart: 0.1,
|
||||
alphaFinish: 0.1,
|
||||
textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png",
|
||||
emitterShouldTrail: false,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function createGun(position) {
|
||||
|
@ -1084,7 +1146,7 @@ MasterReset = function() {
|
|||
y: 0,
|
||||
z: 0.06
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(0,-90, -90)
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90)
|
||||
},
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue