diff --git a/.github/workflows/pr_build.yml b/.github/workflows/pr_build.yml
index 757a6fd7c8..8a3dce98ec 100644
--- a/.github/workflows/pr_build.yml
+++ b/.github/workflows/pr_build.yml
@@ -14,7 +14,9 @@ env:
   RELEASE_TYPE: PR
   RELEASE_NUMBER: ${{ github.event.number }}
   VERSION_CODE: ${{ github.event.number }}
-
+  # Sentry Crash Reporting
+  CMAKE_BACKTRACE_URL: ${{ secrets.MINIDUMP_TOKEN }}
+  CMAKE_BACKTRACE_TOKEN: PR_${{ github.event.number }}_${{ github.sha }}
 
   # OSX specific variables
   DEVELOPER_DIR: /Applications/Xcode_11.2.app/Contents/Developer
@@ -169,7 +171,7 @@ jobs:
     - name: Build for Android + Quest
       if: matrix.build_type == 'android'
       shell: bash
-      working-directory: ${{runner.workspace}}/project-athena
+      working-directory: ${{runner.workspace}}/vircadia
       run: |
         echo "Pre-cache the vcpkg managed dependencies"
         $PYTHON_EXEC prebuild.py --build-root ${{runner.workspace}}/build --android interface
diff --git a/BUILD_ANDROID.md b/BUILD_ANDROID.md
index 0bea3e5a90..fc73d7905e 100644
--- a/BUILD_ANDROID.md
+++ b/BUILD_ANDROID.md
@@ -66,7 +66,7 @@ The above code to suppress modules is not necessary, but will speed up the build
 
 ### Clone the repository
 
-`git clone https://github.com/kasenvr/project-athena.git`
+`git clone https://github.com/vircadia/vircadia.git`
 
 ## Building & Running
 
@@ -119,4 +119,4 @@ Some things you can try if you want to do a clean build
 * In Android Studio, click _File > Invalidate Caches / Restart_ and select _Invalidate and Restart_
 
 If you see lots of "couldn't acquire lock" errors,
-* Open Task Manager and close any running Clang / Gradle processes
\ No newline at end of file
+* Open Task Manager and close any running Clang / Gradle processes
diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md
index 8d6062f5e6..90782e90b4 100644
--- a/BUILD_LINUX.md
+++ b/BUILD_LINUX.md
@@ -4,7 +4,7 @@
 
 Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file.
 
