Merge pull request #7043 from zzmp/fix/render-ui

Revamp the render engine ui
This commit is contained in:
samcake 2016-02-11 09:57:51 -08:00
commit 99e9b3ecdd
9 changed files with 247 additions and 229 deletions

View file

@ -0,0 +1,66 @@
//
// ConfigSlider.qml
// examples/utilities/tools/render
//
// Created by Zach Pomerantz on 2/8/2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
Item {
id: root
width: 400
height: 24
property bool integral: false
property var config
property string property
property alias label: labelControl.text
property alias min: sliderControl.minimumValue
property alias max: sliderControl.maximumValue
Component.onCompleted: {
// Binding favors qml value, so set it first
sliderControl.value = root.config[root.property];
bindingControl.when = true;
}
Label {
id: labelControl
text: root.label
anchors.left: root.left
anchors.leftMargin: 8
anchors.top: root.top
anchors.topMargin: 7
}
Label {
text: sliderControl.value.toFixed(root.integral ? 0 : 2)
anchors.left: root.left
anchors.leftMargin: 140
anchors.top: root.top
anchors.topMargin: 7
}
Binding {
id: bindingControl
target: root.config
property: root.property
value: sliderControl.value
when: false
}
Slider {
id: sliderControl
stepSize: root.integral ? 1.0 : 0.0
width: 192
height: 20
anchors.right: root.right
anchors.rightMargin: 8
anchors.top: root.top
anchors.topMargin: 3
}
}

View file

@ -0,0 +1,42 @@
//
// debug.js
// examples/utilities/tools/render
//
// Zach Pomerantz, created on 1/27/2016.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
oldConfig = Render.toJSON();
Render.RenderShadowTask.enabled = true;
var RDT = Render.RenderDeferredTask;
RDT.AmbientOcclusion.enabled = true;
RDT.DebugDeferredBuffer.enabled = false;
["DrawOpaqueDeferred", "DrawTransparentDeferred", "DrawOverlay3DOpaque", "DrawOverlay3DTransparent"]
.map(function(name) { return RDT[name]; })
.forEach(function(job) { job.maxDrawn = job.numDrawn; });
// Set up the qml ui
var qml = Script.resolvePath('main.qml');
var window = new OverlayWindow({
title: 'Render Engine Configuration',
source: qml,
width: 400, height: 900,
});
window.setPosition(25, 50);
window.closed.connect(function() { Script.stop(); });
// Debug buffer sizing
var resizing = false;
Controller.mousePressEvent.connect(function() { resizing = true; });
Controller.mouseReleaseEvent.connect(function() { resizing = false; });
Controller.mouseMoveEvent.connect(function(e) { resizing && setDebugBufferSize(e.x); });
function setDebugBufferSize(x) {
x = (2.0 * (x / Window.innerWidth) - 1.0); // scale
x = Math.min(Math.max(-1, x), 1); // clamp
Render.RenderDeferredTask.DebugDeferredBuffer.size = {x: x, y: -1, z: 1, w: 1};
}
Script.scriptEnding.connect(function() { Render.fromJSON(oldConfig); } );

View file

