diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index a3a155871f..601b5254df 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -18,4 +18,5 @@ Script.load("users.js"); Script.load("grab.js"); Script.load("pointer.js"); Script.load("directory.js"); +Script.load("mouseLook.js"); Script.load("dialTone.js"); diff --git a/examples/mouseLook.js b/examples/mouseLook.js new file mode 100644 index 0000000000..bf48a51c79 --- /dev/null +++ b/examples/mouseLook.js @@ -0,0 +1,200 @@ +// +// mouseLook.js +// examples +// +// Created by Sam Gondelman on 6/16/15 +// 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 +// + +var lastX = Window.getCursorPositionX(); +var lastY = Window.getCursorPositionY(); +var yawFromMouse = 0; +var pitchFromMouse = 0; + +var yawSpeed = 0; +var pitchSpeed = 0; + +var DEFAULT_PARAMETERS = { + MOUSE_YAW_SCALE: -0.125, + MOUSE_PITCH_SCALE: -0.125, + MOUSE_SENSITIVITY: 0.5, + + // Damping frequency, adjust to change mouse look behavior + W: 10, +} + +var movementParameters = DEFAULT_PARAMETERS; + +var mouseLook = (function () { + + var BUTTON_WIDTH = 50, + BUTTON_HEIGHT = 50, + BUTTON_ALPHA = 0.9, + BUTTON_MARGIN = 8, + active = false, + keyboardID = 0; + + function onKeyPressEvent(event) { + if (event.text == 'm' && event.isMeta) { + active = !active; + updateMapping(); + } + } + + function findInput(name) { + var availableInputs = Controller.getAvailableInputs(keyboardID); + for (i = 0; i < availableInputs.length; i++) { + if (availableInputs[i].inputName == name) { + return availableInputs[i].input; + } + } + // If the input isn't found, it will default to the first available input + return availableInputs[0].input; + } + + function findAction(name) { + var actions = Controller.getAllActions(); + for (var i = 0; i < actions.length; i++) { + if (actions[i].actionName == name) { + return i; + } + } + // If the action isn't found, it will default to the first available action + return 0; + } + + function updateMapping() { + if (keyboardID != 0) { + if (active) { + // Turn mouselook on + yawFromMouse = 0; + pitchFromMouse = 0; + yawSpeed = 0; + pitchSpeed = 0; + + var a = findInput("A").channel; + var d = findInput("D").channel; + var left = findInput("Left").channel; + var right = findInput("Right").channel; + var shift = findInput("Shift").channel; + + for (var i = findAction("YAW_LEFT"); i <= findAction("YAW_RIGHT"); i++) { + var inputChannels = Controller.getAllActions()[i].inputChannels; + for (var j = 0; j < inputChannels.length; j++) { + var inputChannel = inputChannels[j]; + // make a, d, left, and right strafe + if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.device == 0) { + Controller.removeInputChannel(inputChannel); + inputChannel.action = findAction("LATERAL_LEFT"); + Controller.addInputChannel(inputChannel); + } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.device == 0) { + Controller.removeInputChannel(inputChannel); + inputChannel.action = findAction("LATERAL_RIGHT"); + Controller.addInputChannel(inputChannel); + } + } + } + for (var i = findAction("LATERAL_LEFT"); i <= findAction("LATERAL_RIGHT"); i++) { + var inputChannels = Controller.getAllActions()[i].inputChannels; + for (var j = 0; j < inputChannels.length; j++) { + var inputChannel = inputChannels[j]; + // make shift + a/d/left/right change yaw/pitch + if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.channel == shift) { + Controller.removeInputChannel(inputChannel); + inputChannel.action = findAction("YAW_LEFT"); + Controller.addInputChannel(inputChannel); + } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.channel == shift) { + Controller.removeInputChannel(inputChannel); + inputChannel.action = findAction("YAW_RIGHT"); + Controller.addInputChannel(inputChannel); + } + } + } + } else { + Controller.resetDevice(keyboardID); + } + } + } + + function onScriptUpdate(dt) { + if (active && Window.hasFocus()) { + var x = Window.getCursorPositionX(); + // I'm not sure why this + 0.5 is necessary? + var y = Window.getCursorPositionY() + 0.5; + + yawFromMouse += ((x - lastX) * movementParameters.MOUSE_YAW_SCALE * movementParameters.MOUSE_SENSITIVITY); + pitchFromMouse += ((y - lastY) * movementParameters.MOUSE_PITCH_SCALE * movementParameters.MOUSE_SENSITIVITY); + pitchFromMouse = Math.max(-180, Math.min(180, pitchFromMouse)); + + resetCursorPosition(); + + // Here we use a linear damping model - http://en.wikipedia.org/wiki/Damping#Linear_damping + // Because we are using a critically damped model (no oscillation), ΞΆ = 1 and + // so we derive the formula: acceleration = -(2 * w0 * v) - (w0^2 * x) + var W = movementParameters.W; + yawAccel = (W * W * yawFromMouse) - (2 * W * yawSpeed); + pitchAccel = (W * W * pitchFromMouse) - (2 * W * pitchSpeed); + + yawSpeed += yawAccel * dt; + var yawMove = yawSpeed * dt; + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees( { x: 0, y: yawMove, z: 0 } )); + MyAvatar.orientation = newOrientation; + yawFromMouse -= yawMove; + + pitchSpeed += pitchAccel * dt; + var pitchMove = pitchSpeed * dt; + var newPitch = MyAvatar.headPitch + pitchMove; + MyAvatar.headPitch = newPitch; + pitchFromMouse -= pitchMove; + } + } + + function resetCursorPosition() { + var newX = Window.x + Window.innerWidth / 2.0; + var newY = Window.y + Window.innerHeight / 2.0; + Window.setCursorPosition(newX, newY); + lastX = newX; + lastY = newY; + } + + function setUp() { + keyboardID = Controller.findDevice("Keyboard"); + + Controller.keyPressEvent.connect(onKeyPressEvent); + + Menu.menuItemEvent.connect(handleMenuEvent); + + Script.update.connect(onScriptUpdate); + } + + function setupMenu() { + Menu.addMenuItem({ menuName: "View", menuItemName: "Mouselook Mode", shortcutKey: "META+M", + afterItem: "Mirror", isCheckable: true, isChecked: false }); + } + + setupMenu(); + + function cleanupMenu() { + Menu.removeMenuItem("View", "Mouselook Mode"); + } + + function handleMenuEvent(menuItem) { + if (menuItem == "Mouselook Mode") { + active = !active; + updateMapping(); + } + } + + function tearDown() { + if (keyboardID != 0) { + Controller.resetDevice(keyboardID); + } + cleanupMenu(); + } + + setUp(); + Script.scriptEnding.connect(tearDown); +}()); \ No newline at end of file diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 136b5b7f82..2ec34fcec8 100755 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -120,6 +120,23 @@ Slider = function(x,y,width,thumbSize) { this.onValueChanged = function(value) {}; + this.setMaxValue = function(maxValue) { + if (this.maxValue == maxValue) { + return; + } + var currentVal = this.getValue(); + this.maxValue = maxValue; + this.setValue(currentVal); + } + this.setMinValue = function(minValue) { + if (this.minValue == minValue) { + return; + } + var currentVal = this.getValue(); + this.minValue = minValue; + this.setValue(currentVal); + } + this.destroy = function() { Overlays.deleteOverlay(this.background); Overlays.deleteOverlay(this.thumb); @@ -613,6 +630,14 @@ Panel = function(x, y) { return null; } + this.getWidget = function(name) { + var item = this.items[name]; + if (item != null) { + return item.widget; + } + return null; + } + this.update = function(name) { var item = this.items[name]; if (item != null) { diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 79b0010210..8185a24078 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -10,25 +10,7 @@ Script.include("cookies.js"); -var panel = new Panel(10, 400); - -panel.newCheckbox("Enable Cull Opaque", - function(value) { Scene.setEngineCullOpaque((value != 0)); }, - function() { return Scene.doEngineCullOpaque(); }, - function(value) { return (value); } -); - -panel.newCheckbox("Enable Sort Opaque", - function(value) { Scene.setEngineSortOpaque((value != 0)); }, - function() { return Scene.doEngineSortOpaque(); }, - function(value) { return (value); } -); - -panel.newCheckbox("Enable Render Opaque", - function(value) { Scene.setEngineRenderOpaque((value != 0)); }, - function() { return Scene.doEngineRenderOpaque(); }, - function(value) { return (value); } -); +var panel = new Panel(10, 800); panel.newSlider("Num Feed Opaques", 0, 1000, function(value) { }, @@ -48,24 +30,6 @@ panel.newSlider("Max Drawn Opaques", -1, 1000, function(value) { return (value); } ); -panel.newCheckbox("Enable Cull Transparent", - function(value) { Scene.setEngineCullTransparent((value != 0)); }, - function() { return Scene.doEngineCullTransparent(); }, - function(value) { return (value); } -); - -panel.newCheckbox("Enable Sort Transparent", - function(value) { Scene.setEngineSortTransparent((value != 0)); }, - function() { return Scene.doEngineSortTransparent(); }, - function(value) { return (value); } -); - -panel.newCheckbox("Enable Render Transparent", - function(value) { Scene.setEngineRenderTransparent((value != 0)); }, - function() { return Scene.doEngineRenderTransparent(); }, - function(value) { return (value); } -); - panel.newSlider("Num Feed Transparents", 0, 100, function(value) { }, function() { return Scene.getEngineNumFeedTransparentItems(); }, @@ -84,13 +48,52 @@ panel.newSlider("Max Drawn Transparents", -1, 100, function(value) { return (value); } ); +panel.newSlider("Num Feed Overlay3Ds", 0, 100, + function(value) { }, + function() { return Scene.getEngineNumFeedOverlay3DItems(); }, + function(value) { return (value); } +); + +panel.newSlider("Num Drawn Overlay3Ds", 0, 100, + function(value) { }, + function() { return Scene.getEngineNumDrawnOverlay3DItems(); }, + function(value) { return (value); } +); + +panel.newSlider("Max Drawn Overlay3Ds", -1, 100, + function(value) { Scene.setEngineMaxDrawnOverlay3DItems(value); }, + function() { return Scene.getEngineMaxDrawnOverlay3DItems(); }, + function(value) { return (value); } +); + var tickTackPeriod = 500; function updateCounters() { - panel.set("Num Feed Opaques", panel.get("Num Feed Opaques")); - panel.set("Num Drawn Opaques", panel.get("Num Drawn Opaques")); - panel.set("Num Feed Transparents", panel.get("Num Feed Transparents")); - panel.set("Num Drawn Transparents", panel.get("Num Drawn Transparents")); + var numFeedOpaques = panel.get("Num Feed Opaques"); + var numFeedTransparents = panel.get("Num Feed Transparents"); + var numFeedOverlay3Ds = panel.get("Num Feed Overlay3Ds"); + + panel.set("Num Feed Opaques", numFeedOpaques); + panel.set("Num Drawn Opaques", panel.get("Num Drawn Opaques")); + panel.set("Num Feed Transparents", numFeedTransparents); + panel.set("Num Drawn Transparents", panel.get("Num Drawn Transparents")); + panel.set("Num Feed Overlay3Ds", numFeedOverlay3Ds); + panel.set("Num Drawn Overlay3Ds", panel.get("Num Drawn Overlay3Ds")); + + var numMax = Math.max(numFeedOpaques * 1.2, 1); + panel.getWidget("Num Feed Opaques").setMaxValue(numMax); + panel.getWidget("Num Drawn Opaques").setMaxValue(numMax); + panel.getWidget("Max Drawn Opaques").setMaxValue(numMax); + + numMax = Math.max(numFeedTransparents * 1.2, 1); + panel.getWidget("Num Feed Transparents").setMaxValue(numMax); + panel.getWidget("Num Drawn Transparents").setMaxValue(numMax); + panel.getWidget("Max Drawn Transparents").setMaxValue(numMax); + + numMax = Math.max(numFeedOverlay3Ds * 1.2, 1); + panel.getWidget("Num Feed Overlay3Ds").setMaxValue(numMax); + panel.getWidget("Num Drawn Overlay3Ds").setMaxValue(numMax); + panel.getWidget("Max Drawn Overlay3Ds").setMaxValue(numMax); } Script.setInterval(updateCounters, tickTackPeriod); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ad64f74056..2086e651c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -909,13 +909,18 @@ void Application::paintGL() { } } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + - _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale()); if (OculusManager::isConnected()) { _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation()); } else { _myCamera.setRotation(_myAvatar->getHead()->getOrientation()); } + if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { + _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + + _myCamera.getRotation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale()); + } else { + _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + + _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f) * _myAvatar->getBoomLength() * _myAvatar->getScale()); + } } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); @@ -2418,6 +2423,12 @@ void Application::cameraMenuChanged() { } } +void Application::rotationModeChanged() { + if (!Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { + _myAvatar->setHeadPitch(0); + } +} + void Application::updateCamera(float deltaTime) { PerformanceTimer perfTimer("updateCamera"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); @@ -3530,6 +3541,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems(); renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems(); + renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems(); renderArgs->_shouldRender = LODManager::shouldRender; @@ -3546,7 +3558,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems); sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems); - + + sceneInterface->setEngineFeedOverlay3DItems(engineRC->_numFeedOverlay3DItems); + sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems); } //Render the sixense lasers if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { diff --git a/interface/src/Application.h b/interface/src/Application.h index c9e5bea76e..3239b84c6c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -450,6 +450,7 @@ private slots: void setEnable3DTVMode(bool enable3DTVMode); void setEnableVRMode(bool enableVRMode); void cameraMenuChanged(); + void rotationModeChanged(); glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 216f733709..6671320f0c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -277,6 +277,9 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, 0, // QML Qt::Key_H, false, qApp, SLOT(cameraMenuChanged())); + + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CenterPlayerInView, + 0, false, qApp, SLOT(rotationModeChanged())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, #ifdef Q_OS_MAC diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6b892ebc3c..be0ac12d0d 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -199,6 +199,7 @@ namespace MenuOption { const QString FrameTimer = "Show Timer"; const QString Fullscreen = "Fullscreen"; const QString FullscreenMirror = "Fullscreen Mirror"; + const QString CenterPlayerInView = "Center Player In View"; const QString GlowWhenSpeaking = "Glow When Speaking"; const QString NamesAboveHeads = "Names Above Heads"; const QString HMDTools = "HMD Tools"; diff --git a/interface/src/devices/KeyboardMouseDevice.cpp b/interface/src/devices/KeyboardMouseDevice.cpp index fcb60cca26..9fadf7be82 100755 --- a/interface/src/devices/KeyboardMouseDevice.cpp +++ b/interface/src/devices/KeyboardMouseDevice.cpp @@ -242,8 +242,6 @@ void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) { mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED); mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED); - mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); - mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED); mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::RightButton), BUTTON_YAW_SPEED); mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::RightButton), BUTTON_YAW_SPEED); mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED); diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 2c747195a7..851c523c5d 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -457,6 +457,14 @@ void ControllerScriptingInterface::resetAllDeviceBindings() { Application::getUserInputMapper()->resetAllDeviceBindings(); } +void ControllerScriptingInterface::resetDevice(unsigned int device) { + Application::getUserInputMapper()->resetDevice(device); +} + +int ControllerScriptingInterface::findDevice(QString name) { + return Application::getUserInputMapper()->findDevice(name); +} + InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) : AbstractInputController(), _deviceTrackerId(deviceTrackerId), diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 9414dc887b..3a54826195 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -91,6 +91,8 @@ public slots: Q_INVOKABLE virtual bool removeInputChannel(UserInputMapper::InputChannel inputChannel); Q_INVOKABLE virtual QVector getAvailableInputs(unsigned int device); Q_INVOKABLE virtual void resetAllDeviceBindings(); + Q_INVOKABLE virtual void resetDevice(unsigned int device); + Q_INVOKABLE virtual int findDevice(QString name); virtual bool isPrimaryButtonPressed() const; virtual glm::vec2 getPrimaryJoystickPosition() const; diff --git a/interface/src/ui/UserInputMapper.cpp b/interface/src/ui/UserInputMapper.cpp index 2c28b79c75..fd2f384fb6 100755 --- a/interface/src/ui/UserInputMapper.cpp +++ b/interface/src/ui/UserInputMapper.cpp @@ -41,6 +41,22 @@ void UserInputMapper::resetAllDeviceBindings() { } } +void UserInputMapper::resetDevice(uint16 deviceID) { + auto device = _registeredDevices.find(deviceID); + if (device != _registeredDevices.end()) { + device->second->resetDeviceBindings(); + } +} + +int UserInputMapper::findDevice(QString name) { + for (auto device : _registeredDevices) { + if (device.second->_name.split(" (")[0] == name) { + return device.first; + } + } + return 0; +} + bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) { return addInputChannel(action, input, Input(), scale); } diff --git a/interface/src/ui/UserInputMapper.h b/interface/src/ui/UserInputMapper.h index 84ca192e3e..91aa724ea6 100755 --- a/interface/src/ui/UserInputMapper.h +++ b/interface/src/ui/UserInputMapper.h @@ -116,6 +116,8 @@ public: QString getDeviceName(uint16 deviceID) { return _registeredDevices[deviceID]->_name; } QVector getAvailableInputs(uint16 deviceID) { return _registeredDevices[deviceID]->getAvailabeInputs(); } void resetAllDeviceBindings(); + void resetDevice(uint16 deviceID); + int findDevice(QString name); // Actions are the output channels of the Mapper, that's what the InputChannel map to // For now the Actions are hardcoded, this is bad, but we will fix that in the near future diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index 77debf304f..034095291f 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -11,6 +11,7 @@ // include this before QGLWidget, which includes an earlier version of OpenGL #include "InterfaceConfig.h" +#include #include #include #include @@ -101,206 +102,185 @@ void Circle3DOverlay::render(RenderArgs* args) { bool colorChanged = colorX.red != _lastColor.red || colorX.green != _lastColor.green || colorX.blue != _lastColor.blue; _lastColor = colorX; - glDisable(GL_LIGHTING); - - glm::vec3 position = getPosition(); - glm::vec3 center = getCenter(); - glm::vec2 dimensions = getDimensions(); - glm::quat rotation = getRotation(); - - float glowLevel = getGlowLevel(); - Glower* glower = NULL; - if (glowLevel > 0.0f) { - glower = new Glower(glowLevel); - } - - glPushMatrix(); - glTranslatef(position.x, position.y, position.z); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - glPushMatrix(); - glm::vec3 positionToCenter = center - position; - glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); - glScalef(dimensions.x / 2.0f, dimensions.y / 2.0f, 1.0f); - - glLineWidth(_lineWidth); - - auto geometryCache = DependencyManager::get(); - - // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise - // we just draw a line... - if (getIsSolid()) { - if (_quadVerticesID == GeometryCache::UNKNOWN_ID) { - _quadVerticesID = geometryCache->allocateID(); - } - - if (geometryChanged || colorChanged) { - - QVector points; - - float angle = startAt; - float angleInRadians = glm::radians(angle); - glm::vec2 firstInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); - glm::vec2 firstOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); - - points << firstInnerPoint << firstOuterPoint; - - while (angle < endAt) { - angleInRadians = glm::radians(angle); - glm::vec2 thisInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); - glm::vec2 thisOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); - - points << thisOuterPoint << thisInnerPoint; - - angle += SLICE_ANGLE; - } - - // get the last slice portion.... - angle = endAt; - angleInRadians = glm::radians(angle); - glm::vec2 lastInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); - glm::vec2 lastOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); - - points << lastOuterPoint << lastInnerPoint; - - geometryCache->updateVertices(_quadVerticesID, points, color); - } - - geometryCache->renderVertices(gpu::QUAD_STRIP, _quadVerticesID); - - } else { - if (_lineVerticesID == GeometryCache::UNKNOWN_ID) { - _lineVerticesID = geometryCache->allocateID(); - } - - if (geometryChanged || colorChanged) { - QVector points; - - float angle = startAt; - float angleInRadians = glm::radians(angle); - glm::vec2 firstPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); - points << firstPoint; - - while (angle < endAt) { - angle += SLICE_ANGLE; - angleInRadians = glm::radians(angle); - glm::vec2 thisPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); - points << thisPoint; - - if (getIsDashedLine()) { - angle += SLICE_ANGLE / 2.0f; // short gap - angleInRadians = glm::radians(angle); - glm::vec2 dashStartPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); - points << dashStartPoint; - } - } - - // get the last slice portion.... - angle = endAt; - angleInRadians = glm::radians(angle); - glm::vec2 lastPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); - points << lastPoint; - - geometryCache->updateVertices(_lineVerticesID, points, color); - } + auto geometryCache = DependencyManager::get(); + Transform transform; + transform.setTranslation(getCenter()); + transform.setRotation(getRotation()); + transform.setScale(glm::vec3(getDimensions(), 0.01f)); + + + auto& batch = *args->_batch; + batch._glLineWidth(_lineWidth); + batch.setModelTransform(transform); + DependencyManager::get()->bindSimpleProgram(batch, false, false); + + // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise + // we just draw a line... + if (getIsSolid()) { + if (_quadVerticesID == GeometryCache::UNKNOWN_ID) { + _quadVerticesID = geometryCache->allocateID(); + } + + if (geometryChanged || colorChanged) { + + QVector points; + + float angle = startAt; + float angleInRadians = glm::radians(angle); + glm::vec2 firstInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); + glm::vec2 firstOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); + + points << firstInnerPoint << firstOuterPoint; + + while (angle < endAt) { + angleInRadians = glm::radians(angle); + glm::vec2 thisInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); + glm::vec2 thisOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); + + points << thisOuterPoint << thisInnerPoint; + + angle += SLICE_ANGLE; + } + + // get the last slice portion.... + angle = endAt; + angleInRadians = glm::radians(angle); + glm::vec2 lastInnerPoint(cosf(angleInRadians) * innerRadius, sinf(angleInRadians) * innerRadius); + glm::vec2 lastOuterPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); + + points << lastOuterPoint << lastInnerPoint; + + geometryCache->updateVertices(_quadVerticesID, points, color); + } + + geometryCache->renderVertices(batch, gpu::QUAD_STRIP, _quadVerticesID); + + } else { + if (_lineVerticesID == GeometryCache::UNKNOWN_ID) { + _lineVerticesID = geometryCache->allocateID(); + } + + if (geometryChanged || colorChanged) { + QVector points; + + float angle = startAt; + float angleInRadians = glm::radians(angle); + glm::vec2 firstPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); + points << firstPoint; + + while (angle < endAt) { + angle += SLICE_ANGLE; + angleInRadians = glm::radians(angle); + glm::vec2 thisPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); + points << thisPoint; + if (getIsDashedLine()) { - geometryCache->renderVertices(gpu::LINES, _lineVerticesID); - } else { - geometryCache->renderVertices(gpu::LINE_STRIP, _lineVerticesID); + angle += SLICE_ANGLE / 2.0f; // short gap + angleInRadians = glm::radians(angle); + glm::vec2 dashStartPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); + points << dashStartPoint; } } - - // draw our tick marks - // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise - // we just draw a line... - if (getHasTickMarks()) { - - if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) { - _majorTicksVerticesID = geometryCache->allocateID(); + + // get the last slice portion.... + angle = endAt; + angleInRadians = glm::radians(angle); + glm::vec2 lastPoint(cosf(angleInRadians) * outerRadius, sinf(angleInRadians) * outerRadius); + points << lastPoint; + + geometryCache->updateVertices(_lineVerticesID, points, color); + } + + if (getIsDashedLine()) { + geometryCache->renderVertices(batch, gpu::LINES, _lineVerticesID); + } else { + geometryCache->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID); + } + } + + // draw our tick marks + // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise + // we just draw a line... + if (getHasTickMarks()) { + + if (_majorTicksVerticesID == GeometryCache::UNKNOWN_ID) { + _majorTicksVerticesID = geometryCache->allocateID(); + } + if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) { + _minorTicksVerticesID = geometryCache->allocateID(); + } + + if (geometryChanged) { + QVector majorPoints; + QVector minorPoints; + + // draw our major tick marks + if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { + + float tickMarkAngle = getMajorTickMarksAngle(); + float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; + float angleInRadians = glm::radians(angle); + float tickMarkLength = getMajorTickMarksLength(); + float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; + float endRadius = startRadius + tickMarkLength; + + while (angle <= endAt) { + angleInRadians = glm::radians(angle); + + glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); + glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); + + majorPoints << thisPointA << thisPointB; + + angle += tickMarkAngle; } - if (_minorTicksVerticesID == GeometryCache::UNKNOWN_ID) { - _minorTicksVerticesID = geometryCache->allocateID(); - } - - if (geometryChanged) { - QVector majorPoints; - QVector minorPoints; - - // draw our major tick marks - if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { - - float tickMarkAngle = getMajorTickMarksAngle(); - float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; - float angleInRadians = glm::radians(angle); - float tickMarkLength = getMajorTickMarksLength(); - float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; - float endRadius = startRadius + tickMarkLength; - - while (angle <= endAt) { - angleInRadians = glm::radians(angle); - - glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); - glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); - - majorPoints << thisPointA << thisPointB; - - angle += tickMarkAngle; - } - } - - // draw our minor tick marks - if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { - - float tickMarkAngle = getMinorTickMarksAngle(); - float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; - float angleInRadians = glm::radians(angle); - float tickMarkLength = getMinorTickMarksLength(); - float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; - float endRadius = startRadius + tickMarkLength; - - while (angle <= endAt) { - angleInRadians = glm::radians(angle); - - glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); - glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); - - minorPoints << thisPointA << thisPointB; - - angle += tickMarkAngle; - } - } - - xColor majorColorX = getMajorTickMarksColor(); - glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha); - - geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor); - - xColor minorColorX = getMinorTickMarksColor(); - glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha); - - geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor); - } - - geometryCache->renderVertices(gpu::LINES, _majorTicksVerticesID); - - geometryCache->renderVertices(gpu::LINES, _minorTicksVerticesID); } - - - glPopMatrix(); - glPopMatrix(); - + + // draw our minor tick marks + if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { + + float tickMarkAngle = getMinorTickMarksAngle(); + float angle = startAt - fmodf(startAt, tickMarkAngle) + tickMarkAngle; + float angleInRadians = glm::radians(angle); + float tickMarkLength = getMinorTickMarksLength(); + float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; + float endRadius = startRadius + tickMarkLength; + + while (angle <= endAt) { + angleInRadians = glm::radians(angle); + + glm::vec2 thisPointA(cosf(angleInRadians) * startRadius, sinf(angleInRadians) * startRadius); + glm::vec2 thisPointB(cosf(angleInRadians) * endRadius, sinf(angleInRadians) * endRadius); + + minorPoints << thisPointA << thisPointB; + + angle += tickMarkAngle; + } + } + + xColor majorColorX = getMajorTickMarksColor(); + glm::vec4 majorColor(majorColorX.red / MAX_COLOR, majorColorX.green / MAX_COLOR, majorColorX.blue / MAX_COLOR, alpha); + + geometryCache->updateVertices(_majorTicksVerticesID, majorPoints, majorColor); + + xColor minorColorX = getMinorTickMarksColor(); + glm::vec4 minorColor(minorColorX.red / MAX_COLOR, minorColorX.green / MAX_COLOR, minorColorX.blue / MAX_COLOR, alpha); + + geometryCache->updateVertices(_minorTicksVerticesID, minorPoints, minorColor); + } + + geometryCache->renderVertices(batch, gpu::LINES, _majorTicksVerticesID); + + geometryCache->renderVertices(batch, gpu::LINES, _minorTicksVerticesID); + } + if (geometryChanged) { _lastStartAt = startAt; _lastEndAt = endAt; _lastInnerRadius = innerRadius; _lastOuterRadius = outerRadius; } - - if (glower) { - delete glower; - } } void Circle3DOverlay::setProperties(const QScriptValue &properties) { diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 2397f65911..236e2979f5 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -506,7 +506,7 @@ FBXNode parseFBX(QIODevice* device) { QVector createVec4Vector(const QVector& doubleVector) { QVector values; - for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 4 * 4); it != end; ) { + for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 4) * 4); it != end; ) { float x = *it++; float y = *it++; float z = *it++; @@ -516,9 +516,27 @@ QVector createVec4Vector(const QVector& doubleVector) { return values; } + +QVector createVec4VectorRGBA(const QVector& doubleVector, glm::vec4& average) { + QVector values; + for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 4) * 4); it != end; ) { + float x = *it++; + float y = *it++; + float z = *it++; + float w = *it++; + auto val = glm::vec4(x, y, z, w); + values.append(val); + average += val; + } + if (!values.isEmpty()) { + average *= (1.0f / float(values.size())); + } + return values; +} + QVector createVec3Vector(const QVector& doubleVector) { QVector values; - for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 3 * 3); it != end; ) { + for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 3) * 3); it != end; ) { float x = *it++; float y = *it++; float z = *it++; @@ -529,7 +547,7 @@ QVector createVec3Vector(const QVector& doubleVector) { QVector createVec2Vector(const QVector& doubleVector) { QVector values; - for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 2 * 2); it != end; ) { + for (const double* it = doubleVector.constData(), *end = it + ((doubleVector.size() / 2) * 2); it != end; ) { float s = *it++; float t = *it++; values.append(glm::vec2(s, -t)); @@ -799,6 +817,7 @@ public: QVector normalIndices; bool colorsByVertex; + glm::vec4 averageColor{1.0f, 1.0f, 1.0f, 1.0f}; QVector colors; QVector colorIndices; @@ -940,8 +959,7 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { bool indexToDirect = false; foreach (const FBXNode& subdata, child.children) { if (subdata.name == "Colors") { - data.colors = createVec4Vector(getDoubleVector(subdata)); - + data.colors = createVec4VectorRGBA(getDoubleVector(subdata), data.averageColor); } else if (subdata.name == "ColorsIndex") { data.colorIndices = getIntVector(subdata); @@ -956,6 +974,19 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) { // hack to work around wacky Makehuman exports data.colorsByVertex = true; } + +#if defined(FBXREADER_KILL_BLACK_COLOR_ATTRIBUTE) + // Potential feature where we decide to kill the color attribute is to dark? + // Tested with the model: + // https://hifi-public.s3.amazonaws.com/ryan/gardenLight2.fbx + // let's check if we did have true data ? + if (glm::all(glm::lessThanEqual(data.averageColor, glm::vec4(0.09f)))) { + data.colors.clear(); + data.colorIndices.clear(); + data.colorsByVertex = false; + qCDebug(modelformat) << "LayerElementColor has an average value of 0.0f... let's forget it."; + } +#endif } else if (child.name == "LayerElementUV") { if (child.properties.at(0).toInt() == 0) { diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 154d6b9e3f..5ef101225c 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -450,6 +450,7 @@ void GLBackend::do_glUniform1i(Batch& batch, uint32 paramOffset) { // because these uniform setters are deprecated and we don;t want to create side effect return; } + updatePipeline(); glUniform1f( batch._params[paramOffset + 1]._int, batch._params[paramOffset + 0]._int); @@ -472,6 +473,8 @@ void GLBackend::do_glUniform1f(Batch& batch, uint32 paramOffset) { // because these uniform setters are deprecated and we don;t want to create side effect return; } + updatePipeline(); + glUniform1f( batch._params[paramOffset + 1]._int, batch._params[paramOffset + 0]._float); @@ -494,6 +497,7 @@ void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) { // because these uniform setters are deprecated and we don;t want to create side effect return; } + updatePipeline(); glUniform2f( batch._params[paramOffset + 2]._int, batch._params[paramOffset + 1]._float, @@ -518,6 +522,7 @@ void GLBackend::do_glUniform3f(Batch& batch, uint32 paramOffset) { // because these uniform setters are deprecated and we don;t want to create side effect return; } + updatePipeline(); glUniform3f( batch._params[paramOffset + 3]._int, batch._params[paramOffset + 2]._float, @@ -542,6 +547,7 @@ void GLBackend::do_glUniform3fv(Batch& batch, uint32 paramOffset) { // because these uniform setters are deprecated and we don;t want to create side effect return; } + updatePipeline(); glUniform3fv( batch._params[paramOffset + 2]._int, batch._params[paramOffset + 1]._uint, @@ -567,6 +573,7 @@ void GLBackend::do_glUniform4fv(Batch& batch, uint32 paramOffset) { // because these uniform setters are deprecated and we don;t want to create side effect return; } + updatePipeline(); glUniform4fv( batch._params[paramOffset + 2]._int, batch._params[paramOffset + 1]._uint, @@ -592,6 +599,7 @@ void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) { // because these uniform setters are deprecated and we don;t want to create side effect return; } + updatePipeline(); glUniformMatrix4fv( batch._params[paramOffset + 3]._int, batch._params[paramOffset + 2]._uint, diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 999173e5b7..05e1e8fed8 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -343,10 +343,10 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { if (bytes && texture.isAutogenerateMips()) { glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } else { + }/* else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } + }*/ object->_target = GL_TEXTURE_2D; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index f0a52af086..b49d1985bb 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -61,15 +61,26 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); gpu::Shader::makeProgram(*programTextured, slotBindings); - + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + + gpu::StatePointer stateCullNone = gpu::StatePointer(new gpu::State()); + stateCullNone->setCullMode(gpu::State::CULL_NONE); + stateCullNone->setDepthTest(true, true, gpu::LESS_EQUAL); + stateCullNone->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + _simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + _simpleProgramCullNone = gpu::PipelinePointer(gpu::Pipeline::create(program, stateCullNone)); _simpleProgramTextured = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, state)); + _simpleProgramTexturedCullNone = gpu::PipelinePointer(gpu::Pipeline::create(programTextured, stateCullNone)); _viewState = viewState; loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations); @@ -106,13 +117,21 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); } -void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured) { +void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled) { // DependencyManager::get()->setPrimaryDrawBuffers(batch, true, true, true); if (textured) { - batch.setPipeline(_simpleProgramTextured); + if (culled) { + batch.setPipeline(_simpleProgramTextured); + } else { + batch.setPipeline(_simpleProgramTexturedCullNone); + } } else { - batch.setPipeline(_simpleProgram); + if (culled) { + batch.setPipeline(_simpleProgram); + } else { + batch.setPipeline(_simpleProgramCullNone); + } } } @@ -191,7 +210,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu } } -void DeferredLightingEffect::prepare() { +void DeferredLightingEffect::prepare(RenderArgs* args) { // clear the normal and specular buffers auto textureCache = DependencyManager::get(); textureCache->setPrimaryDrawBuffers(false, true, false); @@ -205,7 +224,7 @@ void DeferredLightingEffect::prepare() { textureCache->setPrimaryDrawBuffers(true, false, false); } -void DeferredLightingEffect::render() { +void DeferredLightingEffect::render(RenderArgs* args) { // perform deferred lighting, rendering to free fbo glDisable(GL_BLEND); glDisable(GL_LIGHTING); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index bd7fcb286b..9d66bf08c0 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -34,7 +34,7 @@ public: void init(AbstractViewStateInterface* viewState); /// Sets up the state necessary to render static untextured geometry with the simple program. - void bindSimpleProgram(gpu::Batch& batch, bool textured = false); + void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true); /// Tears down the state necessary to render static untextured geometry with the simple program. void releaseSimpleProgram(gpu::Batch& batch); @@ -66,8 +66,8 @@ public: void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f), float intensity = 0.5f, const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI); - void prepare(); - void render(); + void prepare(RenderArgs* args); + void render(RenderArgs* args); void copyBack(RenderArgs* args); void setupTransparent(RenderArgs* args, int lightBufferUnit); @@ -100,7 +100,9 @@ private: static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations); gpu::PipelinePointer _simpleProgram; + gpu::PipelinePointer _simpleProgramCullNone; gpu::PipelinePointer _simpleProgramTextured; + gpu::PipelinePointer _simpleProgramTexturedCullNone; ProgramObject _directionalSkyboxLight; LightLocations _directionalSkyboxLightLocations; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 803673a06e..1b991f2179 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1804,6 +1804,7 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { } void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) { + PerformanceTimer perfTimer("Model::renderPart"); if (!_readyWhenAdded) { return; // bail asap } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index ce3c6769ca..ced83da5e9 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -19,42 +19,54 @@ #include -#include "overlay3D_vert.h" +#include "overlay3D_vert.h" #include "overlay3D_frag.h" using namespace render; -template <> void render::jobRun(const PrepareDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("PrepareDeferred"); - DependencyManager::get()->prepare(); +void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + DependencyManager::get()->prepare(renderContext->args); } -template <> void render::jobRun(const RenderDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("RenderDeferred"); - DependencyManager::get()->render(); -// renderContext->args->_context->syncCache(); +void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + DependencyManager::get()->render(renderContext->args); } -template <> void render::jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { +void ResolveDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { PerformanceTimer perfTimer("ResolveDeferred"); DependencyManager::get()->copyBack(renderContext->args); - renderContext->args->_context->syncCache(); - } - - RenderDeferredTask::RenderDeferredTask() : Task() { - _jobs.push_back(Job(PrepareDeferred())); - _jobs.push_back(Job(DrawBackground())); - _jobs.push_back(Job(DrawOpaqueDeferred())); - _jobs.push_back(Job(DrawLight())); - _jobs.push_back(Job(ResetGLState())); - _jobs.push_back(Job(RenderDeferred())); - _jobs.push_back(Job(ResolveDeferred())); - _jobs.push_back(Job(DrawTransparentDeferred())); - _jobs.push_back(Job(DrawOverlay3D())); - _jobs.push_back(Job(ResetGLState())); + _jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred"))); + _jobs.push_back(Job(new DrawBackground::JobModel("DrawBackground"))); + _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", + FetchItems( + [] (const RenderContextPointer& context, int count) { + context->_numFeedOpaqueItems = count; + } + ) + ))); + _jobs.push_back(Job(new CullItems::JobModel("CullOpaque", _jobs.back().getOutput()))); + _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput()))); + _jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", _jobs.back().getOutput()))); + _jobs.push_back(Job(new DrawLight::JobModel("DrawLight"))); + _jobs.push_back(Job(new ResetGLState::JobModel())); + _jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred"))); + _jobs.push_back(Job(new ResolveDeferred::JobModel("ResolveDeferred"))); + _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", + FetchItems( + ItemFilter::Builder::transparentShape().withoutLayered(), + [] (const RenderContextPointer& context, int count) { + context->_numFeedTransparentItems = count; + } + ) + ))); + _jobs.push_back(Job(new CullItems::JobModel("CullTransparent", _jobs.back().getOutput()))); + _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)))); + _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput()))); + _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); + _jobs.push_back(Job(new ResetGLState::JobModel())); } RenderDeferredTask::~RenderDeferredTask() { @@ -80,181 +92,104 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend } }; - - -template <> void render::jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("DrawOpaqueDeferred"); +void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { assert(renderContext->args); assert(renderContext->args->_viewFrustum); - // render opaques - auto& scene = sceneContext->_scene; - auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape().withoutLayered()); - auto& renderDetails = renderContext->args->_details; + RenderArgs* args = renderContext->args; + gpu::Batch batch; + args->_batch = &batch; - ItemIDsBounds inItems; - inItems.reserve(items.size()); - for (auto id : items) { - inItems.emplace_back(ItemIDAndBounds(id)); + renderContext->_numDrawnOpaqueItems = inItems.size(); + + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { + viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); } - ItemIDsBounds& renderedItems = inItems; + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); - renderContext->_numFeedOpaqueItems = renderedItems.size(); - - ItemIDsBounds culledItems; - culledItems.reserve(inItems.size()); - if (renderContext->_cullOpaque) { - renderDetails.pointTo(RenderDetails::OPAQUE_ITEM); - cullItems(sceneContext, renderContext, renderedItems, culledItems); - renderDetails.pointTo(RenderDetails::OTHER_ITEM); - renderedItems = culledItems; + { + GLenum buffers[3]; + int bufferCount = 0; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; + batch._glDrawBuffers(bufferCount, buffers); + const float OPAQUE_ALPHA_THRESHOLD = 0.5f; + args->_alphaThreshold = OPAQUE_ALPHA_THRESHOLD; } - renderContext->_numDrawnOpaqueItems = renderedItems.size(); + renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOpaqueItems); - - ItemIDsBounds sortedItems; - sortedItems.reserve(culledItems.size()); - if (renderContext->_sortOpaque) { - depthSortItems(sceneContext, renderContext, true, renderedItems, sortedItems); // Sort Front to back opaque items! - renderedItems = sortedItems; - } - - // ItemIDsBounds sortedItems; - /* ItemMaterialBucketMap stateSortedItems; - stateSortedItems.allocateStandardMaterialBuckets(); - if (true) { - for (auto& itemIDAndBound : renderedItems) { - stateSortedItems.insert(itemIDAndBound.id, scene->getItem(itemIDAndBound.id).getMaterialKey()); - } - } -*/ - - if (renderContext->_renderOpaque) { - RenderArgs* args = renderContext->args; - gpu::Batch batch; - args->_batch = &batch; - - glm::mat4 projMat; - Transform viewMat; - args->_viewFrustum->evalProjectionMatrix(projMat); - args->_viewFrustum->evalViewTransform(viewMat); - if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { - viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); - } - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - - { - GLenum buffers[3]; - int bufferCount = 0; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; - batch._glDrawBuffers(bufferCount, buffers); - } - - renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnOpaqueItems); - - args->_context->render((*args->_batch)); - args->_batch = nullptr; - } + // Before rendering the batch make sure we re in sync with gl state + args->_context->syncCache(); + renderContext->args->_context->syncCache(); + args->_context->render((*args->_batch)); + args->_batch = nullptr; } - -template <> void render::jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("DrawTransparentDeferred"); +void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { assert(renderContext->args); assert(renderContext->args->_viewFrustum); - - // render transparents - auto& scene = sceneContext->_scene; - auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape().withoutLayered()); auto& renderDetails = renderContext->args->_details; + + RenderArgs* args = renderContext->args; + gpu::Batch batch; + args->_batch = &batch; - ItemIDsBounds inItems; - inItems.reserve(items.size()); - for (auto id : items) { - inItems.push_back(id); + renderContext->_numDrawnTransparentItems = inItems.size(); + + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { + viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); } - ItemIDsBounds& renderedItems = inItems; - - renderContext->_numFeedTransparentItems = renderedItems.size(); - - ItemIDsBounds culledItems; - if (renderContext->_cullTransparent) { - renderDetails.pointTo(RenderDetails::TRANSLUCENT_ITEM); - cullItems(sceneContext, renderContext, inItems, culledItems); - renderDetails.pointTo(RenderDetails::OTHER_ITEM); - renderedItems = culledItems; + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f; + + { + GLenum buffers[3]; + int bufferCount = 0; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; + batch._glDrawBuffers(bufferCount, buffers); + args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD; } - renderContext->_numDrawnTransparentItems = renderedItems.size(); - - ItemIDsBounds sortedItems; - if (renderContext->_sortTransparent) { - depthSortItems(sceneContext, renderContext, false, renderedItems, sortedItems); // Sort Back to front transparent items! - renderedItems = sortedItems; - } - - if (renderContext->_renderTransparent) { - RenderArgs* args = renderContext->args; - gpu::Batch batch; - args->_batch = &batch; + + renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnTransparentItems); + + // Before rendering the batch make sure we re in sync with gl state + args->_context->syncCache(); + args->_context->render((*args->_batch)); + args->_batch = nullptr; + + // reset blend function to standard... + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); +} +const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const { + if (!_opaquePipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag))); + auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto state = gpu::StatePointer(new gpu::State()); + state->setDepthTest(true, true, gpu::LESS_EQUAL); - glm::mat4 projMat; - Transform viewMat; - args->_viewFrustum->evalProjectionMatrix(projMat); - args->_viewFrustum->evalViewTransform(viewMat); - if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { - viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); - } - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - - const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f; - - { - GLenum buffers[3]; - int bufferCount = 0; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; - batch._glDrawBuffers(bufferCount, buffers); - args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD; - } - - - renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnTransparentItems); - - // Before rendering the batch make sure we re in sync with gl state - args->_context->syncCache(); - args->_context->render((*args->_batch)); - args->_batch = nullptr; - - // reset blend function to standard... - // glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + _opaquePipeline.reset(gpu::Pipeline::create(program, state)); } + return _opaquePipeline; } -const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() const { - if (!_opaquePipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag))); - - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); - - auto state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - - _opaquePipeline.reset(gpu::Pipeline::create(program, state)); - } - return _opaquePipeline; -} - -template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("DrawOverlay3D"); +void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { assert(renderContext->args); assert(renderContext->args->_viewFrustum); @@ -271,13 +206,14 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin inItems.emplace_back(id); } } - + renderContext->_numFeedOverlay3DItems = inItems.size(); + renderContext->_numDrawnOverlay3DItems = inItems.size(); + RenderArgs* args = renderContext->args; gpu::Batch batch; args->_batch = &batch; args->_whiteTexture = DependencyManager::get()->getWhiteTexture(); - glm::mat4 projMat; Transform viewMat; args->_viewFrustum->evalProjectionMatrix(projMat); @@ -287,12 +223,13 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin } batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - batch.setPipeline(job.getOpaquePipeline()); + + batch.setPipeline(getOpaquePipeline()); batch.setUniformTexture(0, args->_whiteTexture); if (!inItems.empty()) { - batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0); - renderItems(sceneContext, renderContext, inItems); + batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0); + renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOverlay3DItems); } // Before rendering the batch make sure we re in sync with gl state @@ -301,3 +238,4 @@ template <> void render::jobRun(const DrawOverlay3D& job, const SceneContextPoin args->_batch = nullptr; args->_whiteTexture.reset(); } + diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 3b0ffdfc9b..2fc30d7267 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -18,48 +18,49 @@ class PrepareDeferred { public: + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + + typedef render::Job::Model JobModel; }; -namespace render { -template <> void jobRun(const PrepareDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); -} + class RenderDeferred { public: + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + + typedef render::Job::Model JobModel; }; -namespace render { -template <> void jobRun(const RenderDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); -} class ResolveDeferred { public: -}; -namespace render { -template <> void jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); -} + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + typedef render::Job::Model JobModel; +}; class DrawOpaqueDeferred { public: + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); + + typedef render::Job::ModelI JobModel; }; -namespace render { -template <> void jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); -} class DrawTransparentDeferred { public: -}; -namespace render { -template <> void jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); -} + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems); -class DrawOverlay3D { - mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable -public: - const gpu::PipelinePointer& getOpaquePipeline() const; + typedef render::Job::ModelI JobModel; +}; + +class DrawOverlay3D { + mutable gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable +public: + const gpu::PipelinePointer& getOpaquePipeline() const; + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + + typedef render::Job::Model JobModel; }; -namespace render { -template <> void jobRun(const DrawOverlay3D& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); -} class RenderDeferredTask : public render::Task { public: diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index bb4ba00cee..6076ec0006 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -25,11 +25,6 @@ using namespace render; DrawSceneTask::DrawSceneTask() : Task() { - - _jobs.push_back(Job(DrawOpaque())); - _jobs.push_back(Job(DrawLight())); - _jobs.push_back(Job(DrawTransparent())); - _jobs.push_back(Job(ResetGLState())); } DrawSceneTask::~DrawSceneTask() { @@ -56,8 +51,11 @@ void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderCon Job::~Job() { } + + + + void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - PerformanceTimer perfTimer("cullItems"); assert(renderContext->args); assert(renderContext->args->_viewFrustum); @@ -68,17 +66,9 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont renderDetails->_considered += inItems.size(); // Culling / LOD - for (auto itemDetails : inItems) { - auto item = scene->getItem(itemDetails.id); - AABox bound; - { - PerformanceTimer perfTimer("getBound"); - - bound = item.getBound(); - } - - if (bound.isNull()) { - outItems.emplace_back(ItemIDAndBounds(itemDetails.id)); // One more Item to render + for (auto item : inItems) { + if (item.bounds.isNull()) { + outItems.emplace_back(item); // One more Item to render continue; } @@ -87,16 +77,16 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont bool outOfView; { PerformanceTimer perfTimer("boxInFrustum"); - outOfView = args->_viewFrustum->boxInFrustum(bound) == ViewFrustum::OUTSIDE; + outOfView = args->_viewFrustum->boxInFrustum(item.bounds) == ViewFrustum::OUTSIDE; } if (!outOfView) { bool bigEnoughToRender; { PerformanceTimer perfTimer("shouldRender"); - bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, bound) : true; + bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, item.bounds) : true; } if (bigEnoughToRender) { - outItems.emplace_back(ItemIDAndBounds(itemDetails.id, bound)); // One more Item to render + outItems.emplace_back(item); // One more Item to render } else { renderDetails->_tooSmall++; } @@ -107,6 +97,32 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont renderDetails->_rendered += outItems.size(); } + +void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) { + auto& scene = sceneContext->_scene; + auto& items = scene->getMasterBucket().at(_filter); + auto& renderDetails = renderContext->args->_details; + + outItems.clear(); + outItems.reserve(items.size()); + for (auto id : items) { + auto& item = scene->getItem(id); + outItems.emplace_back(ItemIDAndBounds(id, item.getBound())); + } + + if (_probeNumItems) { + _probeNumItems(renderContext, outItems.size()); + } +} + +void CullItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { + + outItems.clear(); + outItems.reserve(inItems.size()); + cullItems(sceneContext, renderContext, inItems, outItems); +} + + struct ItemBound { float _centerDepth = 0.0f; float _nearDepth = 0.0f; @@ -130,7 +146,6 @@ struct BackToFrontSort { }; void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - PerformanceTimer perfTimer("depthSortItems"); assert(renderContext->args); assert(renderContext->args->_viewFrustum); @@ -139,9 +154,10 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende // Allocate and simply copy + outItems.clear(); outItems.reserve(inItems.size()); - + // Make a local dataset of the center distance and closest point distance std::vector itemBounds; itemBounds.reserve(outItems.size()); @@ -169,8 +185,14 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende } } + +void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { + outItems.clear(); + outItems.reserve(inItems.size()); + depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems); +} + void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems) { - PerformanceTimer perfTimer("renderItems"); auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->args; // render @@ -183,6 +205,10 @@ void render::renderItems(const SceneContextPointer& sceneContext, const RenderCo int numItems = 0; for (auto itemDetails : inItems) { auto item = scene->getItem(itemDetails.id); + if (numItems + 1 >= maxDrawnItems) { + item.render(args); + return; + } item.render(args); numItems++; if (numItems >= maxDrawnItems) { @@ -224,8 +250,7 @@ void addClearStateCommands(gpu::Batch& batch) { // Back to no program batch._glUseProgram(0); } - -template <> void render::jobRun(const ResetGLState& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { +void ResetGLState::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { gpu::Batch theBatch; addClearStateCommands(theBatch); @@ -233,160 +258,7 @@ template <> void render::jobRun(const ResetGLState& job, const SceneContextPoint renderContext->args->_context->render(theBatch); } -template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("DrawOpaque"); - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); - - // render opaques - auto& scene = sceneContext->_scene; - auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape()); - auto& renderDetails = renderContext->args->_details; - - ItemIDsBounds inItems; - inItems.reserve(items.size()); - for (auto id : items) { - inItems.emplace_back(ItemIDAndBounds(id)); - } - ItemIDsBounds& renderedItems = inItems; - - renderContext->_numFeedOpaqueItems = renderedItems.size(); - - ItemIDsBounds culledItems; - culledItems.reserve(inItems.size()); - if (renderContext->_cullOpaque) { - renderDetails.pointTo(RenderDetails::OPAQUE_ITEM); - cullItems(sceneContext, renderContext, renderedItems, culledItems); - renderDetails.pointTo(RenderDetails::OTHER_ITEM); - renderedItems = culledItems; - } - - renderContext->_numDrawnOpaqueItems = renderedItems.size(); - - ItemIDsBounds sortedItems; - sortedItems.reserve(culledItems.size()); - if (renderContext->_sortOpaque) { - depthSortItems(sceneContext, renderContext, true, renderedItems, sortedItems); // Sort Front to back opaque items! - renderedItems = sortedItems; - } - - if (renderContext->_renderOpaque) { - RenderArgs* args = renderContext->args; - gpu::Batch batch; - args->_batch = &batch; - - glm::mat4 projMat; - Transform viewMat; - args->_viewFrustum->evalProjectionMatrix(projMat); - args->_viewFrustum->evalViewTransform(viewMat); - if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { - viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); - } - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - - { - GLenum buffers[3]; - int bufferCount = 0; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; - batch._glDrawBuffers(bufferCount, buffers); - } - - renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnOpaqueItems); - - args->_context->render((*args->_batch)); - args->_batch = nullptr; - } -} - - -template <> void render::jobRun(const DrawTransparent& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("DrawTransparent"); - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); - - // render transparents - auto& scene = sceneContext->_scene; - auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape()); - auto& renderDetails = renderContext->args->_details; - - ItemIDsBounds inItems; - inItems.reserve(items.size()); - for (auto id : items) { - inItems.emplace_back(id); - } - ItemIDsBounds& renderedItems = inItems; - - renderContext->_numFeedTransparentItems = renderedItems.size(); - - ItemIDsBounds culledItems; - culledItems.reserve(inItems.size()); - if (renderContext->_cullTransparent) { - renderDetails.pointTo(RenderDetails::TRANSLUCENT_ITEM); - cullItems(sceneContext, renderContext, inItems, culledItems); - renderDetails.pointTo(RenderDetails::OTHER_ITEM); - renderedItems = culledItems; - } - - renderContext->_numDrawnTransparentItems = renderedItems.size(); - - ItemIDsBounds sortedItems; - sortedItems.reserve(culledItems.size()); - if (renderContext->_sortTransparent) { - depthSortItems(sceneContext, renderContext, false, renderedItems, sortedItems); // Sort Back to front transparent items! - renderedItems = sortedItems; - } - - if (renderContext->_renderTransparent) { - RenderArgs* args = renderContext->args; - gpu::Batch batch; - args->_batch = &batch; - - glm::mat4 projMat; - Transform viewMat; - args->_viewFrustum->evalProjectionMatrix(projMat); - args->_viewFrustum->evalViewTransform(viewMat); - if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { - viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); - } - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - - const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; - const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f; - - // render translucent meshes afterwards - { - GLenum buffers[2]; - int bufferCount = 0; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; - batch._glDrawBuffers(bufferCount, buffers); - args->_alphaThreshold = MOSTLY_OPAQUE_THRESHOLD; - } - - renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnTransparentItems); - - { - GLenum buffers[3]; - int bufferCount = 0; - buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; - batch._glDrawBuffers(bufferCount, buffers); - args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD; - } - - - renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnTransparentItems); - - args->_context->render((*args->_batch)); - args->_batch = nullptr; - } -} - -template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("DrawLight"); +void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { assert(renderContext->args); assert(renderContext->args->_viewFrustum); @@ -398,7 +270,8 @@ template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& ItemIDsBounds inItems; inItems.reserve(items.size()); for (auto id : items) { - inItems.emplace_back(id); + auto item = scene->getItem(id); + inItems.emplace_back(ItemIDAndBounds(id, item.getBound())); } ItemIDsBounds culledItems; @@ -413,8 +286,7 @@ template <> void render::jobRun(const DrawLight& job, const SceneContextPointer& args->_batch = nullptr; } -template <> void render::jobRun(const DrawBackground& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("DrawBackground"); +void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { assert(renderContext->args); assert(renderContext->args->_viewFrustum); @@ -450,53 +322,6 @@ template <> void render::jobRun(const DrawBackground& job, const SceneContextPoi args->_context->syncCache(); } -template <> void render::jobRun(const DrawPostLayered& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("DrawPostLayered"); - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); - - // render backgrounds - auto& scene = sceneContext->_scene; - auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape().withLayered()); - - - ItemIDsBounds inItems; - inItems.reserve(items.size()); - for (auto id : items) { - auto& item = scene->getItem(id); - if (item.getKey().isVisible() && (item.getLayer() > 0)) { - inItems.emplace_back(id); - } - } - if (inItems.empty()) { - return; - } - - RenderArgs* args = renderContext->args; - gpu::Batch batch; - args->_batch = &batch; - - glm::mat4 projMat; - Transform viewMat; - args->_viewFrustum->evalProjectionMatrix(projMat); - args->_viewFrustum->evalViewTransform(viewMat); - if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { - viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); - } - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - - batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0); - - renderItems(sceneContext, renderContext, inItems); - args->_context->render((*args->_batch)); - args->_batch = nullptr; - - // Force the context sync - args->_context->syncCache(); -} - - void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) { // Insert the itemID in every bucket where it filters true for (auto& bucket : (*this)) { diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 0052c314c0..8a4d424005 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -13,42 +13,173 @@ #define hifi_render_Task_h #include "Engine.h" +#include "gpu/Batch.h" +#include + namespace render { -template void jobRun(const T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { } +template void jobRun(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + jobModel.run(sceneContext, renderContext); +} +template void jobRunI(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input) { + jobModel.run(sceneContext, renderContext, input); +} +template void jobRunO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, O& output) { + jobModel.run(sceneContext, renderContext, output); +} +template void jobRunIO(T& jobModel, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const I& input, O& output) { + jobModel.run(sceneContext, renderContext, input, output); +} class Job { public: - template - Job(T data) : _concept(new Model(data)) {} + // Varying represent a varying piece of data + class Varying { + public: + + Varying(const Varying& var): _concept(var._concept) {} + + Varying() {} + template + Varying(const T& data) : _concept(new Job::Varying::Model(data)) {} + + // Access the _data contained win the concept explicitely + template T& edit() { return (static_cast*> (_concept.get())->_data); } + template const T& get() const { return (static_cast*> (_concept.get())->_data); } + + protected: + friend class Job; + + std::vector> _consumerJobs; + + void addJobConsumer(const std::shared_ptr& job) { + _consumerJobs.push_back(job); + } + + class Concept { + public: + virtual ~Concept() = default; + }; + template class Model : public Concept { + public: + typedef T Data; + Data _data; + Model(const Model& source): _data(source.data) {} + Model(const Data& data): _data(data) {} + virtual ~Model() {} + }; + + std::shared_ptr _concept; + }; + Job(const Job& other) : _concept(other._concept) {} ~Job(); - virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - if (_concept) { - _concept->run(sceneContext, renderContext); - } + const std::string& getName() const { return _concept->getName(); } + const Varying getInput() const { return _concept->getInput(); } + const Varying getOutput() const { return _concept->getOutput(); } + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + PerformanceTimer perfTimer(getName().c_str()); + PROFILE_RANGE(getName().c_str()); + _concept->run(sceneContext, renderContext); } protected: +public: + class Concept { + std::string _name; public: + Concept() : _name() {} + Concept(const std::string& name) : _name(name) {} virtual ~Concept() = default; + + void setName(const std::string& name) { _name = name; } + const std::string& getName() const { return _name; } + + virtual const Varying getInput() const { return Varying(); } + virtual const Varying getOutput() const { return Varying(); } virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0; }; + Job(Concept* concept) : _concept(concept) {} + +public: template class Model : public Concept { public: typedef T Data; - + Data _data; + + Model() {} + Model(const std::string& name): Concept(name) {} Model(Data data): _data(data) {} + Model(Data data, const std::string& name): Concept(name), _data(data) {} void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRun(_data, sceneContext, renderContext); } }; + template class ModelI : public Concept { + public: + typedef T Data; + typedef I Input; + + Data _data; + Varying _input; + + const Varying getInput() const { return _input; } + + ModelI(const std::string& name, const Varying& input): Concept(name), _input(input) {} + ModelI(const std::string& name, Data data): Concept(name), _data(data) {} + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRunI(_data, sceneContext, renderContext, _input.get()); } + }; + + template class ModelO : public Concept { + public: + typedef T Data; + typedef O Output; + + Data _data; + Varying _output; + + const Varying getOutput() const { return _output; } + + ModelO(const std::string& name): Concept(name), _output(Output()) { + + } + + ModelO(const std::string& name, Data data): Concept(name), _data(data), _output(Output()) {} + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + jobRunO(_data, sceneContext, renderContext, _output.edit()); + } + }; + + template class ModelIO : public Concept { + public: + typedef T Data; + typedef I Input; + typedef O Output; + + Data _data; + Varying _input; + Varying _output; + + const Varying getInput() const { return _input; } + const Varying getOutput() const { return _output; } + + ModelIO(const std::string& name, const Varying& input, Data data = Data()): Concept(name), _data(data), _input(input), _output(Output()) {} + ModelIO(const std::string& name, Data data, Output output): Concept(name), _data(data), _output(output) {} + + void setInput(const Varying& input) { _input = input; } + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRunIO(_data, sceneContext, renderContext, _input.get(), _output.edit()); } + }; + std::shared_ptr _concept; }; @@ -62,43 +193,59 @@ void depthSortItems(const SceneContextPointer& sceneContext, const RenderContext void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); - -void materialSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); - - -class DrawOpaque { +class FetchItems { public: + typedef std::function ProbeNumItems; + FetchItems(const ProbeNumItems& probe): _probeNumItems(probe) {} + FetchItems(const ItemFilter& filter, const ProbeNumItems& probe): _filter(filter), _probeNumItems(probe) {} + + ItemFilter _filter = ItemFilter::Builder::opaqueShape().withoutLayered(); + ProbeNumItems _probeNumItems; + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems); + + typedef Job::ModelO JobModel; }; -template <> void jobRun(const DrawOpaque& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); - -class DrawTransparent { +class CullItems { public: + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); + + typedef Job::ModelIO JobModel; +}; + +class DepthSortItems { +public: + bool _frontToBack = true; + + DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {} + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems); + + typedef Job::ModelIO JobModel; }; -template <> void jobRun(const DrawTransparent& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); class DrawLight { public: + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); + + typedef Job::Model JobModel; }; -template <> void jobRun(const DrawLight& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); class DrawBackground { public: + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); + + typedef Job::Model JobModel; }; -template <> void jobRun(const DrawBackground& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); - - -class DrawPostLayered { -public: -}; -template <> void jobRun(const DrawPostLayered& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); - - class ResetGLState { public: + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); + + typedef Job::Model JobModel; }; -template <> void jobRun(const ResetGLState& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); + class DrawSceneTask : public Task { @@ -126,6 +273,7 @@ public: // standard builders allocating the main buckets void allocateStandardMaterialBuckets(); }; +void materialSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); } diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 121d6458e9..054f7e5ce4 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -45,6 +45,10 @@ public: int _numDrawnTransparentItems = 0; int _maxDrawnTransparentItems = -1; + int _numFeedOverlay3DItems = 0; + int _numDrawnOverlay3DItems = 0; + int _maxDrawnOverlay3DItems = -1; + RenderContext() {} }; typedef std::shared_ptr RenderContextPointer; diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 679ec1180f..debba309c5 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -159,4 +159,6 @@ void SceneScriptingInterface::clearEngineCounters() { _numDrawnOpaqueItems = 0; _numFeedTransparentItems = 0; _numDrawnTransparentItems = 0; + _numFeedOverlay3DItems = 0; + _numDrawnOverlay3DItems = 0; } diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 543f55a971..8359aa58fa 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -90,17 +90,22 @@ public: Q_INVOKABLE int getEngineNumDrawnOpaqueItems() { return _numDrawnOpaqueItems; } void setEngineDrawnTransparentItems(int count) { _numDrawnTransparentItems = count; } Q_INVOKABLE int getEngineNumDrawnTransparentItems() { return _numDrawnTransparentItems; } + void setEngineDrawnOverlay3DItems(int count) { _numDrawnOverlay3DItems = count; } + Q_INVOKABLE int getEngineNumDrawnOverlay3DItems() { return _numDrawnOverlay3DItems; } void setEngineFeedOpaqueItems(int count) { _numFeedOpaqueItems = count; } Q_INVOKABLE int getEngineNumFeedOpaqueItems() { return _numFeedOpaqueItems; } void setEngineFeedTransparentItems(int count) { _numFeedTransparentItems = count; } Q_INVOKABLE int getEngineNumFeedTransparentItems() { return _numFeedTransparentItems; } + void setEngineFeedOverlay3DItems(int count) { _numFeedOverlay3DItems = count; } + Q_INVOKABLE int getEngineNumFeedOverlay3DItems() { return _numFeedOverlay3DItems; } Q_INVOKABLE void setEngineMaxDrawnOpaqueItems(int count) { _maxDrawnOpaqueItems = count; } Q_INVOKABLE int getEngineMaxDrawnOpaqueItems() { return _maxDrawnOpaqueItems; } Q_INVOKABLE void setEngineMaxDrawnTransparentItems(int count) { _maxDrawnTransparentItems = count; } Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _maxDrawnTransparentItems; } - + Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; } + Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; } signals: void shouldRenderAvatarsChanged(bool shouldRenderAvatars); void shouldRenderEntitiesChanged(bool shouldRenderEntities); @@ -124,9 +129,12 @@ protected: int _numDrawnOpaqueItems = 0; int _numFeedTransparentItems = 0; int _numDrawnTransparentItems = 0; + int _numFeedOverlay3DItems = 0; + int _numDrawnOverlay3DItems = 0; int _maxDrawnOpaqueItems = -1; int _maxDrawnTransparentItems = -1; + int _maxDrawnOverlay3DItems = -1; };