-You can use the [Vircadia Builder](https://github.com/kasenvr/vircadia-builder) to build on Linux more easily. Alternatively, you can follow the manual steps below.
+You can use the [Vircadia Builder](https://github.com/vircadia/vircadia-builder) to build on Linux more easily. Alternatively, you can follow the manual steps below.
 
 ## Ubuntu 16.04/18.04 specific build guide
 ### Ubuntu 16.04 only
@@ -78,7 +78,7 @@ sudo apt-get install nodejs
 
 Clone this repository:
 ```bash
-git clone https://github.com/kasenvr/project-athena.git
+git clone https://github.com/vircadia/vircadia.git
 ```
 
 To compile a DEV version checkout the branch you need. To get a list of all tags:
@@ -105,7 +105,7 @@ Qt must be installed in `$HIFI_QT_BASE/$VIRCADIA_USE_QT_VERSION/qt5-install`.
 
 Create the build directory:
 ```bash
-cd project-athena
+cd vircadia
 mkdir build
 cd build
 ```
diff --git a/BUILD_WIN.md b/BUILD_WIN.md
index 321663ed39..aa99bf1776 100644
--- a/BUILD_WIN.md
+++ b/BUILD_WIN.md
@@ -100,7 +100,7 @@ Note: You can also run Interface by launching it from command line or File Explo
 For any problems after Step #6, first try this:  
 * Delete your locally cloned copy of the Vircadia repository  
 * Restart your computer  
-* Redownload the [repository](https://github.com/kasenvr/project-athena)  
+* Redownload the [repository](https://github.com/vircadia/vircadia)  
 * Restart directions from Step #6  
 
 #### CMake gives you the same error message repeatedly after the build fails
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index aeb6f49280..72f296e92e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,3 +1,4 @@
+
 The project embraces distributed development and if you'd like to help, it would be greatly appreciated. Just open a pull request with the revisions.
 
 Contributing
@@ -6,7 +7,7 @@ Contributing
 2. Clone your fork of the repository locally
 
   ```
-  git clone git://github.com/USERNAME/project-athena.git
+  git clone git://github.com/USERNAME/vircadia.git
   ```
 3. Create a new branch
   
@@ -20,7 +21,7 @@ Contributing
 6. Update your branch
   
   ```
-  git remote add upstream https://github.com/kasenvr/project-athena
+  git remote add upstream https://github.com/vircadia/vircadia
   git pull upstream master
   ```
   
@@ -35,13 +36,22 @@ Contributing
 
   *You can follow [GitHub's guide](https://help.github.com/articles/creating-a-pull-request) to find out how to create a pull request.*
   
+Tips for Pull Requests 
+===
+To make the QA process go as smoothly as possible.
+
+1. Have a basic description in your pull request. 
+2. Write a basic test plan if you are altering or adding features.
+3. If a new API is added, try to make sure that some level of basic documentation on how you can utilize it is included.
+4. If an added API or feature requires an external service, try to document or link to instructions on how to create a basic working setup.
+
 Reporting Bugs
 ===
 1. Always update to the latest code on master, we make many merges every day and it is possible the bug has already been fixed!
-2. Search [issues](https://github.com/kasenvr/project-athena/issues) to make sure that somebody has not already reported the same bug. 
-3. [Add](https://github.com/kasenvr/project-athena/issues/new) your report to the issues list!
+2. Search [issues](https://github.com/vircadia/vircadia/issues) to make sure that somebody has not already reported the same bug. 
+3. [Add](https://github.com/vircadia/vircadia/issues/new) your report to the issues list!
 
 Requesting a Feature
 ===
-1. Search [issues](https://github.com/kasenvr/project-athena/issues) to make sure that somebody has not already requested the same feature. 
-2. [Add](https://github.com/kasenvr/project-athena/issues/new) your request to the issues list!
+1. Search [issues](https://github.com/vircadia/vircadia/issues) to make sure that somebody has not already requested the same feature. 
+2. [Add](https://github.com/vircadia/vircadia/issues/new) your request to the issues list!
diff --git a/README.md b/README.md
index baf333d81f..0368799c73 100644
--- a/README.md
+++ b/README.md
@@ -8,17 +8,17 @@ Vircadia is a 3D social software project seeking to incrementally bring about a
 
 ### Releases
 
-[View Releases here](https://github.com/kasenvr/project-athena/releases/)
+[View Releases here](https://github.com/vircadia/vircadia/releases/)
 
 ### How to build the Interface
 
-[For Windows](https://github.com/kasenvr/project-athena/blob/master/BUILD_WIN.md)
+[For Windows](https://github.com/vircadia/vircadia/blob/master/BUILD_WIN.md)
 
-[For Mac](https://github.com/kasenvr/project-athena/blob/master/BUILD_OSX.md)
+[For Mac](https://github.com/vircadia/vircadia/blob/master/BUILD_OSX.md)
 
-[For Linux](https://github.com/kasenvr/project-athena/blob/master/BUILD_LINUX.md)
+[For Linux](https://github.com/vircadia/vircadia/blob/master/BUILD_LINUX.md)
 
-[For Linux - Vircadia Builder](https://github.com/kasenvr/vircadia-builder)
+[For Linux - Vircadia Builder](https://github.com/vircadia/vircadia-builder)
 
 ### How to deploy a Server
 
@@ -26,13 +26,13 @@ Vircadia is a 3D social software project seeking to incrementally bring about a
 
 ### How to build a Server
 
-[For Linux - Vircadia Builder](https://github.com/kasenvr/vircadia-builder)
+[For Linux - Vircadia Builder](https://github.com/vircadia/vircadia-builder)
 
 ### How to generate an Installer
 
-[For Windows](https://github.com/kasenvr/project-athena/blob/master/INSTALL.md)
+[For Windows](https://github.com/vircadia/vircadia/blob/master/INSTALL.md)
 
-[For Linux - AppImage - Vircadia Builder](https://github.com/kasenvr/vircadia-builder/blob/master/README.md#building-appimages)
+[For Linux - AppImage - Vircadia Builder](https://github.com/vircadia/vircadia-builder/blob/master/README.md#building-appimages)
 
 ### Boot to Metaverse: The Goal
 
diff --git a/android/containerized_build.sh b/android/containerized_build.sh
index 94b5b28831..bbf0b605d8 100755
--- a/android/containerized_build.sh
+++ b/android/containerized_build.sh
@@ -17,7 +17,7 @@ test -z "$STABLE_BUILD" && export STABLE_BUILD=0
 docker run \
    --rm \
    --security-opt seccomp:unconfined \
-   -v "${WORKSPACE}":/home/gha/project-athena \
+   -v "${WORKSPACE}":/home/gha/vircadia \
    -e RELEASE_NUMBER \
    -e RELEASE_TYPE \
    -e ANDROID_APP \
diff --git a/android/docker/Dockerfile b/android/docker/Dockerfile
index 144f6caffa..ab5ddb562d 100644
--- a/android/docker/Dockerfile
+++ b/android/docker/Dockerfile
@@ -72,17 +72,17 @@ RUN mkdir "$HIFI_BASE" && \
     mkdir "$HIFI_ANDROID_PRECOMPILED"
 
 # Download the repo
-RUN git clone https://github.com/kasenvr/project-athena.git
+RUN git clone https://github.com/vircadia/vircadia.git
 
-WORKDIR /home/gha/project-athena
+WORKDIR /home/gha/vircadia
 
 RUN mkdir build
 
 # Pre-cache the vcpkg managed dependencies
-WORKDIR /home/gha/project-athena/build
+WORKDIR /home/gha/vircadia/build
 RUN python3 ../prebuild.py --build-root `pwd` --android interface
 
 # Pre-cache the gradle dependencies
-WORKDIR /home/gha/project-athena/android
+WORKDIR /home/gha/vircadia/android
 RUN ./gradlew -m tasks -PHIFI_ANDROID_PRECOMPILED=$HIFI_ANDROID_PRECOMPILED
 #RUN ./gradlew extractDependencies -PHIFI_ANDROID_PRECOMPILED=$HIFI_ANDROID_PRECOMPILED 
diff --git a/cmake/ports/etc2comp/portfile.cmake b/cmake/ports/etc2comp/portfile.cmake
index 343f67169b..1369492599 100644
--- a/cmake/ports/etc2comp/portfile.cmake
+++ b/cmake/ports/etc2comp/portfile.cmake
@@ -19,7 +19,7 @@ include(vcpkg_common_functions)
 
 vcpkg_from_github(
     OUT_SOURCE_PATH SOURCE_PATH
-    REPO kasenvr/etc2comp
+    REPO vircadia/etc2comp
     REF 7f1843bf07825c21cab711360c1ddbad04641036
     SHA512 d747076acda8537d39585858c793a35c3dcc9ef283d723619a47f8c81ec1454c95b3340ad35f0655a939eae5b8271c801c48a9a7568311a01903a344c44af25b
     HEAD_REF master
diff --git a/cmake/ports/hifi-scribe/portfile.cmake b/cmake/ports/hifi-scribe/portfile.cmake
index 498e8a455b..19d03b5db4 100644
--- a/cmake/ports/hifi-scribe/portfile.cmake
+++ b/cmake/ports/hifi-scribe/portfile.cmake
@@ -3,7 +3,7 @@ include(vcpkg_common_functions)
 
 vcpkg_from_github(
     OUT_SOURCE_PATH SOURCE_PATH
-    REPO kasenvr/scribe
+    REPO vircadia/scribe
     REF 1bd638a36ca771e5a68d01985b6389b71835cbd2
     SHA512 dbe241d86df3912e544f6b9839873f9875df54efc93822b145e7b13243eaf2e3d690bc8a28b1e52d05bdcd7e68fca6b0b2f5c43ffd0f56a9b7a50d54dcf9e31e
     HEAD_REF master
diff --git a/cmake/ports/nvtt/portfile.cmake b/cmake/ports/nvtt/portfile.cmake
index c7bf068e13..b21bb5609c 100644
--- a/cmake/ports/nvtt/portfile.cmake
+++ b/cmake/ports/nvtt/portfile.cmake
@@ -9,7 +9,7 @@ include(vcpkg_common_functions)
 
 vcpkg_from_github(
     OUT_SOURCE_PATH SOURCE_PATH
-    REPO kasenvr/nvidia-texture-tools
+    REPO vircadia/nvidia-texture-tools
     REF 330c4d56274a0f602a5c70596e2eb670a4ed56c2
     SHA512 4c0bc2f369120d696cc27710b6d33086b27eef55f537ec66b9a5c8b1839bc2426c0413670b0f65be52c5d353468f0126dfe024be1f0690611d4d7e33ac530127
     HEAD_REF master
diff --git a/domain-server/resources/metadata_exporter/index.html b/domain-server/resources/metadata_exporter/index.html
index a22d50fe22..1b18c508cc 100644
--- a/domain-server/resources/metadata_exporter/index.html
+++ b/domain-server/resources/metadata_exporter/index.html
@@ -2,7 +2,7 @@
 //
 //  index.html
 //
-//  Created by kasenvr@gmail.com on 21 Jul 2020
+//  Created by somnilibertas@gmail.com on 21 Jul 2020
 //  Copyright 2020 Vircadia and contributors.
 //
 //  Distributed under the Apache License, Version 2.0.
diff --git a/domain-server/resources/web/assignment/placeholder.js b/domain-server/resources/web/assignment/placeholder.js
index 95c9903e32..3666396d6e 100644
--- a/domain-server/resources/web/assignment/placeholder.js
+++ b/domain-server/resources/web/assignment/placeholder.js
@@ -1,3 +1,3 @@
 // Here you can put a script that will be run by an assignment-client (AC)
-// For examples, please go to https://github.com/kasenvr/project-athena/tree/master/script-archive/acScripts
+// For examples, please go to https://github.com/vircadia/vircadia/tree/master/script-archive/acScripts
 // The directory named acScripts contains assignment-client specific scripts you can try.
diff --git a/hifi_qt.py b/hifi_qt.py
index c59c7b1202..48e9b337a6 100644
--- a/hifi_qt.py
+++ b/hifi_qt.py
@@ -81,7 +81,7 @@ endif()
             else:
                 print("Sorry, " + distro.name(pretty=True) + " is not supported. Please consider helping us out.")
                 print("It's also possible to build Qt for your distribution, please see the documentation at:")
-                print("https://github.com/kasenvr/project-athena/tree/master/tools/qt-builder")
+                print("https://github.com/vircadia/vircadia/tree/master/tools/qt-builder")
                 raise Exception('UNKNOWN LINUX VERSION!!!')
         else:
             print("System      : " + platform.system())
diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml
index 9a9252112c..971fb06414 100644
--- a/interface/resources/qml/desktop/Desktop.qml
+++ b/interface/resources/qml/desktop/Desktop.qml
@@ -309,8 +309,8 @@ FocusScope {
             if (child.hasOwnProperty("modality")) {
                 var mappedPoint = mapToItem(child, point.x, point.y);
                 if (child.hasOwnProperty("frame")) {
-                    var outLine = child.frame.children[2];
-                    var framePoint = outLine.mapFromGlobal(point.x, point.y);
+                    var outLine = child.frame.children[2];  // sizeOutline
+                    var framePoint = mapToItem(outLine, point.x, point.y);
                     if (outLine.contains(framePoint)) {
                         return true;
                     }
diff --git a/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml b/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml
index a943da32a0..f7a4061f45 100644
--- a/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml
+++ b/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml
@@ -54,10 +54,10 @@ Rectangle {
             textFormat: Text.StyledText
             linkColor: "#00B4EF"
             color: "white"
-            text: "<a href=\"https://github.com/kasenvr/project-athena\">Vircadia Github</a>."
+            text: "<a href=\"https://github.com/vircadia/vircadia\">Vircadia Github</a>."
             size: 20
             onLinkActivated: {
-                About.openUrl("https:/github.com/kasenvr/project-athena");
+                About.openUrl("https:/github.com/vircadia/vircadia");
             }
 
         }
diff --git a/interface/resources/qml/hifi/dialogs/security/EntityScriptQMLWhitelist.qml b/interface/resources/qml/hifi/dialogs/security/EntityScriptQMLWhitelist.qml
index 9e0b6ba4cf..8180475527 100644
--- a/interface/resources/qml/hifi/dialogs/security/EntityScriptQMLWhitelist.qml
+++ b/interface/resources/qml/hifi/dialogs/security/EntityScriptQMLWhitelist.qml
@@ -2,8 +2,8 @@
 //  EntityScriptQMLWhitelist.qml
 //  interface/resources/qml/hifi/dialogs/security
 //
-//  Created by Kasen IO on 2019.12.05 | realities.dev | kasenvr@gmail.com
-//  Copyright 2019 Kasen IO
+//  Created by Kalila L. on 2019.12.05 | realities.dev | somnilibertas@gmail.com
+//  Copyright 2019 Kalila L.
 //
 //  Distributed under the Apache License, Version 2.0.
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
diff --git a/interface/resources/qml/hifi/dialogs/security/Security.qml b/interface/resources/qml/hifi/dialogs/security/Security.qml
index 918a0a2ca6..b109f83a23 100644
--- a/interface/resources/qml/hifi/dialogs/security/Security.qml
+++ b/interface/resources/qml/hifi/dialogs/security/Security.qml
@@ -314,7 +314,7 @@ Rectangle {
                         onClicked: {
                             lightboxPopup.titleText = "Script Plugin Infrastructure";
                             lightboxPopup.bodyText = "Toggles the activation of scripting plugins in the 'plugins/scripting' folder. \n\n"
-                              + "Created by:\n    humbletim@gmail.com\n    kasenvr@gmail.com";
+                              + "Created by:\n    humbletim@gmail.com\n    somnilibertas@gmail.com";
                             lightboxPopup.button1text = "OK";
                             lightboxPopup.button1method = function() {
                                 lightboxPopup.visible = false;
diff --git a/interface/resources/qml/windows/Frame.qml b/interface/resources/qml/windows/Frame.qml
index 7b0fbf8d8c..cfff40bbf6 100644
--- a/interface/resources/qml/windows/Frame.qml
+++ b/interface/resources/qml/windows/Frame.qml
@@ -27,7 +27,6 @@ Item {
     readonly property int frameMarginRight: frame.decoration ? frame.decoration.frameMarginRight : 0
     readonly property int frameMarginTop: frame.decoration ? frame.decoration.frameMarginTop : 0
     readonly property int frameMarginBottom: frame.decoration ? frame.decoration.frameMarginBottom : 0
-    readonly property int offsetCorrection: 20
 
     // Frames always fill their parents, but their decorations may extend
     // beyond the window via negative margin sizes
@@ -76,7 +75,7 @@ Item {
     Rectangle {
         id: sizeOutline
         x: -frameMarginLeft
-        y: -frameMarginTop - offsetCorrection
+        y: -frameMarginTop
         width: window ? window.width + frameMarginLeft + frameMarginRight + 2 : 0
         height: window ? window.height + frameMarginTop + frameMarginBottom + 2 : 0
         color: hifi.colors.baseGrayHighlight15
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index c1f972eb30..cc46d8591b 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -8712,7 +8712,7 @@ void Application::notifyPacketVersionMismatch() {
 }
 
 void Application::checkSkeleton() const {
-    if (getMyAvatar()->getSkeletonModel()->isActive() && !getMyAvatar()->getSkeletonModel()->hasSkeleton()) {
+    if (getMyAvatar()->getSkeletonModel()->isLoaded() && !getMyAvatar()->getSkeletonModel()->hasSkeleton()) {
         qCDebug(interfaceapp) << "MyAvatar model has no skeleton";
 
         QString message = "Your selected avatar body has no skeleton.\n\nThe default body will be loaded...";
diff --git a/interface/src/ui/OverlayConductor.cpp b/interface/src/ui/OverlayConductor.cpp
index 8edd8ee3a5..557b4d09bf 100644
--- a/interface/src/ui/OverlayConductor.cpp
+++ b/interface/src/ui/OverlayConductor.cpp
@@ -23,7 +23,7 @@ OverlayConductor::OverlayConductor() {
 OverlayConductor::~OverlayConductor() {
 }
 
-bool OverlayConductor::headOutsideOverlay() const {
+bool OverlayConductor::headNotCenteredInOverlay() const {
     glm::mat4 hmdMat = qApp->getHMDSensorPose();
     glm::vec3 hmdPos = extractTranslation(hmdMat);
     glm::vec3 hmdForward = transformVectorFast(hmdMat, glm::vec3(0.0f, 0.0f, -1.0f));
@@ -32,8 +32,8 @@ bool OverlayConductor::headOutsideOverlay() const {
     glm::vec3 uiPos = uiTransform.getTranslation();
     glm::vec3 uiForward = uiTransform.getRotation() * glm::vec3(0.0f, 0.0f, -1.0f);
 
-    const float MAX_COMPOSITOR_DISTANCE = 0.99f;  // If you're 1m from center of ui sphere, you're at the surface.
-    const float MAX_COMPOSITOR_ANGLE = 180.0f;    // rotation check is effectively disabled
+    const float MAX_COMPOSITOR_DISTANCE = 0.33f;
+    const float MAX_COMPOSITOR_ANGLE = 90.0f;
     if (glm::distance(uiPos, hmdPos) > MAX_COMPOSITOR_DISTANCE ||
         glm::dot(uiForward, hmdForward) < cosf(glm::radians(MAX_COMPOSITOR_ANGLE))) {
         return true;
@@ -70,6 +70,8 @@ bool OverlayConductor::updateAvatarIsAtRest() {
 void OverlayConductor::centerUI() {
     // place the overlay at the current hmd position in sensor space
     auto camMat = cancelOutRollAndPitch(qApp->getHMDSensorPose());
+    // Set its radius.
+    camMat = glm::scale(camMat, glm::vec3(HUD_RADIUS));
     qApp->getApplicationCompositor().setModelTransform(Transform(camMat));
 }
 
@@ -83,7 +85,6 @@ void OverlayConductor::update(float dt) {
     if (!desktop) {
         return;
     }
-    bool currentVisible = !desktop->property("pinned").toBool();
 
     auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
     // centerUI when hmd mode is first enabled and mounted
@@ -96,24 +97,24 @@ void OverlayConductor::update(float dt) {
         _hmdMode = false;
     }
 
-    bool shouldRecenter = false;
-
-    if (_suppressedByHead) {
-        if (updateAvatarIsAtRest()) {
-            _suppressedByHead = false;
-            shouldRecenter = true;
-        }
-    } else {
-        if (_hmdMode && headOutsideOverlay()) {
-            _suppressedByHead = true;
-        }
+    bool initiateRecenter = false;
+    if (_hmdMode && headNotCenteredInOverlay()) {
+        initiateRecenter = true;
     }
 
+    bool shouldRecenter = false;
+    if (initiateRecenter || _suppressedByHead) {
+        _suppressedByHead = !updateAvatarIsAtRest();
+        shouldRecenter = !_suppressedByHead;
+    }
+
+    bool currentVisible = !desktop->property("pinned").toBool();
     bool targetVisible = Menu::getInstance()->isOptionChecked(MenuOption::Overlays) && !_suppressedByHead;
     if (targetVisible != currentVisible) {
         offscreenUi->setPinned(!targetVisible);
     }
-    if (shouldRecenter && !_suppressedByHead) {
+
+    if (shouldRecenter) {
         centerUI();
     }
 #endif
diff --git a/interface/src/ui/OverlayConductor.h b/interface/src/ui/OverlayConductor.h
index 6c3732cf3c..7e7cf5bd3c 100644
--- a/interface/src/ui/OverlayConductor.h
+++ b/interface/src/ui/OverlayConductor.h
@@ -22,7 +22,7 @@ public:
     void centerUI();
 
 private:
-    bool headOutsideOverlay() const;
+    bool headNotCenteredInOverlay() const;
     bool updateAvatarIsAtRest();
 
 #if !defined(DISABLE_QML)
diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
index 16dc99ab49..d859454a99 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
@@ -1246,7 +1246,7 @@ glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
         }
         case CAMERA_MATRIX_INDEX: {
             glm::quat rotation;
-            if (_skeletonModel && _skeletonModel->isActive()) {
+            if (_skeletonModel && _skeletonModel->isLoaded()) {
                 int headJointIndex = getJointIndex("Head");
                 if (headJointIndex >= 0) {
                     _skeletonModel->getAbsoluteJointRotationInRigFrame(headJointIndex, rotation);
@@ -1298,7 +1298,7 @@ glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
         }
         case CAMERA_MATRIX_INDEX: {
             glm::vec3 translation;
-            if (_skeletonModel && _skeletonModel->isActive()) {
+            if (_skeletonModel && _skeletonModel->isLoaded()) {
                 int headJointIndex = getJointIndex("Head");
                 if (headJointIndex >= 0) {
                     _skeletonModel->getAbsoluteJointTranslationInRigFrame(headJointIndex, translation);
@@ -1427,7 +1427,7 @@ void Avatar::withValidJointIndicesCache(std::function<void()> const& worker) con
             QWriteLocker writeLock(&_modelJointIndicesCacheLock);
             if (!_modelJointsCached) {
                 _modelJointIndicesCache.clear();
-                if (_skeletonModel && _skeletonModel->isActive()) {
+                if (_skeletonModel && _skeletonModel->isLoaded()) {
                     _modelJointIndicesCache = _skeletonModel->getHFMModel().jointIndices;
                     _modelJointsCached = true;
                 }
diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp
index ccc87c28f3..4950b86f75 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp
+++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp
@@ -176,7 +176,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
         updateRenderItems();
     }
 
-    if (!isActive() || !_owningAvatar->isMyAvatar()) {
+    if (!isLoaded() || !_owningAvatar->isMyAvatar()) {
         return; // only simulate for own avatar
     }
 
@@ -255,19 +255,19 @@ bool SkeletonModel::getRightHandPosition(glm::vec3& position) const {
 }
 
 bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const {
-    return isActive() && getJointPositionInWorldFrame(_rig.indexOfJoint("Head"), headPosition);
+    return isLoaded() && getJointPositionInWorldFrame(_rig.indexOfJoint("Head"), headPosition);
 }
 
 bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const {
-    return isActive() && getJointPositionInWorldFrame(_rig.indexOfJoint("Neck"), neckPosition);
+    return isLoaded() && getJointPositionInWorldFrame(_rig.indexOfJoint("Neck"), neckPosition);
 }
 
 bool SkeletonModel::getLocalNeckPosition(glm::vec3& neckPosition) const {
-    return isActive() && getJointPosition(_rig.indexOfJoint("Neck"), neckPosition);
+    return isLoaded() && getJointPosition(_rig.indexOfJoint("Neck"), neckPosition);
 }
 
 bool SkeletonModel::getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
-    if (!isActive()) {
+    if (!isLoaded()) {
         return false;
     }
 
@@ -361,7 +361,7 @@ void SkeletonModel::renderBoundingCollisionShapes(RenderArgs* args, gpu::Batch&
 }
 
 bool SkeletonModel::hasSkeleton() {
-    return isActive() ? _rig.indexOfJoint("Hips") != -1 : false;
+    return isLoaded() ? _rig.indexOfJoint("Hips") != -1 : false;
 }
 
 void SkeletonModel::onInvalidate() {
diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h
index 6b0bd79f0b..e24d969461 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h
+++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.h
@@ -44,10 +44,10 @@ public:
     bool getIsJointOverridden(int jointIndex) const;
 
     /// Returns the index of the left hand joint, or -1 if not found.
-    int getLeftHandJointIndex() const { return isActive() ? _rig.indexOfJoint("LeftHand") : -1; }
+    int getLeftHandJointIndex() const { return isLoaded() ? _rig.indexOfJoint("LeftHand") : -1; }
 
     /// Returns the index of the right hand joint, or -1 if not found.
-    int getRightHandJointIndex() const { return isActive() ? _rig.indexOfJoint("RightHand") : -1; }
+    int getRightHandJointIndex() const { return isLoaded() ? _rig.indexOfJoint("RightHand") : -1; }
 
     bool getLeftGrabPosition(glm::vec3& position) const;
     bool getRightGrabPosition(glm::vec3& position) const;
diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp
index 9b6946bbcc..c645c39eb4 100644
--- a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp
+++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp
@@ -41,10 +41,10 @@ static const float reticleSize = TWO_PI / 100.0f;
 //EntityItemID CompositorHelper::_noItemId;
 static QString _tooltipId;
 
-const uvec2 CompositorHelper::VIRTUAL_SCREEN_SIZE = uvec2(3960, 1188); // ~10% more pixel density than old version, 72dx240d FOV
-const QRect CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT = QRect(956, 0, 2048, 1188); // don't include entire width only center 2048
+const uvec2 CompositorHelper::VIRTUAL_SCREEN_SIZE = uvec2(2640, 1188);
+const QRect CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT = QRect(296, 0, 2048, 1188);  // Center 2048 pixels.
 const float CompositorHelper::VIRTUAL_UI_ASPECT_RATIO = (float)VIRTUAL_SCREEN_SIZE.x / (float)VIRTUAL_SCREEN_SIZE.y;
-const vec2 CompositorHelper::VIRTUAL_UI_TARGET_FOV = vec2(PI * 3.0f / 2.0f, PI * 3.0f / 2.0f / VIRTUAL_UI_ASPECT_RATIO);
+const vec2 CompositorHelper::VIRTUAL_UI_TARGET_FOV = vec2(PI, PI / VIRTUAL_UI_ASPECT_RATIO);
 const vec2 CompositorHelper::MOUSE_EXTENTS_ANGULAR_SIZE = vec2(PI * 2.0f, PI * 0.95f); // horizontal: full sphere,  vertical: ~5deg from poles
 const vec2 CompositorHelper::MOUSE_EXTENTS_PIXELS = vec2(VIRTUAL_SCREEN_SIZE) * (MOUSE_EXTENTS_ANGULAR_SIZE / VIRTUAL_UI_TARGET_FOV);
 
@@ -384,9 +384,9 @@ bool CompositorHelper::calculateRayUICollisionPoint(const glm::vec3& position, c
     glm::vec3 localPosition = transformPoint(worldToUi, position);
     glm::vec3 localDirection = glm::normalize(transformVectorFast(worldToUi, direction));
 
-    const float UI_RADIUS = 1.0f;
+    const float UNIT_RADIUS = 1.0f;
     float intersectionDistance;
-    if (raySphereIntersect(localDirection, localPosition, UI_RADIUS, &intersectionDistance)) {
+    if (raySphereIntersect(localDirection, localPosition, UNIT_RADIUS, &intersectionDistance)) {
         result = transformPoint(uiToWorld, localPosition + localDirection * intersectionDistance);
 #ifdef WANT_DEBUG
         DebugDraw::getInstance().drawRay(position, result, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
@@ -407,9 +407,8 @@ bool CompositorHelper::calculateParabolaUICollisionPoint(const glm::vec3& origin
     glm::vec3 localVelocity = glm::normalize(transformVectorFast(worldToUi, velocity));
     glm::vec3 localAcceleration = glm::normalize(transformVectorFast(worldToUi, acceleration));
 
-    const float UI_RADIUS = 1.0f;
     float intersectionDistance;
-    if (findParabolaSphereIntersection(localOrigin, localVelocity, localAcceleration, glm::vec3(0.0f), UI_RADIUS, intersectionDistance)) {
+    if (findParabolaSphereIntersection(localOrigin, localVelocity, localAcceleration, glm::vec3(0.0f), HUD_RADIUS, intersectionDistance)) {
         result = origin + velocity * intersectionDistance + 0.5f * acceleration * intersectionDistance * intersectionDistance;
         parabolicDistance = intersectionDistance;
         return true;
diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.h b/libraries/display-plugins/src/display-plugins/CompositorHelper.h
index c45119fd63..b44d6ffbd9 100644
--- a/libraries/display-plugins/src/display-plugins/CompositorHelper.h
+++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.h
@@ -27,7 +27,8 @@
 
 class ReticleInterface;
 
-const float DEFAULT_RETICLE_DEPTH = 1.0f; // FIXME - probably should be based on UI radius
+const float HUD_RADIUS = 1.5f;
+const float DEFAULT_RETICLE_DEPTH = HUD_RADIUS;
 
 const float MAGNIFY_WIDTH = 220.0f;
 const float MAGNIFY_HEIGHT = 100.0f;
@@ -154,7 +155,7 @@ private:
     std::unique_ptr<QPropertyAnimation> _alphaPropertyAnimation;
 
     std::atomic<bool> _reticleVisible { true };
-    std::atomic<float> _reticleDepth { 1.0f };
+    std::atomic<float> _reticleDepth { DEFAULT_RETICLE_DEPTH };
 
     // NOTE: when the compositor is running in HMD mode, it will control the reticle position as a custom
     // application specific position, when it's in desktop mode, the reticle position will simply move
diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index 807a240763..b116423b75 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -431,13 +431,13 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa
         _visible = entity->getVisible();
         setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera());
         setRenderLayer(entity->getRenderLayer());
-        setPrimitiveMode(entity->getPrimitiveMode());
+        _primitiveMode = entity->getPrimitiveMode();
         _canCastShadow = entity->getCanCastShadow();
         setCullWithParent(entity->getCullWithParent());
         _cauterized = entity->getCauterized();
         if (entity->needsZoneOcclusionUpdate()) {
             entity->resetNeedsZoneOcclusionUpdate();
-            setRenderWithZones(entity->getRenderWithZones());
+            _renderWithZones = entity->getRenderWithZones();
         }
         entity->setNeedsRenderUpdate(false);
     });
@@ -469,11 +469,13 @@ void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) {
 void EntityRenderer::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
     std::lock_guard<std::mutex> lock(_materialsLock);
     _materials[parentMaterialName].push(material);
+    emit requestRenderUpdate();
 }
 
 void EntityRenderer::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
     std::lock_guard<std::mutex> lock(_materialsLock);
     _materials[parentMaterialName].remove(material);
+    emit requestRenderUpdate();
 }
 
 glm::vec4 EntityRenderer::calculatePulseColor(const glm::vec4& color, const PulsePropertyGroup& pulseProperties, quint64 start) {
diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h
index 69fb9aca23..ca3e024338 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableEntityItem.h
@@ -108,18 +108,7 @@ protected:
 
     virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; }
     virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; }
-    virtual void setPrimitiveMode(PrimitiveMode value) { _primitiveMode = value; }
     virtual void setCullWithParent(bool value) { _cullWithParent = value; }
-    virtual void setRenderWithZones(const QVector<QUuid>& renderWithZones) { _renderWithZones = renderWithZones; }
-
-    template <typename F, typename T>
-    T withReadLockResult(const std::function<T()>& f) {
-        T result;
-        withReadLock([&] {
-            result = f();
-        });
-        return result;
-    }
 
 signals:
     void requestRenderUpdate();
diff --git a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp
index 7a36ae2707..6928454eb0 100644
--- a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp
@@ -52,14 +52,11 @@ void GizmoEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
 void GizmoEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
     bool dirty = false;
     RingGizmoPropertyGroup ringProperties = entity->getRingProperties();
-    withWriteLock([&] {
-        _gizmoType = entity->getGizmoType();
-        if (_ringProperties != ringProperties) {
-            _ringProperties = ringProperties;
-            dirty = true;
-
-        }
-    });
+    _gizmoType = entity->getGizmoType();
+    if (_ringProperties != ringProperties) {
+        _ringProperties = ringProperties;
+        dirty = true;
+    }
 
     if (dirty || _prevPrimitiveMode != _primitiveMode || !_ringGeometryID || !_majorTicksGeometryID || !_minorTicksGeometryID) {
         _prevPrimitiveMode = _primitiveMode;
@@ -242,19 +239,20 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) {
 
     if (_gizmoType == GizmoType::RING) {
         Transform transform;
-        bool hasTickMarks;
-        glm::vec4 tickProperties;
+        bool hasTickMarks = _ringProperties.getHasTickMarks();
+        glm::vec4 tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(),
+                                             _ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength());
         bool forward;
+        bool wireframe;
+        bool transparent;
         withReadLock([&] {
             transform = _renderTransform;
-            hasTickMarks = _ringProperties.getHasTickMarks();
-            tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(),
-                                       _ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength());
+            transparent = isTransparent();
+            wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
             forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
         });
 
-        bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
-        geometryCache->bindSimpleProgram(batch, false, isTransparent(), wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
+        geometryCache->bindSimpleProgram(batch, false, transparent, wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
 
         batch.setModelTransform(transform);
 
diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp
index 52900d0798..35702c63e4 100644
--- a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp
@@ -30,16 +30,6 @@ bool GridEntityRenderer::isTransparent() const {
 }
 
 void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
-    withWriteLock([&] {
-        _color = entity->getColor();
-        _alpha = entity->getAlpha();
-        _pulseProperties = entity->getPulseProperties();
-
-        _followCamera = entity->getFollowCamera();
-        _majorGridEvery = entity->getMajorGridEvery();
-        _minorGridEvery = entity->getMinorGridEvery();
-    });
-
     void* key = (void*)this;
     AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
         withWriteLock([&] {
@@ -49,6 +39,16 @@ void GridEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
     });
 }
 
+void GridEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
+    _color = entity->getColor();
+    _alpha = entity->getAlpha();
+    _pulseProperties = entity->getPulseProperties();
+
+    _followCamera = entity->getFollowCamera();
+    _majorGridEvery = entity->getMajorGridEvery();
+    _minorGridEvery = entity->getMinorGridEvery();
+}
+
 Item::Bound GridEntityRenderer::getBound() {
     if (_followCamera) {
         // This is a UI element that should always be in view, lie to the octree to avoid culling
@@ -73,13 +73,12 @@ ShapeKey GridEntityRenderer::getShapeKey() {
 }
 
 void GridEntityRenderer::doRender(RenderArgs* args) {
-    glm::vec4 color;
+    glm::vec4 color = glm::vec4(toGlm(_color), _alpha);
+    color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
     glm::vec3 dimensions;
     Transform renderTransform;
     bool forward;
     withReadLock([&] {
-        color = glm::vec4(toGlm(_color), _alpha);
-        color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
         dimensions = _dimensions;
         renderTransform = _renderTransform;
         forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.h b/libraries/entities-renderer/src/RenderableGridEntityItem.h
index 2ecff01d01..1958d17136 100644
--- a/libraries/entities-renderer/src/RenderableGridEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableGridEntityItem.h
@@ -30,10 +30,11 @@ protected:
 
 private:
     virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
+    virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
     virtual void doRender(RenderArgs* args) override;
 
     glm::u8vec3 _color;
-    float _alpha;
+    float _alpha { NAN };
     PulsePropertyGroup _pulseProperties;
 
     bool _followCamera;
diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp
index 4d19a83ae6..b9b30ea9c7 100644
--- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp
@@ -29,44 +29,7 @@ bool ImageEntityRenderer::isTransparent() const {
     return Parent::isTransparent() || (_textureIsLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha()) || _alpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE;
 }
 
-bool ImageEntityRenderer::needsRenderUpdate() const {
-    if (resultWithReadLock<bool>([&] {
-        return !_textureIsLoaded;
-    })) {
-        return true;
-    }
-
-    return Parent::needsRenderUpdate();
-}
-
 void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
-    withWriteLock([&] {
-        auto imageURL = entity->getImageURL();
-        if (_imageURL != imageURL) {
-            _imageURL = imageURL;
-            if (imageURL.isEmpty()) {
-                _texture.reset();
-            } else {
-                _texture = DependencyManager::get<TextureCache>()->getTexture(_imageURL);
-            }
-            _textureIsLoaded = false;
-        }
-
-        _emissive = entity->getEmissive();
-        _keepAspectRatio = entity->getKeepAspectRatio();
-        _subImage = entity->getSubImage();
-
-        _color = entity->getColor();
-        _alpha = entity->getAlpha();
-        _pulseProperties = entity->getPulseProperties();
-        _billboardMode = entity->getBillboardMode();
-
-        if (!_textureIsLoaded) {
-            emit requestRenderUpdate();
-        }
-        _textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
-    });
-
     void* key = (void*)this;
     AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
         withWriteLock([&] {
@@ -76,6 +39,33 @@ void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
     });
 }
 
+void ImageEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
+    auto imageURL = entity->getImageURL();
+    if (_imageURL != imageURL) {
+        _imageURL = imageURL;
+        if (imageURL.isEmpty()) {
+            _texture.reset();
+        } else {
+            _texture = DependencyManager::get<TextureCache>()->getTexture(_imageURL);
+        }
+        _textureIsLoaded = false;
+    }
+
+    _emissive = entity->getEmissive();
+    _keepAspectRatio = entity->getKeepAspectRatio();
+    _subImage = entity->getSubImage();
+
+    _color = entity->getColor();
+    _alpha = entity->getAlpha();
+    _pulseProperties = entity->getPulseProperties();
+    _billboardMode = entity->getBillboardMode();
+
+    if (!_textureIsLoaded) {
+        emit requestRenderUpdate();
+    }
+    _textureIsLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
+}
+
 Item::Bound ImageEntityRenderer::getBound() {
     auto bound = Parent::getBound();
     if (_billboardMode != BillboardMode::NONE) {
@@ -93,33 +83,26 @@ ShapeKey ImageEntityRenderer::getShapeKey() {
         builder.withTranslucent();
     }
 
-    withReadLock([&] {
-        if (_emissive) {
-            builder.withUnlit();
-        }
+    if (_emissive) {
+        builder.withUnlit();
+    }
 
-        if (_primitiveMode == PrimitiveMode::LINES) {
-            builder.withWireframe();
-        }
-    });
+    if (_primitiveMode == PrimitiveMode::LINES) {
+        builder.withWireframe();
+    }
 
     return builder.build();
 }
 
 void ImageEntityRenderer::doRender(RenderArgs* args) {
-    NetworkTexturePointer texture;
-    QRect subImage;
-    glm::vec4 color;
+    glm::vec4 color = glm::vec4(toGlm(_color), _alpha);
+    color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
     Transform transform;
     withReadLock([&] {
-        texture = _texture;
-        subImage = _subImage;
-        color = glm::vec4(toGlm(_color), _alpha);
-        color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
         transform = _renderTransform;
     });
 
-    if (!_visible || !texture || !texture->isLoaded() || color.a == 0.0f) {
+    if (!_visible || !_texture || !_texture->isLoaded() || color.a == 0.0f) {
         return;
     }
 
@@ -129,28 +112,28 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
     transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
 
     batch->setModelTransform(transform);
-    batch->setResourceTexture(0, texture->getGPUTexture());
+    batch->setResourceTexture(0, _texture->getGPUTexture());
 
-    float imageWidth = texture->getWidth();
-    float imageHeight = texture->getHeight();
+    float imageWidth = _texture->getWidth();
+    float imageHeight = _texture->getHeight();
 
     QRect fromImage;
-    if (subImage.width() <= 0) {
+    if (_subImage.width() <= 0) {
         fromImage.setX(0);
         fromImage.setWidth(imageWidth);
     } else {
-        float scaleX = imageWidth / texture->getOriginalWidth();
-        fromImage.setX(scaleX * subImage.x());
-        fromImage.setWidth(scaleX * subImage.width());
+        float scaleX = imageWidth / _texture->getOriginalWidth();
+        fromImage.setX(scaleX * _subImage.x());
+        fromImage.setWidth(scaleX * _subImage.width());
     }
 
-    if (subImage.height() <= 0) {
+    if (_subImage.height() <= 0) {
         fromImage.setY(0);
         fromImage.setHeight(imageHeight);
     } else {
-        float scaleY = imageHeight / texture->getOriginalHeight();
-        fromImage.setY(scaleY * subImage.y());
-        fromImage.setHeight(scaleY * subImage.height());
+        float scaleY = imageHeight / _texture->getOriginalHeight();
+        fromImage.setY(scaleY * _subImage.y());
+        fromImage.setHeight(scaleY * _subImage.height());
     }
 
     float maxSize = glm::max(fromImage.width(), fromImage.height());
diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.h b/libraries/entities-renderer/src/RenderableImageEntityItem.h
index d73bc9bc05..35d60a230f 100644
--- a/libraries/entities-renderer/src/RenderableImageEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableImageEntityItem.h
@@ -29,8 +29,8 @@ protected:
     bool isTransparent() const override;
 
 private:
-    virtual bool needsRenderUpdate() const override;
     virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
+    virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
     virtual void doRender(RenderArgs* args) override;
 
     QString _imageURL;
diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
index c1b024a478..3d2e59518c 100644
--- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
@@ -16,197 +16,177 @@
 using namespace render;
 using namespace render::entities;
 
-bool MaterialEntityRenderer::needsRenderUpdate() const {
-    if (_retryApply) {
-        return true;
-    }
-    if (!_texturesLoaded) {
-        return true;
-    }
-    return Parent::needsRenderUpdate();
-}
-
-bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
-    if (resultWithReadLock<bool>([&] {
-        if (entity->getTransform() != _transform) {
-            return true;
-        }
-        if (entity->getUnscaledDimensions() != _dimensions) {
-            return true;
-        }
-        if (entity->getParentID() != _parentID) {
-            return true;
-        }
-
-        return false;
-    })) {
-        return true;
-    }
-    return false;
+void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
+    void* key = (void*)this;
+    AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
+        withWriteLock([&] {
+            _renderTransform = getModelTransform();
+            // Material entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1
+            // is a half unit sphere.  However, the geometry cache renders a UNIT sphere, so we need to scale down.
+            const float MATERIAL_ENTITY_SCALE = 0.5f;
+            _renderTransform.postScale(MATERIAL_ENTITY_SCALE);
+            _renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
+        });
+    });
 }
 
 void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
-    withWriteLock([&] {
-        bool deleteNeeded = false;
-        bool addNeeded = _retryApply;
-        bool transformChanged = false;
-        {
-            MaterialMappingMode mode = entity->getMaterialMappingMode();
-            if (mode != _materialMappingMode) {
-                _materialMappingMode = mode;
-                transformChanged = true;
-            }
+    bool deleteNeeded = false;
+    bool addNeeded = _retryApply;
+    bool transformChanged = false;
+    {
+        MaterialMappingMode mode = entity->getMaterialMappingMode();
+        if (mode != _materialMappingMode) {
+            _materialMappingMode = mode;
+            transformChanged = true;
         }
-        {
-            bool repeat = entity->getMaterialRepeat();
-            if (repeat != _materialRepeat) {
-                _materialRepeat = repeat;
-                transformChanged = true;
-            }
+    }
+    {
+        bool repeat = entity->getMaterialRepeat();
+        if (repeat != _materialRepeat) {
+            _materialRepeat = repeat;
+            transformChanged = true;
         }
-        {
-            glm::vec2 mappingPos = entity->getMaterialMappingPos();
-            glm::vec2 mappingScale = entity->getMaterialMappingScale();
-            float mappingRot = entity->getMaterialMappingRot();
-            if (mappingPos != _materialMappingPos || mappingScale != _materialMappingScale || mappingRot != _materialMappingRot) {
-                _materialMappingPos = mappingPos;
-                _materialMappingScale = mappingScale;
-                _materialMappingRot = mappingRot;
-                transformChanged |= _materialMappingMode == MaterialMappingMode::UV;
-            }
+    }
+    {
+        glm::vec2 mappingPos = entity->getMaterialMappingPos();
+        glm::vec2 mappingScale = entity->getMaterialMappingScale();
+        float mappingRot = entity->getMaterialMappingRot();
+        if (mappingPos != _materialMappingPos || mappingScale != _materialMappingScale || mappingRot != _materialMappingRot) {
+            _materialMappingPos = mappingPos;
+            _materialMappingScale = mappingScale;
+            _materialMappingRot = mappingRot;
+            transformChanged |= _materialMappingMode == MaterialMappingMode::UV;
         }
-        {
-            Transform transform = entity->getTransform();
-            glm::vec3 dimensions = entity->getUnscaledDimensions();
-            if (transform != _transform || dimensions != _dimensions) {
-                _transform = transform;
-                _dimensions = dimensions;
-                transformChanged |= _materialMappingMode == MaterialMappingMode::PROJECTED;
-            }
+    }
+    {
+        Transform transform = entity->getTransform();
+        glm::vec3 dimensions = entity->getUnscaledDimensions();
+        if (transform != _transform || dimensions != _dimensions) {
+            _transform = transform;
+            _dimensions = dimensions;
+            transformChanged |= _materialMappingMode == MaterialMappingMode::PROJECTED;
         }
+    }
 
-        {
-            auto material = getMaterial();
-            // Update the old material regardless of if it's going to change
-            if (transformChanged && material && !_parentID.isNull()) {
-                deleteNeeded = true;
-                addNeeded = true;
-                applyTextureTransform(material);
-            }
+    {
+        auto material = getMaterial();
+        // Update the old material regardless of if it's going to change
+        if (transformChanged && material && !_parentID.isNull()) {
+            deleteNeeded = true;
+            addNeeded = true;
+            applyTextureTransform(material);
         }
+    }
 
-        bool urlChanged = false;
-        std::string newCurrentMaterialName = _currentMaterialName;
-        {
-            QString materialURL = entity->getMaterialURL();
-            if (materialURL != _materialURL) {
-                _materialURL = materialURL;
-                if (_materialURL.contains("#")) {
-                    auto split = _materialURL.split("#");
-                    newCurrentMaterialName = split.last().toStdString();
-                } else if (_materialURL.contains("?")) {
-                    qDebug() << "DEPRECATED: Use # instead of ? for material URLS:" << _materialURL;
-                    auto split = _materialURL.split("?");
-                    newCurrentMaterialName = split.last().toStdString();
-                }
-                urlChanged = true;
+    bool urlChanged = false;
+    std::string newCurrentMaterialName = _currentMaterialName;
+    {
+        QString materialURL = entity->getMaterialURL();
+        if (materialURL != _materialURL) {
+            _materialURL = materialURL;
+            if (_materialURL.contains("#")) {
+                auto split = _materialURL.split("#");
+                newCurrentMaterialName = split.last().toStdString();
+            } else if (_materialURL.contains("?")) {
+                qDebug() << "DEPRECATED: Use # instead of ? for material URLS:" << _materialURL;
+                auto split = _materialURL.split("?");
+                newCurrentMaterialName = split.last().toStdString();
             }
+            urlChanged = true;
         }
+    }
 
-        bool usingMaterialData = _materialURL.startsWith("materialData");
-        bool materialDataChanged = false;
-        QUuid oldParentID = _parentID;
-        QString oldParentMaterialName = _parentMaterialName;
-        {
-            QString materialData = entity->getMaterialData();
-            if (materialData != _materialData) {
-                _materialData = materialData;
-                if (usingMaterialData) {
-                    materialDataChanged = true;
-                }
+    bool usingMaterialData = _materialURL.startsWith("materialData");
+    bool materialDataChanged = false;
+    QUuid oldParentID = _parentID;
+    QString oldParentMaterialName = _parentMaterialName;
+    {
+        QString materialData = entity->getMaterialData();
+        if (materialData != _materialData) {
+            _materialData = materialData;
+            if (usingMaterialData) {
+                materialDataChanged = true;
             }
         }
-        {
-            QString parentMaterialName = entity->getParentMaterialName();
-            if (parentMaterialName != _parentMaterialName) {
-                _parentMaterialName = parentMaterialName;
-                deleteNeeded = true;
-                addNeeded = true;
-            }
+    }
+    {
+        QString parentMaterialName = entity->getParentMaterialName();
+        if (parentMaterialName != _parentMaterialName) {
+            _parentMaterialName = parentMaterialName;
+            deleteNeeded = true;
+            addNeeded = true;
         }
-        {
-            QUuid parentID = entity->getParentID();
-            if (parentID != _parentID) {
-                _parentID = parentID;
-                deleteNeeded = true;
-                addNeeded = true;
-            }
+    }
+    {
+        QUuid parentID = entity->getParentID();
+        if (parentID != _parentID) {
+            _parentID = parentID;
+            deleteNeeded = true;
+            addNeeded = true;
         }
-        {
-            quint16 priority = entity->getPriority();
-            if (priority != _priority) {
-                _priority = priority;
-                deleteNeeded = true;
-                addNeeded = true;
-            }
+    }
+    {
+        quint16 priority = entity->getPriority();
+        if (priority != _priority) {
+            _priority = priority;
+            deleteNeeded = true;
+            addNeeded = true;
         }
+    }
 
-        if (urlChanged && !usingMaterialData) {
-            _networkMaterial = DependencyManager::get<MaterialCache>()->getMaterial(_materialURL);
-            auto onMaterialRequestFinished = [this, entity, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
-                if (success) {
-                    deleteMaterial(oldParentID, oldParentMaterialName);
-                    _texturesLoaded = false;
-                    _parsedMaterials = _networkMaterial->parsedMaterials;
-                    setCurrentMaterialName(newCurrentMaterialName);
-                    applyMaterial(entity);
-                } else {
-                    deleteMaterial(oldParentID, oldParentMaterialName);
-                    _retryApply = false;
-                    _texturesLoaded = true;
-                }
-            };
-            if (_networkMaterial) {
-                if (_networkMaterial->isLoaded()) {
-                    onMaterialRequestFinished(!_networkMaterial->isFailed());
-                } else {
-                    connect(_networkMaterial.data(), &Resource::finished, this, [this, onMaterialRequestFinished](bool success) {
-                        withWriteLock([&] {
-                            onMaterialRequestFinished(success);
-                        });
-                    });
-                }
-            }
-        } else if (materialDataChanged && usingMaterialData) {
+    if (urlChanged && !usingMaterialData) {
+        _networkMaterial = DependencyManager::get<MaterialCache>()->getMaterial(_materialURL);
+        auto onMaterialRequestFinished = [this, entity, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
             deleteMaterial(oldParentID, oldParentMaterialName);
-            _texturesLoaded = false;
-            _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL);
-            // Since our material changed, the current name might not be valid anymore, so we need to update
-            setCurrentMaterialName(newCurrentMaterialName);
-            applyMaterial(entity);
-        } else {
-            if (deleteNeeded) {
-                deleteMaterial(oldParentID, oldParentMaterialName);
-            }
-            if (addNeeded) {
+            if (success) {
+                _texturesLoaded = false;
+                _parsedMaterials = _networkMaterial->parsedMaterials;
+                setCurrentMaterialName(newCurrentMaterialName);
                 applyMaterial(entity);
+                emit requestRenderUpdate();
+            } else {
+                _retryApply = false;
+                _texturesLoaded = true;
+            }
+        };
+        if (_networkMaterial) {
+            if (_networkMaterial->isLoaded()) {
+                onMaterialRequestFinished(!_networkMaterial->isFailed());
+            } else {
+                connect(_networkMaterial.data(), &Resource::finished, this, [this, onMaterialRequestFinished](bool success) {
+                    onMaterialRequestFinished(success);
+                });
             }
         }
-
-        {
-            auto material = getMaterial();
-            bool newTexturesLoaded = material ? !material->isMissingTexture() : false;
-            if (!_texturesLoaded && newTexturesLoaded) {
-                material->checkResetOpacityMap();
-            }
-            _texturesLoaded = newTexturesLoaded;
+    } else if (materialDataChanged && usingMaterialData) {
+        deleteMaterial(oldParentID, oldParentMaterialName);
+        _texturesLoaded = false;
+        _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), _materialURL);
+        // Since our material changed, the current name might not be valid anymore, so we need to update
+        setCurrentMaterialName(newCurrentMaterialName);
+        applyMaterial(entity);
+    } else {
+        if (deleteNeeded) {
+            deleteMaterial(oldParentID, oldParentMaterialName);
         }
+        if (addNeeded) {
+            applyMaterial(entity);
+        }
+    }
 
-        _renderTransform = getModelTransform();
-        const float MATERIAL_ENTITY_SCALE = 0.5f;
-        _renderTransform.postScale(MATERIAL_ENTITY_SCALE);
-        _renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
-    });
+    {
+        auto material = getMaterial();
+        bool newTexturesLoaded = material ? !material->isMissingTexture() : false;
+        if (!_texturesLoaded && newTexturesLoaded) {
+            material->checkResetOpacityMap();
+        }
+        _texturesLoaded = newTexturesLoaded;
+    }
+
+    if (!_texturesLoaded || _retryApply) {
+        emit requestRenderUpdate();
+    }
 }
 
 ItemKey MaterialEntityRenderer::getKey() {
@@ -268,33 +248,30 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
     gpu::Batch& batch = *args->_batch;
 
     // Don't render if our parent is set or our material is null
-    QUuid parentID;
-    withReadLock([&] {
-        parentID = _parentID;
-    });
-    if (!parentID.isNull()) {
+    if (!_parentID.isNull()) {
         return;
     }
 
-    Transform renderTransform;
-    graphics::MaterialPointer drawMaterial;
+    graphics::MaterialPointer drawMaterial = getMaterial();
     bool proceduralRender = false;
     Transform textureTransform;
+    textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
+    textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
+    textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
+
+    Transform renderTransform;
     withReadLock([&] {
         renderTransform = _renderTransform;
-        drawMaterial = getMaterial();
-        textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
-        textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
-        textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
-
-        if (drawMaterial && drawMaterial->isProcedural() && drawMaterial->isReady()) {
-            proceduralRender = true;
-        }
     });
+
     if (!drawMaterial) {
         return;
     }
 
+    if (drawMaterial->isProcedural() && drawMaterial->isReady()) {
+        proceduralRender = true;
+    }
+
     batch.setModelTransform(renderTransform);
 
     if (!proceduralRender) {
diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h
index 3a73c988eb..340d169f29 100644
--- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h
@@ -27,8 +27,7 @@ public:
     ~MaterialEntityRenderer() { deleteMaterial(_parentID, _parentMaterialName); }
 
 private:
-    virtual bool needsRenderUpdate() const override;
-    virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
+    virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
     virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
     virtual void doRender(RenderArgs* args) override;
 
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index 8c766d0ab8..e13ab6f837 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -51,12 +51,6 @@ ModelPointer ModelEntityWrapper::getModel() const {
     });
 }
 
-bool ModelEntityWrapper::isModelLoaded() const {
-    return resultWithReadLock<bool>([&] {
-        return _model.operator bool() && _model->isLoaded();
-    });
-}
-
 EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
     EntityItemPointer entity(new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()),
                              [](EntityItem* ptr) { ptr->deleteLater(); });
@@ -69,8 +63,7 @@ EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityI
 RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) :
     ModelEntityWrapper(entityItemID),
     _dimensionsInitialized(dimensionsInitialized) {
-    
-    
+
 }
 
 RenderableModelEntityItem::~RenderableModelEntityItem() { }
@@ -83,34 +76,6 @@ void RenderableModelEntityItem::setUnscaledDimensions(const glm::vec3& value) {
     }
 }
 
-void RenderableModelEntityItem::doInitialModelSimulation() {
-    DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
-    ModelPointer model = getModel();
-    if (!model) {
-        return;
-    }
-    // The machinery for updateModelBounds will give existing models the opportunity to fix their
-    // translation/rotation/scale/registration.  The first two are straightforward, but the latter two have guards to
-    // make sure they don't happen after they've already been set.  Here we reset those guards. This doesn't cause the
-    // entity values to change -- it just allows the model to match once it comes in.
-    model->setScaleToFit(false, getScaledDimensions());
-    model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
-
-    // now recalculate the bounds and registration
-    model->setScaleToFit(true, getScaledDimensions());
-    model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
-    model->setRotation(getWorldOrientation());
-    model->setTranslation(getWorldPosition());
-
-    glm::vec3 scale = model->getScale();
-    model->setUseDualQuaternionSkinning(!isNonUniformScale(scale));
-
-    if (_needsInitialSimulation) {
-        model->simulate(0.0f);
-        _needsInitialSimulation = false;
-    }
-}
-
 void RenderableModelEntityItem::autoResizeJointArrays() {
     ModelPointer model = getModel();
     if (model && model->isLoaded() && !_needsInitialSimulation) {
@@ -125,7 +90,7 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const {
         return false;
     }
 
-    if (!_dimensionsInitialized || !model->isActive()) {
+    if (!_dimensionsInitialized || !model->isLoaded()) {
         return false;
     }
 
@@ -182,22 +147,25 @@ void RenderableModelEntityItem::updateModelBounds() {
     }
 
     bool overridingModelTransform = model->isOverridingModelTransformAndOffset();
+    glm::vec3 scaledDimensions = getScaledDimensions();
+    glm::vec3 registrationPoint = getRegistrationPoint();
     if (!overridingModelTransform &&
-        (model->getScaleToFitDimensions() != getScaledDimensions() ||
-         model->getRegistrationPoint() != getRegistrationPoint() ||
-         !model->getIsScaledToFit())) {
+        (model->getScaleToFitDimensions() != scaledDimensions ||
+         model->getRegistrationPoint() != registrationPoint ||
+         !model->getIsScaledToFit() || _needsToRescaleModel)) {
         // The machinery for updateModelBounds will give existing models the opportunity to fix their
         // translation/rotation/scale/registration.  The first two are straightforward, but the latter two
         // have guards to make sure they don't happen after they've already been set.  Here we reset those guards.
         // This doesn't cause the entity values to change -- it just allows the model to match once it comes in.
-        model->setScaleToFit(false, getScaledDimensions());
-        model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
+        model->setScaleToFit(false, scaledDimensions);
+        model->setSnapModelToRegistrationPoint(false, registrationPoint);
 
         // now recalculate the bounds and registration
-        model->setScaleToFit(true, getScaledDimensions());
-        model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
+        model->setScaleToFit(true, scaledDimensions);
+        model->setSnapModelToRegistrationPoint(true, registrationPoint);
         updateRenderItems = true;
         model->scaleToFit();
+        _needsToRescaleModel = false;
     }
 
     bool success;
@@ -221,6 +189,9 @@ void RenderableModelEntityItem::updateModelBounds() {
         glm::vec3 scale = model->getScale();
         model->setUseDualQuaternionSkinning(!isNonUniformScale(scale));
         model->updateRenderItems();
+
+        markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+        locationChanged();
     }
 }
 
@@ -248,8 +219,6 @@ EntityItemProperties RenderableModelEntityItem::getProperties(const EntityProper
         }
     }
 
-
-
     return properties;
 }
 
@@ -261,7 +230,7 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
                          OctreeElementPointer& element, float& distance, BoxFace& face,
                          glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
     auto model = getModel();
-    if (!model || !isModelLoaded()) {
+    if (!model || !model->isLoaded()) {
         return false;
     }
 
@@ -273,7 +242,7 @@ bool RenderableModelEntityItem::findDetailedParabolaIntersection(const glm::vec3
                         const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance, BoxFace& face,
                         glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
     auto model = getModel();
-    if (!model || !isModelLoaded()) {
+    if (!model || !model->isLoaded()) {
         return false;
     }
 
@@ -281,8 +250,23 @@ bool RenderableModelEntityItem::findDetailedParabolaIntersection(const glm::vec3
         face, surfaceNormal, extraInfo, precisionPicking, false);
 }
 
+QString RenderableModelEntityItem::getCollisionShapeURL() const {
+    return getShapeType() == SHAPE_TYPE_COMPOUND ? getCompoundShapeURL() : getModelURL();
+}
+
 void RenderableModelEntityItem::fetchCollisionGeometryResource() {
     _collisionGeometryResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(getCollisionShapeURL());
+    if (_collisionGeometryResource) {
+        if (_collisionGeometryResource->isLoaded()) {
+            markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+            locationChanged();
+        } else {
+            connect(_collisionGeometryResource.get(), &GeometryResource::finished, this, [&] {
+                markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+                locationChanged();
+            });
+        }
+    }
 }
 
 bool RenderableModelEntityItem::unableToLoadCollisionShape() {
@@ -299,7 +283,7 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) {
         if (!_collisionGeometryResource && !getCollisionShapeURL().isEmpty()) {
             fetchCollisionGeometryResource();
         }
-    } else if (_collisionGeometryResource && !getCompoundShapeURL().isEmpty()) {
+    } else if (_collisionGeometryResource) {
         // the compoundURL has been set but the shapeType does not agree
         _collisionGeometryResource.reset();
     }
@@ -308,49 +292,43 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) {
 void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
     auto currentCompoundShapeURL = getCompoundShapeURL();
     ModelEntityItem::setCompoundShapeURL(url);
-    if (getCompoundShapeURL() != currentCompoundShapeURL || !getModel()) {
-        if (getShapeType() == SHAPE_TYPE_COMPOUND) {
+    if (url != currentCompoundShapeURL && !url.isEmpty()) {
+        auto shapeType = getShapeType();
+        if (shapeType == SHAPE_TYPE_COMPOUND) {
+            fetchCollisionGeometryResource();
+        }
+    }
+}
+
+void RenderableModelEntityItem::setModelURL(const QString& url) {
+    auto currentModelURL = getModelURL();
+    ModelEntityItem::setModelURL(url);
+    if (url != currentModelURL && !url.isEmpty()) {
+        auto shapeType = getShapeType();
+        if (shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
             fetchCollisionGeometryResource();
         }
     }
 }
 
 bool RenderableModelEntityItem::isReadyToComputeShape() const {
-    ShapeType type = getShapeType();
     auto model = getModel();
     auto shapeType = getShapeType();
     if (shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
         auto shapeURL = getCollisionShapeURL();
-
-        if (!model || shapeURL.isEmpty()) {
-            return false;
-        }
-
-        if (model->getURL().isEmpty() || !_dimensionsInitialized) {
-            // we need a render geometry with a scale to proceed, so give up.
-            return false;
-        }
-
-        if (model->isLoaded()) {
-            if (!shapeURL.isEmpty() && !_collisionGeometryResource) {
+        // we need a render geometry with a scale to proceed
+        if (model && !model->getURL().isEmpty() && !shapeURL.isEmpty() && _dimensionsInitialized && model->isLoaded()) {
+            if (!_collisionGeometryResource) {
                 const_cast<RenderableModelEntityItem*>(this)->fetchCollisionGeometryResource();
             }
 
-            if (_collisionGeometryResource && _collisionGeometryResource->isLoaded()) {
-                // we have both URLs AND both geometries AND they are both fully loaded.
-                if (_needsInitialSimulation) {
-                    // the _model's offset will be wrong until _needsInitialSimulation is false
-                    DETAILED_PERFORMANCE_TIMER("_model->simulate");
-                    const_cast<RenderableModelEntityItem*>(this)->doInitialModelSimulation();
-                }
-                return true;
-            }
+            // do we have both URLs AND both geometries AND they are both fully loaded?
+            return _collisionGeometryResource && _collisionGeometryResource->isLoaded() && _collisionGeometryResource->isHFMModelLoaded();
         }
 
-        // the model is still being downloaded.
         return false;
-    } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
-        return isModelLoaded();
+    } else if (shapeType >= SHAPE_TYPE_SIMPLE_HULL && shapeType <= SHAPE_TYPE_STATIC_MESH) {
+        return model && model->isLoaded() && _dimensionsInitialized;
     }
     return true;
 }
@@ -362,20 +340,31 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
     ShapeType type = getShapeType();
 
     auto model = getModel();
-    if (!model || !model->isLoaded()) {
-        type = SHAPE_TYPE_NONE;
+    if (type >= SHAPE_TYPE_COMPOUND && type <= SHAPE_TYPE_STATIC_MESH) {
+        if (!model) {
+            type = SHAPE_TYPE_NONE;
+        } else if (!model->isLoaded()) {
+            type = SHAPE_TYPE_NONE;
+            if (!model->didVisualGeometryRequestFail()) {
+                markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+                locationChanged();
+            }
+        }
+    }
+
+    if (type == SHAPE_TYPE_COMPOUND || type == SHAPE_TYPE_SIMPLE_COMPOUND) {
+        if (!_collisionGeometryResource || !_collisionGeometryResource->isLoaded() || !_collisionGeometryResource->isHFMModelLoaded()) {
+            type = SHAPE_TYPE_NONE;
+            if (!_collisionGeometryResource->isFailed()) {
+                markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
+                locationChanged();
+            }
+        }
     }
 
     if (type == SHAPE_TYPE_COMPOUND) {
-        if (!_collisionGeometryResource || !_collisionGeometryResource->isLoaded()) {
-            return;
-        }
-
         updateModelBounds();
 
-        // should never fall in here when collision model not fully loaded
-        // TODO: assert that all geometries exist and are loaded
-        //assert(_model && _model->isLoaded() && _collisionGeometryResource && _collisionGeometryResource->isLoaded());
         const HFMModel& collisionGeometry = _collisionGeometryResource->getHFMModel();
 
         ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
@@ -452,7 +441,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
         // collision model's extents).
 
         glm::vec3 dimensions = getScaledDimensions();
-        glm::vec3 scaleToFit = dimensions / model->getHFMModel().getUnscaledMeshExtents().size();
+        glm::vec3 extents = model->getHFMModel().getUnscaledMeshExtents().size();
+        glm::vec3 scaleToFit = dimensions / extents;
         // multiply each point by scale before handing the point-set off to the physics engine.
         // also determine the extents of the collision model.
         glm::vec3 registrationOffset = dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
@@ -462,12 +452,10 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
                 pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + model->getOffset()) - registrationOffset;
             }
         }
-        shapeInfo.setParams(type, dimensions, getCompoundShapeURL());
+        shapeInfo.setParams(type, 0.5f * extents, getCompoundShapeURL());
         adjustShapeInfoByRegistration(shapeInfo);
     } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
         updateModelBounds();
-        // assert we never fall in here when model not fully loaded
-        assert(model && model->isLoaded());
         model->updateGeometry();
 
         // compute meshPart local transforms
@@ -476,16 +464,16 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
         int numHFMMeshes = hfmModel.meshes.size();
         int totalNumVertices = 0;
         glm::vec3 dimensions = getScaledDimensions();
-        glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
+        glm::mat4 invRegistrationOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
         for (int i = 0; i < numHFMMeshes; i++) {
             const HFMMesh& mesh = hfmModel.meshes.at(i);
             if (mesh.clusters.size() > 0) {
                 const HFMCluster& cluster = mesh.clusters.at(0);
                 auto jointMatrix = model->getRig().getJointTransform(cluster.jointIndex);
                 // we backtranslate by the registration offset so we can apply that offset to the shapeInfo later
-                localTransforms.push_back(invRegistraionOffset * jointMatrix * cluster.inverseBindMatrix);
+                localTransforms.push_back(invRegistrationOffset * jointMatrix * cluster.inverseBindMatrix);
             } else {
-                localTransforms.push_back(invRegistraionOffset);
+                localTransforms.push_back(invRegistrationOffset);
             }
             totalNumVertices += mesh.vertices.size();
         }
@@ -697,7 +685,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
             }
         }
 
-        shapeInfo.setParams(type, 0.5f * dimensions, getModelURL());
+        shapeInfo.setParams(type, 0.5f * extents.size(), getModelURL());
         adjustShapeInfoByRegistration(shapeInfo);
     } else {
         EntityItem::computeShapeInfo(shapeInfo);
@@ -716,8 +704,8 @@ void RenderableModelEntityItem::setJointMap(std::vector<int> jointMap) {
 
 int RenderableModelEntityItem::avatarJointIndex(int modelJointIndex) {
     int result = -1;
-    int mapSize = (int) _jointMap.size();
-    if (modelJointIndex >=0 && modelJointIndex < mapSize) {
+    int mapSize = (int)_jointMap.size();
+    if (modelJointIndex >= 0 && modelJointIndex < mapSize) {
         result = _jointMap[modelJointIndex];
     }
 
@@ -726,28 +714,44 @@ int RenderableModelEntityItem::avatarJointIndex(int modelJointIndex) {
 
 bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
     auto model = getModel();
-    if (EntityItem::contains(point) && model && _collisionGeometryResource && _collisionGeometryResource->isLoaded()) {
-        glm::mat4 worldToHFMMatrix = model->getWorldToHFMMatrix();
-        glm::vec3 hfmPoint = worldToHFMMatrix * glm::vec4(point, 1.0f);
-        return _collisionGeometryResource->getHFMModel().convexHullContains(hfmPoint);
+    if (model && model->isLoaded()) {
+        auto shapeType = getShapeType();
+        if (shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
+            if (_collisionGeometryResource && _collisionGeometryResource->isLoaded() && _collisionGeometryResource->isHFMModelLoaded() && EntityItem::contains(point)) {
+                glm::mat4 worldToHFMMatrix = model->getWorldToHFMMatrix();
+                glm::vec3 hfmPoint = worldToHFMMatrix * glm::vec4(point, 1.0f);
+                return _collisionGeometryResource->getHFMModel().convexHullContains(hfmPoint);
+            }
+        } else if (shapeType >= SHAPE_TYPE_SIMPLE_HULL && shapeType <= SHAPE_TYPE_STATIC_MESH) {
+            if (EntityItem::contains(point)) {
+                glm::mat4 worldToHFMMatrix = model->getWorldToHFMMatrix();
+                glm::vec3 hfmPoint = worldToHFMMatrix * glm::vec4(point, 1.0f);
+                return model->getHFMModel().convexHullContains(hfmPoint);
+            }
+        } else {
+            return EntityItem::contains(point);
+        }
     }
 
     return false;
 }
 
 bool RenderableModelEntityItem::shouldBePhysical() const {
-    auto model = getModel();
-    // If we have a model, make sure it hasn't failed to download.
-    // If it has, we'll report back that we shouldn't be physical so that physics aren't held waiting for us to be ready.
+    bool physicalModelLoaded = false;
     ShapeType shapeType = getShapeType();
-    if (model) {
-        if ((shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) && model->didCollisionGeometryRequestFail()) {
-            return false;
-        } else if (shapeType != SHAPE_TYPE_NONE && model->didVisualGeometryRequestFail()) {
-            return false;
+    if (shapeType >= SHAPE_TYPE_COMPOUND && shapeType <= SHAPE_TYPE_STATIC_MESH) {
+        auto model = getModel();
+        // If we have a model, make sure it hasn't failed to download.
+        // If it has, we'll report back that we shouldn't be physical so that physics aren't held waiting for us to be ready.
+        physicalModelLoaded = model && !model->didVisualGeometryRequestFail();
+        if (shapeType == SHAPE_TYPE_COMPOUND || shapeType == SHAPE_TYPE_SIMPLE_COMPOUND) {
+            physicalModelLoaded &= _collisionGeometryResource && !_collisionGeometryResource->isFailed();
         }
+    } else if (shapeType != SHAPE_TYPE_NONE) {
+        physicalModelLoaded = true;
     }
-    return !isDead() && shapeType != SHAPE_TYPE_NONE && !isLocalEntity() && QUrl(_modelURL).isValid();
+
+    return physicalModelLoaded && !isDead() && !isLocalEntity() && QUrl(getModelURL()).isValid();
 }
 
 int RenderableModelEntityItem::getJointParent(int index) const {
@@ -943,13 +947,13 @@ void RenderableModelEntityItem::locationChanged(bool tellPhysics, bool tellChild
 
 int RenderableModelEntityItem::getJointIndex(const QString& name) const {
     auto model = getModel();
-    return (model && model->isActive()) ? model->getRig().indexOfJoint(name) : -1;
+    return (model && model->isLoaded()) ? model->getRig().indexOfJoint(name) : -1;
 }
 
 QStringList RenderableModelEntityItem::getJointNames() const {
     QStringList result;
     auto model = getModel();
-    if (model && model->isActive()) {
+    if (model && model->isLoaded()) {
         const Rig& rig = model->getRig();
         int jointCount = rig.getJointStateCount();
         for (int jointIndex = 0; jointIndex < jointCount; jointIndex++) {
@@ -960,13 +964,13 @@ QStringList RenderableModelEntityItem::getJointNames() const {
 }
 
 scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScriptableModel() {
-    auto model = resultWithReadLock<ModelPointer>([this]{ return _model; });
+    auto model = resultWithReadLock<ModelPointer>([&] { return _model; });
 
     if (!model || !model->isLoaded()) {
         return scriptable::ScriptableModelBase();
     }
 
-    auto result = _model->getScriptableModel();
+    auto result = model->getScriptableModel();
     result.objectID = getEntity()->getID();
     {
         std::lock_guard<std::mutex> lock(_materialsLock);
@@ -1036,7 +1040,7 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
     });
 
     if (changed) {
-        locationChanged(true, true);
+        locationChanged();
     }
 }
 
@@ -1054,10 +1058,14 @@ ModelEntityRenderer::ModelEntityRenderer(const EntityItemPointer& entity) : Pare
 
 }
 
-void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed) {
+void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed, const ModelPointer& model) {
     auto builder = ItemKey::Builder().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
 
-    if (!_cullWithParent && _model && _model->isGroupCulled()) {
+    if (!_visible) {
+        builder.withInvisible();
+    }
+
+    if (!_cullWithParent && model && model->isGroupCulled()) {
         builder.withMetaCullGroup();
     } else if (_cullWithParent) {
         builder.withSubMetaCulled();
@@ -1075,8 +1083,9 @@ ItemKey ModelEntityRenderer::getKey() {
 }
 
 uint32_t ModelEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
-    if (_model) {
-        auto metaSubItems = _model->fetchRenderItemIDs();
+    auto model = resultWithReadLock<ModelPointer>([&] { return _model; });
+    if (model) {
+        auto metaSubItems = model->fetchRenderItemIDs();
         subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end());
         return (uint32_t)metaSubItems.size();
     }
@@ -1089,8 +1098,9 @@ void ModelEntityRenderer::handleBlendedVertices(int blendshapeNumber, const QVec
 }
 
 void ModelEntityRenderer::removeFromScene(const ScenePointer& scene, Transaction& transaction) {
-    if (_model) {
-        _model->removeFromScene(scene, transaction);
+    auto model = resultWithReadLock<ModelPointer>([&] { return _model; });
+    if (model) {
+        model->removeFromScene(scene, transaction);
     }
     Parent::removeFromScene(scene, transaction);
 }
@@ -1099,14 +1109,14 @@ void ModelEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entit
     entity->setModel({});
 }
 
-void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
+void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelPointer& model) {
     if (!_animation || !_animation->isLoaded()) {
         return;
     }
 
     QVector<EntityJointData> jointsData;
 
-    const QVector<HFMAnimationFrame>&  frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
+    const QVector<HFMAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
     int frameCount = frames.size();
     if (frameCount <= 0) {
         return;
@@ -1124,17 +1134,17 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
         _lastKnownCurrentFrame = currentIntegerFrame;
     }
 
-    if (_jointMapping.size() != _model->getJointStateCount()) {
+    if (_jointMapping.size() != model->getJointStateCount()) {
         qCWarning(entitiesrenderer) << "RenderableModelEntityItem::getAnimationFrame -- joint count mismatch"
-                    << _jointMapping.size() << _model->getJointStateCount();
+                    << _jointMapping.size() << model->getJointStateCount();
         return;
     }
 
     QStringList animationJointNames = _animation->getHFMModel().getJointNames();
     auto& hfmJoints = _animation->getHFMModel().joints;
 
-    auto& originalHFMJoints = _model->getHFMModel().joints;
-    auto& originalHFMIndices = _model->getHFMModel().jointIndices;
+    auto& originalHFMJoints = model->getHFMModel().joints;
+    auto& originalHFMIndices = model->getHFMModel().jointIndices;
 
     bool allowTranslation = entity->getAnimationAllowTranslation();
 
@@ -1182,146 +1192,49 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
     entity->copyAnimationJointDataToModel();
 }
 
-bool ModelEntityRenderer::needsRenderUpdate() const {
-    if (resultWithReadLock<bool>([&] {
-        if (_moving || _animating) {
-            return true;
-        }
-
-        if (!_texturesLoaded) {
-            return true;
-        }
-
-        if (!_prevModelLoaded) {
-            return true;
-        }
-
-        return false;
-    })) {
+bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
+    if (entity->blendshapesChanged()) {
         return true;
     }
 
-    ModelPointer model;
-    QUrl parsedModelURL;
-    withReadLock([&] {
-        model = _model;
-        parsedModelURL = _parsedModelURL;
-    });
-
-    if (model) {
-        // When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
-        // we will watch for that and ask the model to update it's render items
-        if (parsedModelURL != model->getURL()) {
-            return true;
-        }
-
-        if (model->needsReload()) {
-            return true;
-        }
-
-        if (model->needsFixupInScene()) {
-            return true;
-        }
-
-        if (model->getRenderItemsNeedUpdate()) {
-            return true;
-        }
-    }
-    return Parent::needsRenderUpdate();
-}
-
-bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
-    if (resultWithReadLock<bool>([&] {
-        if (entity->hasModel() != _hasModel) {
-            return true;
-        }
-
-        // No model to render, early exit
-        if (!_hasModel) {
-            return false;
-        }
-
-        if (_animating != entity->isAnimatingSomething()) {
-            return true;
-        }
-
-        return false;
-    })) { return true; }
-
-    ModelPointer model;
-    withReadLock([&] {
-        model = _model;
-    });
-
-    if (model && model->isLoaded()) {
-        if (!entity->_dimensionsInitialized || entity->_needsInitialSimulation || !entity->_originalTexturesRead) {
-            return true;
-        }
-
-        if (entity->blendshapesChanged()) {
-            return true;
-        }
-
-        // Check to see if we need to update the model bounds
-        if (entity->needsUpdateModelBounds()) {
-            return true;
-        }
-
-        // Check to see if we need to update the model bounds
-        auto transform = entity->getTransform();
-        if (model->getTranslation() != transform.getTranslation() ||
-            model->getRotation() != transform.getRotation()) {
-            return true;
-        }
-
-        if (model->getScaleToFitDimensions() != entity->getScaledDimensions() ||
-            model->getRegistrationPoint() != entity->getRegistrationPoint()) {
-            return true;
-        }
+    // Check to see if we need to update the model bounds
+    if (entity->needsUpdateModelBounds()) {
+        return true;
     }
 
-    return false;
+    return Parent::needsRenderUpdateFromTypedEntity(entity);
 }
 
-void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
+void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
     DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
-    if (_hasModel != entity->hasModel()) {
-        withWriteLock([&] {
-            _hasModel = entity->hasModel();
-        });
+
+    _hasModel = entity->hasModel();
+    QUrl modelURL = QUrl(entity->getModelURL());
+    if (_parsedModelURL != modelURL) {
+        _parsedModelURL = modelURL;
     }
 
-    withWriteLock([&] {
-        _animating = entity->isAnimatingSomething();
-        if (_parsedModelURL != entity->getModelURL()) {
-            _parsedModelURL = QUrl(entity->getModelURL());
-        }
+    ModelPointer model = resultWithReadLock<ModelPointer>([&] {
+        return _model;
     });
 
-    ModelPointer model;
-    withReadLock([&] { model = _model; });
+    bool visuallyReady = model && model->isLoaded() && _didLastVisualGeometryRequestSucceed && _texturesLoaded;
+    entity->setVisuallyReady(visuallyReady);
 
-    withWriteLock([&] {
-        bool visuallyReady = true;
-        if (_hasModel) {
-            if (model && _didLastVisualGeometryRequestSucceed) {
-                visuallyReady = (_prevModelLoaded && _texturesLoaded);
-            }
-        }
-        entity->setVisuallyReady(visuallyReady);
-    });
+    const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene();
+    render::Transaction transaction;
 
     // Check for removal
     if (!_hasModel) {
         if (model) {
             model->removeFromScene(scene, transaction);
             entity->bumpAncestorChainRenderableVersion();
-            withWriteLock([&] { _model.reset(); });
             emit DependencyManager::get<scriptable::ModelProviderFactory>()->
-                modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, _model);
+                modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, model);
+            withWriteLock([&] { _model.reset(); });
         }
-        setKey(false);
         _didLastVisualGeometryRequestSucceed = false;
+        setKey(_didLastVisualGeometryRequestSucceed, model);
         return;
     }
 
@@ -1330,48 +1243,52 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
         model = std::make_shared<Model>(nullptr, entity.get(), _created);
         connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
         connect(model.get(), &Model::setURLFinished, this, [&](bool didVisualGeometryRequestSucceed) {
-            setKey(didVisualGeometryRequestSucceed);
-            _model->setTagMask(getTagMask());
-            _model->setHifiRenderLayer(getHifiRenderLayer());
-            _model->setPrimitiveMode(_primitiveMode);
-            _model->setCullWithParent(_cullWithParent);
-            _model->setRenderWithZones(_renderWithZones);
-            emit requestRenderUpdate();
-            if (didVisualGeometryRequestSucceed) {
-                emit DependencyManager::get<scriptable::ModelProviderFactory>()->
-                    modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, _model);
-            }
             _didLastVisualGeometryRequestSucceed = didVisualGeometryRequestSucceed;
+            const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene();
+            render::Transaction transaction;
+            transaction.updateItem<PayloadProxyInterface>(_renderItemID, [&](PayloadProxyInterface& self) {
+                const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene();
+                withWriteLock([&] {
+                    setKey(didVisualGeometryRequestSucceed, _model);
+                    _model->setVisibleInScene(_visible, scene);
+                    _model->setCauterized(_cauterized, scene);
+                    _model->setCanCastShadow(_canCastShadow, scene);
+                    _model->setGroupCulled(entity->getGroupCulled(), scene);
+                    _model->setTagMask(getTagMask(), scene);
+                    _model->setHifiRenderLayer(getHifiRenderLayer(), scene);
+                    _model->setPrimitiveMode(_primitiveMode, scene);
+                    _model->setCullWithParent(_cullWithParent, scene);
+                    _model->setRenderWithZones(_renderWithZones, scene);
+                });
+                if (didVisualGeometryRequestSucceed) {
+                    emit DependencyManager::get<scriptable::ModelProviderFactory>()->
+                        modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, model);
+                }
+                entity->_originalTexturesRead = false;
+                entity->_needsJointSimulation = true;
+                entity->_needsToRescaleModel = true;
+                emit requestRenderUpdate();
+            });
+            scene->enqueueTransaction(transaction);
         });
-        model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
         entity->setModel(model);
         withWriteLock([&] { _model = model; });
     }
 
     // From here on, we are guaranteed a populated model
     if (_parsedModelURL != model->getURL()) {
-        withWriteLock([&] {
-            _texturesLoaded = false;
-            _jointMappingCompleted = false;
-            model->setURL(_parsedModelURL);
-        });
+        _texturesLoaded = false;
+        _jointMappingCompleted = false;
+        model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
+        model->setURL(_parsedModelURL);
     }
 
     // Nothing else to do unless the model is loaded
     if (!model->isLoaded()) {
-        withWriteLock([&] {
-            _prevModelLoaded = false;
-        });
-        emit requestRenderUpdate();
         return;
-    } else if (!_prevModelLoaded) {
-        withWriteLock([&] {
-            _prevModelLoaded = true;
-        });
     }
 
     // Check for initializing the model
-    // FIXME: There are several places below here where we are modifying the entity, which we should not be doing from the renderable
     if (!entity->_dimensionsInitialized) {
         EntityItemProperties properties;
         properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it
@@ -1391,53 +1308,39 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
         entity->_originalTexturesRead = true;
     }
 
-    if (_textures != entity->getTextures()) {
+    auto textures = entity->getTextures();
+    if (_textures != textures) {
         QVariantMap newTextures;
-        withWriteLock([&] {
-            _texturesLoaded = false;
-            _textures = entity->getTextures();
-            newTextures = parseTexturesToMap(_textures, entity->_originalTextures);
-        });
+        _texturesLoaded = false;
+        _textures = textures;
+        newTextures = parseTexturesToMap(_textures, entity->_originalTextures);
         model->setTextures(newTextures);
     }
+
     if (entity->_needsJointSimulation) {
         entity->copyAnimationJointDataToModel();
     }
     entity->updateModelBounds();
     entity->stopModelOverrideIfNoParent();
 
-    if (model->isVisible() != _visible) {
+    withWriteLock([&] {
+        setKey(_didLastVisualGeometryRequestSucceed, model);
         model->setVisibleInScene(_visible, scene);
-    }
-
-    if (model->isCauterized() != _cauterized) {
         model->setCauterized(_cauterized, scene);
-    }
-
-    render::hifi::Tag tagMask = getTagMask();
-    if (model->getTagMask() != tagMask) {
-        model->setTagMask(tagMask, scene);
-    }
+        model->setCanCastShadow(_canCastShadow, scene);
+        model->setGroupCulled(entity->getGroupCulled(), scene);
+        model->setTagMask(getTagMask(), scene);
+        model->setHifiRenderLayer(getHifiRenderLayer(), scene);
+        model->setPrimitiveMode(_primitiveMode, scene);
+        model->setCullWithParent(_cullWithParent, scene);
+        model->setRenderWithZones(_renderWithZones, scene);
+    });
 
     if (entity->blendshapesChanged()) {
         model->setBlendshapeCoefficients(entity->getBlendshapeCoefficientVector());
         model->updateBlendshapes();
     }
 
-    // TODO? early exit here when not visible?
-
-    if (model->canCastShadow() != _canCastShadow) {
-        model->setCanCastShadow(_canCastShadow, scene);
-    }
-
-    {
-        bool groupCulled = entity->getGroupCulled();
-        if (model->isGroupCulled() != groupCulled) {
-            model->setGroupCulled(groupCulled);
-            setKey(_didLastVisualGeometryRequestSucceed);
-        }
-    }
-
     {
         DETAILED_PROFILE_RANGE(simulation_physics, "Fixup");
         if (model->needsFixupInScene()) {
@@ -1451,11 +1354,10 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
         }
     }
 
+    bool needsUpdate = false;
     if (!_texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) {
-        withWriteLock([&] {
-            _texturesLoaded = true;
-        });
-        model->updateRenderItems();
+        _texturesLoaded = true;
+        needsUpdate = true;
     } else if (!_texturesLoaded) {
         emit requestRenderUpdate();
     }
@@ -1481,19 +1383,23 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
             emit requestRenderUpdate();
         } else {
             _allProceduralMaterialsLoaded = true;
-            model->setRenderItemsNeedUpdate();
+            needsUpdate = true;
         }
     }
 
     // When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
     // we will watch for that and ask the model to update it's render items
-    if (model->getRenderItemsNeedUpdate()) {
+    if (needsUpdate || model->getRenderItemsNeedUpdate()) {
         model->updateRenderItems();
     }
 
+    scene->enqueueTransaction(transaction);
+}
+
+void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
     // The code to deal with the change of properties is now in ModelEntityItem.cpp
     // That is where _currentFrame and _lastAnimated were updated.
-    if (_animating) {
+    if (entity->isAnimatingSomething()) {
         DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
 
         auto animationURL = entity->getAnimationURL();
@@ -1502,18 +1408,22 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
             _animationURL = animationURL;
 
             if (_animation) {
-                //(_animation->getURL().toString() != entity->getAnimationURL())) { // bad check
                 // the joints have been mapped before but we have a new animation to load
                 _animation.reset();
                 _jointMappingCompleted = false;
             }
         }
-
-        if (!_jointMappingCompleted) {
-            mapJoints(entity, model);
-        }
-        if (entity->readyToAnimate()) {
-            animate(entity);
+        
+        ModelPointer model = resultWithReadLock<ModelPointer>([&] {
+            return _model;
+        });
+        if (model && model->isLoaded()) {
+            if (!_jointMappingCompleted) {
+                mapJoints(entity, model);
+            }
+            if (entity->readyToAnimate()) {
+                animate(entity, model);
+            }
         }
         emit requestRenderUpdate();
     }
@@ -1521,40 +1431,20 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
 
 void ModelEntityRenderer::setIsVisibleInSecondaryCamera(bool value) {
     Parent::setIsVisibleInSecondaryCamera(value);
-    setKey(_didLastVisualGeometryRequestSucceed);
-    if (_model) {
-        _model->setTagMask(getTagMask());
-    }
+    // called within a lock so no need to lock for _model
+    setKey(_didLastVisualGeometryRequestSucceed, _model);
 }
 
 void ModelEntityRenderer::setRenderLayer(RenderLayer value) {
     Parent::setRenderLayer(value);
-    setKey(_didLastVisualGeometryRequestSucceed);
-    if (_model) {
-        _model->setHifiRenderLayer(getHifiRenderLayer());
-    }
-}
-
-void ModelEntityRenderer::setPrimitiveMode(PrimitiveMode value) {
-    Parent::setPrimitiveMode(value);
-    if (_model) {
-        _model->setPrimitiveMode(_primitiveMode);
-    }
+    // called within a lock so no need to lock for _model
+    setKey(_didLastVisualGeometryRequestSucceed, _model);
 }
 
 void ModelEntityRenderer::setCullWithParent(bool value) {
     Parent::setCullWithParent(value);
-    setKey(_didLastVisualGeometryRequestSucceed);
-    if (_model) {
-        _model->setCullWithParent(_cullWithParent);
-    }
-}
-
-void ModelEntityRenderer::setRenderWithZones(const QVector<QUuid>& renderWithZones) {
-    Parent::setRenderWithZones(renderWithZones);
-    if (_model) {
-        _model->setRenderWithZones(renderWithZones);
-    }
+    // called within a lock so no need to lock for _model
+    setKey(_didLastVisualGeometryRequestSucceed, _model);
 }
 
 // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
@@ -1570,9 +1460,8 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
     geometryCache->renderWireCubeInstance(args, batch, greenColor, geometryCache->getShapePipelinePointer(false, false, args->_renderMethod == Args::RenderMethod::FORWARD));
 
 #if WANT_EXTRA_DEBUGGING
-    ModelPointer model;
-    withReadLock([&] {
-        model = _model;
+    ModelPointer model = resultWithReadLock<ModelPointer>([&] {
+        return _model;
     });
     if (model) {
         model->renderDebugMeshBoxes(batch, args->_renderMethod == Args::RenderMethod::FORWARD);
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h
index 850617d1af..4501f6d88c 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h
@@ -41,7 +41,6 @@ protected:
     ModelEntityWrapper(const EntityItemID& entityItemID) : Parent(entityItemID) {}
     void setModel(const ModelPointer& model);
     ModelPointer getModel() const;
-    bool isModelLoaded() const;
 
     bool _needsInitialSimulation{ true };
 private:
@@ -62,7 +61,6 @@ public:
     virtual void setUnscaledDimensions(const glm::vec3& value) override;
 
     virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override;
-    void doInitialModelSimulation();
     void updateModelBounds();
 
     virtual bool supportsDetailedIntersection() const override;
@@ -77,6 +75,7 @@ public:
 
     virtual void setShapeType(ShapeType type) override;
     virtual void setCompoundShapeURL(const QString& url) override;
+    virtual void setModelURL(const QString& url) override;
 
     virtual bool isReadyToComputeShape() const override;
     virtual void computeShapeInfo(ShapeInfo& shapeInfo) override;
@@ -121,6 +120,8 @@ private:
     bool readyToAnimate() const;
     void fetchCollisionGeometryResource();
 
+    QString getCollisionShapeURL() const;
+
     GeometryResource::Pointer _collisionGeometryResource;
     std::vector<int> _jointMap;
     QVariantMap _originalTextures;
@@ -128,6 +129,7 @@ private:
     bool _originalTexturesRead { false };
     bool _dimensionsInitialized { true };
     bool _needsJointSimulation { false };
+    bool _needsToRescaleModel { false };
 };
 
 namespace render { namespace entities { 
@@ -153,25 +155,23 @@ protected:
     virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;
     virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
 
-    void setKey(bool didVisualGeometryRequestSucceed);
+    void setKey(bool didVisualGeometryRequestSucceed, const ModelPointer& model);
     virtual ItemKey getKey() override;
     virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
     virtual void handleBlendedVertices(int blendshapeNumber, const QVector<BlendshapeOffset>& blendshapeOffsets,
                                        const QVector<int>& blendedMeshSizes, const render::ItemIDs& subItemIDs) override;
 
     virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
-    virtual bool needsRenderUpdate() const override;
-    virtual void doRender(RenderArgs* args) override;
     virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
+    virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
+    virtual void doRender(RenderArgs* args) override;
 
     void setIsVisibleInSecondaryCamera(bool value) override;
     void setRenderLayer(RenderLayer value) override;
-    void setPrimitiveMode(PrimitiveMode value) override;
     void setCullWithParent(bool value) override;
-    void setRenderWithZones(const QVector<QUuid>& renderWithZones) override;
 
 private:
-    void animate(const TypedEntityPointer& entity);
+    void animate(const TypedEntityPointer& entity, const ModelPointer& model);
     void mapJoints(const TypedEntityPointer& entity, const ModelPointer& model);
 
     // Transparency is handled in ModelMeshPartPayload
@@ -186,20 +186,16 @@ private:
     bool _hasTransitioned{ false };
 #endif
 
-    const void* _collisionMeshKey { nullptr };
-
     QUrl _parsedModelURL;
     bool _jointMappingCompleted { false };
     QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints
     AnimationPointer _animation;
-    bool _animating { false };
     QString _animationURL;
     uint64_t _lastAnimated { 0 };
 
     render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() };
 
     bool _didLastVisualGeometryRequestSucceed { true };
-    bool _prevModelLoaded { false };
 
     void processMaterials();
     bool _allProceduralMaterialsLoaded { false };
diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
index 8bca6cbe96..e53e52d105 100644
--- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
@@ -64,84 +64,7 @@ ParticleEffectEntityRenderer::ParticleEffectEntityRenderer(const EntityItemPoint
     });
 }
 
-bool ParticleEffectEntityRenderer::needsRenderUpdate() const {
-    if (resultWithReadLock<bool>([&] {
-        return !_textureLoaded;
-    })) {
-        return true;
-    }
-
-    return Parent::needsRenderUpdate();
-}
-
 void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
-    auto newParticleProperties = entity->getParticleProperties();
-    if (!newParticleProperties.valid()) {
-        qCWarning(entitiesrenderer) << "Bad particle properties";
-    }
-
-    if (resultWithReadLock<bool>([&] { return _particleProperties != newParticleProperties; })) {
-        _timeUntilNextEmit = 0;
-        withWriteLock([&] {
-            _particleProperties = newParticleProperties;
-            if (!_prevEmitterShouldTrailInitialized) {
-                _prevEmitterShouldTrailInitialized = true;
-                _prevEmitterShouldTrail = _particleProperties.emission.shouldTrail;
-            }
-        });
-    }
-
-    withWriteLock([&] {
-        _pulseProperties = entity->getPulseProperties();
-        _shapeType = entity->getShapeType();
-        QString compoundShapeURL = entity->getCompoundShapeURL();
-        if (_compoundShapeURL != compoundShapeURL) {
-            _compoundShapeURL = compoundShapeURL;
-            _hasComputedTriangles = false;
-            fetchGeometryResource();
-        }
-    });
-    _emitting = entity->getIsEmitting();
-
-    bool textureEmpty = resultWithReadLock<bool>([&] { return _particleProperties.textures.isEmpty(); });
-    if (textureEmpty) {
-        if (_networkTexture) {
-            withWriteLock([&] {
-                _networkTexture.reset();
-            });
-        }
-
-        withWriteLock([&] {
-            _textureLoaded = true;
-            entity->setVisuallyReady(true);
-        });
-    } else {
-        bool textureNeedsUpdate = resultWithReadLock<bool>([&] {
-            return !_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures);
-        });
-        if (textureNeedsUpdate) {
-            withWriteLock([&] {
-                _networkTexture = DependencyManager::get<TextureCache>()->getTexture(_particleProperties.textures);
-                _textureLoaded = false;
-                entity->setVisuallyReady(false);
-            });
-        }
-
-        if (!_textureLoaded) {
-            emit requestRenderUpdate();
-        }
-
-        bool textureLoaded = resultWithReadLock<bool>([&] {
-            return _networkTexture && (_networkTexture->isLoaded() || _networkTexture->isFailed());
-        });
-        if (textureLoaded) {
-            withWriteLock([&] {
-                entity->setVisuallyReady(true);
-                _textureLoaded = true;
-            });
-        }
-    }
-
     void* key = (void*)this;
     AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this] {
         withWriteLock([&] {
@@ -151,20 +74,66 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi
 }
 
 void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
+    auto newParticleProperties = entity->getParticleProperties();
+    if (!newParticleProperties.valid()) {
+        qCWarning(entitiesrenderer) << "Bad particle properties";
+    }
+
+    if (_particleProperties != newParticleProperties) {
+        _timeUntilNextEmit = 0;
+        _particleProperties = newParticleProperties;
+        if (!_prevEmitterShouldTrailInitialized) {
+            _prevEmitterShouldTrailInitialized = true;
+            _prevEmitterShouldTrail = _particleProperties.emission.shouldTrail;
+        }
+    }
+
+    _pulseProperties = entity->getPulseProperties();
+    _shapeType = entity->getShapeType();
+    QString compoundShapeURL = entity->getCompoundShapeURL();
+    if (_compoundShapeURL != compoundShapeURL) {
+        _compoundShapeURL = compoundShapeURL;
+        _hasComputedTriangles = false;
+        fetchGeometryResource();
+    }
+    _emitting = entity->getIsEmitting();
+
+    if (_particleProperties.textures.isEmpty()) {
+        if (_networkTexture) {
+            _networkTexture.reset();
+        }
+
+        _textureLoaded = true;
+        entity->setVisuallyReady(true);
+    } else {
+        if (!_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures)) {
+            _networkTexture = DependencyManager::get<TextureCache>()->getTexture(_particleProperties.textures);
+            _textureLoaded = false;
+            entity->setVisuallyReady(false);
+        }
+
+        if (!_textureLoaded) {
+            emit requestRenderUpdate();
+        }
+
+        if (_networkTexture && (_networkTexture->isLoaded() || _networkTexture->isFailed())) {
+            entity->setVisuallyReady(true);
+            _textureLoaded = true;
+        }
+    }
+
     // Fill in Uniforms structure
     ParticleUniforms particleUniforms;
-    withReadLock([&] {
-        particleUniforms.radius.start = _particleProperties.radius.range.start;
-        particleUniforms.radius.middle = _particleProperties.radius.gradient.target;
-        particleUniforms.radius.finish = _particleProperties.radius.range.finish;
-        particleUniforms.radius.spread = _particleProperties.radius.gradient.spread;
-        particleUniforms.spin.start = _particleProperties.spin.range.start;
-        particleUniforms.spin.middle = _particleProperties.spin.gradient.target;
-        particleUniforms.spin.finish = _particleProperties.spin.range.finish;
-        particleUniforms.spin.spread = _particleProperties.spin.gradient.spread;
-        particleUniforms.lifespan = _particleProperties.lifespan;
-        particleUniforms.rotateWithEntity = _particleProperties.rotateWithEntity ? 1 : 0;
-    });
+    particleUniforms.radius.start = _particleProperties.radius.range.start;
+    particleUniforms.radius.middle = _particleProperties.radius.gradient.target;
+    particleUniforms.radius.finish = _particleProperties.radius.range.finish;
+    particleUniforms.radius.spread = _particleProperties.radius.gradient.spread;
+    particleUniforms.spin.start = _particleProperties.spin.range.start;
+    particleUniforms.spin.middle = _particleProperties.spin.gradient.target;
+    particleUniforms.spin.finish = _particleProperties.spin.range.finish;
+    particleUniforms.spin.spread = _particleProperties.spin.gradient.spread;
+    particleUniforms.lifespan = _particleProperties.lifespan;
+    particleUniforms.rotateWithEntity = _particleProperties.rotateWithEntity ? 1 : 0;
     // Update particle uniforms
     _uniformBuffer.edit<ParticleUniforms>() = particleUniforms;
 }
@@ -403,27 +372,18 @@ void ParticleEffectEntityRenderer::stepSimulation() {
     const auto interval = std::min<uint64_t>(USECS_PER_SECOND / 60, now - _lastSimulated);
     _lastSimulated = now;
 
-    particle::Properties particleProperties;
-    ShapeType shapeType;
-    GeometryResource::Pointer geometryResource;
-    withReadLock([&] {
-        particleProperties = _particleProperties;
-        shapeType = _shapeType;
-        geometryResource = _geometryResource;
-    });
-
     const auto& modelTransform = getModelTransform();
-    if (_emitting && particleProperties.emitting() &&
-        (shapeType != SHAPE_TYPE_COMPOUND || (geometryResource && geometryResource->isLoaded()))) {
-        uint64_t emitInterval = particleProperties.emitIntervalUsecs();
+    if (_emitting && _particleProperties.emitting() &&
+        (_shapeType != SHAPE_TYPE_COMPOUND || (_geometryResource && _geometryResource->isLoaded()))) {
+        uint64_t emitInterval = _particleProperties.emitIntervalUsecs();
         if (emitInterval > 0 && interval >= _timeUntilNextEmit) {
             auto timeRemaining = interval;
             while (timeRemaining > _timeUntilNextEmit) {
                 if (_shapeType == SHAPE_TYPE_COMPOUND && !_hasComputedTriangles) {
-                    computeTriangles(geometryResource->getHFMModel());
+                    computeTriangles(_geometryResource->getHFMModel());
                 }
                 // emit particle
-                _cpuParticles.push_back(createParticle(modelTransform, particleProperties, shapeType, geometryResource, _triangleInfo));
+                _cpuParticles.push_back(createParticle(modelTransform, _particleProperties, _shapeType, _geometryResource, _triangleInfo));
                 _timeUntilNextEmit = emitInterval;
                 if (emitInterval < timeRemaining) {
                     timeRemaining -= emitInterval;
@@ -435,14 +395,14 @@ void ParticleEffectEntityRenderer::stepSimulation() {
     }
 
     // Kill any particles that have expired or are over the max size
-    while (_cpuParticles.size() > particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration == 0)) {
+    while (_cpuParticles.size() > _particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration == 0)) {
         _cpuParticles.pop_front();
     }
 
     const float deltaTime = (float)interval / (float)USECS_PER_SECOND;
     // update the particles
     for (auto& particle : _cpuParticles) {
-        if (_prevEmitterShouldTrail != particleProperties.emission.shouldTrail) {
+        if (_prevEmitterShouldTrail != _particleProperties.emission.shouldTrail) {
             if (_prevEmitterShouldTrail) {
                 particle.relativePosition = particle.relativePosition + particle.basePosition - modelTransform.getTranslation();
             }
@@ -451,14 +411,14 @@ void ParticleEffectEntityRenderer::stepSimulation() {
         particle.expiration = particle.expiration >= interval ? particle.expiration - interval : 0;
         particle.integrate(deltaTime);
     }
-    _prevEmitterShouldTrail = particleProperties.emission.shouldTrail;
+    _prevEmitterShouldTrail = _particleProperties.emission.shouldTrail;
 
     // Build particle primitives
     static GpuParticles gpuParticles;
     gpuParticles.clear();
     gpuParticles.reserve(_cpuParticles.size()); // Reserve space
-    std::transform(_cpuParticles.begin(), _cpuParticles.end(), std::back_inserter(gpuParticles), [&particleProperties, &modelTransform] (const CpuParticle& particle) {
-        glm::vec3 position = particle.relativePosition + (particleProperties.emission.shouldTrail ? particle.basePosition : modelTransform.getTranslation());
+    std::transform(_cpuParticles.begin(), _cpuParticles.end(), std::back_inserter(gpuParticles), [this, &modelTransform] (const CpuParticle& particle) {
+        glm::vec3 position = particle.relativePosition + (_particleProperties.emission.shouldTrail ? particle.basePosition : modelTransform.getTranslation());
         return GpuParticle(position, glm::vec2(particle.lifetime, particle.seed));
     });
 
@@ -487,13 +447,14 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) {
     // if the particles are marked rotateWithEntity
     withReadLock([&] {
         transform.setRotation(_renderTransform.getRotation());
-        auto& color = _uniformBuffer.edit<ParticleUniforms>().color;
-        color.start = EntityRenderer::calculatePulseColor(_particleProperties.getColorStart(), _pulseProperties, _created);
-        color.middle = EntityRenderer::calculatePulseColor(_particleProperties.getColorMiddle(), _pulseProperties, _created);
-        color.finish = EntityRenderer::calculatePulseColor(_particleProperties.getColorFinish(), _pulseProperties, _created);
-        color.spread = EntityRenderer::calculatePulseColor(_particleProperties.getColorSpread(), _pulseProperties, _created);
     });
 
+    auto& color = _uniformBuffer.edit<ParticleUniforms>().color;
+    color.start = EntityRenderer::calculatePulseColor(_particleProperties.getColorStart(), _pulseProperties, _created);
+    color.middle = EntityRenderer::calculatePulseColor(_particleProperties.getColorMiddle(), _pulseProperties, _created);
+    color.finish = EntityRenderer::calculatePulseColor(_particleProperties.getColorFinish(), _pulseProperties, _created);
+    color.spread = EntityRenderer::calculatePulseColor(_particleProperties.getColorSpread(), _pulseProperties, _created);
+
     batch.setModelTransform(transform);
     batch.setUniformBuffer(0, _uniformBuffer);
     batch.setInputFormat(_vertexFormat);
diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h
index 0811b231d8..ca6bc859fb 100644
--- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h
@@ -25,7 +25,6 @@ public:
     ParticleEffectEntityRenderer(const EntityItemPointer& entity);
 
 protected:
-    virtual bool needsRenderUpdate() const override;
     virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
     virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
 
diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
index a843083831..f98a54d594 100644
--- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
@@ -121,16 +121,6 @@ ShapeKey PolyLineEntityRenderer::getShapeKey() {
     return builder.build();
 }
 
-bool PolyLineEntityRenderer::needsRenderUpdate() const {
-    if (resultWithReadLock<bool>([&] {
-        return (!_textureLoaded && _texture && _texture->isLoaded());
-    })) {
-        return true;
-    }
-
-    return Parent::needsRenderUpdate();
-}
-
 bool PolyLineEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
     if (entity->pointsChanged() || entity->widthsChanged() || entity->normalsChanged() || entity->texturesChanged() || entity->colorsChanged()) {
         return true;
@@ -140,6 +130,15 @@ bool PolyLineEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP
 }
 
 void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
+    void* key = (void*)this;
+    AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this] {
+        withWriteLock([&] {
+            _renderTransform = getModelTransform();
+        });
+    });
+}
+
+void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
     auto pointsChanged = entity->pointsChanged();
     auto widthsChanged = entity->widthsChanged();
     auto normalsChanged = entity->normalsChanged();
@@ -159,13 +158,15 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
         if (!textures.isEmpty()) {
             entityTextures = QUrl(textures);
         }
-        withWriteLock([&] {
-            _texture = DependencyManager::get<TextureCache>()->getTexture(entityTextures);
-        });
+        _texture = DependencyManager::get<TextureCache>()->getTexture(entityTextures);
         _textureAspectRatio = 1.0f;
         _textureLoaded = false;
     }
 
+    if (!_textureLoaded) {
+        emit requestRenderUpdate();
+    }
+
     bool textureChanged = false;
     if (!_textureLoaded && _texture && _texture->isLoaded()) {
         textureChanged = true;
@@ -175,13 +176,11 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
 
     // Data
     bool faceCameraChanged = faceCamera != _faceCamera;
-    withWriteLock([&] {
-        if (faceCameraChanged || glow != _glow) {
-            _faceCamera = faceCamera;
-            _glow = glow;
-            updateData();
-        }
-    });
+    if (faceCameraChanged || glow != _glow) {
+        _faceCamera = faceCamera;
+        _glow = glow;
+        updateData();
+    }
 
     // Geometry
     if (pointsChanged) {
@@ -200,19 +199,10 @@ void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer&
 
     bool uvModeStretchChanged = _isUVModeStretch != isUVModeStretch;
     _isUVModeStretch = isUVModeStretch;
-    
-    bool geometryChanged = uvModeStretchChanged || pointsChanged || widthsChanged || normalsChanged || colorsChanged || textureChanged || faceCameraChanged;
 
-    void* key = (void*)this;
-    AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, geometryChanged] {
-        withWriteLock([&] {
-            _renderTransform = getModelTransform();
-
-            if (geometryChanged) {
-                updateGeometry();
-            }
-        });
-    });
+    if (uvModeStretchChanged || pointsChanged || widthsChanged || normalsChanged || colorsChanged || textureChanged || faceCameraChanged) {
+        updateGeometry();
+    }
 }
 
 void PolyLineEntityRenderer::updateGeometry() {
@@ -318,19 +308,16 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
     Q_ASSERT(args->_batch);
     gpu::Batch& batch = *args->_batch;
 
-    size_t numVertices;
     Transform transform;
-    gpu::TexturePointer texture;
+    gpu::TexturePointer texture = _textureLoaded ? _texture->getGPUTexture() : DependencyManager::get<TextureCache>()->getWhiteTexture();
     withReadLock([&] {
-        numVertices = _numVertices;
         transform = _renderTransform;
-        texture = _textureLoaded ? _texture->getGPUTexture() : DependencyManager::get<TextureCache>()->getWhiteTexture();
-
-        batch.setResourceBuffer(0, _polylineGeometryBuffer);
-        batch.setUniformBuffer(0, _polylineDataBuffer);
     });
 
-    if (numVertices < 2) {
+    batch.setResourceBuffer(0, _polylineGeometryBuffer);
+    batch.setUniformBuffer(0, _polylineDataBuffer);
+
+    if (_numVertices < 2) {
         return;
     }
 
@@ -341,5 +328,5 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
     batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]);
     batch.setModelTransform(transform);
     batch.setResourceTexture(0, texture);
-    batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * numVertices), 0);
+    batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * _numVertices), 0);
 }
diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h
index 41b66c0e51..c4fbb9a776 100644
--- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h
+++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h
@@ -30,9 +30,9 @@ public:
     virtual bool isTransparent() const override;
 
 protected:
-    virtual bool needsRenderUpdate() const override;
     virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
     virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
+    virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
 
     virtual ItemKey getKey() override;
     virtual ShapeKey getShapeKey() override;
diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
index 1555604604..f0a6684654 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
@@ -1802,25 +1802,44 @@ ShapeKey PolyVoxEntityRenderer::getShapeKey() {
 }
 
 bool PolyVoxEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
-    if (entity->voxelToWorldMatrix() != _lastVoxelToWorldMatrix) {
+    if (resultWithReadLock<bool>([&] {
+        if (entity->voxelToWorldMatrix() != _lastVoxelToWorldMatrix) {
+            return true;
+        }
+
+        if (entity->_mesh != _mesh) {
+            return true;
+        }
+
+        return false;
+    })) {
         return true;
     }
 
-    if (entity->_mesh != _mesh) {
-        return true;
-    }
-
-    return false;
+    return Parent::needsRenderUpdateFromTypedEntity(entity);
 }
 
 void PolyVoxEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
-
 #ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
     if (!_hasTransitioned) {
         transaction.resetTransitionOnItem(_renderItemID, render::Transition::ELEMENT_ENTER_DOMAIN);
         _hasTransitioned = true;
     }
 #endif
+}
+
+void PolyVoxEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
+    _lastVoxelToWorldMatrix = entity->voxelToWorldMatrix();
+    _lastVoxelVolumeSize = entity->getVoxelVolumeSize();
+    _params->setSubData(0, vec4(_lastVoxelVolumeSize, 0.0));
+    graphics::MeshPointer newMesh;
+    entity->withReadLock([&] {
+        newMesh = entity->_mesh;
+    });
+
+    if (newMesh && newMesh->getIndexBuffer()._buffer) {
+        _mesh = newMesh;
+    }
 
     std::array<QString, 3> xyzTextureURLs{ {
         entity->getXTextureURL(),
@@ -1838,20 +1857,6 @@ void PolyVoxEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& s
     }
 }
 
-void PolyVoxEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
-    _lastVoxelToWorldMatrix = entity->voxelToWorldMatrix();
-    _lastVoxelVolumeSize = entity->getVoxelVolumeSize();
-    _params->setSubData(0, vec4(_lastVoxelVolumeSize, 0.0));
-    graphics::MeshPointer newMesh;
-    entity->withReadLock([&] {
-        newMesh = entity->_mesh;
-    });
-
-    if (newMesh && newMesh->getIndexBuffer()._buffer) {
-        _mesh = newMesh;
-    }
-}
-
 void PolyVoxEntityRenderer::doRender(RenderArgs* args) {
     if (!_mesh || !_mesh->getIndexBuffer()._buffer) {
         return;
diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
index 4c6f5adc13..06ccdef753 100644
--- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
@@ -51,24 +51,7 @@ bool ShapeEntityRenderer::needsRenderUpdate() const {
     return Parent::needsRenderUpdate();
 }
 
-bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
-    if (_dimensions != entity->getScaledDimensions()) {
-        return true;
-    }
-
-    if (_proceduralData != entity->getUserData()) {
-        return true;
-    }
-
-    return false;
-}
-
 void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
-    withWriteLock([&] {
-        _shape = entity->getShape();
-        _pulseProperties = entity->getPulseProperties();
-    });
-
     void* key = (void*)this;
     AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
         withWriteLock([&] {
@@ -86,47 +69,53 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
 }
 
 void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
+    _shape = entity->getShape();
+    _pulseProperties = entity->getPulseProperties();
+
+    bool materialChanged = false;
+    glm::vec3 color = toGlm(entity->getColor());
+    if (_color != color) {
+        _color = color;
+        _material->setAlbedo(color);
+        materialChanged = true;
+    }
+
+    float alpha = entity->getAlpha();
+    if (_alpha != alpha) {
+        _alpha = alpha;
+        _material->setOpacity(alpha);
+        materialChanged = true;
+    }
+
+    auto userData = entity->getUserData();
+    if (_proceduralData != userData) {
+        _proceduralData = userData;
+        _material->setProceduralData(_proceduralData);
+        materialChanged = true;
+    }
+
     withReadLock([&] {
-        auto mat = _materials.find("0");
-        if (mat != _materials.end() && mat->second.top().material && mat->second.top().material->isProcedural() && mat->second.top().material->isReady()) {
-            auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(mat->second.top().material);
-            if (procedural->isFading()) {
-                procedural->setIsFading(Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) < 1.0f);
-            }
-        }
-    });
-
-    withWriteLock([&] {
-        bool materialChanged = false;
-        glm::vec3 color = toGlm(entity->getColor());
-        if (_color != color) {
-            _color = color;
-            _material->setAlbedo(color);
-            materialChanged = true;
-        }
-
-        float alpha = entity->getAlpha();
-        if (_alpha != alpha) {
-            _alpha = alpha;
-            _material->setOpacity(alpha);
-            materialChanged = true;
-        }
-
-        auto userData = entity->getUserData();
-        if (_proceduralData != userData) {
-            _proceduralData = userData;
-            _material->setProceduralData(_proceduralData);
-            materialChanged = true;
-        }
-
         auto materials = _materials.find("0");
         if (materials != _materials.end()) {
             if (materialChanged) {
                 materials->second.setNeedsUpdate(true);
             }
 
+            bool requestUpdate = false;
+            if (materials->second.top().material && materials->second.top().material->isProcedural() && materials->second.top().material->isReady()) {
+                auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials->second.top().material);
+                if (procedural->isFading()) {
+                    procedural->setIsFading(Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) < 1.0f);
+                    requestUpdate = true;
+                }
+            }
+
             if (materials->second.shouldUpdate()) {
                 RenderPipelines::updateMultiMaterial(materials->second);
+                requestUpdate = true;
+            }
+
+            if (requestUpdate) {
                 emit requestRenderUpdate();
             }
         }
@@ -231,13 +220,12 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
 
     graphics::MultiMaterial materials;
     auto geometryCache = DependencyManager::get<GeometryCache>();
-    GeometryCache::Shape geometryShape;
+    GeometryCache::Shape geometryShape = geometryCache->getShapeForEntityShape(_shape);
     PrimitiveMode primitiveMode;
     RenderLayer renderLayer;
     glm::vec4 outColor;
     Pipeline pipelineType;
     withReadLock([&] {
-        geometryShape = geometryCache->getShapeForEntityShape(_shape);
         primitiveMode = _primitiveMode;
         renderLayer = _renderLayer;
         batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
@@ -245,9 +233,10 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
         pipelineType = getPipelineType(materials);
         auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
         outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
-        outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
     });
 
+    outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
+
     if (outColor.a == 0.0f) {
         return;
     }
@@ -256,7 +245,9 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
         auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials.top().material);
         outColor = procedural->getColor(outColor);
         outColor.a *= procedural->isFading() ? Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) : 1.0f;
-        procedural->prepare(batch, _position, _dimensions, _orientation, _created, ProceduralProgramKey(outColor.a < 1.0f));
+        withReadLock([&] {
+            procedural->prepare(batch, _position, _dimensions, _orientation, _created, ProceduralProgramKey(outColor.a < 1.0f));
+        });
 
         if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
             geometryCache->renderWireShape(batch, geometryShape, outColor);
diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h
index e4d6d099a6..9fb2fa8f23 100644
--- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h
@@ -30,7 +30,6 @@ protected:
 
 private:
     virtual bool needsRenderUpdate() const override;
-    virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
     virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
     virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
     virtual void doRender(RenderArgs* args) override;
diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
index a744fc9a62..04ad86c7e1 100644
--- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
@@ -92,14 +92,6 @@ uint32_t TextEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
     return parentSubs;
 }
 
-bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
-    if (_dimensions != entity->getScaledDimensions()) {
-        return true;
-    }
-
-    return false;
-}
-
 void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
     void* key = (void*)this;
     AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] {
@@ -112,26 +104,24 @@ void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
 }
 
 void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
-    withWriteLock([&] {
-        _pulseProperties = entity->getPulseProperties();
-        _text = entity->getText();
-        _lineHeight = entity->getLineHeight();
-        _textColor = toGlm(entity->getTextColor());
-        _textAlpha = entity->getTextAlpha();
-        _backgroundColor = toGlm(entity->getBackgroundColor());
-        _backgroundAlpha = entity->getBackgroundAlpha();
-        _billboardMode = entity->getBillboardMode();
-        _leftMargin = entity->getLeftMargin();
-        _rightMargin = entity->getRightMargin();
-        _topMargin = entity->getTopMargin();
-        _bottomMargin = entity->getBottomMargin();
-        _unlit = entity->getUnlit();
-        _font = entity->getFont();
-        _effect = entity->getTextEffect();
-        _effectColor = toGlm(entity->getTextEffectColor());
-        _effectThickness = entity->getTextEffectThickness();
-        updateTextRenderItem();
-    });
+    _pulseProperties = entity->getPulseProperties();
+    _text = entity->getText();
+    _lineHeight = entity->getLineHeight();
+    _textColor = toGlm(entity->getTextColor());
+    _textAlpha = entity->getTextAlpha();
+    _backgroundColor = toGlm(entity->getBackgroundColor());
+    _backgroundAlpha = entity->getBackgroundAlpha();
+    _billboardMode = entity->getBillboardMode();
+    _leftMargin = entity->getLeftMargin();
+    _rightMargin = entity->getRightMargin();
+    _topMargin = entity->getTopMargin();
+    _bottomMargin = entity->getBottomMargin();
+    _unlit = entity->getUnlit();
+    _font = entity->getFont();
+    _effect = entity->getTextEffect();
+    _effectColor = toGlm(entity->getTextEffectColor());
+    _effectThickness = entity->getTextEffectThickness();
+    updateTextRenderItem();
 }
 
 void TextEntityRenderer::doRender(RenderArgs* args) {
@@ -141,25 +131,23 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
 
     glm::vec4 backgroundColor;
     Transform modelTransform;
-    BillboardMode billboardMode;
     PrimitiveMode primitiveMode;
     RenderLayer renderLayer;
     withReadLock([&] {
         modelTransform = _renderTransform;
-        billboardMode = _billboardMode;
         primitiveMode = _primitiveMode;
         renderLayer = _renderLayer;
 
         float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
         backgroundColor = glm::vec4(_backgroundColor, fadeRatio * _backgroundAlpha);
-        backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created);
     });
+    backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created);
 
     if (backgroundColor.a <= 0.0f) {
         return;
     }
 
-    modelTransform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), billboardMode, args->getViewFrustum().getPosition()));
+    modelTransform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
     batch.setModelTransform(modelTransform);
 
     auto geometryCache = DependencyManager::get<GeometryCache>();
@@ -323,53 +311,36 @@ void entities::TextPayload::render(RenderArgs* args) {
     glm::vec3 dimensions;
     BillboardMode billboardMode;
 
-    QString text;
     glm::vec4 textColor;
-    QString font;
-    TextEffect effect;
-    glm::vec3 effectColor;
-    float effectThickness;
-    float lineHeight, leftMargin, rightMargin, topMargin, bottomMargin;
     bool forward;
     textRenderable->withReadLock([&] {
         modelTransform = textRenderable->_renderTransform;
         dimensions = textRenderable->_dimensions;
         billboardMode = textRenderable->_billboardMode;
 
-        text = textRenderable->_text;
-        font = textRenderable->_font;
-        effect = textRenderable->_effect;
-        effectThickness = textRenderable->_effectThickness;
-
-        lineHeight = textRenderable->_lineHeight;
-        leftMargin = textRenderable->_leftMargin;
-        rightMargin = textRenderable->_rightMargin;
-        topMargin = textRenderable->_topMargin;
-        bottomMargin = textRenderable->_bottomMargin;
-
         float fadeRatio = textRenderable->_isFading ? Interpolate::calculateFadeRatio(textRenderable->_fadeStartTime) : 1.0f;
         textColor = glm::vec4(textRenderable->_textColor, fadeRatio * textRenderable->_textAlpha);
-        textColor = EntityRenderer::calculatePulseColor(textColor, textRenderable->_pulseProperties, textRenderable->_created);
-
-        effectColor = EntityRenderer::calculatePulseColor(textRenderable->_effectColor, textRenderable->_pulseProperties, textRenderable->_created);
 
         forward = textRenderable->_renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
     });
 
+    textColor = EntityRenderer::calculatePulseColor(textColor, textRenderable->_pulseProperties, textRenderable->_created);
+    glm::vec3 effectColor = EntityRenderer::calculatePulseColor(textRenderable->_effectColor, textRenderable->_pulseProperties, textRenderable->_created);
+
     if (textColor.a <= 0.0f) {
         return;
     }
 
     modelTransform.setRotation(EntityItem::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), billboardMode, args->getViewFrustum().getPosition()));
 
-    float scale = lineHeight / textRenderer->getFontSize();
+    float scale = textRenderable->_lineHeight / textRenderer->getFontSize();
     modelTransform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z));
     modelTransform.setScale(scale);
     batch.setModelTransform(modelTransform);
 
-    glm::vec2 bounds = glm::vec2(dimensions.x - (leftMargin + rightMargin), dimensions.y - (topMargin + bottomMargin));
-    textRenderer->draw(batch, leftMargin / scale, -topMargin / scale, bounds / scale, scale,
-                       text, font, textColor, effectColor, effectThickness, effect,
+    glm::vec2 bounds = glm::vec2(dimensions.x - (textRenderable->_leftMargin + textRenderable->_rightMargin), dimensions.y - (textRenderable->_topMargin + textRenderable->_bottomMargin));
+    textRenderer->draw(batch, textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale, bounds / scale, scale,
+                       textRenderable->_text, textRenderable->_font, textColor, effectColor, textRenderable->_effectThickness, textRenderable->_effect,
                        textRenderable->_unlit, forward);
 }
 
diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h
index 87102daa32..51651d98ba 100644
--- a/libraries/entities-renderer/src/RenderableTextEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h
@@ -42,7 +42,6 @@ protected:
     void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
 
 private:
-    virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
     virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
     virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
     virtual void doRender(RenderArgs* args) override;
diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
index e88ebcf19a..8b41a85cf8 100644
--- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
@@ -125,16 +125,6 @@ bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointe
     return false;
 }
 
-bool WebEntityRenderer::needsRenderUpdate() const {
-    if (resultWithReadLock<bool>([this] {
-        return !_webSurface;
-    })) {
-        return true;
-    }
-
-    return Parent::needsRenderUpdate();
-}
-
 void WebEntityRenderer::onTimeout() {
     uint64_t lastRenderTime;
     if (!resultWithReadLock<bool>([&] {
@@ -261,6 +251,8 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
                     _renderTransform.postScale(entity->getScaledDimensions());
                 });
             });
+        } else {
+            emit requestRenderUpdate();
         }
     });
 }
@@ -339,8 +331,11 @@ void WebEntityRenderer::buildWebSurface(const EntityItemPointer& entity, const Q
         return;
     }
 
-    ++_currentWebCount;
-    WebEntityRenderer::acquireWebSurface(newSourceURL, _contentType == ContentType::HtmlContent, _webSurface, _cachedWebSurface);
+    bool isHTML = _contentType == ContentType::HtmlContent;
+    if (isHTML) {
+        ++_currentWebCount;
+    }
+    WebEntityRenderer::acquireWebSurface(newSourceURL, isHTML, _webSurface, _cachedWebSurface);
     _fadeStartTime = usecTimestampNow();
     _webSurface->resume();
 
@@ -358,12 +353,15 @@ void WebEntityRenderer::destroyWebSurface() {
     QSharedPointer<OffscreenQmlSurface> webSurface;
     withWriteLock([&] {
         webSurface.swap(_webSurface);
-        _contentType = ContentType::NoContent;
 
         if (webSurface) {
-            --_currentWebCount;
+            if (_contentType == ContentType::HtmlContent) {
+                --_currentWebCount;
+            }
             WebEntityRenderer::releaseWebSurface(webSurface, _cachedWebSurface, _connections);
         }
+
+        _contentType = ContentType::NoContent;
     });
 }
 
diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h
index ffd5880c1e..63ec722811 100644
--- a/libraries/entities-renderer/src/RenderableWebEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h
@@ -55,7 +55,6 @@ public:
     virtual QObject* getEventHandler() override;
 
 protected:
-    virtual bool needsRenderUpdate() const override;
     virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
     virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
     virtual void doRender(RenderArgs* args) override;
diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
index d3c9225b88..ce2dae8d28 100644
--- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
@@ -189,7 +189,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
     CullTest::_containingZones.insert(_entityID);
 }
 
-void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
+void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
     auto position = entity->getWorldPosition();
     auto rotation = entity->getWorldOrientation();
     auto dimensions = entity->getScaledDimensions();
@@ -199,7 +199,11 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
     auto visible = entity->getVisible();
     if (transformChanged || visible != _lastVisible) {
         _lastVisible = visible;
-        DependencyManager::get<EntityTreeRenderer>()->updateZone(entity->getID());
+        void* key = (void*)this;
+        EntityItemID id = entity->getID();
+        AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [id] {
+            DependencyManager::get<EntityTreeRenderer>()->updateZone(id);
+        });
     }
 
     auto proceduralUserData = entity->getUserData();
@@ -267,10 +271,6 @@ ItemKey ZoneEntityRenderer::getKey() {
 }
 
 bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
-    if (entity->getVisible() != _lastVisible) {
-        return true;
-    }
-
     if (entity->keyLightPropertiesChanged() ||
         entity->ambientLightPropertiesChanged() ||
         entity->hazePropertiesChanged() ||
@@ -280,29 +280,11 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
         return true;
     }
 
-    if (_skyboxTextureURL != entity->getSkyboxProperties().getURL()) {
-        return true;
-    }
-
-    if (entity->getWorldPosition() != _lastPosition) {
-        return true;
-    }
-    if (entity->getScaledDimensions() != _lastDimensions) {
-        return true;
-    }
-    if (entity->getWorldOrientation() != _lastRotation) {
-        return true;
-    }
-
-    if (entity->getUserData() != _proceduralUserData) {
-        return true;
-    }
-
     return false;
 }
 
 void ZoneEntityRenderer::updateKeySunFromEntity(const TypedEntityPointer& entity) {
-    setKeyLightMode((ComponentMode)entity->getKeyLightMode());
+    _keyLightMode = (ComponentMode)entity->getKeyLightMode();
 
     const auto& sunLight = editSunLight();
     sunLight->setType(graphics::Light::SUN);
@@ -319,7 +301,7 @@ void ZoneEntityRenderer::updateKeySunFromEntity(const TypedEntityPointer& entity
 }
 
 void ZoneEntityRenderer::updateAmbientLightFromEntity(const TypedEntityPointer& entity) {
-    setAmbientLightMode((ComponentMode)entity->getAmbientLightMode());
+    _ambientLightMode = (ComponentMode)entity->getAmbientLightMode();
 
     const auto& ambientLight = editAmbientLight();
     ambientLight->setType(graphics::Light::AMBIENT);
@@ -339,11 +321,12 @@ void ZoneEntityRenderer::updateAmbientLightFromEntity(const TypedEntityPointer&
 }
 
 void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity) {
-    setHazeMode((ComponentMode)entity->getHazeMode());
+    const uint32_t hazeMode = entity->getHazeMode();
+
+    _hazeMode = (ComponentMode)hazeMode;
 
     const auto& haze = editHaze();
 
-    const uint32_t hazeMode = entity->getHazeMode();
     haze->setHazeActive(hazeMode == COMPONENT_MODE_ENABLED);
     haze->setAltitudeBased(_hazeProperties.getHazeAltitudeEffect());
 
@@ -367,7 +350,7 @@ void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity)
 }
 
 void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity) {
-    setBloomMode((ComponentMode)entity->getBloomMode());
+    _bloomMode = (ComponentMode)entity->getBloomMode();
 
     const auto& bloom = editBloom();
 
@@ -377,7 +360,7 @@ void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity)
 }
 
 void ZoneEntityRenderer::updateKeyBackgroundFromEntity(const TypedEntityPointer& entity) {
-    setSkyboxMode((ComponentMode)entity->getSkyboxMode());
+    _skyboxMode = (ComponentMode)entity->getSkyboxMode();
 
     editBackground();
     setSkyboxColor(toGlm(_skyboxProperties.getColor()));
@@ -478,26 +461,6 @@ void ZoneEntityRenderer::updateSkyboxMap() {
     }
 }
 
-void ZoneEntityRenderer::setHazeMode(ComponentMode mode) {
-    _hazeMode = mode;
-}
-
-void ZoneEntityRenderer::setKeyLightMode(ComponentMode mode) {
-    _keyLightMode = mode;
-}
-
-void ZoneEntityRenderer::setAmbientLightMode(ComponentMode mode) {
-    _ambientLightMode = mode;
-}
-
-void ZoneEntityRenderer::setSkyboxMode(ComponentMode mode) {
-    _skyboxMode = mode;
-}
-
-void ZoneEntityRenderer::setBloomMode(ComponentMode mode) {
-    _bloomMode = mode;
-}
-
 void ZoneEntityRenderer::setSkyboxColor(const glm::vec3& color) {
     editSkybox()->setColor(color);
 }
diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h
index d4e3d16408..d2ee90b1e4 100644
--- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h
@@ -38,7 +38,7 @@ protected:
     virtual ItemKey getKey() override;
     virtual void doRender(RenderArgs* args) override;
     virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
-    virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
+    virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
 
 private:
     void updateKeyZoneItemFromEntity(const TypedEntityPointer& entity);
@@ -52,12 +52,6 @@ private:
     void setAmbientURL(const QString& ambientUrl);
     void setSkyboxURL(const QString& skyboxUrl);
 
-    void setHazeMode(ComponentMode mode);
-    void setKeyLightMode(ComponentMode mode);
-    void setAmbientLightMode(ComponentMode mode);
-    void setSkyboxMode(ComponentMode mode);
-    void setBloomMode(ComponentMode mode);
-
     void setSkyboxColor(const glm::vec3& color);
     void setProceduralUserData(const QString& userData);
 
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index ddedf0db18..d7a5e992e1 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -1911,13 +1911,11 @@ void EntityItem::setUnscaledDimensions(const glm::vec3& value) {
     if (glm::length2(getUnscaledDimensions() - newDimensions) > MIN_SCALE_CHANGE_SQUARED) {
         withWriteLock([&] {
             _unscaledDimensions = newDimensions;
-        });
-        locationChanged();
-        dimensionsChanged();
-        withWriteLock([&] {
             _flags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
             _queryAACubeSet = false;
         });
+        locationChanged();
+        dimensionsChanged();
     }
 }
 
diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp
index 715b457bde..0dcb5d125a 100644
--- a/libraries/entities/src/LightEntityItem.cpp
+++ b/libraries/entities/src/LightEntityItem.cpp
@@ -78,7 +78,14 @@ void LightEntityItem::setFalloffRadius(float value) {
 }
 
 void LightEntityItem::setIsSpotlight(bool value) {
-    if (value == getIsSpotlight()) {
+    bool needsRenderUpdate;
+    withWriteLock([&] {
+        needsRenderUpdate = value != _isSpotlight;
+        _needsRenderUpdate |= needsRenderUpdate;
+        _isSpotlight = value;
+    });
+
+    if (!needsRenderUpdate) {
         return;
     }
 
@@ -92,25 +99,25 @@ void LightEntityItem::setIsSpotlight(bool value) {
         newDimensions = glm::vec3(glm::compMax(dimensions));
     }
 
-    withWriteLock([&] {
-        _needsRenderUpdate = true;
-        _isSpotlight = value;
-    });
     setScaledDimensions(newDimensions);
 }
 
 void LightEntityItem::setCutoff(float value) {
     value = glm::clamp(value, MIN_CUTOFF, MAX_CUTOFF);
-    if (value == getCutoff()) {
+    bool needsRenderUpdate;
+    bool spotlight;
+    withWriteLock([&] {
+        needsRenderUpdate = value != _cutoff;
+        _needsRenderUpdate |= needsRenderUpdate;
+        _cutoff = value;
+        spotlight = _isSpotlight;
+    });
+
+    if (!needsRenderUpdate) {
         return;
     }
 
-    withWriteLock([&] {
-        _needsRenderUpdate = true;
-        _cutoff = value;
-    });
-
-    if (getIsSpotlight()) {
+    if (spotlight) {
         // If we are a spotlight, adjusting the cutoff will affect the area we encapsulate,
         // so update the dimensions to reflect this.
         const float length = getScaledDimensions().z;
diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp
index cd27c1cf36..4716db6a41 100644
--- a/libraries/entities/src/ModelEntityItem.cpp
+++ b/libraries/entities/src/ModelEntityItem.cpp
@@ -254,26 +254,30 @@ void ModelEntityItem::debugDump() const {
 }
 
 void ModelEntityItem::setShapeType(ShapeType type) {
+    bool changed = false;
+    uint32_t flags = 0;
     withWriteLock([&] {
         if (type != _shapeType) {
             if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) {
                 // dynamic and STATIC_MESH are incompatible
                 // since the shape is being set here we clear the dynamic bit
                 _dynamic = false;
-                _flags |= Simulation::DIRTY_MOTION_TYPE;
+                flags = Simulation::DIRTY_MOTION_TYPE;
             }
             _shapeType = type;
-            _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+            flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
+            changed = true;
         }
     });
+
+    if (changed) {
+        markDirtyFlags(flags);
+        locationChanged();
+    }
 }
 
 ShapeType ModelEntityItem::getShapeType() const {
-    return computeTrueShapeType();
-}
-
-ShapeType ModelEntityItem::computeTrueShapeType() const {
-    ShapeType type = _shapeType;
+    ShapeType type = resultWithReadLock<ShapeType>([&] { return _shapeType; });
     if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) {
         // dynamic is incompatible with STATIC_MESH
         // shouldn't fall in here but just in case --> fall back to COMPOUND
@@ -290,7 +294,6 @@ void ModelEntityItem::setModelURL(const QString& url) {
     withWriteLock([&] {
         if (_modelURL != url) {
             _modelURL = url;
-            _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
             _needsRenderUpdate = true;
         }
     });
@@ -325,18 +328,10 @@ void ModelEntityItem::setCompoundShapeURL(const QString& url) {
     withWriteLock([&] {
         if (_compoundShapeURL.get() != url) {
             _compoundShapeURL.set(url);
-            _flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
         }
     });
 }
 
-void ModelEntityItem::setAnimationURL(const QString& url) {
-    _flags |= Simulation::DIRTY_UPDATEABLE;
-    withWriteLock([&] {
-        _animationProperties.setURL(url);
-    });
-}
-
 void ModelEntityItem::setAnimationSettings(const QString& value) {
     // NOTE: this method only called for old bitstream format
 
@@ -399,20 +394,6 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
     });
 }
 
-void ModelEntityItem::setAnimationIsPlaying(bool value) {
-    _flags |= Simulation::DIRTY_UPDATEABLE;
-    withWriteLock([&] {
-        _animationProperties.setRunning(value);
-    });
-}
-
-void ModelEntityItem::setAnimationFPS(float value) {
-    _flags |= Simulation::DIRTY_UPDATEABLE;
-    withWriteLock([&] {
-        _animationProperties.setFPS(value);
-    });
-}
-
 void ModelEntityItem::resizeJointArrays(int newSize) {
     if (newSize < 0) {
         return;
@@ -588,10 +569,6 @@ QString ModelEntityItem::getCompoundShapeURL() const {
     return _compoundShapeURL.get();
 }
 
-QString ModelEntityItem::getCollisionShapeURL() const {
-    return getShapeType() == SHAPE_TYPE_COMPOUND ? getCompoundShapeURL() : getModelURL();
-}
-
 void ModelEntityItem::setColor(const glm::u8vec3& value) {
     withWriteLock([&] {
         _color = value;
@@ -629,61 +606,18 @@ void ModelEntityItem::setAnimationCurrentFrame(float value) {
     });
 }
 
-void ModelEntityItem::setAnimationAllowTranslation(bool value) {
-    withWriteLock([&] {
-        _animationProperties.setAllowTranslation(value);
-    });
-}
-
 bool ModelEntityItem::getAnimationAllowTranslation() const {
     return resultWithReadLock<bool>([&] {
         return _animationProperties.getAllowTranslation();
     });
 }
 
-void ModelEntityItem::setAnimationLoop(bool loop) { 
-    withWriteLock([&] {
-        _animationProperties.setLoop(loop);
-    });
-}
-
-bool ModelEntityItem::getAnimationLoop() const {
-    return resultWithReadLock<bool>([&] {
-        return _animationProperties.getLoop();
-    });
-}
-
-
-void ModelEntityItem::setAnimationHold(bool hold) { 
-    withWriteLock([&] {
-        _animationProperties.setHold(hold);
-    });
-}
-
-bool ModelEntityItem::getAnimationHold() const { 
-    return resultWithReadLock<bool>([&] {
-        return _animationProperties.getHold();
-    });
-}
-
-bool ModelEntityItem::getAnimationIsPlaying() const { 
-    return resultWithReadLock<bool>([&] {
-        return _animationProperties.getRunning();
-    });
-}
-
 float ModelEntityItem::getAnimationCurrentFrame() const { 
     return resultWithReadLock<float>([&] {
         return _animationProperties.getCurrentFrame();
     });
 }
 
-float ModelEntityItem::getAnimationFPS() const {
-    return resultWithReadLock<float>([&] {
-        return _animationProperties.getFPS();
-    });
-}
-
 bool ModelEntityItem::isAnimatingSomething() const {
     return resultWithReadLock<bool>([&] {
         return _animationProperties.isValidAndRunning();
@@ -722,6 +656,7 @@ bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProp
     bool somethingChanged = newProperties != _animationProperties;
     if (somethingChanged) {
         _animationProperties = newProperties;
+        _needsRenderUpdate = true;
         _flags |= Simulation::DIRTY_UPDATEABLE;
     }
     return somethingChanged;
diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h
index 795630a72a..b835b48d13 100644
--- a/libraries/entities/src/ModelEntityItem.h
+++ b/libraries/entities/src/ModelEntityItem.h
@@ -76,33 +76,18 @@ public:
     static const QString DEFAULT_COMPOUND_SHAPE_URL;
     QString getCompoundShapeURL() const;
 
-    // Returns the URL used for the collision shape
-    QString getCollisionShapeURL() const;
-
     // model related properties
     virtual void setModelURL(const QString& url);
     virtual void setCompoundShapeURL(const QString& url);
 
     // Animation related items...
     AnimationPropertyGroup getAnimationProperties() const;
-
-    // TODO: audit and remove unused Animation accessors
     bool hasAnimation() const;
     QString getAnimationURL() const;
-    virtual void setAnimationURL(const QString& url);
-
     void setAnimationCurrentFrame(float value);
-    void setAnimationIsPlaying(bool value);
-    void setAnimationFPS(float value); 
-
-    void setAnimationAllowTranslation(bool value);
+    float getAnimationCurrentFrame() const;
     bool getAnimationAllowTranslation() const;
-
-    void setAnimationLoop(bool loop);
-    bool getAnimationLoop() const;
-
-    void setAnimationHold(bool hold);
-    bool getAnimationHold() const;
+    bool isAnimatingSomething() const;
 
     void setRelayParentJoints(bool relayJoints);
     bool getRelayParentJoints() const;
@@ -110,11 +95,6 @@ public:
     void setGroupCulled(bool value);
     bool getGroupCulled() const;
 
-    bool getAnimationIsPlaying() const;
-    float getAnimationCurrentFrame() const;
-    float getAnimationFPS() const;
-    bool isAnimatingSomething() const;
-
     static const QString DEFAULT_TEXTURES;
     const QString getTextures() const;
     void setTextures(const QString& textures);
@@ -142,7 +122,6 @@ public:
 private:
     void setAnimationSettings(const QString& value); // only called for old bitstream format
     bool applyNewAnimationProperties(AnimationPropertyGroup newProperties);
-    ShapeType computeTrueShapeType() const;
 
 protected:
     void resizeJointArrays(int newSize);
diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp
index 909bc132fb..4aaf0ad521 100644
--- a/libraries/entities/src/PolyLineEntityItem.cpp
+++ b/libraries/entities/src/PolyLineEntityItem.cpp
@@ -266,21 +266,21 @@ glm::u8vec3 PolyLineEntityItem::getColor() const {
 
 void PolyLineEntityItem::setIsUVModeStretch(bool isUVModeStretch) {
     withWriteLock([&] {
-        _needsRenderUpdate = _isUVModeStretch != isUVModeStretch;
+        _needsRenderUpdate |= _isUVModeStretch != isUVModeStretch;
         _isUVModeStretch = isUVModeStretch;
     });
 }
 
 void PolyLineEntityItem::setGlow(bool glow) {
     withWriteLock([&] {
-        _needsRenderUpdate = _glow != glow;
+        _needsRenderUpdate |= _glow != glow;
         _glow = glow;
     });
 }
 
 void PolyLineEntityItem::setFaceCamera(bool faceCamera) {
     withWriteLock([&] {
-        _needsRenderUpdate = _faceCamera != faceCamera;
+        _needsRenderUpdate |= _faceCamera != faceCamera;
         _faceCamera = faceCamera;
     });
 }
diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp
index 5e140665b3..3dbb02775a 100644
--- a/libraries/entities/src/ShapeEntityItem.cpp
+++ b/libraries/entities/src/ShapeEntityItem.cpp
@@ -442,4 +442,11 @@ PulsePropertyGroup ShapeEntityItem::getPulseProperties() const {
     return resultWithReadLock<PulsePropertyGroup>([&] {
         return _pulseProperties;
     });
+}
+
+void ShapeEntityItem::setUserData(const QString& value) {
+    withWriteLock([&] {
+        _needsRenderUpdate |= _userData != value;
+        _userData = value;
+    });
 }
\ No newline at end of file
diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h
index 7320867430..c0dc9642fe 100644
--- a/libraries/entities/src/ShapeEntityItem.h
+++ b/libraries/entities/src/ShapeEntityItem.h
@@ -101,6 +101,8 @@ public:
 
     PulsePropertyGroup getPulseProperties() const;
 
+    void setUserData(const QString& value) override;
+
 protected:
     glm::u8vec3 _color;
     float _alpha { 1.0f };
diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp
index 88466caff0..8b020e92d5 100644
--- a/libraries/entities/src/ZoneEntityItem.cpp
+++ b/libraries/entities/src/ZoneEntityItem.cpp
@@ -84,12 +84,12 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie
 
     // Contains a QString property, must be synchronized
     withWriteLock([&] {
-        _keyLightPropertiesChanged = _keyLightProperties.setProperties(properties);
-        _ambientLightPropertiesChanged = _ambientLightProperties.setProperties(properties);
-        _skyboxPropertiesChanged = _skyboxProperties.setProperties(properties);
+        _keyLightPropertiesChanged |= _keyLightProperties.setProperties(properties);
+        _ambientLightPropertiesChanged |= _ambientLightProperties.setProperties(properties);
+        _skyboxPropertiesChanged |= _skyboxProperties.setProperties(properties);
     });
-    _hazePropertiesChanged = _hazeProperties.setProperties(properties);
-    _bloomPropertiesChanged = _bloomProperties.setProperties(properties);
+    _hazePropertiesChanged |= _hazeProperties.setProperties(properties);
+    _bloomPropertiesChanged |= _bloomProperties.setProperties(properties);
 
     SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed);
     SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed);
@@ -125,7 +125,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
             bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
                 propertyFlags, overwriteLocalData, _keyLightPropertiesChanged);
         });
-        somethingChanged = somethingChanged || _keyLightPropertiesChanged;
+        somethingChanged |= _keyLightPropertiesChanged;
         bytesRead += bytesFromKeylight;
         dataAt += bytesFromKeylight;
     }
@@ -136,7 +136,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
             bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
                 propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged);
         });
-        somethingChanged = somethingChanged || _ambientLightPropertiesChanged;
+        somethingChanged |= _ambientLightPropertiesChanged;
         bytesRead += bytesFromAmbientlight;
         dataAt += bytesFromAmbientlight;
     }
@@ -147,7 +147,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
             bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
                 propertyFlags, overwriteLocalData, _skyboxPropertiesChanged);
         });
-        somethingChanged = somethingChanged || _skyboxPropertiesChanged;
+        somethingChanged |= _skyboxPropertiesChanged;
         bytesRead += bytesFromSkybox;
         dataAt += bytesFromSkybox;
     }
@@ -155,7 +155,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
     {
         int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
             propertyFlags, overwriteLocalData, _hazePropertiesChanged);
-        somethingChanged = somethingChanged || _hazePropertiesChanged;
+        somethingChanged |= _hazePropertiesChanged;
         bytesRead += bytesFromHaze;
         dataAt += bytesFromHaze;
     }
@@ -163,7 +163,7 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
     {
         int bytesFromBloom = _bloomProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
             propertyFlags, overwriteLocalData, _bloomPropertiesChanged);
-        somethingChanged = somethingChanged || _bloomPropertiesChanged;
+        somethingChanged |= _bloomPropertiesChanged;
         bytesRead += bytesFromBloom;
         dataAt += bytesFromBloom;
     }
@@ -444,6 +444,13 @@ uint32_t ZoneEntityItem::getSkyboxMode() const {
     return _skyboxMode;
 }
 
+void ZoneEntityItem::setUserData(const QString& value) {
+    withWriteLock([&] {
+        _needsRenderUpdate |= _userData != value;
+        _userData = value;
+    });
+}
+
 void ZoneEntityItem::fetchCollisionGeometryResource() {
     QUrl hullURL(getCompoundShapeURL());
     if (hullURL.isEmpty()) {
diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h
index dda03f9115..9c8e3839b7 100644
--- a/libraries/entities/src/ZoneEntityItem.h
+++ b/libraries/entities/src/ZoneEntityItem.h
@@ -104,6 +104,8 @@ public:
     uint32_t getScreenshare() const { return _screenshare; }
     void setScreenshare(uint32_t value) { _screenshare = value; }
 
+    void setUserData(const QString& value) override;
+
     bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; }
     bool ambientLightPropertiesChanged() const { return _ambientLightPropertiesChanged; }
     bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; }
diff --git a/libraries/networking/src/NetworkingConstants.h b/libraries/networking/src/NetworkingConstants.h
index 58cefb35ad..b64a0845ac 100644
--- a/libraries/networking/src/NetworkingConstants.h
+++ b/libraries/networking/src/NetworkingConstants.h
@@ -72,7 +72,7 @@ namespace NetworkingConstants {
     const QUrl HELP_FORUM_URL { "https://forums.vircadia.dev" };
     const QUrl HELP_SCRIPTING_REFERENCE_URL{ "https://apidocs.vircadia.dev/" };
     const QUrl HELP_RELEASE_NOTES_URL{ "https://docs.vircadia.dev/release-notes.html" };
-    const QUrl HELP_BUG_REPORT_URL{ "https://github.com/kasenvr/project-athena/issues" };
+    const QUrl HELP_BUG_REPORT_URL{ "https://github.com/vircadia/vircadia/issues" };
     
     const QString DEFAULT_VIRCADIA_ADDRESS = "file:///~/serverless/tutorial.json";
     const QString DEFAULT_HOME_ADDRESS = "file:///~/serverless/tutorial.json";
diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp
index 4a2ee9184f..d0d900e14d 100644
--- a/libraries/physics/src/PhysicalEntitySimulation.cpp
+++ b/libraries/physics/src/PhysicalEntitySimulation.cpp
@@ -425,12 +425,12 @@ void PhysicalEntitySimulation::buildPhysicsTransaction(PhysicsEngine::Transactio
             continue;
         }
 
-        bool needsNewShape = object->needsNewShape();
+        bool needsNewShape = object->needsNewShape() && object->_entity->isReadyToComputeShape();
         if (needsNewShape) {
             ShapeType shapeType = object->getShapeType();
             if (shapeType == SHAPE_TYPE_STATIC_MESH) {
                 ShapeRequest shapeRequest(object->_entity);
-                ShapeRequests::iterator  requestItr = _shapeRequests.find(shapeRequest);
+                ShapeRequests::iterator requestItr = _shapeRequests.find(shapeRequest);
                 if (requestItr == _shapeRequests.end()) {
                     ShapeInfo shapeInfo;
                     object->_entity->computeShapeInfo(shapeInfo);
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 182b83762c..9ad343639d 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -338,7 +338,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
     bool intersectedSomething = false;
 
     // if we aren't active, we can't pick yet...
-    if (!isActive()) {
+    if (!isLoaded()) {
         return intersectedSomething;
     }
 
@@ -493,7 +493,7 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co
     bool intersectedSomething = false;
 
     // if we aren't active, we can't pick yet...
-    if (!isActive()) {
+    if (!isLoaded()) {
         return intersectedSomething;
     }
 
@@ -958,16 +958,42 @@ void Model::setCauterized(bool cauterized, const render::ScenePointer& scene) {
     }
 }
 
-void Model::setPrimitiveMode(PrimitiveMode primitiveMode) {
+void Model::setPrimitiveMode(PrimitiveMode primitiveMode, const render::ScenePointer& scene) {
     if (_primitiveMode != primitiveMode) {
         _primitiveMode = primitiveMode;
-        updateRenderItemsKey(nullptr);
+        if (!scene) {
+            _needsFixupInScene = true;
+            return;
+        }
+
+        bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
+        std::unordered_map<int, bool> shouldInvalidatePayloadShapeKeyMap;
+
+        for (auto& shape : _modelMeshRenderItemShapes) {
+            shouldInvalidatePayloadShapeKeyMap[shape.meshIndex] = shouldInvalidatePayloadShapeKey(shape.meshIndex);
+        }
+
+        render::Transaction transaction;
+
+        for (int i = 0; i < (int)_modelMeshRenderItemIDs.size(); i++) {
+            auto itemID = _modelMeshRenderItemIDs[i];
+            auto meshIndex = _modelMeshRenderItemShapes[i].meshIndex;
+            bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
+            transaction.updateItem<ModelMeshPartPayload>(itemID, [invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning] (ModelMeshPartPayload& data) {
+                data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
+            });
+        }
+        scene->enqueueTransaction(transaction);
     }
 }
 
-void Model::setCullWithParent(bool cullWithParent) {
+void Model::setCullWithParent(bool cullWithParent, const render::ScenePointer& scene) {
     if (_cullWithParent != cullWithParent) {
         _cullWithParent = cullWithParent;
+        if (!scene) {
+            _needsFixupInScene = true;
+            return;
+        }
 
         render::Transaction transaction;
         auto renderItemsKey = _renderItemKeyGlobalFlags;
@@ -977,14 +1003,27 @@ void Model::setCullWithParent(bool cullWithParent) {
                 data.updateKey(renderItemsKey);
             });
         }
-        AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
+        scene->enqueueTransaction(transaction);
     }
 }
 
-void Model::setRenderWithZones(const QVector<QUuid>& renderWithZones) {
+void Model::setRenderWithZones(const QVector<QUuid>& renderWithZones, const render::ScenePointer& scene) {
     if (_renderWithZones != renderWithZones) {
         _renderWithZones = renderWithZones;
-        setRenderItemsNeedUpdate();
+
+        if (!scene) {
+            _needsFixupInScene = true;
+            return;
+        }
+
+        render::Transaction transaction;
+        auto renderItemsKey = _renderItemKeyGlobalFlags;
+        for (auto item : _modelMeshRenderItemIDs) {
+            transaction.updateItem<ModelMeshPartPayload>(item, [renderWithZones, renderItemsKey](ModelMeshPartPayload& data) {
+                data.setRenderWithZones(renderWithZones);
+            });
+        }
+        scene->enqueueTransaction(transaction);
     }
 }
 
@@ -1129,7 +1168,7 @@ void Model::renderDebugMeshBoxes(gpu::Batch& batch, bool forward) {
 }
 
 Extents Model::getBindExtents() const {
-    if (!isActive()) {
+    if (!isLoaded()) {
         return Extents();
     }
     const Extents& bindExtents = getHFMModel().bindExtents;
@@ -1143,7 +1182,7 @@ glm::vec3 Model::getNaturalDimensions() const {
 }
 
 Extents Model::getMeshExtents() const {
-    if (!isActive()) {
+    if (!isLoaded()) {
         return Extents();
     }
     const Extents& extents = getHFMModel().meshExtents;
@@ -1157,7 +1196,7 @@ Extents Model::getMeshExtents() const {
 }
 
 Extents Model::getUnscaledMeshExtents() const {
-    if (!isActive()) {
+    if (!isLoaded()) {
         return Extents();
     }
 
@@ -1189,7 +1228,7 @@ void Model::setJointTranslation(int index, bool valid, const glm::vec3& translat
 }
 
 int Model::getParentJointIndex(int jointIndex) const {
-    return (isActive() && jointIndex != -1) ? getHFMModel().joints.at(jointIndex).parentIndex : -1;
+    return (isLoaded() && jointIndex != -1) ? getHFMModel().joints.at(jointIndex).parentIndex : -1;
 }
 
 void Model::setTextures(const QVariantMap& textures) {
@@ -1290,7 +1329,7 @@ QStringList Model::getJointNames() const {
             Q_RETURN_ARG(QStringList, result));
         return result;
     }
-    return isActive() ? getHFMModel().getJointNames() : QStringList();
+    return isLoaded() ? getHFMModel().getJointNames() : QStringList();
 }
 
 void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions, bool forceRescale) {
@@ -1306,7 +1345,7 @@ void Model::setScaleToFit(bool scaleToFit, float largestDimension, bool forceRes
     // mesh, and so we can't do the needed calculations for scaling to fit to a single largest dimension. In this
     // case we will record that we do want to do this, but we will stick our desired single dimension into the
     // first element of the vec3 for the non-fixed aspect ration dimensions
-    if (!isActive()) {
+    if (!isLoaded()) {
         _scaleToFit = scaleToFit;
         if (scaleToFit) {
             _scaleToFitDimensions = glm::vec3(largestDimension, FAKE_DIMENSION_PLACEHOLDER, FAKE_DIMENSION_PLACEHOLDER);
@@ -1387,7 +1426,7 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
     fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit)
                     || (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint);
 
-    if (isActive() && fullUpdate) {
+    if (isLoaded() && fullUpdate) {
         onInvalidate();
 
         // check for scale to fit
@@ -1454,7 +1493,6 @@ void Model::updateBlendshapes() {
 }
 
 void Model::deleteGeometry() {
-    _deleteGeometryCounter++;
     _meshStates.clear();
     _rig.destroyAnimGraph();
     _blendedBlendshapeCoefficients.clear();
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index 4585ad0009..1e7ab55d5a 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -116,14 +116,14 @@ public:
     void setHifiRenderLayer(render::hifi::Layer layer, const render::ScenePointer& scene = nullptr);
 
     bool isCauterized() const { return _cauterized; }
-    void setCauterized(bool value, const render::ScenePointer& scene);
+    void setCauterized(bool value, const render::ScenePointer& scene = nullptr);
 
-    void setPrimitiveMode(PrimitiveMode primitiveMode);
+    void setPrimitiveMode(PrimitiveMode primitiveMode, const render::ScenePointer& scene = nullptr);
     PrimitiveMode getPrimitiveMode() const { return _primitiveMode; }
 
-    void setCullWithParent(bool value);
+    void setCullWithParent(bool value, const render::ScenePointer& scene = nullptr);
 
-    void setRenderWithZones(const QVector<QUuid>& renderWithZones);
+    void setRenderWithZones(const QVector<QUuid>& renderWithZones, const render::ScenePointer& scene = nullptr);
     const QVector<QUuid>& getRenderWithZones() const { return _renderWithZones; }
 
     // Access the current RenderItemKey Global Flags used by the model and applied to the render items  representing the parts of the model.
@@ -183,10 +183,7 @@ public:
     const HFMModel& getHFMModel() const { assert(isLoaded()); return _renderGeometry->getHFMModel(); }
     const MaterialMapping& getMaterialMapping() const { assert(isLoaded()); return _renderGeometry->getMaterialMapping(); }
 
-    bool isActive() const { return isLoaded(); }
-
     bool didVisualGeometryRequestFail() const { return _visualGeometryRequestFailed; }
-    bool didCollisionGeometryRequestFail() const { return _collisionGeometryRequestFailed; }
 
     glm::mat4 getWorldToHFMMatrix() const;
 
@@ -338,7 +335,6 @@ public:
 
     const MeshState& getMeshState(int index) { return _meshStates.at(index); }
 
-    uint32_t getGeometryCounter() const { return _deleteGeometryCounter; }
     const QMap<render::ItemID, render::PayloadPointer>& getRenderItems() const { return _modelMeshRenderItemsMap; }
     BlendShapeOperator getModelBlendshapeOperator() const { return _modelBlendshapeOperator; }
 
@@ -474,10 +470,7 @@ protected:
     friend class ModelMeshPartPayload;
     Rig _rig;
 
-    uint32_t _deleteGeometryCounter { 0 };
-
     bool _visualGeometryRequestFailed { false };
-    bool _collisionGeometryRequestFailed { false };
 
     bool _renderItemsNeedUpdate { false };
 
diff --git a/pkg-scripts/README b/pkg-scripts/README
index 92a9bf00d3..6eb74980d0 100644
--- a/pkg-scripts/README
+++ b/pkg-scripts/README
@@ -1,5 +1,5 @@
 Collection of scripts to create server distribution packages.  Most of these scripts assume
-use of the build script at https://github.com/kasenvr/vircadia-builder, specifically that
+use of the build script at https://github.com/vircadia/vircadia-builder, specifically that
 the following directory structure exists
 
 base folder/
diff --git a/pkg-scripts/server-control b/pkg-scripts/server-control
index c80b8da724..3ed23b7149 100644
--- a/pkg-scripts/server-control
+++ b/pkg-scripts/server-control
@@ -5,8 +5,8 @@ Maintainer: Heather Anderson <heath@odysseus.anderson.name>
 Build-Depends: debhelper (>= 10)
 Standards-Version: 4.1.2
 Homepage: https://vircadia.com
-Vcs-Git: https://github.com/kasenvr/project-athena.git
-Vcs-Browser: https://github.com/kasenvr/project-athena
+Vcs-Git: https://github.com/vircadia/vircadia.git
+Vcs-Browser: https://github.com/vircadia/vircadia
 
 Package: vircadia-server
 Architecture: any
diff --git a/pkg-scripts/vircadia-server.spec b/pkg-scripts/vircadia-server.spec
index 3e0eed896e..575ad9589e 100644
--- a/pkg-scripts/vircadia-server.spec
+++ b/pkg-scripts/vircadia-server.spec
@@ -9,7 +9,7 @@ Summary:        Vircadia metaverse platform, based on the High Fidelity Engine.
 
 License:        ASL 2.0
 URL:            https://vircadia.com
-Source0:        https://github.com/kasenvr/vircadia-builder/blob/master/vircadia-builder
+Source0:        https://github.com/vircadia/vircadia-builder/blob/master/vircadia-builder
 
 #BuildRequires:  systemd-rpm-macros
 BuildRequires:  chrpath
diff --git a/plugins/JSAPIExample/src/JSAPIExample.cpp b/plugins/JSAPIExample/src/JSAPIExample.cpp
index ed637e198b..91aa8bd32a 100644
--- a/plugins/JSAPIExample/src/JSAPIExample.cpp
+++ b/plugins/JSAPIExample/src/JSAPIExample.cpp
@@ -3,7 +3,7 @@
 //  plugins/JSAPIExample/src
 //
 //  Copyright (c) 2019-2020 humbletim (humbletim@gmail.com)
-//  Copyright (c) 2019 Kalila L. (kasenvr@gmail.com)
+//  Copyright (c) 2019 Kalila L. (somnilibertas@gmail.com)
 //
 //  Distributed under the Apache License, Version 2.0.
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
diff --git a/prebuild.py b/prebuild.py
index 21363bb9de..d5bed2d813 100644
--- a/prebuild.py
+++ b/prebuild.py
@@ -102,7 +102,7 @@ def parse_args():
     if True:
         args = parser.parse_args()
     else:
-        args = parser.parse_args(['--android', 'questInterface', '--build-root', 'C:/git/project-athena/android/apps/questInterface/.externalNativeBuild/cmake/debug/arm64-v8a'])
+        args = parser.parse_args(['--android', 'questInterface', '--build-root', 'C:/git/vircadia/android/apps/questInterface/.externalNativeBuild/cmake/debug/arm64-v8a'])
     return args
 
 def main():
diff --git a/scripts/system/more/more.html b/scripts/system/more/more.html
index db1f73cc85..a8bdaca913 100644
--- a/scripts/system/more/more.html
+++ b/scripts/system/more/more.html
@@ -5,8 +5,8 @@
 //  Created by Keb Helion, February 2020.
 //  Copyright 2020 Vircadia contributors.
 //
-//  App maintained in: https://github.com/kasenvr/community-apps
-//  App copied to: https://github.com/kasenvr/project-athena
+//  App maintained in: https://github.com/vircadia/community-apps
+//  App copied to: https://github.com/vircadia/vircadia
 //
 //
 //  Distributed under the Apache License, Version 2.0.
diff --git a/server-console/package.json b/server-console/package.json
index 1ceed08d4d..d5b2a0793d 100644
--- a/server-console/package.json
+++ b/server-console/package.json
@@ -13,7 +13,7 @@
   },
   "repository": {
     "type": "git",
-    "url": "https://github.com/kasenvr/project-athena.git"
+    "url": "https://github.com/vircadia/vircadia.git"
   },
   "main": "src/main.js",
   "scripts": {