@ -0,0 +1,110 @@
//
// main.qml
// examples/utilities/tools/render
//
// Created by Zach Pomerantz on 2/8/2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
Column {
spacing: 8
Repeater {
model: [ "Opaque:DrawOpaqueDeferred", "Transparent:DrawTransparentDeferred",
"Opaque Overlays:DrawOverlay3DOpaque", "Transparent Overlays:DrawOverlay3DTransparent" ]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: true
config: Render.getConfig(modelData.split(":")[1])
property: "maxDrawn"
max: config.numDrawn
}
}
Row {
CheckBox {
text: qsTr("Display Status")
onCheckedChanged: { Render.getConfig("DrawStatus").showDisplay = checked }
}
CheckBox {
text: qsTr("Network/Physics Status")
onCheckedChanged: { Render.getConfig("DrawStatus").showNetwork = checked }
}
}
ConfigSlider {
label: qsTr("Tone Mapping Exposure")
config: Render.getConfig("ToneMapping")
property: "exposure"
min: -10; max: 10
}
Column {
id: ambientOcclusion
property var config: Render.getConfig("AmbientOcclusion")
Label { text: qsTr("Ambient Occlusion") }
// TODO: Add gpuTimer
CheckBox { text: qsTr("Dithering"); checked: ambientOcclusion.config.ditheringEnabled }
Repeater {
model: [
"Resolution Level:resolutionLevel:4",
"Obscurance Level:obscuranceLevel:1",
"Radius:radius:2",
"Falloff Bias:falloffBias:0.2",
"Edge Sharpness:edgeSharpness:1",
"Blur Radius:blurRadius:6",
"Blur Deviation:blurDeviation:3"
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
config: ambientOcclusion.config
property: modelData.split(":")[1]
max: modelData.split(":")[2]
}
}
Repeater {
model: [
"Samples:numSamples:32",
"Spiral Turns:numSpiralTurns:30:"
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: true
config: ambientOcclusion.config
property: modelData.split(":")[1]
max: modelData.split(":")[2]
}
}
}
Column {
id: debug
property var config: Render.getConfig("DebugDeferredBuffer")
function setDebugMode(mode) {
debug.config.enabled = (mode != 0);
debug.config.mode = mode;
}
Label { text: qsTr("Debug Buffer") }
ExclusiveGroup { id: bufferGroup }
Repeater {
model: [
"Off", "Diffuse", "Metallic", "Roughness", "Normal", "Depth",
"Lighting", "Shadow", "Pyramid Depth", "Ambient Occlusion", "Custom Shader"
]
RadioButton {
text: qsTr(modelData)
exclusiveGroup: bufferGroup
checked: index == 0
onCheckedChanged: if (checked) debug.setDebugMode(index);
}
}
}
}

View file

