diff --git a/src/quick3d/qquick3dviewport.cpp b/src/quick3d/qquick3dviewport.cpp
index 6ba79a175b72adaa962997c3b01eba059165a851..6a9c996f964919860ca7a6f0e2968731e70f93a0 100644
--- a/src/quick3d/qquick3dviewport.cpp
+++ b/src/quick3d/qquick3dviewport.cpp
@@ -469,15 +469,14 @@ QSGNode *QQuick3DViewport::updatePaintNode(QSGNode *node, QQuickItem::UpdatePain
         n->devicePixelRatio = window()->effectiveDevicePixelRatio();
         desiredFboSize *= n->devicePixelRatio;
 
-        n->renderer->synchronize(this, desiredFboSize);
-
-        updateDynamicTextures();
-
         n->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
         n->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
         n->setRect(0, 0, width(), height());
-
-        n->scheduleRender();
+        if (checkIsVisible()) {
+            n->renderer->synchronize(this, desiredFboSize);
+            updateDynamicTextures();
+            n->scheduleRender();
+        }
         return n;
     } else if (m_renderMode == Underlay) {
         setupDirectRenderer(Underlay);
@@ -503,9 +502,11 @@ QSGNode *QQuick3DViewport::updatePaintNode(QSGNode *node, QQuickItem::UpdatePain
 
         const QSize targetSize = window()->effectiveDevicePixelRatio() * QSize(width(), height());
 
-        n->renderer->synchronize(this, targetSize, false);
-        updateDynamicTextures();
-        n->markDirty(QSGNode::DirtyMaterial);
+        if (isVisible()) {
+            n->renderer->synchronize(this, targetSize, false);
+            updateDynamicTextures();
+            n->markDirty(QSGNode::DirtyMaterial);
+        }
 
         return n;
     }
@@ -756,10 +757,10 @@ void QQuick3DViewport::setupDirectRenderer(RenderMode mode)
         doImportShaderCache();
     }
     const QSizeF targetSize = window()->effectiveDevicePixelRatio() * QSizeF(width(), height());
-    m_directRenderer->renderer()->synchronize(this, targetSize.toSize(), false);
     m_directRenderer->setViewport(QRectF(window()->effectiveDevicePixelRatio() * mapToScene(QPointF(0, 0)), targetSize));
     m_directRenderer->setVisibility(isVisible());
     if (isVisible()) {
+        m_directRenderer->renderer()->synchronize(this, targetSize.toSize(), false);
         updateDynamicTextures();
         m_directRenderer->requestRender();
     }
@@ -772,4 +773,14 @@ void QQuick3DViewport::updateClearBeforeRendering()
     window()->setClearBeforeRendering(m_renderMode != Underlay || !isVisible());
 }
 
+// This is used for offscreen mode since we need to check if
+// this item is used by an effect but hidden
+bool QQuick3DViewport::checkIsVisible() const
+{
+    auto childPrivate = QQuickItemPrivate::get(this);
+    return (childPrivate->explicitVisible ||
+            (childPrivate->extra.isAllocated() && childPrivate->extra->effectRefCount));
+
+}
+
 QT_END_NAMESPACE
diff --git a/src/quick3d/qquick3dviewport_p.h b/src/quick3d/qquick3dviewport_p.h
index f7307d5b19186934bc2c152ded980985551006a9..56cc5574e3e50648f2ea55a922445b99a73706dd 100644
--- a/src/quick3d/qquick3dviewport_p.h
+++ b/src/quick3d/qquick3dviewport_p.h
@@ -141,6 +141,7 @@ private:
     void updateDynamicTextures();
     void setupDirectRenderer(RenderMode mode);
     void updateClearBeforeRendering();
+    bool checkIsVisible() const;
 
     void readShaderCache();
     void writeShaderCache(const QUrl &shaderCacheFile);