From a1fe908380642b73c1601f764943e5a235376def Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 17 Jan 2017 12:56:56 +1300 Subject: [PATCH 01/20] Remove a lingering line of old code --- scripts/system/html/js/marketplacesInject.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 0944c4113e..d5f0f4cb06 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -148,7 +148,6 @@ if (!canWriteAssets) { console.log("ERROR: Clara.io FBX: File download cancelled because no permissions to write to Asset Server"); EventBridge.emitWebEvent(WARN_USER_NO_PERMISSIONS); - event.stopPropagation(); return; } From c9fd650e70939bfe62fea6323f16d986519d999c Mon Sep 17 00:00:00 2001 From: humbletim Date: Mon, 16 Jan 2017 19:37:31 -0500 Subject: [PATCH 02/20] update to support click/far-click toggling and userData.disabled setting --- .../tutorials/entity_scripts/ambientSound.js | 330 +++++++++++++++--- 1 file changed, 282 insertions(+), 48 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 620b371400..64adcf379a 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -1,55 +1,70 @@ // ambientSound.js // // This entity script will allow you to create an ambient sound that loops when a person is within a given -// range of this entity. Great way to add one or more ambisonic soundfields to your environment. +// range of this entity. Great way to add one or more ambisonic soundfields to your environment. // -// In the userData section for the entity, add/edit three values: -// userData.soundURL should be a string giving the URL to the sound file. Defaults to 100 meters if not set. +// In the userData section for the entity, add/edit three values: +// userData.soundURL should be a string giving the URL to the sound file. Defaults to 100 meters if not set. // userData.range should be an integer for the max distance away from the entity where the sound will be audible. -// userData.volume is the max volume at which the clip should play. Defaults to 1.0 full volume) +// userData.maxVolume is the max volume at which the clip should play. Defaults to 1.0 full volume. +// userData.disabled is an optionanl boolean flag which can be used to disable the ambient sound. Defaults to false. +// +// The rotation of the entity is copied to the ambisonic field, so by rotating the entity you will rotate the +// direction in-which a certain sound comes from. // -// The rotation of the entity is copied to the ambisonic field, so by rotating the entity you will rotate the -// direction in-which a certain sound comes from. -// // Remember that the entity has to be visible to the user for the sound to play at all, so make sure the entity is -// large enough to be loaded at the range you set, particularly for large ranges. -// +// large enough to be loaded at the range you set, particularly for large ranges. +// // 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 // -(function(){ +(function(){ + var VERSION = "0.0.1"; // This sample clip and range will be used if you don't add userData to the entity (see above) var DEFAULT_RANGE = 100; var DEFAULT_URL = "http://hifi-content.s3.amazonaws.com/ken/samples/forest_ambiX.wav"; var DEFAULT_VOLUME = 1.0; var soundURL = ""; + var soundName = ""; + var startTime; + var soundOptions = { + loop: true, + localOnly: true, + //ignorePenumbra: true, + }; var range = DEFAULT_RANGE; var maxVolume = DEFAULT_VOLUME; + var disabled = false; var UPDATE_INTERVAL_MSECS = 100; var rotation; var entity; var ambientSound; var center; - var soundPlaying = false; + var soundPlaying; var checkTimer = false; var _this; - var WANT_COLOR_CHANGE = false; var COLOR_OFF = { red: 128, green: 128, blue: 128 }; var COLOR_ON = { red: 255, green: 0, blue: 0 }; - var WANT_DEBUG = false; + var WANT_DEBUG = true; function debugPrint(string) { if (WANT_DEBUG) { - print(string); + print("ambientSound | " + string); } } + var WANT_DEBUG_BROADCASTS = "ambientSound.js"; + var WANT_DEBUG_OVERLAY = false; + var LINEHEIGHT = 0.1; + // Optionally enable debug overlays using a Settings value + WANT_DEBUG_OVERLAY = WANT_DEBUG_OVERLAY || /ambientSound/.test(Settings.getValue("WANT_DEBUG_OVERLAY")); + this.updateSettings = function() { // Check user data on the entity for any changes var oldSoundURL = soundURL; @@ -58,81 +73,300 @@ var data = JSON.parse(props.userData); if (data.soundURL && !(soundURL === data.soundURL)) { soundURL = data.soundURL; - debugPrint("Read ambient sound URL: " + soundURL); - } else if (!data.soundURL) { - soundURL = DEFAULT_URL; + soundName = (soundURL||"").split("/").pop(); // just filename part + debugPrint("Read ambient sound URL: " + soundURL); } if (data.range && !(range === data.range)) { range = data.range; debugPrint("Read ambient sound range: " + range); } - if (data.volume && !(maxVolume === data.volume)) { - maxVolume = data.volume; + // Check known aliases for the "volume" setting (which allows for inplace upgrade of existing marketplace entities) + data.maxVolume = data.maxVolume || data.soundVolume || data.volume; + if (data.maxVolume && !(maxVolume === data.maxVolume)) { + maxVolume = data.maxVolume; debugPrint("Read ambient sound volume: " + maxVolume); } + if ("disabled" in data && !(disabled === data.disabled)) { + disabled = data.disabled; + debugPrint("Read ambient disabled state: " + disabled); + if (disabled) { + this.cleanup(); + debugState("disabled"); + return; + } + } + /*if ("loop" in data && !(soundOptions.loop === data.loop)) { + soundOptions.loop = data.loop; + debugPrint("Read ambient loop state: " + soundOptions.loop); + }*/ } if (!(soundURL === oldSoundURL) || (soundURL === "")) { - debugPrint("Loading ambient sound into cache"); - ambientSound = SoundCache.getSound(soundURL); + if (soundURL) { + debugState("downloading", "Loading ambient sound into cache"); + // Use prefetch to detect URL loading errors + var resource = SoundCache.prefetch(soundURL); + function onStateChanged() { + if (resource.state === Resource.State.FINISHED) { + resource.stateChanged.disconnect(onStateChanged); + ambientSound = SoundCache.getSound(soundURL); + debugState("idle"); + } else if (resource.state === Resource.State.FAILED) { + resource.stateChanged.disconnect(onStateChanged); + debugPrint("Failed to download ambient sound: " + soundURL); + debugState("error"); + } + debugPrint("onStateChanged: " + JSON.stringify({ + sound: soundName, + state: resource.state, + stateName: Object.keys(Resource.State).filter(function(key) { + return Resource.State[key] === resource.state; + }) + })); + } + resource.stateChanged.connect(onStateChanged); + onStateChanged(resource.state); + } if (soundPlaying && soundPlaying.playing) { + debugPrint("URL changed, stopping current ambient sound"); soundPlaying.stop(); soundPlaying = false; - if (WANT_COLOR_CHANGE) { - Entities.editEntity(entity, { color: COLOR_OFF }); - } - debugPrint("Restarting ambient sound"); } - } + } } - this.preload = function(entityID) { + this.clickDownOnEntity = function(entityID, mouseEvent) { + print("click"); + if (mouseEvent.isPrimaryButton) { + this._toggle("primary click"); + } + }; + + this.startFarTrigger = function() { + this._toggle("far click"); + }; + + this._toggle = function(hint) { + // Toggle between ON/OFF state, but only if not in edit mode + if (Settings.getValue("io.highfidelity.isEditting")) { + return; + } + var props = Entities.getEntityProperties(entity, [ "userData", "age", "scriptTimestamp" ]); + var data = JSON.parse(props.userData); + data.disabled = !data.disabled; + + debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundName + ")"); + var oldState = _debugState; + + if (WANT_DEBUG_BROADCASTS) { + Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: hint, scriptTimestamp: props.scriptTimestamp, oldState: oldState, newState: _debugState, age: props.age })); + } + + this.cleanup(); + + // Save the userData and bump scriptTimestamp, which causes all nearby listeners to apply the state change + Entities.editEntity(entity, { + userData: JSON.stringify(data), + scriptTimestamp: Math.round(props.age * 1000) + }); + //this._updateColor(data.disabled); + }; + + this._updateColor = function(disabled) { + // Update Shape or Text Entity color based on ON/OFF status + var props = Entities.getEntityProperties(entity, [ "color", "textColor" ]); + var targetColor = disabled ? COLOR_OFF : COLOR_ON; + var currentColor = props.textColor || props.color; + var newProps = props.textColor ? { textColor: targetColor } : { color: targetColor }; + + if (currentColor.red !== targetColor.red || + currentColor.green !== targetColor.green || + currentColor.blue !== targetColor.blue) { + Entities.editEntity(entity, newProps); + } + }; + + this.preload = function(entityID) { // Load the sound and range from the entity userData fields, and note the position of the entity. - debugPrint("Ambient sound preload"); + debugPrint("Ambient sound preload " + VERSION); entity = entityID; _this = this; - checkTimer = Script.setInterval(this.maybeUpdate, UPDATE_INTERVAL_MSECS); - }; + + if (WANT_DEBUG_OVERLAY) { + _createDebugOverlays(); + } + + var props = Entities.getEntityProperties(entity, [ "userData" ]); + if (props.userData) { + var data = JSON.parse(props.userData); + this._updateColor(data.disabled); + if (data.disabled) { + _this.maybeUpdate(); + return; + } + } + + checkTimer = Script.setInterval(_this.maybeUpdate, UPDATE_INTERVAL_MSECS); + }; this.maybeUpdate = function() { // Every UPDATE_INTERVAL_MSECS, update the volume of the ambient sound based on distance from my avatar _this.updateSettings(); var HYSTERESIS_FRACTION = 0.1; var props = Entities.getEntityProperties(entity, [ "position", "rotation" ]); + if (!props.position) { + // FIXME: this mysterious state has been happening while testing + // and might indicate a bug where an Entity can become unreachable without `unload` having been called.. + print("FIXME: ambientSound.js -- expected Entity unavailable!") + if (WANT_DEBUG_BROADCASTS) { + Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "FIXME: maybeUpdate", oldState: _debugState })); + } + return _this.cleanup(); + } center = props.position; rotation = props.rotation; var distance = Vec3.length(Vec3.subtract(MyAvatar.position, center)); if (distance <= range) { var volume = (1.0 - distance / range) * maxVolume; - if (!soundPlaying && ambientSound.downloaded) { - soundPlaying = Audio.playSound(ambientSound, { loop: true, - localOnly: true, - orientation: rotation, - volume: volume }); - debugPrint("Starting ambient sound, volume: " + volume); - if (WANT_COLOR_CHANGE) { - Entities.editEntity(entity, { color: COLOR_ON }); - } - + soundOptions.orientation = Quat.rotation; + soundOptions.volume = volume; + if (!soundPlaying && ambientSound && ambientSound.downloaded) { + debugState("playing", "Starting ambient sound: " + soundName + " (duration: " + ambientSound.duration + ")"); + soundPlaying = Audio.playSound(ambientSound, soundOptions); } else if (soundPlaying && soundPlaying.playing) { - soundPlaying.setOptions( { volume: volume, orientation: rotation } ); + soundPlaying.setOptions(soundOptions); } - } else if (soundPlaying && soundPlaying.playing && (distance > range * HYSTERESIS_FRACTION)) { soundPlaying.stop(); soundPlaying = false; - Entities.editEntity(entity, { color: { red: 128, green: 128, blue: 128 }}); - debugPrint("Out of range, stopping ambient sound"); + debugState("idle", "Out of range, stopping ambient sound: " + soundName); + } + if (WANT_DEBUG_OVERLAY) { + updateDebugOverlay(distance); } } - this.unload = function(entityID) { - debugPrint("Ambient sound unload"); + this.unload = function(entityID) { + debugPrint("Ambient sound unload "); + if (WANT_DEBUG_BROADCASTS) { + var offset = ambientSound && (new Date - startTime)/1000 % ambientSound.duration; + Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "unload", oldState: _debugState, offset: offset })); + } + if (WANT_DEBUG_OVERLAY) { + _removeDebugOverlays(); + } + this.cleanup(); + }; + + this.cleanup = function() { if (checkTimer) { Script.clearInterval(checkTimer); + checkTimer = false; } if (soundPlaying && soundPlaying.playing) { soundPlaying.stop(); + soundPlaying = false; } - }; + }; -}) + // Visual debugging overlay (to see set WANT_DEBUG_OVERLAY = true) + + var DEBUG_COLORS = { + //preload: { red: 0, green: 80, blue: 80 }, + disabled: { red: 0, green: 0, blue: 0, alpha: 0.0 }, + downloading: { red: 255, green: 255, blue: 0 }, + error: { red: 255, green: 0, blue: 0 }, + playing: { red: 0, green: 200, blue: 0 }, + idle: { red: 0, green: 100, blue: 0 } + }; + var _debugOverlay; + var _debugState = ""; + function debugState(state, message) { + if (state === "playing") { + startTime = new Date; + } + _debugState = state; + if (message) { + debugPrint(message); + } + updateDebugOverlay(); + if (WANT_DEBUG_BROADCASTS) { + // Broadcast state changes to an implicit entity channel, making multi-user scenarios easier to verify from a single console + Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, state: state })); + } + } + + function updateDebugOverlay(distance) { + var props = Entities.getEntityProperties(entity, [ "name", "dimensions" ]); + if (!props.dimensions) { + return print("ambientSound.js: updateDebugOverlay -- entity no longer available " + entity); + } + var options = soundPlaying && soundPlaying.options; + if (options) { + var offset = soundPlaying.playing && ambientSound && (new Date - startTime)/1000 % ambientSound.duration; + var deg = Quat.safeEulerAngles(options.orientation); + var orientation = [ deg.x, deg.y, deg.z].map(Math.round).join(", "); + var volume = options.volume; + } + var info = { + //loudness: soundPlaying.loudness && soundPlaying.loudness.toFixed(4) || undefined, + offset: offset && ("00"+offset.toFixed(1)).substr(-4)+"s" || undefined, + orientation: orientation, + injector: soundPlaying && soundPlaying.playing && "playing", + resource: ambientSound && ambientSound.downloaded && "ready (" + ambientSound.duration.toFixed(1) + "s)", + name: props.name || undefined, + uuid: entity.split(/\W/)[1], // extracts just the first part of the UUID + sound: soundName, + volume: Math.max(0,volume||0).toFixed(2) + " / " + maxVolume.toFixed(2), + distance: (distance||0).toFixed(1) + "m / " + range.toFixed(1) + "m", + state: _debugState.toUpperCase(), + }; + + // Pretty print key/value pairs, excluding any undefined values + var outputText = Object.keys(info).filter(function(key) { + return info[key] !== undefined; + }).map(function(key) { + return key + ": " + info[key]; + }).join("\n"); + + // Calculate a local position for displaying info just above the Entity + var textSize = Overlays.textSize(_debugOverlay, outputText); + var size = { + x: textSize.width + LINEHEIGHT, + y: textSize.height + LINEHEIGHT + }; + var pos = { x: 0, y: props.dimensions.y + size.y/2, z: 0 }; + + var backgroundColor = DEBUG_COLORS[_debugState]; + var backgroundAlpha = backgroundColor ? backgroundColor.alpha : 0.6; + Overlays.editOverlay(_debugOverlay, { + visible: true, + backgroundColor: backgroundColor, + backgroundAlpha: backgroundAlpha, + text: outputText, + localPosition: pos, + size: size, + }); + } + + function _removeDebugOverlays() { + if (_debugOverlay) { + Overlays.deleteOverlay(_debugOverlay); + _debugOverlay = 0; + } + } + + function _createDebugOverlays() { + _debugOverlay = Overlays.addOverlay("text3d", { + visible: true, + lineHeight: LINEHEIGHT, + leftMargin: LINEHEIGHT/2, + topMargin: LINEHEIGHT/2, + localPosition: Vec3.ZERO, + parentID: entity, + ignoreRayIntersection: true, + isFacingAvatar: true, + textAlpha: 0.6, + //drawInFront: true, + }); + } +}) From 827aa68d3f609146a59fd7edf20c6d4a906e6e6f Mon Sep 17 00:00:00 2001 From: humbletim Date: Mon, 16 Jan 2017 19:50:25 -0500 Subject: [PATCH 03/20] cleanup pass --- .../tutorials/entity_scripts/ambientSound.js | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 64adcf379a..3b75ed6720 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -45,25 +45,25 @@ var entity; var ambientSound; var center; - var soundPlaying; + var soundPlaying = false; var checkTimer = false; var _this; var COLOR_OFF = { red: 128, green: 128, blue: 128 }; var COLOR_ON = { red: 255, green: 0, blue: 0 }; - var WANT_DEBUG = true; + var WANT_DEBUG = false; function debugPrint(string) { if (WANT_DEBUG) { print("ambientSound | " + string); } } - var WANT_DEBUG_BROADCASTS = "ambientSound.js"; var WANT_DEBUG_OVERLAY = false; var LINEHEIGHT = 0.1; // Optionally enable debug overlays using a Settings value WANT_DEBUG_OVERLAY = WANT_DEBUG_OVERLAY || /ambientSound/.test(Settings.getValue("WANT_DEBUG_OVERLAY")); + var WANT_DEBUG_BROADCASTS = WANT_DEBUG_OVERLAY && "ambientSound.js"; this.updateSettings = function() { // Check user data on the entity for any changes @@ -95,10 +95,6 @@ return; } } - /*if ("loop" in data && !(soundOptions.loop === data.loop)) { - soundOptions.loop = data.loop; - debugPrint("Read ambient loop state: " + soundOptions.loop); - }*/ } if (!(soundURL === oldSoundURL) || (soundURL === "")) { if (soundURL) { @@ -135,7 +131,6 @@ } this.clickDownOnEntity = function(entityID, mouseEvent) { - print("click"); if (mouseEvent.isPrimaryButton) { this._toggle("primary click"); } @@ -158,7 +153,7 @@ var oldState = _debugState; if (WANT_DEBUG_BROADCASTS) { - Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: hint, scriptTimestamp: props.scriptTimestamp, oldState: oldState, newState: _debugState, age: props.age })); + Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: hint, scriptTimestamp: props.scriptTimestamp, oldState: oldState, newState: _debugState, age: props.age })); } this.cleanup(); @@ -218,7 +213,7 @@ // and might indicate a bug where an Entity can become unreachable without `unload` having been called.. print("FIXME: ambientSound.js -- expected Entity unavailable!") if (WANT_DEBUG_BROADCASTS) { - Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "FIXME: maybeUpdate", oldState: _debugState })); + Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "FIXME: maybeUpdate", oldState: _debugState })); } return _this.cleanup(); } @@ -227,7 +222,7 @@ var distance = Vec3.length(Vec3.subtract(MyAvatar.position, center)); if (distance <= range) { var volume = (1.0 - distance / range) * maxVolume; - soundOptions.orientation = Quat.rotation; + soundOptions.orientation = rotation; soundOptions.volume = volume; if (!soundPlaying && ambientSound && ambientSound.downloaded) { debugState("playing", "Starting ambient sound: " + soundName + " (duration: " + ambientSound.duration + ")"); @@ -249,7 +244,7 @@ debugPrint("Ambient sound unload "); if (WANT_DEBUG_BROADCASTS) { var offset = ambientSound && (new Date - startTime)/1000 % ambientSound.duration; - Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "unload", oldState: _debugState, offset: offset })); + Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "unload", oldState: _debugState, offset: offset })); } if (WANT_DEBUG_OVERLAY) { _removeDebugOverlays(); @@ -290,8 +285,8 @@ } updateDebugOverlay(); if (WANT_DEBUG_BROADCASTS) { - // Broadcast state changes to an implicit entity channel, making multi-user scenarios easier to verify from a single console - Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, state: state })); + // Broadcast state changes to make multi-user scenarios easier to verify from a single console + Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, state: state })); } } From 83d1c3ad01d630e764ddcd6b31b31d3aaf884ec3 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 16 Jan 2017 17:47:58 -0800 Subject: [PATCH 04/20] Adding support for the meta rendering --- interface/src/avatar/Avatar.cpp | 11 +++- interface/src/avatar/Avatar.h | 1 + .../src/RenderableEntityItem.cpp | 28 +++++--- .../src/RenderableEntityItem.h | 8 ++- .../src/RenderableModelEntityItem.cpp | 15 ++++- .../src/RenderableModelEntityItem.h | 1 + libraries/render-utils/src/Model.cpp | 7 ++ libraries/render-utils/src/Model.h | 3 + .../render-utils/src/RenderDeferredTask.cpp | 17 ++--- .../render-utils/src/RenderForwardTask.cpp | 16 +++-- libraries/render/src/render/Item.h | 64 +++++++++++++------ .../src/render/RenderFetchCullSortTask.cpp | 22 +++++-- .../src/render/RenderFetchCullSortTask.h | 16 ++++- libraries/render/src/render/Scene.cpp | 2 +- libraries/render/src/render/Scene.h | 5 +- 15 files changed, 156 insertions(+), 60 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 81eee6b3a7..d86f82a455 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -62,7 +62,7 @@ const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f); namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) { - return ItemKey::Builder::opaqueShape(); + return ItemKey::Builder::opaqueShape().withTypeMeta(); } template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) { return static_pointer_cast(avatar)->getBounds(); @@ -74,6 +74,15 @@ namespace render { avatarPtr->render(args, qApp->getCamera()->getPosition()); } } + template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems) { + auto avatarPtr = static_pointer_cast(avatar); + if (avatarPtr->getSkeletonModel()) { + auto metaSubItems = avatarPtr->getSkeletonModel()->fetchRenderItemIDs(); + subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end()); + return metaSubItems.size(); + } + return 0; + } } static uint64_t timeProcessingJoints = 0; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index d03a8e9a54..d370402865 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -32,6 +32,7 @@ namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar); template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar); template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args); + template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems); } static const float SCALING_RATIO = .05f; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 359b050803..be9ef08c0b 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -15,21 +15,21 @@ namespace render { template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload) { - if (payload && payload->entity) { - if (payload->entity->getType() == EntityTypes::Light) { - return ItemKey::Builder::light(); + if (payload && payload->_entity) { + if (payload->_entity->getType() == EntityTypes::Light) { + return ItemKey::Builder::light().withTypeMeta(); } - if (payload && payload->entity->isTransparent()) { - return ItemKey::Builder::transparentShape(); + if (payload && payload->_entity->isTransparent()) { + return ItemKey::Builder::transparentShape().withTypeMeta(); } } - return ItemKey::Builder::opaqueShape(); + return ItemKey::Builder::opaqueShape().withTypeMeta(); } template <> const Item::Bound payloadGetBound(const RenderableEntityItemProxy::Pointer& payload) { - if (payload && payload->entity) { + if (payload && payload->_entity) { bool success; - auto result = payload->entity->getAABox(success); + auto result = payload->_entity->getAABox(success); if (!success) { return render::Item::Bound(); } @@ -39,11 +39,19 @@ namespace render { } template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args) { if (args) { - if (payload && payload->entity && payload->entity->getVisible()) { - payload->entity->render(args); + if (payload && payload->_entity && payload->_entity->getVisible()) { + payload->_entity->render(args); } } } + template <> uint32_t metaFetchMetaSubItems(const RenderableEntityItemProxy::Pointer& payload, ItemIDs& subItems) { + auto metaID = payload->_metaID; + if (Item::isValidID(metaID)) { + subItems.emplace_back(metaID); + return 1; + } + return 0; + } } void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status::Getters& statusGetters) { diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index ec65bab1c8..98271ddbbb 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -36,17 +36,19 @@ void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status: class RenderableEntityItemProxy { public: - RenderableEntityItemProxy(EntityItemPointer entity) : entity(entity) { } + RenderableEntityItemProxy(EntityItemPointer entity, render::ItemID metaID) : _entity(entity), _metaID(metaID) { } typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - EntityItemPointer entity; + EntityItemPointer _entity; + render::ItemID _metaID; }; namespace render { template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload); template <> const Item::Bound payloadGetBound(const RenderableEntityItemProxy::Pointer& payload); template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args); + template <> uint32_t metaFetchMetaSubItems(const RenderableEntityItemProxy::Pointer& payload, ItemIDs& subItems); } // Mixin class for implementing basic single item rendering @@ -55,7 +57,7 @@ public: bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { _myItem = scene->allocateID(); - auto renderData = std::make_shared(self); + auto renderData = std::make_shared(self, _myItem); auto renderPayload = std::make_shared(renderData); render::Item::Status::Getters statusGetters; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index b901db38e7..cf1bcafe7c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -194,7 +194,7 @@ public: namespace render { template <> const ItemKey payloadGetKey(const RenderableModelEntityItemMeta::Pointer& payload) { - return ItemKey::Builder::opaqueShape(); + return ItemKey::Builder::opaqueShape().withTypeMeta(); } template <> const Item::Bound payloadGetBound(const RenderableModelEntityItemMeta::Pointer& payload) { @@ -216,6 +216,15 @@ namespace render { } } } + template <> uint32_t metaFetchMetaSubItems(const RenderableModelEntityItemMeta::Pointer& payload, ItemIDs& subItems) { + auto modelEntity = std::static_pointer_cast(payload->entity); + if (modelEntity->hasModel()) { + auto metaSubItems = modelEntity->getModelNotSafe()->fetchRenderItemIDs(); + subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end()); + return (uint32_t) metaSubItems.size(); + } + return 0; + } } bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr scene, @@ -473,6 +482,10 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } } +ModelPointer RenderableModelEntityItem::getModelNotSafe() { + return _model; +} + ModelPointer RenderableModelEntityItem::getModel(QSharedPointer renderer) { if (!renderer) { return nullptr; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 93d48c6085..bac2118326 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -52,6 +52,7 @@ public: BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const override; ModelPointer getModel(QSharedPointer renderer); + ModelPointer getModelNotSafe(); virtual bool needsToCallUpdate() const override; virtual void update(const quint64& now) override; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 7c1a6e14d0..7c615c5414 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -673,6 +673,7 @@ bool Model::addToScene(std::shared_ptr scene, hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent(); verticesCount += renderItem.get()->getVerticesCount(); _modelMeshRenderItems.insert(item, renderPayload); + _modelMeshRenderItemIDs.emplace_back(item); } somethingAdded = !_modelMeshRenderItems.empty(); @@ -695,6 +696,7 @@ void Model::removeFromScene(std::shared_ptr scene, render::Pendin foreach (auto item, _modelMeshRenderItems.keys()) { pendingChanges.removeItem(item); } + _modelMeshRenderItemIDs.clear(); _modelMeshRenderItems.clear(); _modelMeshRenderItemsSet.clear(); @@ -1301,6 +1303,10 @@ AABox Model::getRenderableMeshBound() const { } } +const render::ItemIDs& Model::fetchRenderItemIDs() const { + return _modelMeshRenderItemIDs; +} + void Model::createRenderItemSet() { if (_collisionGeometry) { if (_collisionRenderItemsSet.empty()) { @@ -1479,6 +1485,7 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) { { Lock lock(_mutex); + _modelsRequiringBlends.insert(model); } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 55806b27e1..a11d6d511e 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -105,6 +105,7 @@ public: void setRenderItemsNeedUpdate() { _renderItemsNeedUpdate = true; } bool getRenderItemsNeedUpdate() { return _renderItemsNeedUpdate; } AABox getRenderableMeshBound() const; + const render::ItemIDs& fetchRenderItemIDs() const; bool maybeStartBlender(); @@ -389,6 +390,8 @@ protected: QSet> _modelMeshRenderItemsSet; QMap _modelMeshRenderItems; + render::ItemIDs _modelMeshRenderItemIDs; + bool _addedToScene { false }; // has been added to scene bool _needsFixupInScene { true }; // needs to be removed/re-added to scene bool _needsReload { true }; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index f8cd112007..8547c5adb0 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -53,14 +53,15 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { ShapePlumberPointer shapePlumber = std::make_shared(); initDeferredPipelines(*shapePlumber); - // Extract opaques / transparents / lights / overlays - const auto opaques = items[0]; - const auto transparents = items[1]; - const auto lights = items[2]; - const auto overlayOpaques = items[3]; - const auto overlayTransparents = items[4]; - const auto background = items[5]; - const auto spatialSelection = items[6]; + // Extract opaques / transparents / lights / metas / overlays / background + const auto opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; + const auto transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; + const auto lights = items[RenderFetchCullSortTask::LIGHT]; + const auto metas = items[RenderFetchCullSortTask::META]; + const auto overlayOpaques = items[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; + const auto overlayTransparents = items[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; + const auto background = items[RenderFetchCullSortTask::BACKGROUND]; + const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION]; // Prepare deferred, generate the shared Deferred Frame Transform const auto deferredFrameTransform = addJob("DeferredFrameTransform"); diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index c7a3433c96..7550d2326b 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -36,13 +36,15 @@ RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) { ShapePlumberPointer shapePlumber = std::make_shared(); initForwardPipelines(*shapePlumber); - // Extract opaques / transparents / lights / overlays - const auto opaques = items[0]; - const auto transparents = items[1]; - const auto lights = items[2]; - const auto overlayOpaques = items[3]; - const auto overlayTransparents = items[4]; - const auto background = items[5]; + // Extract opaques / transparents / lights / metas / overlays / background + const auto opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; + const auto transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; + const auto lights = items[RenderFetchCullSortTask::LIGHT]; + const auto metas = items[RenderFetchCullSortTask::META]; + const auto overlayOpaques = items[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE]; + const auto overlayTransparents = items[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE]; + const auto background = items[RenderFetchCullSortTask::BACKGROUND]; + const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION]; const auto framebuffer = addJob("PrepareFramebuffer"); diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 9a65b48021..27bc2b790a 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -38,6 +38,7 @@ public: enum FlagBit { TYPE_SHAPE = 0, // Item is a Shape TYPE_LIGHT, // Item is a Light + TYPE_META, // Item is a Meta: meanning it s used to represent a higher level object, potentially represented by other render items TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work... VIEW_SPACE, // Transformed in view space, and not in world space DYNAMIC, // Dynamic and bound will change unlike static item @@ -72,6 +73,7 @@ public: Builder& withTypeShape() { _flags.set(TYPE_SHAPE); return (*this); } Builder& withTypeLight() { _flags.set(TYPE_LIGHT); return (*this); } + Builder& withTypeMeta() { _flags.set(TYPE_META); return (*this); } Builder& withTransparent() { _flags.set(TRANSLUCENT); return (*this); } Builder& withViewSpace() { _flags.set(VIEW_SPACE); return (*this); } Builder& withDynamic() { _flags.set(DYNAMIC); return (*this); } @@ -91,6 +93,7 @@ public: bool isShape() const { return _flags[TYPE_SHAPE]; } bool isLight() const { return _flags[TYPE_LIGHT]; } + bool isMeta() const { return _flags[TYPE_META]; } bool isOpaque() const { return !_flags[TRANSLUCENT]; } bool isTransparent() const { return _flags[TRANSLUCENT]; } @@ -150,6 +153,7 @@ public: Builder& withTypeShape() { _value.set(ItemKey::TYPE_SHAPE); _mask.set(ItemKey::TYPE_SHAPE); return (*this); } Builder& withTypeLight() { _value.set(ItemKey::TYPE_LIGHT); _mask.set(ItemKey::TYPE_LIGHT); return (*this); } + Builder& withTypeMeta() { _value.set(ItemKey::TYPE_META); _mask.set(ItemKey::TYPE_META); return (*this); } Builder& withOpaque() { _value.reset(ItemKey::TRANSLUCENT); _mask.set(ItemKey::TRANSLUCENT); return (*this); } Builder& withTransparent() { _value.set(ItemKey::TRANSLUCENT); _mask.set(ItemKey::TRANSLUCENT); return (*this); } @@ -179,6 +183,7 @@ public: static Builder opaqueShape() { return Builder().withTypeShape().withOpaque().withWorldSpace(); } static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); } static Builder light() { return Builder().withTypeLight(); } + static Builder meta() { return Builder().withTypeMeta(); } static Builder background() { return Builder().withViewSpace().withLayered(); } static Builder opaqueShapeLayered() { return Builder().withTypeShape().withOpaque().withWorldSpace().withLayered(); } static Builder transparentShapeLayered() { return Builder().withTypeShape().withTransparent().withWorldSpace().withLayered(); } @@ -210,6 +215,25 @@ inline QDebug operator<<(QDebug debug, const ItemFilter& me) { using ItemID = uint32_t; using ItemCell = int32_t; +// A few typedefs for standard containers of ItemIDs +using ItemIDs = std::vector; +using ItemIDSet = std::set; + +// Handy type to just pass the ID and the bound of an item +class ItemBound { + public: + ItemBound(ItemID id) : id(id) { } + ItemBound(ItemID id, const AABox& bound) : id(id), bound(bound) { } + + ItemID id; + AABox bound; +}; + +// many Item Bounds in a vector +using ItemBounds = std::vector; + +// Item is the proxy to a bounded "object" in the scene +// An item is described by its Key class Item { public: typedef std::vector Vector; @@ -295,6 +319,8 @@ public: virtual const ShapeKey getShapeKey() const = 0; + virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const = 0; + ~PayloadInterface() {} // Status interface is local to the base class @@ -313,6 +339,9 @@ public: Item() {} ~Item() {} + // Item exists if it has a valid payload + bool exist() const { return (bool)(_payload); } + // Main scene / item managment interface reset/update/kill void resetPayload(const PayloadPointer& payload); void resetCell(ItemCell cell = INVALID_CELL, bool _small = false) { _cell = cell; _key.setSmaller(_small); } @@ -339,6 +368,9 @@ public: // Shape Type Interface const ShapeKey getShapeKey() const { return _payload->getShapeKey(); } + // Meta Type Interface + uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return _payload->fetchMetaSubItems(subItems); } + // Access the status const StatusPointer& getStatus() const { return _payload->getStatus(); } @@ -370,10 +402,7 @@ inline QDebug operator<<(QDebug debug, const Item& item) { return debug; } -// THe Payload class is the real Payload to be used -// THis allow anything to be turned into a Payload as long as the required interface functions are available -// When creating a new kind of payload from a new "stuff" class then you need to create specialized version for "stuff" -// of the Payload interface +// Item shared interface supported by the payload template const ItemKey payloadGetKey(const std::shared_ptr& payloadData) { return ItemKey(); } template const Item::Bound payloadGetBound(const std::shared_ptr& payloadData) { return Item::Bound(); } template int payloadGetLayer(const std::shared_ptr& payloadData) { return 0; } @@ -385,6 +414,14 @@ template void payloadRender(const std::shared_ptr& payloadData, Ren // implying that the shape will setup its own pipeline without the use of the ShapeKey. template const ShapeKey shapeGetShapeKey(const std::shared_ptr& payloadData) { return ShapeKey::Builder::ownPipeline(); } +// Meta Type Interface +// Meta items act as the grouping object for several sub items (typically shapes). +template uint32_t metaFetchMetaSubItems(const std::shared_ptr& payloadData, ItemIDs& subItems) { return 0; } + +// THe Payload class is the real Payload to be used +// THis allow anything to be turned into a Payload as long as the required interface functions are available +// When creating a new kind of payload from a new "stuff" class then you need to create specialized version for "stuff" +// of the Payload interface template class Payload : public Item::PayloadInterface { public: typedef std::shared_ptr DataPointer; @@ -403,6 +440,9 @@ public: // Shape Type interface virtual const ShapeKey getShapeKey() const override { return shapeGetShapeKey(_data); } + // Meta Type Interface + virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return metaFetchMetaSubItems(_data, subItems); } + protected: DataPointer _data; @@ -450,22 +490,6 @@ template <> const Item::Bound payloadGetBound(const FooPointer& foo) { typedef Item::PayloadPointer PayloadPointer; typedef std::vector< PayloadPointer > Payloads; -// A few typedefs for standard containers of ItemIDs -using ItemIDs = std::vector; -using ItemIDSet = std::set; - -// Handy type to just pass the ID and the bound of an item -class ItemBound { -public: - ItemBound(ItemID id) : id(id) { } - ItemBound(ItemID id, const AABox& bound) : id(id), bound(bound) { } - - ItemID id; - AABox bound; -}; -// many Item Bounds in a vector -using ItemBounds = std::vector; - // A map of items by ShapeKey to optimize rendering pipeline assignments using ShapeBounds = std::unordered_map; diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index 3195d8c5f8..69c415dffd 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -29,33 +29,41 @@ RenderFetchCullSortTask::RenderFetchCullSortTask(CullFunctor cullFunctor) { const auto nonspatialSelection = addJob("FetchOverlaySelection"); // Multi filter visible items into different buckets - const int NUM_FILTERS = 3; + const int NUM_SPATIAL_FILTERS = 4; + const int NUM_NON_SPATIAL_FILTERS = 3; const int OPAQUE_SHAPE_BUCKET = 0; const int TRANSPARENT_SHAPE_BUCKET = 1; const int LIGHT_BUCKET = 2; + const int META_BUCKET = 3; const int BACKGROUND_BUCKET = 2; - MultiFilterItem::ItemFilterArray spatialFilters = { { + MultiFilterItem::ItemFilterArray spatialFilters = { { ItemFilter::Builder::opaqueShape(), ItemFilter::Builder::transparentShape(), - ItemFilter::Builder::light() + ItemFilter::Builder::light(), + ItemFilter::Builder::meta() } }; - MultiFilterItem::ItemFilterArray nonspatialFilters = { { + MultiFilterItem::ItemFilterArray nonspatialFilters = { { ItemFilter::Builder::opaqueShape(), ItemFilter::Builder::transparentShape(), ItemFilter::Builder::background() } }; - const auto filteredSpatialBuckets = addJob>("FilterSceneSelection", culledSpatialSelection, spatialFilters).get::ItemBoundsArray>(); - const auto filteredNonspatialBuckets = addJob>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters).get::ItemBoundsArray>(); + const auto filteredSpatialBuckets = + addJob>("FilterSceneSelection", culledSpatialSelection, spatialFilters) + .get::ItemBoundsArray>(); + const auto filteredNonspatialBuckets = + addJob>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters) + .get::ItemBoundsArray>(); // Extract opaques / transparents / lights / overlays const auto opaques = addJob("DepthSortOpaque", filteredSpatialBuckets[OPAQUE_SHAPE_BUCKET]); const auto transparents = addJob("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto lights = filteredSpatialBuckets[LIGHT_BUCKET]; + const auto metas = filteredSpatialBuckets[META_BUCKET]; const auto overlayOpaques = addJob("DepthSortOverlayOpaque", filteredNonspatialBuckets[OPAQUE_SHAPE_BUCKET]); const auto overlayTransparents = addJob("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET]; setOutput(Output{{ - opaques, transparents, lights, overlayOpaques, overlayTransparents, background, spatialSelection }}); + opaques, transparents, lights, metas, overlayOpaques, overlayTransparents, background, spatialSelection }}); } diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index bea45247b0..1af74939c9 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -19,7 +19,21 @@ class RenderFetchCullSortTask : public render::Task { public: - using Output = std::array; + + enum Buckets { + OPAQUE_SHAPE = 0, + TRANSPARENT_SHAPE, + LIGHT, + META, + OVERLAY_OPAQUE_SHAPE, + OVERLAY_TRANSPARENT_SHAPE, + BACKGROUND, + SPATIAL_SELECTION, + + NUM_BUCKETS + }; + + using Output = std::array; using JobModel = ModelO; RenderFetchCullSortTask(render::CullFunctor cullFunctor); diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index 95fef3e9f0..076879ae25 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -58,7 +58,7 @@ ItemID Scene::allocateID() { return _IDAllocator.fetch_add(1); } -bool Scene::isAllocatedID(const ItemID& id) { +bool Scene::isAllocatedID(const ItemID& id) const { return Item::isValidID(id) && (id < _numAllocatedItems.load()); } diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 13475d0556..f2f8403dc9 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -61,7 +61,7 @@ public: ItemID allocateID(); // Check that the ID is valid and allocated for this scene, this a threadsafe call - bool isAllocatedID(const ItemID& id); + bool isAllocatedID(const ItemID& id) const; // THis is the total number of allocated items, this a threadsafe call size_t getNumItems() const { return _numAllocatedItems.load(); } @@ -78,6 +78,9 @@ public: // WARNING, There is No check on the validity of the ID, so this could return a bad Item const Item& getItem(const ItemID& id) const { return _items[id]; } + // Same as getItem, checking if the id is valid + const Item getItemSafe(const ItemID& id) const { if (isAllocatedID(id)) { return _items[id]; } else { return Item(); } } + // Access the spatialized items const ItemSpatialTree& getSpatialTree() const { return _masterSpatialTree; } From 960f4f0eadf8f813b4fd55f219244c64e8308bab Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 16 Jan 2017 18:33:42 -0800 Subject: [PATCH 05/20] Move the drawBOunds job to DrawTasks --- .../render-utils/src/RenderDeferredTask.cpp | 5 ++ .../render-utils/src/RenderForwardTask.cpp | 55 ----------------- .../render-utils/src/RenderForwardTask.h | 21 ------- libraries/render/src/render/DrawTask.cpp | 60 +++++++++++++++++++ libraries/render/src/render/DrawTask.h | 21 +++++++ 5 files changed, 86 insertions(+), 76 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 8547c5adb0..e0192b5f85 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -159,6 +159,11 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { // Debugging stages { + + + // Bounds do not draw on stencil buffer, so they must come last + addJob("DrawMetaBounds", metas); + // Debugging Deferred buffer job const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); addJob("DebugDeferredBuffer", debugFramebuffers); diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 7550d2326b..45a32c1aaf 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -24,8 +24,6 @@ #include -#include -#include #include "nop_frag.h" using namespace render; @@ -182,57 +180,4 @@ void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderCo args->_batch = nullptr; } -const gpu::PipelinePointer DrawBounds::getPipeline() { - if (!_boundsPipeline) { - auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); - auto ps = gpu::Shader::createPixel(std::string(drawItemBounds_frag)); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - gpu::Shader::BindingSet slotBindings; - gpu::Shader::makeProgram(*program, slotBindings); - - _cornerLocation = program->getUniforms().findLocation("inBoundPos"); - _scaleLocation = program->getUniforms().findLocation("inBoundDim"); - - auto state = std::make_shared(); - state->setDepthTest(true, false, gpu::LESS_EQUAL); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); - - _boundsPipeline = gpu::Pipeline::create(program, state); - } - return _boundsPipeline; -} - -void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, - const Inputs& items) { - RenderArgs* args = renderContext->args; - - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - args->_batch = &batch; - - // Setup projection - glm::mat4 projMat; - Transform viewMat; - args->getViewFrustum().evalProjectionMatrix(projMat); - args->getViewFrustum().evalViewTransform(viewMat); - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - batch.setModelTransform(Transform()); - - // Bind program - batch.setPipeline(getPipeline()); - assert(_cornerLocation >= 0); - assert(_scaleLocation >= 0); - - // Render bounds - for (const auto& item : items) { - batch._glUniform3fv(_cornerLocation, 1, (const float*)(&item.bound.getCorner())); - batch._glUniform3fv(_scaleLocation, 1, (const float*)(&item.bound.getScale())); - - static const int NUM_VERTICES_PER_CUBE = 24; - batch.draw(gpu::LINES, NUM_VERTICES_PER_CUBE, 0); - } - }); -} diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index a957f7493e..62cbca4382 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -68,25 +68,4 @@ public: const Inputs& background); }; -class DrawBounds { -public: - class Config : public render::JobConfig { - public: - Config() : JobConfig(false) {} - }; - - using Inputs = render::ItemBounds; - using JobModel = render::Job::ModelI; - - void configure(const Config& configuration) {} - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, - const Inputs& items); - -private: - const gpu::PipelinePointer getPipeline(); - gpu::PipelinePointer _boundsPipeline; - int _cornerLocation { -1 }; - int _scaleLocation { -1 }; -}; - #endif // hifi_RenderForwardTask_h diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 1c9a92c511..2829c6f8e7 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -19,6 +19,10 @@ #include #include + +#include +#include + using namespace render; void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, int maxDrawnItems) { @@ -134,3 +138,59 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext auto config = std::static_pointer_cast(renderContext->jobConfig); config->setNumDrawn((int)inLights.size()); } + +const gpu::PipelinePointer DrawBounds::getPipeline() { + if (!_boundsPipeline) { + auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); + auto ps = gpu::Shader::createPixel(std::string(drawItemBounds_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + _cornerLocation = program->getUniforms().findLocation("inBoundPos"); + _scaleLocation = program->getUniforms().findLocation("inBoundDim"); + + auto state = std::make_shared(); + state->setDepthTest(true, false, gpu::LESS_EQUAL); + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + _boundsPipeline = gpu::Pipeline::create(program, state); + } + return _boundsPipeline; +} + +void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const Inputs& items) { + RenderArgs* args = renderContext->args; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + // Setup projection + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + // Bind program + batch.setPipeline(getPipeline()); + assert(_cornerLocation >= 0); + assert(_scaleLocation >= 0); + + // Render bounds + for (const auto& item : items) { + batch._glUniform3fv(_cornerLocation, 1, (const float*)(&item.bound.getCorner())); + batch._glUniform3fv(_scaleLocation, 1, (const float*)(&item.bound.getScale())); + + static const int NUM_VERTICES_PER_CUBE = 24; + batch.draw(gpu::LINES, NUM_VERTICES_PER_CUBE, 0); + } + }); +} + diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index aa564980c4..27f07921c3 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -50,6 +50,27 @@ protected: int _maxDrawn; // initialized by Config }; +class DrawBounds { +public: + class Config : public render::JobConfig { + public: + Config() : JobConfig(false) {} + }; + + using Inputs = render::ItemBounds; + using JobModel = render::Job::ModelI; + + void configure(const Config& configuration) {} + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, + const Inputs& items); + +private: + const gpu::PipelinePointer getPipeline(); + gpu::PipelinePointer _boundsPipeline; + int _cornerLocation { -1 }; + int _scaleLocation { -1 }; +}; + } #endif // hifi_render_DrawTask_h From c7a561aff9cbcee7a01fb5ef81aa401f6920a31b Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 17 Jan 2017 01:23:03 -0500 Subject: [PATCH 06/20] trim extra debugging code --- .../tutorials/entity_scripts/ambientSound.js | 150 +----------------- 1 file changed, 4 insertions(+), 146 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 3b75ed6720..700db4753c 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -22,19 +22,15 @@ // (function(){ - var VERSION = "0.0.1"; // This sample clip and range will be used if you don't add userData to the entity (see above) var DEFAULT_RANGE = 100; var DEFAULT_URL = "http://hifi-content.s3.amazonaws.com/ken/samples/forest_ambiX.wav"; var DEFAULT_VOLUME = 1.0; var soundURL = ""; - var soundName = ""; - var startTime; var soundOptions = { loop: true, localOnly: true, - //ignorePenumbra: true, }; var range = DEFAULT_RANGE; var maxVolume = DEFAULT_VOLUME; @@ -59,12 +55,6 @@ } } - var WANT_DEBUG_OVERLAY = false; - var LINEHEIGHT = 0.1; - // Optionally enable debug overlays using a Settings value - WANT_DEBUG_OVERLAY = WANT_DEBUG_OVERLAY || /ambientSound/.test(Settings.getValue("WANT_DEBUG_OVERLAY")); - var WANT_DEBUG_BROADCASTS = WANT_DEBUG_OVERLAY && "ambientSound.js"; - this.updateSettings = function() { // Check user data on the entity for any changes var oldSoundURL = soundURL; @@ -73,7 +63,6 @@ var data = JSON.parse(props.userData); if (data.soundURL && !(soundURL === data.soundURL)) { soundURL = data.soundURL; - soundName = (soundURL||"").split("/").pop(); // just filename part debugPrint("Read ambient sound URL: " + soundURL); } if (data.range && !(range === data.range)) { @@ -111,13 +100,6 @@ debugPrint("Failed to download ambient sound: " + soundURL); debugState("error"); } - debugPrint("onStateChanged: " + JSON.stringify({ - sound: soundName, - state: resource.state, - stateName: Object.keys(Resource.State).filter(function(key) { - return Resource.State[key] === resource.state; - }) - })); } resource.stateChanged.connect(onStateChanged); onStateChanged(resource.state); @@ -149,13 +131,9 @@ var data = JSON.parse(props.userData); data.disabled = !data.disabled; - debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundName + ")"); + debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundURL + ")"); var oldState = _debugState; - if (WANT_DEBUG_BROADCASTS) { - Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: hint, scriptTimestamp: props.scriptTimestamp, oldState: oldState, newState: _debugState, age: props.age })); - } - this.cleanup(); // Save the userData and bump scriptTimestamp, which causes all nearby listeners to apply the state change @@ -182,14 +160,10 @@ this.preload = function(entityID) { // Load the sound and range from the entity userData fields, and note the position of the entity. - debugPrint("Ambient sound preload " + VERSION); + debugPrint("Ambient sound preload"); entity = entityID; _this = this; - if (WANT_DEBUG_OVERLAY) { - _createDebugOverlays(); - } - var props = Entities.getEntityProperties(entity, [ "userData" ]); if (props.userData) { var data = JSON.parse(props.userData); @@ -209,12 +183,7 @@ var HYSTERESIS_FRACTION = 0.1; var props = Entities.getEntityProperties(entity, [ "position", "rotation" ]); if (!props.position) { - // FIXME: this mysterious state has been happening while testing - // and might indicate a bug where an Entity can become unreachable without `unload` having been called.. print("FIXME: ambientSound.js -- expected Entity unavailable!") - if (WANT_DEBUG_BROADCASTS) { - Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "FIXME: maybeUpdate", oldState: _debugState })); - } return _this.cleanup(); } center = props.position; @@ -225,7 +194,7 @@ soundOptions.orientation = rotation; soundOptions.volume = volume; if (!soundPlaying && ambientSound && ambientSound.downloaded) { - debugState("playing", "Starting ambient sound: " + soundName + " (duration: " + ambientSound.duration + ")"); + debugState("playing", "Starting ambient sound: " + soundURL + " (duration: " + ambientSound.duration + ")"); soundPlaying = Audio.playSound(ambientSound, soundOptions); } else if (soundPlaying && soundPlaying.playing) { soundPlaying.setOptions(soundOptions); @@ -233,22 +202,12 @@ } else if (soundPlaying && soundPlaying.playing && (distance > range * HYSTERESIS_FRACTION)) { soundPlaying.stop(); soundPlaying = false; - debugState("idle", "Out of range, stopping ambient sound: " + soundName); - } - if (WANT_DEBUG_OVERLAY) { - updateDebugOverlay(distance); + debugState("idle", "Out of range, stopping ambient sound: " + soundURL); } } this.unload = function(entityID) { debugPrint("Ambient sound unload "); - if (WANT_DEBUG_BROADCASTS) { - var offset = ambientSound && (new Date - startTime)/1000 % ambientSound.duration; - Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "unload", oldState: _debugState, offset: offset })); - } - if (WANT_DEBUG_OVERLAY) { - _removeDebugOverlays(); - } this.cleanup(); }; @@ -263,105 +222,4 @@ } }; - // Visual debugging overlay (to see set WANT_DEBUG_OVERLAY = true) - - var DEBUG_COLORS = { - //preload: { red: 0, green: 80, blue: 80 }, - disabled: { red: 0, green: 0, blue: 0, alpha: 0.0 }, - downloading: { red: 255, green: 255, blue: 0 }, - error: { red: 255, green: 0, blue: 0 }, - playing: { red: 0, green: 200, blue: 0 }, - idle: { red: 0, green: 100, blue: 0 } - }; - var _debugOverlay; - var _debugState = ""; - function debugState(state, message) { - if (state === "playing") { - startTime = new Date; - } - _debugState = state; - if (message) { - debugPrint(message); - } - updateDebugOverlay(); - if (WANT_DEBUG_BROADCASTS) { - // Broadcast state changes to make multi-user scenarios easier to verify from a single console - Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, state: state })); - } - } - - function updateDebugOverlay(distance) { - var props = Entities.getEntityProperties(entity, [ "name", "dimensions" ]); - if (!props.dimensions) { - return print("ambientSound.js: updateDebugOverlay -- entity no longer available " + entity); - } - var options = soundPlaying && soundPlaying.options; - if (options) { - var offset = soundPlaying.playing && ambientSound && (new Date - startTime)/1000 % ambientSound.duration; - var deg = Quat.safeEulerAngles(options.orientation); - var orientation = [ deg.x, deg.y, deg.z].map(Math.round).join(", "); - var volume = options.volume; - } - var info = { - //loudness: soundPlaying.loudness && soundPlaying.loudness.toFixed(4) || undefined, - offset: offset && ("00"+offset.toFixed(1)).substr(-4)+"s" || undefined, - orientation: orientation, - injector: soundPlaying && soundPlaying.playing && "playing", - resource: ambientSound && ambientSound.downloaded && "ready (" + ambientSound.duration.toFixed(1) + "s)", - name: props.name || undefined, - uuid: entity.split(/\W/)[1], // extracts just the first part of the UUID - sound: soundName, - volume: Math.max(0,volume||0).toFixed(2) + " / " + maxVolume.toFixed(2), - distance: (distance||0).toFixed(1) + "m / " + range.toFixed(1) + "m", - state: _debugState.toUpperCase(), - }; - - // Pretty print key/value pairs, excluding any undefined values - var outputText = Object.keys(info).filter(function(key) { - return info[key] !== undefined; - }).map(function(key) { - return key + ": " + info[key]; - }).join("\n"); - - // Calculate a local position for displaying info just above the Entity - var textSize = Overlays.textSize(_debugOverlay, outputText); - var size = { - x: textSize.width + LINEHEIGHT, - y: textSize.height + LINEHEIGHT - }; - var pos = { x: 0, y: props.dimensions.y + size.y/2, z: 0 }; - - var backgroundColor = DEBUG_COLORS[_debugState]; - var backgroundAlpha = backgroundColor ? backgroundColor.alpha : 0.6; - Overlays.editOverlay(_debugOverlay, { - visible: true, - backgroundColor: backgroundColor, - backgroundAlpha: backgroundAlpha, - text: outputText, - localPosition: pos, - size: size, - }); - } - - function _removeDebugOverlays() { - if (_debugOverlay) { - Overlays.deleteOverlay(_debugOverlay); - _debugOverlay = 0; - } - } - - function _createDebugOverlays() { - _debugOverlay = Overlays.addOverlay("text3d", { - visible: true, - lineHeight: LINEHEIGHT, - leftMargin: LINEHEIGHT/2, - topMargin: LINEHEIGHT/2, - localPosition: Vec3.ZERO, - parentID: entity, - ignoreRayIntersection: true, - isFacingAvatar: true, - textAlpha: 0.6, - //drawInFront: true, - }); - } }) From 27a23676345b744465d31195c210a1e2cc8ea886 Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 17 Jan 2017 01:27:48 -0500 Subject: [PATCH 07/20] update debugPrints --- scripts/tutorials/entity_scripts/ambientSound.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 700db4753c..523b96c076 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -80,25 +80,22 @@ debugPrint("Read ambient disabled state: " + disabled); if (disabled) { this.cleanup(); - debugState("disabled"); return; } } } if (!(soundURL === oldSoundURL) || (soundURL === "")) { if (soundURL) { - debugState("downloading", "Loading ambient sound into cache"); + debugPrint("Loading ambient sound into cache"); // Use prefetch to detect URL loading errors var resource = SoundCache.prefetch(soundURL); function onStateChanged() { if (resource.state === Resource.State.FINISHED) { resource.stateChanged.disconnect(onStateChanged); ambientSound = SoundCache.getSound(soundURL); - debugState("idle"); } else if (resource.state === Resource.State.FAILED) { resource.stateChanged.disconnect(onStateChanged); debugPrint("Failed to download ambient sound: " + soundURL); - debugState("error"); } } resource.stateChanged.connect(onStateChanged); @@ -132,7 +129,6 @@ data.disabled = !data.disabled; debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundURL + ")"); - var oldState = _debugState; this.cleanup(); @@ -141,7 +137,6 @@ userData: JSON.stringify(data), scriptTimestamp: Math.round(props.age * 1000) }); - //this._updateColor(data.disabled); }; this._updateColor = function(disabled) { @@ -194,7 +189,7 @@ soundOptions.orientation = rotation; soundOptions.volume = volume; if (!soundPlaying && ambientSound && ambientSound.downloaded) { - debugState("playing", "Starting ambient sound: " + soundURL + " (duration: " + ambientSound.duration + ")"); + debugPrint("Starting ambient sound: " + soundURL + " (duration: " + ambientSound.duration + ")"); soundPlaying = Audio.playSound(ambientSound, soundOptions); } else if (soundPlaying && soundPlaying.playing) { soundPlaying.setOptions(soundOptions); @@ -202,7 +197,7 @@ } else if (soundPlaying && soundPlaying.playing && (distance > range * HYSTERESIS_FRACTION)) { soundPlaying.stop(); soundPlaying = false; - debugState("idle", "Out of range, stopping ambient sound: " + soundURL); + debugPrint("Out of range, stopping ambient sound: " + soundURL); } } From 88b7f9ec9d6edbda0659b48aef1594680627f6f3 Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 17 Jan 2017 01:44:03 -0500 Subject: [PATCH 08/20] add ambient sound test --- scripts/developer/tests/ambientSoundTest.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 scripts/developer/tests/ambientSoundTest.js diff --git a/scripts/developer/tests/ambientSoundTest.js b/scripts/developer/tests/ambientSoundTest.js new file mode 100644 index 0000000000..2d5fd832c6 --- /dev/null +++ b/scripts/developer/tests/ambientSoundTest.js @@ -0,0 +1,18 @@ +var WAVE = 'http://cdn.rawgit.com/ambisonictoolkit/atk-sounds/aa31005c/stereo/Aurora_Surgit-Lux_Aeterna.wav'; +var uuid = Entities.addEntity({ + type: "Shape", + shape: "Icosahedron", + dimensions: Vec3.HALF, + script: Script.resolvePath('../../tutorials/entity_scripts/ambientSound.js'), + position: Vec3.sum(Vec3.multiply(5, Quat.getFront(MyAvatar.orientation)), MyAvatar.position), + userData: JSON.stringify({ + soundURL: WAVE, + maxVolume: 0.1, + range: 25, + disabled: true, + }), + lifetime: 600, +}); +Script.scriptEnding.connect(function() { + Entities.deleteEntity(uuid); +}); From 7025ed59090ac719412606975b56000e3edb40a9 Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 17 Jan 2017 03:18:56 -0500 Subject: [PATCH 09/20] update test script to create a triggerable entity --- scripts/developer/tests/ambientSoundTest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/developer/tests/ambientSoundTest.js b/scripts/developer/tests/ambientSoundTest.js index 2d5fd832c6..5b373715c0 100644 --- a/scripts/developer/tests/ambientSoundTest.js +++ b/scripts/developer/tests/ambientSoundTest.js @@ -10,6 +10,7 @@ var uuid = Entities.addEntity({ maxVolume: 0.1, range: 25, disabled: true, + grabbableKey: { wantsTrigger: true }, }), lifetime: 600, }); From 305e3085751b90a045929f7d233a74fc6dd5adf1 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 17 Jan 2017 10:54:45 -0800 Subject: [PATCH 10/20] avoiding the exclusive filtering behavior --- libraries/render/src/render/CullTask.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 56729083dd..3397f9e41c 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -170,7 +170,7 @@ namespace render { for (size_t i = 0; i < NUM_FILTERS; i++) { if (_filters[i].test(itemKey)) { outItems[i].template edit().emplace_back(itemBound); - break; + // break; } } } From 5ed3b48f9d6333a42d8a9c13c90668bef4b94dc1 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 17 Jan 2017 12:15:09 -0800 Subject: [PATCH 11/20] adding the checkbox to show the meta bounds from the debugDeferredLighting.js --- .../utilities/render/debugDeferredLighting.js | 2 +- .../utilities/render/deferredLighting.qml | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/developer/utilities/render/debugDeferredLighting.js b/scripts/developer/utilities/render/debugDeferredLighting.js index b32a924c10..625f71f8a4 100644 --- a/scripts/developer/utilities/render/debugDeferredLighting.js +++ b/scripts/developer/utilities/render/debugDeferredLighting.js @@ -13,7 +13,7 @@ var qml = Script.resolvePath('deferredLighting.qml'); var window = new OverlayWindow({ title: 'Lighting', source: qml, - width: 400, height:220, + width: 400, height:280, }); window.setPosition(Window.innerWidth - 420, 50); window.closed.connect(function() { Script.stop(); }); diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 4901be8e03..26dbc1f2bc 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -74,7 +74,7 @@ Column { Column { spacing: 10 Repeater { - model: [ "Tone Mapping exposure:ToneMapping:exposure:5.0:-5.0" + model: [ "Tone Mapping Exposure:ToneMapping:exposure:5.0:-5.0" ] ConfigSlider { label: qsTr(modelData.split(":")[0]) @@ -88,7 +88,7 @@ Column { Row { Label { - text: "Debug Framebuffer" + text: "Tone Mapping Curve" anchors.left: root.left } @@ -109,6 +109,7 @@ Column { } Row { id: framebuffer + spacing: 10 Label { text: "Debug Framebuffer" @@ -156,5 +157,14 @@ Column { onCurrentIndexChanged: { framebuffer.setDebugMode(currentIndex) } } } + + Row { + id: metas + CheckBox { + text: "Draw Meta Bounds" + checked: Render.getConfig("DrawMetaBounds")["enabled"] + onCheckedChanged: { Render.getConfig("DrawMetaBounds")["enabled"] = checked } + } + } } From 246dcbd0c0b343531cd3b489abdd7756af91a7fc Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 17 Jan 2017 15:01:27 -0800 Subject: [PATCH 12/20] Removing the warning --- interface/src/avatar/Avatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index d86f82a455..ab4ae02a8e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -79,7 +79,7 @@ namespace render { if (avatarPtr->getSkeletonModel()) { auto metaSubItems = avatarPtr->getSkeletonModel()->fetchRenderItemIDs(); subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end()); - return metaSubItems.size(); + return (uint32_t) metaSubItems.size(); } return 0; } From f5300d3862b8ce9dea56201674aa687965487c0d Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 17 Jan 2017 17:06:18 -0800 Subject: [PATCH 13/20] Removing some PAL-related interface log spam Probably more, but these _seem_ to be the worst --- interface/resources/qml/hifi/Pal.qml | 4 ---- scripts/system/pal.js | 1 - 2 files changed, 5 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 549598dd2e..7260cd1c14 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -476,8 +476,6 @@ Rectangle { // Set the userName appropriately userModel.setProperty(userIndex, "userName", userName); userModelData[userIndex].userName = userName; // Defensive programming - } else { - console.log("updateUsername() called with unknown UUID: ", userId); } } break; @@ -493,8 +491,6 @@ Rectangle { if (userIndex != -1) { userModel.setProperty(userIndex, "audioLevel", audioLevel); userModelData[userIndex].audioLevel = audioLevel; // Defensive programming - } else { - console.log("updateUsername() called with unknown UUID: ", userId); } } } diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 2430ce6e87..c61dbba872 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -498,7 +498,6 @@ function getAudioLevel(id) { var audioLevel = 0.0; var data = id ? ExtendedOverlay.get(id) : myData; if (!data) { - print('no data for', id); return audioLevel; } From 1048c2a3bf2c099d8912b55096eb48f41bc6c5ce Mon Sep 17 00:00:00 2001 From: humbletim Date: Wed, 18 Jan 2017 01:39:55 -0500 Subject: [PATCH 14/20] apply default userData values; add error checking; throttle toggle clicks --- .../tutorials/entity_scripts/ambientSound.js | 67 ++++++++++++++----- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 523b96c076..35c9753221 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -27,6 +27,14 @@ var DEFAULT_URL = "http://hifi-content.s3.amazonaws.com/ken/samples/forest_ambiX.wav"; var DEFAULT_VOLUME = 1.0; + var DEFAULT_USERDATA = { + soundURL: DEFAULT_URL, + range: DEFAULT_RANGE, + maxVolume: DEFAULT_VOLUME, + disabled: true, + grabbableKey: { wantsTrigger: true }, + }; + var soundURL = ""; var soundOptions = { loop: true, @@ -60,7 +68,13 @@ var oldSoundURL = soundURL; var props = Entities.getEntityProperties(entity, [ "userData" ]); if (props.userData) { - var data = JSON.parse(props.userData); + try { + var data = JSON.parse(props.userData); + } catch(e) { + debugPrint("unable to parse userData JSON string: " + props.userData); + this.cleanup(); + return; + } if (data.soundURL && !(soundURL === data.soundURL)) { soundURL = data.soundURL; debugPrint("Read ambient sound URL: " + soundURL); @@ -125,18 +139,27 @@ return; } var props = Entities.getEntityProperties(entity, [ "userData", "age", "scriptTimestamp" ]); + if (!props.userData) { + debugPrint("userData is empty; ignoring " + hint); + this.cleanup(); + return; + } var data = JSON.parse(props.userData); data.disabled = !data.disabled; debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundURL + ")"); this.cleanup(); + // Prevent rapid-fire toggling (which seems to sometimes lead to sound injectors becoming unstoppable) + this._toggle = this.clickDownOnEntity = function(hint) { debugPrint("ignoring additonal clicks" + hint); }; - // Save the userData and bump scriptTimestamp, which causes all nearby listeners to apply the state change - Entities.editEntity(entity, { - userData: JSON.stringify(data), - scriptTimestamp: Math.round(props.age * 1000) - }); + Script.setTimeout(function() { + // Save the userData and bump scriptTimestamp, which causes all nearby listeners to apply the state change + Entities.editEntity(entity, { + userData: JSON.stringify(data), + scriptTimestamp: props.scriptTimestamp + 1 + }); + }, 250); }; this._updateColor = function(disabled) { @@ -155,21 +178,35 @@ this.preload = function(entityID) { // Load the sound and range from the entity userData fields, and note the position of the entity. - debugPrint("Ambient sound preload"); + debugPrint("Ambient sound preload " + entityID); entity = entityID; _this = this; - var props = Entities.getEntityProperties(entity, [ "userData" ]); + var props = Entities.getEntityProperties(entity, [ "name", "userData" ]); + var data = {}; if (props.userData) { - var data = JSON.parse(props.userData); - this._updateColor(data.disabled); - if (data.disabled) { - _this.maybeUpdate(); - return; + data = JSON.parse(props.userData); + } + var changed = false; + for(var p in DEFAULT_USERDATA) { + if (!(p in data)) { + data[p] = DEFAULT_USERDATA[p]; + changed = true; } } - - checkTimer = Script.setInterval(_this.maybeUpdate, UPDATE_INTERVAL_MSECS); + if (!data.grabbableKey.wantsTrigger) { + data.grabbableKey.wantsTrigger = true; + changed = true; + } + if (changed) { + debugPrint("applying default values to userData"); + Entities.editEntity(entity, { userData: JSON.stringify(data) }); + } + this._updateColor(data.disabled); + this.updateSettings(); + if (!data.disabled) { + checkTimer = Script.setInterval(_this.maybeUpdate, UPDATE_INTERVAL_MSECS); + } }; this.maybeUpdate = function() { From f88b39918f8281dd314a188fc41560016727f53f Mon Sep 17 00:00:00 2001 From: humbletim Date: Wed, 18 Jan 2017 02:54:42 -0500 Subject: [PATCH 15/20] switch to messaging for toggle notifications; cleanup --- .../tutorials/entity_scripts/ambientSound.js | 57 +++++++++++-------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 35c9753221..810c9769b8 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -92,12 +92,16 @@ if ("disabled" in data && !(disabled === data.disabled)) { disabled = data.disabled; debugPrint("Read ambient disabled state: " + disabled); - if (disabled) { - this.cleanup(); - return; - } + this._updateColor(disabled); } } + if (disabled) { + this.cleanup(); + soundURL = ""; + return; + } else if (!checkTimer) { + checkTimer = Script.setInterval(_this.maybeUpdate, UPDATE_INTERVAL_MSECS); + } if (!(soundURL === oldSoundURL) || (soundURL === "")) { if (soundURL) { debugPrint("Loading ambient sound into cache"); @@ -138,7 +142,7 @@ if (Settings.getValue("io.highfidelity.isEditting")) { return; } - var props = Entities.getEntityProperties(entity, [ "userData", "age", "scriptTimestamp" ]); + var props = Entities.getEntityProperties(entity, [ "userData" ]); if (!props.userData) { debugPrint("userData is empty; ignoring " + hint); this.cleanup(); @@ -147,19 +151,15 @@ var data = JSON.parse(props.userData); data.disabled = !data.disabled; - debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundURL + ")"); + debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + data.soundURL + ")"); this.cleanup(); - // Prevent rapid-fire toggling (which seems to sometimes lead to sound injectors becoming unstoppable) - this._toggle = this.clickDownOnEntity = function(hint) { debugPrint("ignoring additonal clicks" + hint); }; - Script.setTimeout(function() { - // Save the userData and bump scriptTimestamp, which causes all nearby listeners to apply the state change - Entities.editEntity(entity, { - userData: JSON.stringify(data), - scriptTimestamp: props.scriptTimestamp + 1 - }); - }, 250); + // Save the userData and notify nearby listeners of the change + Entities.editEntity(entity, { + userData: JSON.stringify(data) + }); + Messages.sendMessage(entity, "toggled"); }; this._updateColor = function(disabled) { @@ -182,7 +182,7 @@ entity = entityID; _this = this; - var props = Entities.getEntityProperties(entity, [ "name", "userData" ]); + var props = Entities.getEntityProperties(entity, [ "userData" ]); var data = {}; if (props.userData) { data = JSON.parse(props.userData); @@ -204,8 +204,17 @@ } this._updateColor(data.disabled); this.updateSettings(); - if (!data.disabled) { - checkTimer = Script.setInterval(_this.maybeUpdate, UPDATE_INTERVAL_MSECS); + + // Subscribe to toggle notifications using entity ID as a channel name + Messages.subscribe(entity); + Messages.messageReceived.connect(this, "_onMessageReceived"); + }; + + this._onMessageReceived = function(channel, message, sender, local) { + // Handle incoming toggle notifications + if (channel === entity && message === "toggled"/*&& sender !== MyAvatar.sessionUUID*/) { + debugPrint("received " + message + " from " + sender); + this.updateSettings(); } }; @@ -214,9 +223,9 @@ _this.updateSettings(); var HYSTERESIS_FRACTION = 0.1; var props = Entities.getEntityProperties(entity, [ "position", "rotation" ]); - if (!props.position) { - print("FIXME: ambientSound.js -- expected Entity unavailable!") - return _this.cleanup(); + if (disabled || !props.position) { + _this.cleanup(); + return; } center = props.position; rotation = props.rotation; @@ -236,11 +245,13 @@ soundPlaying = false; debugPrint("Out of range, stopping ambient sound: " + soundURL); } - } + }; this.unload = function(entityID) { - debugPrint("Ambient sound unload "); + debugPrint("Ambient sound unload"); this.cleanup(); + Messages.unsubscribe(entity); + Messages.messageReceived.disconnect(this, "_onMessageReceived"); }; this.cleanup = function() { From 6320d872b40a8f6332e82097fbddccae98c62bec Mon Sep 17 00:00:00 2001 From: humbletim Date: Wed, 18 Jan 2017 02:57:13 -0500 Subject: [PATCH 16/20] remove commented code --- scripts/tutorials/entity_scripts/ambientSound.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 810c9769b8..e0a7d0a3cf 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -212,7 +212,7 @@ this._onMessageReceived = function(channel, message, sender, local) { // Handle incoming toggle notifications - if (channel === entity && message === "toggled"/*&& sender !== MyAvatar.sessionUUID*/) { + if (channel === entity && message === "toggled") { debugPrint("received " + message + " from " + sender); this.updateSettings(); } From 560247998841e390b2194646991532f93199de5f Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Wed, 18 Jan 2017 19:18:48 -0300 Subject: [PATCH 17/20] Create render forward version of pixel shaders --- .../render-utils/src/RenderPipelines.cpp | 17 +++-- libraries/render-utils/src/forward_model.slf | 59 +++++++++++++++++ .../src/forward_model_normal_map.slf | 64 ++++++++++++++++++ .../src/forward_model_normal_specular_map.slf | 66 +++++++++++++++++++ .../src/forward_model_specular_map.slf | 63 ++++++++++++++++++ .../render-utils/src/forward_model_unlit.slf | 45 +++++++++++++ 6 files changed, 309 insertions(+), 5 deletions(-) create mode 100644 libraries/render-utils/src/forward_model.slf create mode 100644 libraries/render-utils/src/forward_model_normal_map.slf create mode 100644 libraries/render-utils/src/forward_model_normal_specular_map.slf create mode 100644 libraries/render-utils/src/forward_model_specular_map.slf create mode 100644 libraries/render-utils/src/forward_model_unlit.slf diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index b0d676ef78..c5a6c4b6ca 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -34,6 +34,13 @@ #include "model_normal_map_frag.h" #include "model_normal_specular_map_frag.h" #include "model_specular_map_frag.h" + +#include "forward_model_frag.h" +#include "forward_model_unlit_frag.h" +#include "forward_model_normal_map_frag.h" +#include "forward_model_normal_specular_map_frag.h" +#include "forward_model_specular_map_frag.h" + #include "model_lightmap_frag.h" #include "model_lightmap_normal_map_frag.h" #include "model_lightmap_normal_specular_map_frag.h" @@ -227,11 +234,11 @@ void initForwardPipelines(render::ShapePlumber& plumber) { auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); // Pixel shaders - auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); - auto modelUnlitPixel = gpu::Shader::createPixel(std::string(model_unlit_frag)); - auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); - auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); - auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); + auto modelPixel = gpu::Shader::createPixel(std::string(forward_model_frag)); + auto modelUnlitPixel = gpu::Shader::createPixel(std::string(forward_model_unlit_frag)); + auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(forward_model_normal_map_frag)); + auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(forward_model_specular_map_frag)); + auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(forward_model_normal_specular_map_frag)); using Key = render::ShapeKey; auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3); diff --git a/libraries/render-utils/src/forward_model.slf b/libraries/render-utils/src/forward_model.slf new file mode 100644 index 0000000000..daeead65ec --- /dev/null +++ b/libraries/render-utils/src/forward_model.slf @@ -0,0 +1,59 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// model.frag +// fragment shader +// +// Created by Andrzej Kapolka on 10/14/13. +// Copyright 2013 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 +// + +<@include DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> + +in vec4 _position; +in vec3 _normal; +in vec3 _color; +in vec2 _texCoord0; +in vec2 _texCoord1; + + +void main(void) { + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + float scattering = getMaterialScattering(mat); + + packDeferredFragment( + normalize(_normal.xyz), + opacity, + albedo, + roughness, + getMaterialMetallic(mat), + emissive, + occlusionTex, + scattering); +} diff --git a/libraries/render-utils/src/forward_model_normal_map.slf b/libraries/render-utils/src/forward_model_normal_map.slf new file mode 100644 index 0000000000..3acdedab2a --- /dev/null +++ b/libraries/render-utils/src/forward_model_normal_map.slf @@ -0,0 +1,64 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_normal_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 10/29/13. +// Copyright 2013 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 +// + +<@include DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION, SCATTERING)$> + +in vec4 _position; +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec3 _normal; +in vec3 _tangent; +in vec3 _color; + +void main(void) { + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex, scatteringTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + vec3 viewNormal; + <$tangentToViewSpace(normalTex, _normal, _tangent, viewNormal)$> + + float scattering = getMaterialScattering(mat); + <$evalMaterialScattering(scatteringTex, scattering, matKey, scattering)$>; + + packDeferredFragment( + viewNormal, + opacity, + albedo, + roughness, + getMaterialMetallic(mat), + emissive, + occlusionTex, + scattering); +} diff --git a/libraries/render-utils/src/forward_model_normal_specular_map.slf b/libraries/render-utils/src/forward_model_normal_specular_map.slf new file mode 100644 index 0000000000..d5dd607b8f --- /dev/null +++ b/libraries/render-utils/src/forward_model_normal_specular_map.slf @@ -0,0 +1,66 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_normal_specular_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/6/14. +// Copyright 2014 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 +// + +<@include DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC, EMISSIVE, OCCLUSION)$> + +in vec4 _position; +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec3 _normal; +in vec3 _tangent; +in vec3 _color; + +void main(void) { + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, metallicTex, emissiveTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + vec3 viewNormal; + <$tangentToViewSpace(normalTex, _normal, _tangent, viewNormal)$> + + float metallic = getMaterialMetallic(mat); + <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; + + float scattering = getMaterialScattering(mat); + + packDeferredFragment( + normalize(viewNormal.xyz), + opacity, + albedo, + roughness, + metallic, + emissive, + occlusionTex, + scattering); +} diff --git a/libraries/render-utils/src/forward_model_specular_map.slf b/libraries/render-utils/src/forward_model_specular_map.slf new file mode 100644 index 0000000000..47b5e3389d --- /dev/null +++ b/libraries/render-utils/src/forward_model_specular_map.slf @@ -0,0 +1,63 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_specular_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/6/14. +// Copyright 2014 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 +// + +<@include DeferredBufferWrite.slh@> + +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC, EMISSIVE, OCCLUSION)$> + +in vec4 _position; +in vec2 _texCoord0; +in vec2 _texCoord1; +in vec3 _normal; +in vec3 _color; + + +void main(void) { + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, metallicTex, emissiveTex)$> + <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; + + float metallic = getMaterialMetallic(mat); + <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; + + float scattering = getMaterialScattering(mat); + + packDeferredFragment( + normalize(_normal), + opacity, + albedo, + roughness, + metallic, + emissive, + occlusionTex, + scattering); +} diff --git a/libraries/render-utils/src/forward_model_unlit.slf b/libraries/render-utils/src/forward_model_unlit.slf new file mode 100644 index 0000000000..750b51fe8c --- /dev/null +++ b/libraries/render-utils/src/forward_model_unlit.slf @@ -0,0 +1,45 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// material_opaque_unlit.frag +// fragment shader +// +// Created by Sam Gateau on 5/5/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 +// + +<@include DeferredBufferWrite.slh@> +<@include LightingModel.slh@> +<@include model/Material.slh@> + +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO)$> + +in vec2 _texCoord0; +in vec3 _normal; +in vec3 _color; +in float _alpha; + +void main(void) { + + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$> + + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>; + <$discardTransparent(opacity)$>; + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + packDeferredFragmentUnlit( + normalize(_normal), + opacity, + albedo * isUnlitEnabled()); +} From e3da6aa9f1812da18121074929a65da0e38185aa Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 18 Jan 2017 15:03:31 -0800 Subject: [PATCH 18/20] Removing the comment --- libraries/render/src/render/CullTask.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 3397f9e41c..1a709ed102 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -170,7 +170,6 @@ namespace render { for (size_t i = 0; i < NUM_FILTERS; i++) { if (_filters[i].test(itemKey)) { outItems[i].template edit().emplace_back(itemBound); - // break; } } } From 1ef4ac9a6c6b62190a2e6946bfcb5c8a82e28a07 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 18 Jan 2017 11:06:57 -0800 Subject: [PATCH 19/20] Additional trace details for GPU timing, frame data updates --- interface/src/Application.cpp | 14 +++++++++++--- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 17 +++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4f35b10a1b..8abf63f9f2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3398,6 +3398,8 @@ void Application::idle(float nsecsElapsed) { PROFILE_COUNTER(app, "cpuSystem", { { "system", kernelUserAndSystem.z } }); #endif + + auto displayPlugin = getActiveDisplayPlugin(); if (displayPlugin) { PROFILE_COUNTER_IF_CHANGED(app, "present", float, displayPlugin->presentRate()); @@ -3407,9 +3409,15 @@ void Application::idle(float nsecsElapsed) { PROFILE_COUNTER_IF_CHANGED(app, "pendingDownloads", int, ResourceCache::getPendingRequestCount()); PROFILE_COUNTER_IF_CHANGED(app, "currentProcessing", int, DependencyManager::get()->getStat("Processing").toInt()); PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, DependencyManager::get()->getStat("PendingProcessing").toInt()); - - - + auto renderConfig = _renderEngine->getConfiguration(); + PROFILE_COUNTER_IF_CHANGED(render, "gpuTime", float, (float)_gpuContext->getFrameTimerGPUAverage()); + PROFILE_COUNTER(render_detail, "gpuTimes", { + { "OpaqueRangeTimer", renderConfig->getConfig("OpaqueRangeTimer")->property("gpuRunTime") }, + { "LinearDepth", renderConfig->getConfig("LinearDepth")->property("gpuRunTime") }, + { "SurfaceGeometry", renderConfig->getConfig("SurfaceGeometry")->property("gpuRunTime") }, + { "RenderDeferred", renderConfig->getConfig("RenderDeferred")->property("gpuRunTime") }, + { "ToneAndPostRangeTimer", renderConfig->getConfig("ToneAndPostRangeTimer")->property("gpuRunTime") } + }); PROFILE_RANGE(app, __FUNCTION__); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index e57c2b1d52..574c574f66 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -482,6 +482,7 @@ void OpenGLDisplayPlugin::submitFrame(const gpu::FramePointer& newFrame) { } void OpenGLDisplayPlugin::updateFrameData() { + PROFILE_RANGE(render, __FUNCTION__) if (_lockCurrentTexture) { return; } @@ -596,12 +597,16 @@ void OpenGLDisplayPlugin::internalPresent() { } void OpenGLDisplayPlugin::present() { - PROFILE_RANGE_EX(render, __FUNCTION__, 0xffffff00, (uint64_t)presentCount()) - updateFrameData(); + auto frameId = (uint64_t)presentCount(); + PROFILE_RANGE_EX(render, __FUNCTION__, 0xffffff00, frameId) + { + PROFILE_RANGE_EX(render, "updateFrameData", 0xff00ff00, frameId) + updateFrameData(); + } incrementPresentCount(); { - PROFILE_RANGE_EX(render, "recycle", 0xff00ff00, (uint64_t)presentCount()) + PROFILE_RANGE_EX(render, "recycle", 0xff00ff00, frameId) _gpuContext->recycle(); } @@ -615,19 +620,19 @@ void OpenGLDisplayPlugin::present() { _lastFrame = _currentFrame.get(); }); // Execute the frame rendering commands - PROFILE_RANGE_EX(render, "execute", 0xff00ff00, (uint64_t)presentCount()) + PROFILE_RANGE_EX(render, "execute", 0xff00ff00, frameId) _gpuContext->executeFrame(_currentFrame); } // Write all layers to a local framebuffer { - PROFILE_RANGE_EX(render, "composite", 0xff00ffff, (uint64_t)presentCount()) + PROFILE_RANGE_EX(render, "composite", 0xff00ffff, frameId) compositeLayers(); } // Take the composite framebuffer and send it to the output device { - PROFILE_RANGE_EX(render, "internalPresent", 0xff00ffff, (uint64_t)presentCount()) + PROFILE_RANGE_EX(render, "internalPresent", 0xff00ffff, frameId) internalPresent(); } From 027bd30cbc9e80495d9c691efab388c92ff39cbb Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 18 Jan 2017 16:59:50 -0800 Subject: [PATCH 20/20] Removing macOS warning --- libraries/render/src/render/Item.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 27bc2b790a..551b48fd7d 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -441,7 +441,7 @@ public: virtual const ShapeKey getShapeKey() const override { return shapeGetShapeKey(_data); } // Meta Type Interface - virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return metaFetchMetaSubItems(_data, subItems); } + virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const override { return metaFetchMetaSubItems(_data, subItems); } protected: DataPointer _data;