@ -1,216 +0,0 @@
//
// renderEngineDebug.js
// examples/utilities/tools
//
// Sam Gateau
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("cookies.js");
var MENU = "Developer>Render>Debug Deferred Buffer";
var ACTIONS = ["Off", "Diffuse", "Metallic", "Roughness", "Normal", "Depth", "Lighting", "Shadow", "PyramidDepth", "AmbientOcclusion", "OcclusionBlurred", "Custom"];
var SETTINGS_KEY = "EngineDebugScript.DebugMode";
Number.prototype.clamp = function(min, max) {
return Math.min(Math.max(this, min), max);
};
var panel = new Panel(10, 100);
function CounterWidget(parentPanel, name, counter) {
var subPanel = parentPanel.newSubPanel(name);
var widget = parentPanel.items[name];
widget.editTitle({ width: 270 });
subPanel.newSlider('Max Drawn', -1, 1,
function(value) { counter.maxDrawn = value; }, // setter
function() { return counter.maxDrawn; }, // getter
function(value) { return value; });
var slider = subPanel.getWidget('Max Drawn');
this.update = function () {
var numDrawn = counter.numDrawn; // avoid double polling
var numMax = Math.max(numDrawn, 1);
var title = [
' ' + name,
numDrawn + ' / ' + counter.numFeed
].join('\t');
widget.editTitle({ text: title });
slider.setMaxValue(numMax);
};
};
var opaquesCounter = new CounterWidget(panel, "Opaques", Render.opaque);
var transparentsCounter = new CounterWidget(panel, "Transparents", Render.transparent);
var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D);
var resizing = false;
var previousMode = Settings.getValue(SETTINGS_KEY, -1);
previousMode = 8;
Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]);
Render.deferredDebugMode = previousMode;
Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size
function setEngineDeferredDebugSize(eventX) {
var scaledX = (2.0 * (eventX / Window.innerWidth) - 1.0).clamp(-1.0, 1.0);
Render.deferredDebugSize = { x: scaledX, y: -1.0, z: 1.0, w: 1.0 };
}
function shouldStartResizing(eventX) {
var x = Math.abs(eventX - Window.innerWidth * (1.0 + Render.deferredDebugSize.x) / 2.0);
var mode = Render.deferredDebugMode;
return mode !== -1 && x < 20;
}
function menuItemEvent(menuItem) {
var index = ACTIONS.indexOf(menuItem);
if (index >= 0) {
Render.deferredDebugMode = (index - 1);
}
}
// see libraries/render/src/render/Engine.h
var showDisplayStatusFlag = 1;
var showNetworkStatusFlag = 2;
panel.newCheckbox("Display status",
function(value) { Render.displayItemStatus = (value ?
Render.displayItemStatus | showDisplayStatusFlag :
Render.displayItemStatus & ~showDisplayStatusFlag); },
function() { return (Render.displayItemStatus & showDisplayStatusFlag) > 0; },
function(value) { return (value & showDisplayStatusFlag) > 0; }
);
panel.newCheckbox("Network/Physics status",
function(value) { Render.displayItemStatus = (value ?
Render.displayItemStatus | showNetworkStatusFlag :
Render.displayItemStatus & ~showNetworkStatusFlag); },
function() { return (Render.displayItemStatus & showNetworkStatusFlag) > 0; },
function(value) { return (value & showNetworkStatusFlag) > 0; }
);
panel.newSlider("Tone Mapping Exposure", -10, 10,
function (value) { Render.tone.exposure = value; },
function() { return Render.tone.exposure; },
function (value) { return (value); });
panel.newSlider("Ambient Occlusion Resolution Level", 0.0, 4.0,
function (value) { Render.ambientOcclusion.resolutionLevel = value; },
function() { return Render.ambientOcclusion.resolutionLevel; },
function (value) { return (value); });
panel.newSlider("Ambient Occlusion Radius", 0.0, 2.0,
function (value) { Render.ambientOcclusion.radius = value; },
function() { return Render.ambientOcclusion.radius; },
function (value) { return (value.toFixed(2)); });
panel.newSlider("Ambient Occlusion Level", 0.0, 1.0,
function (value) { Render.ambientOcclusion.level = value; },
function() { return Render.ambientOcclusion.level; },
function (value) { return (value.toFixed(2)); });
panel.newSlider("Ambient Occlusion Num Samples", 1, 32,
function (value) { Render.ambientOcclusion.numSamples = value; },
function() { return Render.ambientOcclusion.numSamples; },
function (value) { return (value); });
panel.newSlider("Ambient Occlusion Num Spiral Turns", 0.0, 30.0,
function (value) { Render.ambientOcclusion.numSpiralTurns = value; },
function() { return Render.ambientOcclusion.numSpiralTurns; },
function (value) { return (value.toFixed(2)); });
panel.newCheckbox("Ambient Occlusion Dithering",
function (value) { Render.ambientOcclusion.ditheringEnabled = value; },
function() { return Render.ambientOcclusion.ditheringEnabled; },
function (value) { return (value); });
panel.newSlider("Ambient Occlusion Falloff Bias", 0.0, 0.2,
function (value) { Render.ambientOcclusion.falloffBias = value; },
function() { return Render.ambientOcclusion.falloffBias; },
function (value) { return (value.toFixed(2)); });
panel.newSlider("Ambient Occlusion Edge Sharpness", 0.0, 1.0,
function (value) { Render.ambientOcclusion.edgeSharpness = value; },
function() { return Render.ambientOcclusion.edgeSharpness; },
function (value) { return (value.toFixed(2)); });
panel.newSlider("Ambient Occlusion Blur Radius", 0.0, 6.0,
function (value) { Render.ambientOcclusion.blurRadius = value; },
function() { return Render.ambientOcclusion.blurRadius; },
function (value) { return (value); });
panel.newSlider("Ambient Occlusion Blur Deviation", 0.0, 3.0,
function (value) { Render.ambientOcclusion.blurDeviation = value; },
function() { return Render.ambientOcclusion.blurDeviation; },
function (value) { return (value.toFixed(2)); });
panel.newSlider("Ambient Occlusion GPU time", 0.0, 10.0,
function (value) {},
function() { return Render.ambientOcclusion.gpuTime; },
function (value) { return (value.toFixed(2) + " ms"); });
var tickTackPeriod = 500;
function updateCounters() {
opaquesCounter.update();
transparentsCounter.update();
overlaysCounter.update();
panel.update("Ambient Occlusion GPU time");
}
Script.setInterval(updateCounters, tickTackPeriod);
function mouseMoveEvent(event) {
if (resizing) {
setEngineDeferredDebugSize(event.x);
} else {
panel.mouseMoveEvent(event);
}
}
function mousePressEvent(event) {
if (shouldStartResizing(event.x)) {
resizing = true;
} else {
panel.mousePressEvent(event);
}
}
function mouseReleaseEvent(event) {
if (resizing) {
resizing = false;
} else {
panel.mouseReleaseEvent(event);
}
}
Controller.mouseMoveEvent.connect(mouseMoveEvent);
Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
Menu.menuItemEvent.connect(menuItemEvent);
function scriptEnding() {
panel.destroy();
Menu.removeActionGroup(MENU);
// Reset
Settings.setValue(SETTINGS_KEY, Render.deferredDebugMode);
Render.deferredDebugMode = -1;
Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 };
Render.opaque.maxDrawn = -1;
Render.transparent.maxDrawn = -1;
Render.overlay3D.maxDrawn = -1;
}
Script.scriptEnding.connect(scriptEnding);
// Collapse items
panel.mousePressEvent({ x: panel.x, y: panel.items["Overlays"].y});
panel.mousePressEvent({ x: panel.x, y: panel.items["Transparents"].y});
panel.mousePressEvent({ x: panel.x, y: panel.items["Opaques"].y});

View file

@ -27,7 +27,7 @@ public:
void setMode(int newMode);
int mode{ 0 };
glm::vec4 size{ 0.0f, 0.0f, 0.0f, 0.0f };
glm::vec4 size{ 0.0f, -1.0f, 1.0f, 1.0f };
signals:
void dirty();
};

View file

@ -142,7 +142,8 @@ void DrawDeferred::run(const SceneContextPointer& sceneContext, const RenderCont
batch.setStateScissorRect(args->_viewport);
args->_batch = &batch;
config->numDrawn = (int)inItems.size();
config->setNumDrawn((int)inItems.size());
emit config->numDrawnChanged();
glm::mat4 projMat;
Transform viewMat;
@ -179,7 +180,8 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
inItems.emplace_back(id);
}
}
config->numItems = (int)inItems.size();
config->setNumDrawn((int)inItems.size());
emit config->numDrawnChanged();
if (!inItems.empty()) {
RenderArgs* args = renderContext->args;

View file

@ -40,15 +40,20 @@ public:
class DrawConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(int numDrawn READ getNumDrawn)
Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged)
Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty)
public:
int getNumDrawn() { return numDrawn; }
void setNumDrawn(int num) { numDrawn = num; emit numDrawnChanged(); }
int numDrawn{ 0 };
int maxDrawn{ -1 };
signals:
void numDrawnChanged();
void dirty();
protected:
int numDrawn{ 0 };
};
class DrawDeferred {
@ -86,15 +91,20 @@ public:
class DrawOverlay3DConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(int numItems READ getNumItems)
Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged)
Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty)
public:
int getNumItems() { return numItems; }
int getNumDrawn() { return numDrawn; }
void setNumDrawn(int num) { numDrawn = num; emit numDrawnChanged(); }
int numItems{ 0 };
int maxDrawn{ -1 };
signals:
void numDrawnChanged();
void dirty();
protected:
int numDrawn{ 0 };
};
class DrawOverlay3D {

View file

@ -71,10 +71,12 @@ public:
bool alwaysEnabled{ true };
bool enabled{ true };
// This must be named toJSON to integrate with the global scripting JSON object
Q_INVOKABLE QString toJSON() { return QJsonDocument(toJsonValue(*this).toObject()).toJson(QJsonDocument::Compact); }
Q_INVOKABLE void load(const QVariantMap& map) { qObjectFromJsonValue(QJsonObject::fromVariantMap(map), *this); }
public slots:
void load(const QJsonValue& json) { qObjectFromJsonValue(json, *this); }
void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); }
};
class TaskConfig : public JobConfig {
@ -85,6 +87,9 @@ public:
void init(Task* task) { _task = task; }
// getter for qml integration, prefer the templated getter
Q_INVOKABLE QObject* getConfig(const QString& name) { return QObject::findChild<JobConfig*>(name); }
// getter for cpp (strictly typed), prefer this getter
template <class T> typename T::Config* getConfig(std::string job = "") const {
QString name = job.empty() ? QString() : QString(job.c_str()); // an empty string is not a null string
return findChild<typename T::Config*>(name);

View file

@ -111,10 +111,9 @@ void qObjectFromJsonValue(const QJsonValue& j, QObject& o) {
for (auto it = object.begin(); it != object.end(); it++) {
std::string key = it.key().toStdString();
if (it.value().isObject()) {
QVariant child = o.property(key.c_str());
if (child.isValid()) {
QObject* object = child.value<QObject*>();
qObjectFromJsonValue(it.value(), *object);
QObject* child = o.findChild<QObject*>(key.c_str(), Qt::FindChildOption::FindDirectChildrenOnly);
if (child) {
qObjectFromJsonValue(it.value(), *child);
}
} else {
o.setProperty(key.c_str(), it.value());