diff options
Diffstat (limited to 'src/runtimerender/rendererimpl')
10 files changed, 974 insertions, 345 deletions
diff --git a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp index 712214a..095badc 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp @@ -290,9 +290,31 @@ namespace render { } } - context.SetCullingEnabled(true); + context.SetCullingEnabled(m_Material.m_CullMode != DefaultMaterialCullMode::None); context.SetInputAssembler(m_Subset.m_InputAssembler); - context.Draw(m_Subset.m_PrimitiveType, m_Subset.m_Count, m_Subset.m_Offset); + if (m_Material.m_CullMode != DefaultMaterialCullMode::None) { + NVScopedRefCounted<qt3ds::render::NVRenderRasterizerState> rsdefaultstate = + context.CreateRasterizerState(0.0, 0.0, qt3ds::render::NVRenderFaces::Back); + qt3ds::render::NVRenderFaces::Enum face = qt3ds::render::NVRenderFaces::Back; + switch (m_Material.m_CullMode) { + case DefaultMaterialCullMode::Front: + face = qt3ds::render::NVRenderFaces::Front; + break; + case DefaultMaterialCullMode::FrontAndBack: + face = qt3ds::render::NVRenderFaces::FrontAndBack; + break; + default: + break; + } + + NVScopedRefCounted<qt3ds::render::NVRenderRasterizerState> rasterState = + context.CreateRasterizerState(0.0, 0.0, face); + context.SetRasterizerState(rasterState); + context.Draw(m_Subset.m_PrimitiveType, m_Subset.m_Count, m_Subset.m_Offset); + context.SetRasterizerState(rsdefaultstate); + } else { + context.Draw(m_Subset.m_PrimitiveType, m_Subset.m_Count, m_Subset.m_Offset); + } } void SSubsetRenderable::RenderShadow(const QT3DSVec2 &inCameraVec, @@ -600,5 +622,14 @@ namespace render { theRenderContext, m_Generator.GetLayerGlobalRenderProperties(), TShaderFeatureSet()); } + + void SOrderedGroupRenderable::update() + { + QT3DSVec3 sum(0.0f, 0.0f, 0.0f); + for (int i = 0; i < m_renderables.size(); i++) + sum += m_renderables[i]->m_WorldCenterPoint; + sum *= 1.0f / m_renderables.size(); + m_WorldCenterPoint = sum; + } } } diff --git a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h index abc8143..12533c4 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h +++ b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h @@ -63,6 +63,7 @@ namespace render { ShadowCaster = 1 << 10, DistanceField = 1 << 11, HasAlphaTest = 1 << 12, + OrderedGroup = 1 << 13, }; }; @@ -167,6 +168,14 @@ namespace render { { return *this & RenderPreparationResultFlagValues::HasAlphaTest; } + bool isOrderedGroup() const + { + return *this & RenderPreparationResultFlagValues::OrderedGroup; + } + void setOrderedGroup(bool ordered) + { + ClearOrSet(ordered, RenderPreparationResultFlagValues::OrderedGroup); + } }; struct SNodeLightEntry @@ -480,6 +489,20 @@ namespace render { void RenderShadowMapPass(const QT3DSVec2 &inCameraVec, const SLight *inLight, const SCamera &inCamera, SShadowMapEntry *inShadowMapEntry); }; + + struct SOrderedGroupRenderable : public SRenderableObject + { + SOrderedGroupRenderable(SRenderableObjectFlags inFlags, const QT3DSVec3 &inWorldCenterPt, + const QT3DSMat44 &inGlobalTransform, const NVBounds3 &inBounds, + NVAllocatorCallback &allocator) + : SRenderableObject(inFlags, inWorldCenterPt, inGlobalTransform, inBounds) + , m_renderables(allocator, "SOrderedGroupRenderable::m_renderables") + { + m_RenderableFlags.setOrderedGroup(true); + } + void update(); + nvvector<SRenderableObject *> m_renderables; + }; } } diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp index a0ea8b1..b39cc91 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp @@ -57,6 +57,7 @@ #include "Qt3DSRenderPath.h" #include "Qt3DSRenderShaderCodeGeneratorV2.h" #include "Qt3DSRenderDefaultMaterialShaderGenerator.h" +#include "backends/gl/Qt3DSOpenGLUtil.h" #include <stdlib.h> #ifdef _WIN32 @@ -128,6 +129,7 @@ namespace render { , m_PickRenderPlugins(true) , m_LayerCachingEnabled(true) , m_LayerGPuProfilingEnabled(false) + , m_SignalProxy(ctx.GetSignalProxy()) { } Qt3DSRendererImpl::~Qt3DSRendererImpl() @@ -232,11 +234,9 @@ namespace render { } bool Qt3DSRendererImpl::PrepareLayerForRender(SLayer &inLayer, - const QT3DSVec2 &inViewportDimensions, bool inRenderSiblings, const SRenderInstanceId id) { - (void)inViewportDimensions; nvvector<SLayer *> renderableLayers(m_qt3dsContext.GetPerFrameAllocator(), "LayerVector"); // Found by fair roll of the dice. renderableLayers.reserve(4); @@ -253,7 +253,7 @@ namespace render { SLayerRenderData *theRenderData = GetOrCreateLayerRenderDataForNode(*theLayer, id); if (theRenderData) { - theRenderData->PrepareForRender(); + bool needsRender = theRenderData->PrepareForRender(); if (id) { if (m_initialPrepareData.contains(theLayer)) { // Copy dirty state from the initial since the graph is @@ -268,7 +268,8 @@ namespace render { m_initialPrepareData.insert(theLayer, theRenderData); } } - retval = retval || theRenderData->m_LayerPrepResult->m_Flags.WasDirty(); + retval = retval || needsRender + || theRenderData->m_LayerPrepResult->m_Flags.WasDirty() ; } else { QT3DS_ASSERT(false); } @@ -367,7 +368,7 @@ namespace render { SLayerRenderData *theRenderData = QT3DS_NEW(m_Context->GetAllocator(), SLayerRenderData)( const_cast<SLayer &>(*theLayer), *this); m_InstanceRenderMap.insert(make_pair(combineLayerAndId(theLayer, id), theRenderData)); - + theRenderData->m_SignalProxy = (QRuntimeViewSignalProxy *)m_SignalProxy; // create a profiler if enabled if (IsLayerGpuProfilingEnabled() && theRenderData) theRenderData->CreateGpuProfiler(); @@ -968,20 +969,53 @@ namespace render { return mouseVec; } - uint Qt3DSRendererImpl::getLayerTextureId(SLayer &layer) + uint Qt3DSRendererImpl::getLayerTextureId(SLayer &layer, const SRenderInstanceId id) { - SLayerRenderData *data = GetOrCreateLayerRenderDataForNode(layer); - if (data->m_LayerCachedTexture) { + SLayerRenderData *data = GetOrCreateLayerRenderDataForNode(layer, id); + if (data->m_LayerCachedTexture[data->getCameraIndex()]) { return static_cast<uint>(reinterpret_cast<size_t>( - data->m_LayerCachedTexture->GetTextureObjectHandle())); + data->m_LayerCachedTexture[data->getCameraIndex()]->GetTextureObjectHandle())); } - if (data->m_LayerTexture) { + if (data->m_LayerTexture[data->getCameraIndex()]) { return static_cast<uint>(reinterpret_cast<size_t>( - data->m_LayerTexture->GetTextureObjectHandle())); + data->m_LayerTexture[data->getCameraIndex()]->GetTextureObjectHandle())); } return 0; } + GLenum Qt3DSRendererImpl::getTextureGlFormat(NVRenderTextureFormats::Enum internalFormat) + { + auto ctxType = m_Context->GetRenderContextType(); + GLConversion conversion; + GLenum glInternalFormat, glformat, gltype; + + if (NVRenderTextureFormats::isUncompressedTextureFormat(internalFormat)) { + conversion.fromUncompressedTextureFormatToGL(ctxType, internalFormat, + glformat, gltype, glInternalFormat); + return glInternalFormat; + } else if (NVRenderTextureFormats::isCompressedTextureFormat(internalFormat)) { + return conversion.fromCompressedTextureFormatToGL(internalFormat); + } else if (NVRenderTextureFormats::isDepthTextureFormat(internalFormat)) { + conversion.fromDepthTextureFormatToGL(ctxType, internalFormat, glformat, + gltype, glInternalFormat); + return glInternalFormat; + } else { + return GL_INVALID_ENUM; + } + } + + STextureDetails Qt3DSRendererImpl::getLayerTextureDetails(SLayer &inLayer, const SRenderInstanceId id) + { + SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inLayer, id); + + if (theData->m_LayerCachedTexture[theData->getCameraIndex()]) + return theData->m_LayerCachedTexture[theData->getCameraIndex()]->GetTextureDetails(); + if (theData->m_LayerTexture[theData->getCameraIndex()]) + return theData->m_LayerTexture[theData->getCameraIndex()]->GetTextureDetails(); + + return {}; + } + Option<SLayerPickSetup> Qt3DSRendererImpl::GetLayerPickSetup(SLayer &inLayer, const QT3DSVec2 &inMouseCoords, const QSize &inPickDims) @@ -1405,61 +1439,72 @@ namespace render { } void Qt3DSRendererImpl::GetLayerHitObjectList(SLayerRenderData &inLayerRenderData, - const QT3DSVec2 &inViewportDimensions, - const QT3DSVec2 &inPresCoords, bool inPickEverything, - TPickResultArray &outIntersectionResult, - NVAllocatorCallback &inTempAllocator) + const QT3DSVec2 &inViewportDimensions, + const QT3DSVec2 &inPresCoords, + bool inPickEverything, + TPickResultArray &outIntersectionResult, + NVAllocatorCallback &inTempAllocator) { // This function assumes the layer was rendered to the scene itself. There is another - // function - // for completely offscreen layers that don't get rendered to the scene. + // function for completely offscreen layers that don't get rendered to the scene. bool wasRenderToTarget(inLayerRenderData.m_Layer.m_Flags.IsLayerRenderToTarget()); - if (wasRenderToTarget && inLayerRenderData.m_Camera != nullptr) { - Option<SRay> theHitRay; - if (inLayerRenderData.m_LayerPrepResult.hasValue()) { - theHitRay = inLayerRenderData.m_LayerPrepResult->GetPickRay( - inPresCoords, inViewportDimensions, false, m_Context->isSceneCameraView()); - } - if (inLayerRenderData.m_LastFrameOffscreenRenderer.mPtr == nullptr) { - if (theHitRay.hasValue()) { - // Scale the mouse coords to change them into the camera's numerical space. - SRay thePickRay = *theHitRay; - for (QT3DSU32 idx = inLayerRenderData.m_OpaqueObjects.size(), end = 0; idx > end; - --idx) { - SRenderableObject *theRenderableObject = - inLayerRenderData.m_OpaqueObjects[idx - 1]; - if (inPickEverything - || theRenderableObject->m_RenderableFlags.GetPickable()) - IntersectRayWithSubsetRenderable(thePickRay, *theRenderableObject, - outIntersectionResult, - inTempAllocator); - } - for (QT3DSU32 idx = inLayerRenderData.m_TransparentObjects.size(), end = 0; - idx > end; --idx) { - SRenderableObject *theRenderableObject = - inLayerRenderData.m_TransparentObjects[idx - 1]; - if (inPickEverything - || theRenderableObject->m_RenderableFlags.GetPickable()) - IntersectRayWithSubsetRenderable(thePickRay, *theRenderableObject, - outIntersectionResult, - inTempAllocator); - } + if (!wasRenderToTarget || !inLayerRenderData.m_Camera) + return; + + Option<SRay> theHitRay; + if (inLayerRenderData.m_LayerPrepResult.hasValue()) { + theHitRay = inLayerRenderData.m_LayerPrepResult->GetPickRay( + inPresCoords, inViewportDimensions, false, m_Context->isSceneCameraView()); + } + if (inLayerRenderData.m_LastFrameOffscreenRenderer.mPtr) { + IGraphObjectPickQuery *theQuery = + inLayerRenderData.m_LastFrameOffscreenRenderer->GetGraphObjectPickQuery(this); + if (theQuery) { + Qt3DSRenderPickResult theResult = + theQuery->Pick(inPresCoords, inViewportDimensions, inPickEverything); + if (theResult.m_HitObject) { + theResult.m_OffscreenRenderer = + inLayerRenderData.m_LastFrameOffscreenRenderer; + outIntersectionResult.push_back(theResult); } } else { - IGraphObjectPickQuery *theQuery = - inLayerRenderData.m_LastFrameOffscreenRenderer->GetGraphObjectPickQuery(this); - if (theQuery) { - Qt3DSRenderPickResult theResult = - theQuery->Pick(inPresCoords, inViewportDimensions, inPickEverything); - if (theResult.m_HitObject) { - theResult.m_OffscreenRenderer = - inLayerRenderData.m_LastFrameOffscreenRenderer; - outIntersectionResult.push_back(theResult); - } - } else - inLayerRenderData.m_LastFrameOffscreenRenderer->Pick(inPresCoords, - inViewportDimensions, - this); + inLayerRenderData.m_LastFrameOffscreenRenderer->Pick(inPresCoords, + inViewportDimensions, + this); + } + return; + } + if (!theHitRay.hasValue()) + return; + // Scale the mouse coords to change them into the camera's coordinate space. + SRay thePickRay = *theHitRay; + for (QT3DSU32 idx = inLayerRenderData.m_OpaqueObjects.size(), end = 0; idx > end; --idx) { + SRenderableObject *theRenderableObject = inLayerRenderData.m_OpaqueObjects[idx - 1]; + if (inPickEverything || theRenderableObject->m_RenderableFlags.GetPickable()) { + IntersectRayWithSubsetRenderable(thePickRay, *theRenderableObject, + outIntersectionResult, + inTempAllocator); + } + } + for (QT3DSU32 idx = inLayerRenderData.m_GroupObjects.size(), end = 0; idx > end; --idx) { + SRenderableObject *object = inLayerRenderData.m_GroupObjects[idx - 1]; + SOrderedGroupRenderable &group(static_cast<SOrderedGroupRenderable &>(*object)); + Q_ASSERT(object->m_RenderableFlags.isOrderedGroup()); + for (int i = 0; i < group.m_renderables.size(); ++i) { + if (inPickEverything || group.m_renderables[i]->m_RenderableFlags.GetPickable()) { + IntersectRayWithSubsetRenderable(thePickRay, *group.m_renderables[i], + outIntersectionResult, + inTempAllocator); + } + } + } + for (QT3DSU32 idx = inLayerRenderData.m_TransparentObjects.size(), end = 0; + idx > end; --idx) { + SRenderableObject *renderableObject = inLayerRenderData.m_TransparentObjects[idx - 1]; + if (inPickEverything || renderableObject->m_RenderableFlags.GetPickable()) { + IntersectRayWithSubsetRenderable(thePickRay, *renderableObject, + outIntersectionResult, + inTempAllocator); } } } diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h index 792d71e..2230733 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h @@ -296,6 +296,7 @@ namespace render { bool m_PickRenderPlugins; bool m_LayerCachingEnabled; bool m_LayerGPuProfilingEnabled; + void *m_SignalProxy; SShaderDefaultMaterialKeyProperties m_DefaultMaterialShaderKeyProperties; QHash<SLayer *, SLayerRenderData *> m_initialPrepareData; @@ -305,6 +306,7 @@ namespace render { float m_alphaOp = 1.0f; float m_alphaRef = 1.0f; + public: Qt3DSRendererImpl(IQt3DSRenderContext &ctx); virtual ~Qt3DSRendererImpl(); @@ -342,8 +344,8 @@ namespace render { // Calls prepare layer for render // and then do render layer. - bool PrepareLayerForRender(SLayer &inLayer, const QT3DSVec2 &inViewportDimensions, - bool inRenderSiblings, const SRenderInstanceId id) override; + bool PrepareLayerForRender(SLayer &inLayer, bool inRenderSiblings, + const SRenderInstanceId id) override; void RenderLayer(SLayer &inLayer, const QT3DSVec2 &inViewportDimensions, bool clear, QT3DSVec4 clearColor, bool inRenderSiblings, const SRenderInstanceId id) override; @@ -386,7 +388,11 @@ namespace render { const QT3DSVec3 &inMouseVec) const override; QT3DSVec3 ProjectPosition(SNode &inNode, const QT3DSVec3 &inPosition) const override; - uint getLayerTextureId(SLayer &layer) override; + uint getLayerTextureId(SLayer &layer, const SRenderInstanceId id) override; + + STextureDetails getLayerTextureDetails(SLayer &inLayer, const SRenderInstanceId id) override; + + GLenum getTextureGlFormat(NVRenderTextureFormats::Enum internalFormat) override; Option<SLayerPickSetup> GetLayerPickSetup(SLayer &inLayer, const QT3DSVec2 &inMouseCoords, @@ -566,7 +572,6 @@ namespace render { Option<QT3DSVec2> GetLayerMouseCoords(SLayer &inLayer, const QT3DSVec2 &inMouseCoords, const QT3DSVec2 &inViewportDimensions, bool forceImageIntersect = false) const override; - protected: Option<QT3DSVec2> GetLayerMouseCoords(SLayerRenderData &inLayer, const QT3DSVec2 &inMouseCoords, const QT3DSVec2 &inViewportDimensions, diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp index 95cbc9e..7348fb2 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp @@ -77,7 +77,8 @@ namespace render { SLayerRenderData::SLayerRenderData(SLayer &inLayer, Qt3DSRendererImpl &inRenderer) : SLayerRenderPreparationData(inLayer, inRenderer) - , m_LayerTexture(inRenderer.GetQt3DSContext().GetResourceManager()) + , m_LayerTexture{inRenderer.GetQt3DSContext().GetResourceManager(), + inRenderer.GetQt3DSContext().GetResourceManager()} , m_TemporalAATexture{inRenderer.GetQt3DSContext().GetResourceManager(), inRenderer.GetQt3DSContext().GetResourceManager()} , m_LayerDepthTexture(inRenderer.GetQt3DSContext().GetResourceManager()) @@ -87,7 +88,7 @@ namespace render { , m_LayerMultisampleTexture(inRenderer.GetQt3DSContext().GetResourceManager()) , m_LayerMultisamplePrepassDepthTexture(inRenderer.GetQt3DSContext().GetResourceManager()) , m_LayerMultisampleWidgetTexture(inRenderer.GetQt3DSContext().GetResourceManager()) - , m_LayerCachedTexture(NULL) + , m_LayerCachedTexture{NULL, NULL} , m_AdvancedBlendDrawTexture(NULL) , m_AdvancedBlendBlendTexture(NULL) , m_AdvancedModeDrawFB(NULL) @@ -105,8 +106,10 @@ namespace render { SLayerRenderData::~SLayerRenderData() { IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager()); - if (m_LayerCachedTexture && m_LayerCachedTexture != m_LayerTexture) - theResourceManager.Release(*m_LayerCachedTexture); + if (m_LayerCachedTexture[0] && m_LayerCachedTexture[0] != m_LayerTexture[0]) + theResourceManager.Release(*m_LayerCachedTexture[0]); + if (m_LayerCachedTexture[1] && m_LayerCachedTexture[1] != m_LayerTexture[1]) + theResourceManager.Release(*m_LayerCachedTexture[1]); if (m_AdvancedModeDrawFB) { m_AdvancedModeDrawFB->release(); m_AdvancedModeDrawFB = NULL; @@ -120,9 +123,9 @@ namespace render { if (m_AdvancedBlendDrawTexture) m_AdvancedBlendDrawTexture = NULL; } - void SLayerRenderData::PrepareForRender(const QSize &inViewportDimensions) + bool SLayerRenderData::PrepareForRender(const QSize &inViewportDimensions) { - SLayerRenderPreparationData::PrepareForRender(inViewportDimensions); + bool needsRender = SLayerRenderPreparationData::PrepareForRender(inViewportDimensions); SLayerRenderPreparationResult &thePrepResult(*m_LayerPrepResult); IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager()); @@ -133,13 +136,13 @@ namespace render { } // Get rid of the layer texture if we aren't rendering to texture this frame. - if (m_LayerTexture && !thePrepResult.m_Flags.ShouldRenderToTexture()) { - if (m_LayerCachedTexture && m_LayerCachedTexture != m_LayerTexture) { - theResourceManager.Release(*m_LayerCachedTexture); - m_LayerCachedTexture = NULL; + if (m_LayerTexture[getCameraIndex()] && !thePrepResult.m_Flags.ShouldRenderToTexture()) { + if (m_LayerCachedTexture[getCameraIndex()] && m_LayerCachedTexture[getCameraIndex()] != m_LayerTexture[getCameraIndex()]) { + theResourceManager.Release(*m_LayerCachedTexture[getCameraIndex()]); + m_LayerCachedTexture[getCameraIndex()] = NULL; } - m_LayerTexture.ReleaseTexture(); + m_LayerTexture[getCameraIndex()].ReleaseTexture(); m_LayerDepthTexture.ReleaseTexture(); m_LayerWidgetTexture.ReleaseTexture(); m_LayerSsaoTexture.ReleaseTexture(); @@ -162,7 +165,7 @@ namespace render { // Clean up the texture cache if layer dimensions changed if (inViewportDimensions.width() != m_previousDimensions.width() || inViewportDimensions.height() != m_previousDimensions.height()) { - m_LayerTexture.ReleaseTexture(); + m_LayerTexture[getCameraIndex()].ReleaseTexture(); m_LayerDepthTexture.ReleaseTexture(); m_LayerSsaoTexture.ReleaseTexture(); m_LayerWidgetTexture.ReleaseTexture(); @@ -182,6 +185,13 @@ namespace render { m_Renderer.GetQt3DSContext().GetEffectSystem().GetResourceManager() .DestroyFreeSizedResources(); } + bool isProgressiveAABlendPass = + m_ProgressiveAAPassIndex && m_ProgressiveAAPassIndex < thePrepResult.m_MaxAAPassIndex; + // Save left eye flags for later + if (getCameraIndex() == 0) + m_LeftFlags = SLayerRenderPreparationResultFlags(thePrepResult.m_Flags); + + return needsRender || isProgressiveAABlendPass; } NVRenderTextureFormats::Enum SLayerRenderData::GetDepthBufferFormat() @@ -309,6 +319,36 @@ namespace render { } namespace { + NVBounds3 calculateShadowCameraBoundingBox(const QT3DSVec3 *points, + const QT3DSVec3 &forward, + const QT3DSVec3 &up, const QT3DSVec3 &right) + { + float minDistanceZ = std::numeric_limits<float>::max(); + float maxDistanceZ = -std::numeric_limits<float>::max(); + float minDistanceY = std::numeric_limits<float>::max(); + float maxDistanceY = -std::numeric_limits<float>::max(); + float minDistanceX = std::numeric_limits<float>::max(); + float maxDistanceX = -std::numeric_limits<float>::max(); + for (int i = 0; i < 8; ++i) { + float distanceZ = points[i].dot(forward); + if (distanceZ < minDistanceZ) + minDistanceZ = distanceZ; + if (distanceZ > maxDistanceZ) + maxDistanceZ = distanceZ; + float distanceY = points[i].dot(up); + if (distanceY < minDistanceY) + minDistanceY = distanceY; + if (distanceY > maxDistanceY) + maxDistanceY = distanceY; + float distanceX = points[i].dot(right); + if (distanceX < minDistanceX) + minDistanceX = distanceX; + if (distanceX > maxDistanceX) + maxDistanceX = distanceX; + } + return NVBounds3(QT3DSVec3(minDistanceX, minDistanceY, minDistanceZ), + QT3DSVec3(maxDistanceX, maxDistanceY, maxDistanceZ)); + } void computeFrustumBounds(const SCamera &inCamera, const NVRenderRectF &inViewPort, QT3DSVec3 &ctrBound, QT3DSVec3 camVerts[8]) @@ -350,7 +390,8 @@ namespace render { void SetupCameraForShadowMap(const QT3DSVec2 &inCameraVec, NVRenderContext & /*inContext*/, const NVRenderRectF &inViewport, const SCamera &inCamera, - const SLight *inLight, SCamera &theCamera) + const SLight *inLight, SCamera &theCamera, + QT3DSVec3 *scenePoints = nullptr) { // setup light matrix QT3DSU32 mapRes = 1 << inLight->m_ShadowMapRes; @@ -368,8 +409,15 @@ namespace render { theCamera.m_FOV = inLight->m_ShadowMapFov * QT3DS_DEGREES_TO_RADIANS; if (inLight->m_LightType == RenderLightTypes::Directional) { - QT3DSVec3 frustBounds[8], boundCtr; - computeFrustumBounds(inCamera, inViewport, boundCtr, frustBounds); + QT3DSVec3 frustumPoints[8], boundCtr, sceneCtr; + computeFrustumBounds(inCamera, inViewport, boundCtr, frustumPoints); + + if (scenePoints) { + sceneCtr = QT3DSVec3(0, 0, 0); + for (int i = 0; i < 8; ++i) + sceneCtr += scenePoints[i]; + sceneCtr *= 0.125f; + } QT3DSVec3 forward = inLightDir; forward.normalize(); @@ -379,37 +427,26 @@ namespace render { up.normalize(); // Calculate bounding box of the scene camera frustum - float minDistanceZ = std::numeric_limits<float>::max(); - float maxDistanceZ = -std::numeric_limits<float>::max(); - float minDistanceY = std::numeric_limits<float>::max(); - float maxDistanceY = -std::numeric_limits<float>::max(); - float minDistanceX = std::numeric_limits<float>::max(); - float maxDistanceX = -std::numeric_limits<float>::max(); - for (int i = 0; i < 8; ++i) { - float distanceZ = frustBounds[i].dot(forward); - if (distanceZ < minDistanceZ) - minDistanceZ = distanceZ; - if (distanceZ > maxDistanceZ) - maxDistanceZ = distanceZ; - float distanceY = frustBounds[i].dot(up); - if (distanceY < minDistanceY) - minDistanceY = distanceY; - if (distanceY > maxDistanceY) - maxDistanceY = distanceY; - float distanceX = frustBounds[i].dot(right); - if (distanceX < minDistanceX) - minDistanceX = distanceX; - if (distanceX > maxDistanceX) - maxDistanceX = distanceX; + NVBounds3 bounds = calculateShadowCameraBoundingBox(frustumPoints, forward, up, + right); + inLightPos = boundCtr; + if (scenePoints) { + NVBounds3 sceneBounds = calculateShadowCameraBoundingBox(scenePoints, forward, + up, right); + if (sceneBounds.getExtents().x * sceneBounds.getExtents().y + * sceneBounds.getExtents().z < bounds.getExtents().x + * bounds.getExtents().y * bounds.getExtents().z) { + bounds = sceneBounds; + inLightPos = sceneCtr; + } } // Apply bounding box parameters to shadow map camera projection matrix // so that the whole scene is fit inside the shadow map - inLightPos = boundCtr; - theViewport.m_Height = abs(maxDistanceY - minDistanceY); - theViewport.m_Width = abs(maxDistanceX - minDistanceX); - theCamera.m_ClipNear = -abs(maxDistanceZ - minDistanceZ); - theCamera.m_ClipFar = abs(maxDistanceZ - minDistanceZ); + theViewport.m_Height = bounds.getExtents().y * 2; + theViewport.m_Width = bounds.getExtents().x * 2; + theCamera.m_ClipNear = -bounds.getExtents().z * 2; + theCamera.m_ClipFar = bounds.getExtents().z * 2; } theCamera.m_Flags.SetLeftHanded(false); @@ -668,14 +705,15 @@ namespace render { void SLayerRenderData::RenderShadowMapPass(CResourceFrameBuffer *theFB) { QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), - "SLayerRenderData::RenderShadowMapPass") + "LayerRenderData: RenderShadowMapPass") if (m_Camera == NULL || !GetShadowMapManager()) return; // Check if we have anything to render - if ((m_OpaqueObjects.size() == 0 && GetTransparentRenderableObjects().size() == 0) - || m_Lights.size() == 0) { + if ((m_OpaqueObjects.empty() && GetTransparentRenderableObjects().size() == 0 + && m_GroupObjects.empty()) + || m_Lights.empty()) { return; } @@ -706,6 +744,18 @@ namespace render { | qt3ds::render::NVRenderClearValues::Stencil | qt3ds::render::NVRenderClearValues::Color); + auto bounds = m_Camera->m_Parent->GetBounds(m_Renderer.GetQt3DSContext().GetBufferManager(), + m_Renderer.GetQt3DSContext().GetPathManager()); + QT3DSVec3 scenePoints[8]; + scenePoints[0] = bounds.minimum; + scenePoints[1] = QT3DSVec3(bounds.maximum.x, bounds.minimum.y, bounds.minimum.z); + scenePoints[2] = QT3DSVec3(bounds.minimum.x, bounds.maximum.y, bounds.minimum.z); + scenePoints[3] = QT3DSVec3(bounds.maximum.x, bounds.maximum.y, bounds.minimum.z); + scenePoints[4] = QT3DSVec3(bounds.minimum.x, bounds.minimum.y, bounds.maximum.z); + scenePoints[5] = QT3DSVec3(bounds.maximum.x, bounds.minimum.y, bounds.maximum.z); + scenePoints[6] = QT3DSVec3(bounds.minimum.x, bounds.maximum.y, bounds.maximum.z); + scenePoints[7] = bounds.maximum; + for (QT3DSU32 i = 0; i < m_Lights.size(); i++) { // don't render shadows when not casting if (m_Lights[i]->m_CastShadow == false) @@ -717,7 +767,7 @@ namespace render { QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar); SetupCameraForShadowMap(theCameraProps, m_Renderer.GetContext(), __viewport.m_InitialValue, *m_Camera, - m_Lights[i], theCamera); + m_Lights[i], theCamera, scenePoints); // we need this matrix for the final rendering theCamera.CalculateViewProjectionMatrix(pEntry->m_LightVP); pEntry->m_LightView = theCamera.m_GlobalTransform.getInverse(); @@ -826,13 +876,13 @@ namespace render { void SLayerRenderData::RenderDepthPass(bool inEnableTransparentDepthWrite) { QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), - "SLayerRenderData::RenderDepthPass") + "LayerRenderData: RenderDepthPass") if (m_Camera == NULL) return; // Avoid running this method if possible. - if ((inEnableTransparentDepthWrite == false - && ((m_OpaqueObjects.size() == 0 && m_TransparentObjects.size() == 0) + if ((inEnableTransparentDepthWrite + && ((m_GroupObjects.empty() && m_OpaqueObjects.empty() && m_TransparentObjects.empty()) || m_Layer.m_Flags.IsLayerEnableDepthPrepass() == false)) || m_Layer.m_Flags.IsLayerEnableDepthTest() == false) return; @@ -895,23 +945,98 @@ namespace render { } } - void SLayerRenderData::renderTransparentObjectsPass( - TRenderRenderableFunction inRenderFn, bool inEnableBlending, - bool inEnableTransparentDepthWrite, QT3DSU32 indexLight, - const SCamera &inCamera, CResourceFrameBuffer *theFB) - { - NVDataRef<SRenderableObject *> theTransparentObjects = GetTransparentRenderableObjects(); - NVRenderContext &theRenderContext(m_Renderer.GetContext()); - QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar); - if (inEnableBlending || m_Layer.m_Flags.IsLayerEnableDepthTest() == false) { - theRenderContext.SetBlendingEnabled(true && inEnableBlending); +void SLayerRenderData::renderOrderedGroup( + SRenderableObject &theObject, TRenderRenderableFunction inRenderFn, bool inEnableBlending, + bool inEnableDepthWrite, bool inEnableTransparentDepthWrite, QT3DSU32 indexLight, + const SCamera &inCamera, CResourceFrameBuffer *theFB) +{ + NVRenderContext &theRenderContext(m_Renderer.GetContext()); + SOrderedGroupRenderable &group(static_cast<SOrderedGroupRenderable &>(theObject)); + const bool opaqueDepthTest = m_Layer.m_Flags.IsLayerEnableDepthTest(); + const bool opaqueDepthWrite = opaqueDepthTest && inEnableDepthWrite; + QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar); + for (int i = 0; i < group.m_renderables.size(); ++i) { + SRenderableObject &object(*group.m_renderables[i]); + SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false); + SScopedLightsListScope lightsScope(m_Lights, m_LightDirections, + m_SourceLightDirections, + object.m_ScopedLights); +#ifdef ADVANCED_BLEND_SW_FALLBACK + // SW fallback for advanced blend modes. + // Renders transparent objects to a separate FBO and blends them in shader + // with the opaque items and background. + DefaultMaterialBlendMode::Enum blendMode + = DefaultMaterialBlendMode::Enum::Normal; + if (theObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) + blendMode = static_cast<SSubsetRenderable &>(theObject).getBlendingMode(); + bool useBlendFallback + = (blendMode == DefaultMaterialBlendMode::Overlay + || blendMode == DefaultMaterialBlendMode::ColorBurn + || blendMode == DefaultMaterialBlendMode::ColorDodge) + && !theRenderContext.IsAdvancedBlendHwSupported() + && !theRenderContext.IsAdvancedBlendHwSupportedKHR() && m_LayerPrepassDepthTexture; + if (useBlendFallback) + SetupDrawFB(true); +#endif + if (object.m_RenderableFlags.hasAlphaTest()) { + theRenderContext.SetBlendingEnabled(false); + theRenderContext.SetDepthWriteEnabled(opaqueDepthWrite); + m_Renderer.setAlphaTest(true, 1.0f, -1.0f + (1.0f / 255.0f)); + inRenderFn(*this, object, theCameraProps, GetShaderFeatureSet(), indexLight, + inCamera); + theRenderContext.SetBlendingEnabled(inEnableBlending); + theRenderContext.SetDepthWriteEnabled(inEnableTransparentDepthWrite); + m_Renderer.setAlphaTest(true, -1.0f, 1.0f); + inRenderFn(*this, object, theCameraProps, GetShaderFeatureSet(), indexLight, + inCamera); + m_Renderer.setAlphaTest(false, 1.0, 1.0); + } else { + const bool transparency + = object.m_RenderableFlags.HasTransparency() && inEnableBlending; + theRenderContext.SetBlendingEnabled(transparency); + theRenderContext.SetDepthWriteEnabled((!transparency && opaqueDepthWrite) + || inEnableTransparentDepthWrite); + inRenderFn(*this, object, theCameraProps, GetShaderFeatureSet(), indexLight, + inCamera); + } +#ifdef ADVANCED_BLEND_SW_FALLBACK + // SW fallback for advanced blend modes. + // Continue blending after transparent objects have been rendered to a FBO + if (useBlendFallback) { + BlendAdvancedToFB(blendMode, true, theFB); + // restore blending status + theRenderContext.SetBlendingEnabled(inEnableBlending); + // restore depth test status + theRenderContext.SetDepthTestEnabled( + m_Layer.m_Flags.IsLayerEnableDepthTest()); theRenderContext.SetDepthWriteEnabled(inEnableTransparentDepthWrite); + } +#endif + } +} - // Assume all objects have transparency if the layer's depth test enabled flag is true. - if (m_Layer.m_Flags.IsLayerEnableDepthTest() == true) { - for (QT3DSU32 idx = 0, end = theTransparentObjects.size(); idx < end; ++idx) { - SRenderableObject &theObject(*theTransparentObjects[idx]); - if (!(theObject.m_RenderableFlags.IsCompletelyTransparent())) { +void SLayerRenderData::renderTransparentObjectsPass( + TRenderRenderableFunction inRenderFn, bool inEnableBlending, bool inEnableDepthWrite, + bool inEnableTransparentDepthWrite, QT3DSU32 indexLight, + const SCamera &inCamera, CResourceFrameBuffer *theFB) +{ + NVDataRef<SRenderableObject *> theTransparentObjects = GetTransparentRenderableObjects(); + NVRenderContext &theRenderContext(m_Renderer.GetContext()); + QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar); + if (inEnableBlending || m_Layer.m_Flags.IsLayerEnableDepthTest() == false) { + theRenderContext.SetBlendingEnabled(true && inEnableBlending); + theRenderContext.SetDepthWriteEnabled(inEnableTransparentDepthWrite); + + // Assume all objects have transparency if the layer's depth test enabled flag is true. + if (m_Layer.m_Flags.IsLayerEnableDepthTest()) { + for (QT3DSU32 idx = 0, end = theTransparentObjects.size(); idx < end; ++idx) { + SRenderableObject &theObject(*theTransparentObjects[idx]); + if (!(theObject.m_RenderableFlags.IsCompletelyTransparent())) { + if (theObject.m_RenderableFlags.isOrderedGroup()) { + renderOrderedGroup(theObject, inRenderFn, inEnableBlending, + inEnableDepthWrite, inEnableTransparentDepthWrite, + indexLight, inCamera, theFB); + } else { #ifdef ADVANCED_BLEND_SW_FALLBACK // SW fallback for advanced blend modes. // Renders transparent objects to a separate FBO and blends them in shader @@ -920,12 +1045,13 @@ namespace render { = DefaultMaterialBlendMode::Enum::Normal; if (theObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) blendMode = static_cast<SSubsetRenderable &>(theObject).getBlendingMode(); - bool useBlendFallback = (blendMode == DefaultMaterialBlendMode::Overlay || - blendMode == DefaultMaterialBlendMode::ColorBurn || - blendMode == DefaultMaterialBlendMode::ColorDodge) && - !theRenderContext.IsAdvancedBlendHwSupported() && - !theRenderContext.IsAdvancedBlendHwSupportedKHR() && - m_LayerPrepassDepthTexture; + bool useBlendFallback + = (blendMode == DefaultMaterialBlendMode::Overlay + || blendMode == DefaultMaterialBlendMode::ColorBurn + || blendMode == DefaultMaterialBlendMode::ColorDodge) + && !theRenderContext.IsAdvancedBlendHwSupported() + && !theRenderContext.IsAdvancedBlendHwSupportedKHR() + && m_LayerPrepassDepthTexture; if (useBlendFallback) SetupDrawFB(true); #endif @@ -934,6 +1060,11 @@ namespace render { theObject.m_ScopedLights); SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false); + if (theObject.m_RenderableFlags.hasAlphaTest()) + m_Renderer.setAlphaTest(true, -1.0f, 1.0f); + else + m_Renderer.setAlphaTest(false, 1.0f, 1.0f); + inRenderFn(*this, theObject, theCameraProps, GetShaderFeatureSet(), indexLight, inCamera); #ifdef ADVANCED_BLEND_SW_FALLBACK @@ -952,22 +1083,29 @@ namespace render { } } } - // If the layer doesn't have depth enabled then we have to render via an alternate route - // where the transparent objects vector could have both opaque and transparent objects. - else { - for (QT3DSU32 idx = 0, end = theTransparentObjects.size(); idx < end; ++idx) { - SRenderableObject &theObject(*theTransparentObjects[idx]); - if (!(theObject.m_RenderableFlags.IsCompletelyTransparent())) { + } + // If the layer doesn't have depth enabled then we have to render via an alternate route + // where the transparent objects vector could have both opaque and transparent objects. + else { + for (QT3DSU32 idx = 0, end = theTransparentObjects.size(); idx < end; ++idx) { + SRenderableObject &theObject(*theTransparentObjects[idx]); + if (!(theObject.m_RenderableFlags.IsCompletelyTransparent())) { + if (theObject.m_RenderableFlags.isOrderedGroup()) { + renderOrderedGroup(theObject, inRenderFn, inEnableBlending, + inEnableDepthWrite, inEnableTransparentDepthWrite, + indexLight, inCamera, theFB); + } else { #ifdef ADVANCED_BLEND_SW_FALLBACK DefaultMaterialBlendMode::Enum blendMode = DefaultMaterialBlendMode::Enum::Normal; if (theObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) blendMode = static_cast<SSubsetRenderable &>(theObject).getBlendingMode(); - bool useBlendFallback = (blendMode == DefaultMaterialBlendMode::Overlay || - blendMode == DefaultMaterialBlendMode::ColorBurn || - blendMode == DefaultMaterialBlendMode::ColorDodge) && - !theRenderContext.IsAdvancedBlendHwSupported() && - !theRenderContext.IsAdvancedBlendHwSupportedKHR(); + bool useBlendFallback + = (blendMode == DefaultMaterialBlendMode::Overlay + || blendMode == DefaultMaterialBlendMode::ColorBurn + || blendMode == DefaultMaterialBlendMode::ColorDodge) + && !theRenderContext.IsAdvancedBlendHwSupported() + && !theRenderContext.IsAdvancedBlendHwSupportedKHR(); if (theObject.m_RenderableFlags.HasTransparency()) { theRenderContext.SetBlendingEnabled(true && inEnableBlending); @@ -982,6 +1120,12 @@ namespace render { m_SourceLightDirections, theObject.m_ScopedLights); SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false); + + if (theObject.m_RenderableFlags.hasAlphaTest()) + m_Renderer.setAlphaTest(true, -1.0f, 1.0f); + else + m_Renderer.setAlphaTest(false, 1.0f, 1.0f); + inRenderFn(*this, theObject, theCameraProps, GetShaderFeatureSet(), indexLight, inCamera); #ifdef ADVANCED_BLEND_SW_FALLBACK @@ -996,65 +1140,63 @@ namespace render { } } } - }; - - void SLayerRenderData::RunRenderPass(TRenderRenderableFunction inRenderFn, - bool inEnableBlending, bool inEnableDepthWrite, - bool inEnableTransparentDepthWrite, QT3DSU32 indexLight, - const SCamera &inCamera, CResourceFrameBuffer *theFB) + } +}; + +void SLayerRenderData::RunRenderPass(TRenderRenderableFunction inRenderFn, + bool inEnableBlending, bool inEnableDepthWrite, + bool inEnableTransparentDepthWrite, QT3DSU32 indexLight, + const SCamera &inCamera, CResourceFrameBuffer *theFB) +{ + NVRenderContext &theRenderContext(m_Renderer.GetContext()); + theRenderContext.SetDepthFunction(qt3ds::render::NVRenderBoolOp::LessThanOrEqual); + theRenderContext.SetBlendingEnabled(false); + QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar); { - NVRenderContext &theRenderContext(m_Renderer.GetContext()); - theRenderContext.SetDepthFunction(qt3ds::render::NVRenderBoolOp::LessThanOrEqual); - theRenderContext.SetBlendingEnabled(false); - QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar); + QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), + "LayerRenderData: Render opaque") NVDataRef<SRenderableObject *> theOpaqueObjects = GetOpaqueRenderableObjects(); - if (m_Layer.m_Flags.IsLayerEnableDepthTest()) { - theRenderContext.SetDepthTestEnabled(true); - theRenderContext.SetDepthWriteEnabled(inEnableDepthWrite); - } else { - theRenderContext.SetDepthWriteEnabled(false); - theRenderContext.SetDepthTestEnabled(false); - } + const bool opaqueDepthTest = m_Layer.m_Flags.IsLayerEnableDepthTest(); + const bool opaqueDepthWrite = opaqueDepthTest && inEnableDepthWrite; + + theRenderContext.SetDepthTestEnabled(opaqueDepthTest); + theRenderContext.SetDepthWriteEnabled(opaqueDepthWrite); for (QT3DSU32 idx = 0, end = theOpaqueObjects.size(); idx < end; ++idx) { SRenderableObject &theObject(*theOpaqueObjects[idx]); - SScopedLightsListScope lightsScope(m_Lights, m_LightDirections, m_SourceLightDirections, - theObject.m_ScopedLights); - SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false); - inRenderFn(*this, theObject, theCameraProps, GetShaderFeatureSet(), indexLight, - inCamera); - } - NVDataRef<SRenderableObject *> theTransparentObjects = GetTransparentRenderableObjects(); - // Also draw opaque parts of transparent objects - m_Renderer.setAlphaTest(true, 1.0f, -1.0f + (1.0f / 255.0f)); - for (QT3DSU32 idx = 0, end = theTransparentObjects.size(); idx < end; ++idx) { - SRenderableObject &theObject(*theTransparentObjects[idx]); + QT3DS_ASSERT(!theObject.m_RenderableFlags.isOrderedGroup()); + + theRenderContext.SetBlendingEnabled(false); + theRenderContext.SetDepthWriteEnabled(opaqueDepthWrite); + SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false); SScopedLightsListScope lightsScope(m_Lights, m_LightDirections, m_SourceLightDirections, theObject.m_ScopedLights); - SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false); + + if (theObject.m_RenderableFlags.hasAlphaTest()) + m_Renderer.setAlphaTest(true, 1.0f, -1.0f + (1.0f / 255.0f)); + else + m_Renderer.setAlphaTest(false, 1.0f, 1.0f); + inRenderFn(*this, theObject, theCameraProps, GetShaderFeatureSet(), indexLight, inCamera); } + } - m_Renderer.setAlphaTest(true, -1.0f, 1.0f); - // transparent parts of transparent objects - // does not render objects without alpha test enabled so - // we need another pass without alpha test - renderTransparentObjectsPass(inRenderFn, inEnableBlending, inEnableTransparentDepthWrite, - indexLight, inCamera, theFB); - + { + QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), + "LayerRenderData: Render transparent pass") m_Renderer.setAlphaTest(false, 1.0, 1.0); - // transparent objects without alpha test - renderTransparentObjectsPass(inRenderFn, inEnableBlending, inEnableTransparentDepthWrite, - indexLight, inCamera, theFB); + renderTransparentObjectsPass(inRenderFn, inEnableBlending, inEnableDepthWrite, + inEnableTransparentDepthWrite, indexLight, inCamera, theFB); } +} void SLayerRenderData::Render(CResourceFrameBuffer *theFB) { QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), - "SLayerRenderData::Render") + "LayerRenderData: Render") if (m_Camera == NULL) return; @@ -1217,7 +1359,7 @@ namespace render { theRenderContext.SetDepthTestEnabled(false); theRenderContext.SetDepthWriteEnabled(false); } - BlendAdvancedEquationSwFallback(m_AdvancedBlendDrawTexture, m_LayerTexture, advancedMode); + BlendAdvancedEquationSwFallback(m_AdvancedBlendDrawTexture, m_LayerTexture[getCameraIndex()], advancedMode); theRenderContext.SetRenderTarget(*theFB); // setup read target theRenderContext.SetReadTarget(m_AdvancedModeBlendFB); @@ -1293,6 +1435,12 @@ namespace render { CRegisteredString depthPassStr; + int SLayerRenderData::getCameraIndex() const + { + StereoViews::Enum stereoView = m_Renderer.GetQt3DSContext().GetStereoView(); + return (stereoView == StereoViews::Right) ? 1 : 0; + } + // Render this layer's data to a texture. Required if we have any effects, // prog AA, or if forced. void SLayerRenderData::RenderToTexture() @@ -1300,7 +1448,7 @@ namespace render { QT3DS_ASSERT(m_LayerPrepResult->m_Flags.ShouldRenderToTexture()); SLayerRenderPreparationResult &thePrepResult(*m_LayerPrepResult); NVRenderContext &theRenderContext(m_Renderer.GetContext()); - QSize theLayerTextureDimensions = thePrepResult.GetTextureDimensions(); + QSize theLayerTextureDimensions(thePrepResult.GetTextureDimensions()); QSize theLayerOriginalTextureDimensions = theLayerTextureDimensions; NVRenderTextureFormats::Enum DepthTextureFormat = NVRenderTextureFormats::Depth24Stencil8; NVRenderTextureFormats::Enum ColorTextureFormat = NVRenderTextureFormats::RGBA8; @@ -1332,13 +1480,14 @@ namespace render { // progressive AA algorithm. if (thePrepResult.m_Flags.WasLayerDataDirty() || thePrepResult.m_Flags.WasDirty() + || (getCameraIndex() == 1 && (m_LeftFlags.WasLayerDataDirty() || m_LeftFlags.WasDirty())) || m_Renderer.IsLayerCachingEnabled() == false) { m_ProgressiveAAPassIndex = 0; m_NonDirtyTemporalAAPassIndex = 0; needsRender = true; } - CResourceTexture2D *renderColorTexture = &m_LayerTexture; + CResourceTexture2D *renderColorTexture = &m_LayerTexture[getCameraIndex()]; CResourceTexture2D *renderPrepassDepthTexture = &m_LayerPrepassDepthTexture; CResourceTexture2D *renderWidgetTexture = &m_LayerWidgetTexture; NVRenderContextScopedProperty<bool> __multisampleEnabled( @@ -1356,7 +1505,7 @@ namespace render { QT3DSU32 maxTemporalPassIndex = m_Layer.m_TemporalAAEnabled ? 2 : 0; // If all the dimensions match then we do not have to re-render the layer. - if (m_LayerTexture.TextureMatches(theLayerTextureDimensions.width(), + if (m_LayerTexture[getCameraIndex()].TextureMatches(theLayerTextureDimensions.width(), theLayerTextureDimensions.height(), ColorTextureFormat) && (!thePrepResult.m_Flags.RequiresDepthTexture() || m_LayerDepthTexture.TextureMatches(theLayerTextureDimensions.width(), @@ -1432,19 +1581,21 @@ namespace render { if (isProgressiveAABlendPass || isTemporalAABlendPass) { theBlendShader = m_Renderer.GetLayerProgAABlendShader(); if (theBlendShader) { - m_LayerTexture.EnsureTexture(theLayerOriginalTextureDimensions.width(), + m_LayerTexture[getCameraIndex()].EnsureTexture(theLayerOriginalTextureDimensions.width(), theLayerOriginalTextureDimensions.height(), ColorTextureFormat); QT3DSVec2 theVertexOffsets; if (isProgressiveAABlendPass) { - theLastLayerTexture.StealTexture(m_LayerTexture); + theLastLayerTexture.StealTexture(m_LayerTexture[getCameraIndex()]); aaFactorIndex = (m_ProgressiveAAPassIndex - 1); theVertexOffsets = s_VertexOffsets[aaFactorIndex]; } else { - if (temporalAATexture.GetTexture()) - theLastLayerTexture.StealTexture(temporalAATexture); - else if (hadLayerTexture) - theLastLayerTexture.StealTexture(m_LayerTexture); + if (hadLayerTexture) { + if (temporalAATexture.GetTexture()) + theLastLayerTexture.StealTexture(temporalAATexture); + else + theLastLayerTexture.StealTexture(m_LayerTexture[getCameraIndex()]); + } theVertexOffsets = s_TemporalVertexOffsets[m_TemporalAAPassIndex]; ++m_TemporalAAPassIndex; @@ -1531,11 +1682,26 @@ namespace render { // to that frame buffer. theFB.EnsureFrameBuffer(); - bool hasDepthObjects = m_OpaqueObjects.size() > 0 || m_TransparentObjects.size() > 0; + bool hasDepthObjects = m_OpaqueObjects.size() > 0 || m_TransparentObjects.size() > 0 + || m_GroupObjects.size() > 0; bool requiresDepthStencilBuffer = hasDepthObjects || thePrepResult.m_Flags.RequiresStencilBuffer(); NVRenderRect theNewViewport(0, 0, theLayerTextureDimensions.width(), theLayerTextureDimensions.height()); + + if (m_Layer.m_DynamicResize && theLayerOriginalTextureDimensions.width() != 0) { + // With dynamic resize the viewport should behave like it just crops the full layer + // So a special viewport has to be calculated that keeps the original object sizes + float ratio = theLayerTextureDimensions.width() + / theLayerOriginalTextureDimensions.width(); + auto originalLayerViewport = thePrepResult.getOriginalLayerToPresentationViewport(); + auto layerViewport = thePrepResult.GetLayerToPresentationViewport(); + theNewViewport = NVRenderRect((-layerViewport.m_X + originalLayerViewport.m_X) * ratio, + (-layerViewport.m_Y + originalLayerViewport.m_Y) * ratio, + originalLayerViewport.m_Width * ratio, + originalLayerViewport.m_Height * ratio); + } + { theRenderContext.SetRenderTarget(theFB); NVRenderContextScopedProperty<NVRenderRect> __viewport( @@ -1630,6 +1796,9 @@ namespace render { // will do this. StartProfiling("Render pass", false); Render(&theFB); + + if (m_SignalProxy) // Editor does not have signal proxy, and this signal is not needed + Q_EMIT m_SignalProxy->SigFrameDraw(); // Debug measure to view the depth map to ensure we're rendering it correctly. //if (m_Layer.m_TemporalAAEnabled) { // RenderFakeDepthMapPass(m_ShadowMapManager->GetShadowMapEntry(0)->m_DepthMap, @@ -1644,7 +1813,7 @@ namespace render { if (m_Layer.m_MultisampleAAMode != AAModeValues::SSAA) { // Resolve the FBO to the layer texture CRendererUtil::ResolveMutisampleFBOColorOnly( - theResourceManager, m_LayerTexture, theRenderContext, + theResourceManager, m_LayerTexture[getCameraIndex()], theRenderContext, theLayerTextureDimensions.width(), theLayerTextureDimensions.height(), ColorTextureFormat, *theFB); @@ -1652,7 +1821,7 @@ namespace render { } else { // Resolve the FBO to the layer texture CRendererUtil::ResolveSSAAFBOColorOnly( - theResourceManager, m_LayerTexture, + theResourceManager, m_LayerTexture[getCameraIndex()], theLayerOriginalTextureDimensions.width(), theLayerOriginalTextureDimensions.height(), theRenderContext, theLayerTextureDimensions.width(), theLayerTextureDimensions.height(), @@ -1700,18 +1869,18 @@ namespace render { theRenderContext.SetCullingEnabled(false); theRenderContext.SetActiveShader(theBlendShader->m_Shader); theBlendShader->m_AccumSampler.Set(theLastLayerTexture); - theBlendShader->m_LastFrame.Set(m_LayerTexture); + theBlendShader->m_LastFrame.Set(m_LayerTexture[getCameraIndex()]); theBlendShader->m_BlendFactors.Set(theBlendFactors); m_Renderer.RenderQuad(); theFB->Attach(NVRenderFrameBufferAttachments::Color0, qt3ds::render::NVRenderTextureOrRenderBuffer()); if (isTemporalAABlendPass) - temporalAATexture.StealTexture(m_LayerTexture); - m_LayerTexture.StealTexture(targetTexture); + temporalAATexture.StealTexture(m_LayerTexture[getCameraIndex()]); + m_LayerTexture[getCameraIndex()].StealTexture(targetTexture); } - m_LayerTexture->SetMinFilter(NVRenderTextureMinifyingOp::Linear); - m_LayerTexture->SetMagFilter(NVRenderTextureMagnifyingOp::Linear); + m_LayerTexture[getCameraIndex()]->SetMinFilter(NVRenderTextureMinifyingOp::Linear); + m_LayerTexture[getCameraIndex()]->SetMagFilter(NVRenderTextureMagnifyingOp::Linear); // Don't remember why needs widget texture is false here. // Should have commented why progAA plus widgets is a fail. @@ -1734,6 +1903,8 @@ namespace render { qt3ds::render::NVRenderTextureOrRenderBuffer(), thFboAttachTarget); // Let natural scoping rules destroy the other stuff. } + if (m_Layer.m_DynamicResize) + theResourceManager.DestroyFreeSizedResources(); } void SLayerRenderData::ApplyLayerPostEffects() @@ -1749,10 +1920,10 @@ namespace render { } } if (!effectsActive || !m_Camera) { - if (m_LayerCachedTexture) { + if (m_LayerCachedTexture[getCameraIndex()]) { IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager()); - theResourceManager.Release(*m_LayerCachedTexture); - m_LayerCachedTexture = NULL; + theResourceManager.Release(*m_LayerCachedTexture[getCameraIndex()]); + m_LayerCachedTexture[getCameraIndex()] = NULL; } return; } @@ -1760,14 +1931,24 @@ namespace render { IEffectSystem &theEffectSystem(m_Renderer.GetQt3DSContext().GetEffectSystem()); IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager()); // we use the non MSAA buffer for the effect - NVRenderTexture2D *theLayerColorTexture = m_LayerTexture; + NVRenderTexture2D *theLayerColorTexture = m_LayerTexture[getCameraIndex()]; NVRenderTexture2D *theLayerDepthTexture = m_LayerDepthTexture; - if (!m_LayerCachedTexture) { + if (m_LayerCachedTexture[getCameraIndex()]) { + STextureDetails details(theLayerColorTexture->GetTextureDetails()); + STextureDetails cachedDetails(m_LayerCachedTexture[getCameraIndex()]->GetTextureDetails()); + if (cachedDetails.m_Width != details.m_Width + || cachedDetails.m_Height != details.m_Height) { + theResourceManager.Release(*m_LayerCachedTexture[getCameraIndex()]); + m_LayerCachedTexture[getCameraIndex()] = nullptr; + } + } + + if (!m_LayerCachedTexture[getCameraIndex()]) { STextureDetails details(theLayerColorTexture->GetTextureDetails()); QT3DSU32 finalWidth = ITextRenderer::NextMultipleOf4((QT3DSU32)(details.m_Width)); QT3DSU32 finalHeight = ITextRenderer::NextMultipleOf4((QT3DSU32)(details.m_Height)); - m_LayerCachedTexture = theResourceManager.AllocateTexture2D(finalWidth, finalHeight, + m_LayerCachedTexture[getCameraIndex()] = theResourceManager.AllocateTexture2D(finalWidth, finalHeight, details.m_Format); } @@ -1777,7 +1958,7 @@ namespace render { if (theEffect->m_Flags.IsActive()) { NVRenderTexture2D *targetTexture = nullptr; if (theEffect == lastEffect) - targetTexture = m_LayerCachedTexture; + targetTexture = m_LayerCachedTexture[getCameraIndex()]; StartProfiling(theEffect->m_ClassName, false); @@ -1819,13 +2000,13 @@ namespace render { void SLayerRenderData::RunnableRenderToViewport(qt3ds::render::NVRenderFrameBuffer *theFB) { // If we have an effect, an opaque object, or any transparent objects that aren't completely - // transparent - // or an offscreen renderer or a layer widget texture + // transparent or an offscreen renderer or a layer widget texture // Then we can't possible affect the resulting render target. - bool needsToRender = m_Layer.m_FirstEffect != NULL || m_OpaqueObjects.empty() == false + bool needsToRender = m_Layer.m_FirstEffect || !m_OpaqueObjects.empty() || AnyCompletelyNonTransparentObjects(m_TransparentObjects) || GetOffscreenRenderer() || m_LayerWidgetTexture || m_BoundingRectColor.hasValue() - || m_Layer.m_Background == LayerBackground::Color; + || m_Layer.m_Background == LayerBackground::Color + || !m_GroupObjects.empty(); if (needsToRender == false) return; @@ -1872,7 +2053,7 @@ namespace render { // The render graph should have taken care of the render to texture step. #ifdef QT3DS_CACHED_POST_EFFECT NVRenderTexture2D *theLayerColorTexture = - (m_LayerCachedTexture) ? m_LayerCachedTexture : m_LayerTexture; + (m_LayerCachedTexture[getCameraIndex()]) ? m_LayerCachedTexture[getCameraIndex()] : m_LayerTexture[getCameraIndex()]; #else // Then render all but the last effect IEffectSystem &theEffectSystem(m_Renderer.GetQt3DSContext().GetEffectSystem()); @@ -1913,10 +2094,12 @@ namespace render { // transform. QT3DSMat44 theFinalMVP(QT3DSMat44::createIdentity()); SCamera theTempCamera; + // When layer & scene are part of subpresentation, ignore stereoscopic viewport adjustments + bool noStereo = m_Layer.m_Scene && m_Layer.m_Scene->m_IsSubPresentationScene; NVRenderRect theLayerViewport( - thePrepResult.GetLayerToPresentationViewport().ToIntegerRect()); + thePrepResult.GetLayerToPresentationViewport(noStereo).ToIntegerRect()); NVRenderRect theLayerClip( - thePrepResult.GetLayerToPresentationScissorRect().ToIntegerRect()); + thePrepResult.GetLayerToPresentationScissorRect(noStereo).ToIntegerRect()); { QT3DSMat33 ignored; @@ -2214,7 +2397,7 @@ namespace render { void SLayerRenderData::AddLayerRenderStep() { QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), - "SLayerRenderData::AddLayerRenderStep") + "LayerRenderData: AddLayerRenderStep") QT3DS_ASSERT(m_Camera); if (!m_Camera) return; @@ -2227,13 +2410,13 @@ namespace render { QSize(theCurrentViewport.m_Width, theCurrentViewport.m_Height)); } - void SLayerRenderData::PrepareForRender() + bool SLayerRenderData::PrepareForRender() { // When we render to the scene itself (as opposed to an offscreen buffer somewhere) // then we use the MVP of the layer somewhat. NVRenderRect theViewport = m_Renderer.GetQt3DSContext().GetRenderList().GetViewport(); - PrepareForRender( - QSize((QT3DSU32)theViewport.m_Width, (QT3DSU32)theViewport.m_Height)); + return PrepareForRender( + QSize((QT3DSU32)theViewport.m_Width, (QT3DSU32)theViewport.m_Height)); } void SLayerRenderData::ResetForFrame() diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h index 0f0a838..623e8b2 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h @@ -33,6 +33,7 @@ #include "Qt3DSRender.h" #include "Qt3DSRendererImplLayerRenderPreparationData.h" #include "Qt3DSRenderResourceBufferObjects.h" +#include "Qt3DSRuntimeView.h" namespace qt3ds { namespace render { @@ -52,7 +53,7 @@ struct AdvancedBlendModes // Layers can be rendered offscreen for many reasons; effects, progressive aa, // or just because a flag forces it. If they are rendered offscreen we can then // cache the result so we don't render the layer again if it isn't dirty. - CResourceTexture2D m_LayerTexture; + CResourceTexture2D m_LayerTexture[2]; // Multiple temporal AA textures for stereoscopic needs. // First used for mono/left view, second for right view. CResourceTexture2D m_TemporalAATexture[2]; @@ -66,7 +67,7 @@ struct AdvancedBlendModes CResourceTexture2D m_LayerMultisamplePrepassDepthTexture; CResourceTexture2D m_LayerMultisampleWidgetTexture; // the texture contains the render result inclusive post effects - NVRenderTexture2D *m_LayerCachedTexture; + NVRenderTexture2D *m_LayerCachedTexture[2]; NVRenderTexture2D *m_AdvancedBlendDrawTexture; NVRenderTexture2D *m_AdvancedBlendBlendTexture; @@ -97,15 +98,19 @@ struct AdvancedBlendModes NVRenderTextureFormats::Enum m_DepthBufferFormat; QSize m_previousDimensions; + QRuntimeViewSignalProxy *m_SignalProxy; + SLayerRenderPreparationResultFlags m_LeftFlags; + + int getCameraIndex() const; SLayerRenderData(SLayer &inLayer, Qt3DSRendererImpl &inRenderer); virtual ~SLayerRenderData(); - void PrepareForRender(); + bool PrepareForRender(); // Internal Call - void PrepareForRender(const QSize &inViewportDimensions) override; + bool PrepareForRender(const QSize &inViewportDimensions) override; NVRenderTextureFormats::Enum GetDepthBufferFormat(); NVRenderFrameBufferAttachments::Enum @@ -125,6 +130,10 @@ struct AdvancedBlendModes void Render(CResourceFrameBuffer *theFB = NULL); void ResetForFrame() override; + void renderOrderedGroup(SRenderableObject &theObject, TRenderRenderableFunction inRenderFn, + bool inEnableBlending, bool inEnableDepthWrite, + bool inEnableTransparentDepthWrite, QT3DSU32 indexLight, + const SCamera &inCamera, CResourceFrameBuffer *theFB); void CreateGpuProfiler(); void StartProfiling(CRegisteredString &nameID, bool sync); @@ -179,7 +188,8 @@ struct AdvancedBlendModes CResourceFrameBuffer *theFB); #endif void renderTransparentObjectsPass(TRenderRenderableFunction inRenderFn, - bool inEnableBlending, bool inEnableTransparentDepthWrite, + bool inEnableBlending, bool inEnableDepthWrite, + bool inEnableTransparentDepthWrite, QT3DSU32 indexLight, const SCamera &inCamera, CResourceFrameBuffer *theFB); }; diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp index 4dae3f9..f75a673 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp @@ -70,8 +70,8 @@ QT3DSVec2 ToRectRelativeCoords(const QT3DSVec2 &inCoords, const NVRenderRectF &i SLayerRenderHelper::SLayerRenderHelper() : m_Layer(nullptr) , m_Camera(nullptr) - , m_CameraLeftEye(nullptr) - , m_CameraRightEye(nullptr) + , m_CameraLeftEye() + , m_CameraRightEye() , m_Offscreen(false) { } @@ -84,19 +84,21 @@ SLayerRenderHelper::SLayerRenderHelper(const NVRenderRectF &inPresentationViewpo qt3ds::render::StereoModes::Enum inStereoMode, qt3ds::render::StereoViews::Enum inStereoView, double inStereoEyeSeparation, + double inStereoEyeRotation, qt3ds::QT3DSVec2 inScaleFactor) : m_PresentationViewport(inPresentationViewport) , m_PresentationScissor(inPresentationScissor) , m_PresentationDesignDimensions(inPresentationDesignDimensions) , m_Layer(&inLayer) , m_Camera(nullptr) - , m_CameraLeftEye(nullptr) - , m_CameraRightEye(nullptr) + , m_CameraLeftEye() + , m_CameraRightEye() , m_Offscreen(inOffscreen) , m_ScaleMode(inScaleMode) , m_StereoMode(inStereoMode) , m_StereoView(inStereoView) , m_StereoEyeSeparation(QT3DSF32(inStereoEyeSeparation)) + , m_StereoEyeRotation(QT3DSF32(inStereoEyeRotation)) , m_ScaleFactor(inScaleFactor) { { @@ -178,9 +180,9 @@ SLayerRenderHelper::SLayerRenderHelper(const NVRenderRectF &inPresentationViewpo m_Viewport.m_Width = NVMax(1.0f, m_Viewport.m_Width); m_Viewport.m_Height = NVMax(1.0f, m_Viewport.m_Height); - // Now force the viewport to be a multiple of four in width and height. This is because + // Now force the viewport to be a multiple of four in width and height. This is because // when rendering to a texture we have to respect this and not forcing it causes scaling issues - // that are noticeable especially in situations where customers are using text and such. + // that are noticeable especially in situations where customers are using text. QT3DSF32 originalWidth = m_Viewport.m_Width; QT3DSF32 originalHeight = m_Viewport.m_Height; @@ -191,6 +193,7 @@ SLayerRenderHelper::SLayerRenderHelper(const NVRenderRectF &inPresentationViewpo m_Viewport.m_X += (originalWidth - m_Viewport.m_Width) / 2.0f; m_Viewport.m_Y += (originalHeight - m_Viewport.m_Height) / 2.0f; + m_originalViewport = m_Viewport; m_Scissor = m_Viewport; m_Scissor.EnsureInBounds(inPresentationScissor); QT3DS_ASSERT(m_Scissor.m_Width >= 0.0f); @@ -206,8 +209,11 @@ NVRenderRectF SLayerRenderHelper::GetLayerRenderViewport() const return m_Viewport; } -NVRenderRectF SLayerRenderHelper::GetLayerToPresentationViewport() const +NVRenderRectF SLayerRenderHelper::GetLayerToPresentationViewport(bool noStereo) const { + if (noStereo) + return m_Viewport; + if (m_StereoMode == StereoModes::LeftRight) { if (m_StereoView == StereoViews::Left) { return NVRenderRectF(m_Viewport.m_X, m_Viewport.m_Y, m_Viewport.m_Width/2, @@ -230,8 +236,11 @@ NVRenderRectF SLayerRenderHelper::GetLayerToPresentationViewport() const return m_Viewport; } -NVRenderRectF SLayerRenderHelper::GetLayerToPresentationScissorRect() const +NVRenderRectF SLayerRenderHelper::GetLayerToPresentationScissorRect(bool noStereo) const { + if (noStereo) + return m_Scissor; + if (m_StereoMode == StereoModes::LeftRight) { if (m_StereoView == StereoViews::Left) { return NVRenderRectF(m_Scissor.m_X, m_Scissor.m_Y, @@ -265,9 +274,9 @@ QSize SLayerRenderHelper::GetTextureDimensions() const SCamera *SLayerRenderHelper::GetCamera() { if (m_StereoView == StereoViews::Left) - return m_CameraLeftEye; + return &m_CameraLeftEye; if (m_StereoView == StereoViews::Right) - return m_CameraRightEye; + return &m_CameraRightEye; return m_Camera; } @@ -275,8 +284,10 @@ SCameraGlobalCalculationResult SLayerRenderHelper::SetupCameraForRender(SCamera { m_Camera = &inCamera; - if (isStereoscopic()) + if (isStereoscopic()) { + m_Camera->AddChild(*GetCamera()); adjustCameraStereoSeparation(); + } NVRenderRectF rect = GetLayerRenderViewport(); if (m_ScaleMode == ScaleModes::FitSelected) { @@ -286,10 +297,13 @@ SCameraGlobalCalculationResult SLayerRenderHelper::SetupCameraForRender(SCamera (QT3DSF32)(ITextRenderer::NextMultipleOf4((QT3DSU32)(rect.m_Height / m_ScaleFactor.y))); } // Always calculate main camera variables - if (isStereoscopic()) - m_Camera->CalculateGlobalVariables(rect, m_PresentationDesignDimensions); - // Return current camera variables - return GetCamera()->CalculateGlobalVariables(rect, m_PresentationDesignDimensions); + auto ret = m_Camera->CalculateGlobalVariables(rect, m_PresentationDesignDimensions); + if (isStereoscopic()) { + GetCamera()->CalculateGlobalVariables(rect, m_PresentationDesignDimensions); + m_Camera->RemoveChild(*GetCamera()); + } + + return ret; } Option<QT3DSVec2> SLayerRenderHelper::GetLayerMouseCoords(const QT3DSVec2 &inMouseCoords, @@ -299,7 +313,16 @@ Option<QT3DSVec2> SLayerRenderHelper::GetLayerMouseCoords(const QT3DSVec2 &inMou // First invert the y so we are dealing with numbers in a normal coordinate space. // Second, move into our layer's coordinate space QT3DSVec2 correctCoords(inMouseCoords.x, inWindowDimensions.y - inMouseCoords.y); - QT3DSVec2 theLocalMouse = m_Viewport.ToRectRelative(correctCoords); + QT3DSVec2 theLocalMouse; + + if (m_Layer->m_DynamicResize) { + float widthRatio = m_Viewport.m_Width / m_originalViewport.m_Width; + float heightRatio = m_Viewport.m_Height / m_originalViewport.m_Height; + theLocalMouse = m_originalViewport.ToRectRelative(correctCoords); + theLocalMouse = QT3DSVec2(theLocalMouse.x * widthRatio, theLocalMouse.y * heightRatio); + } else { + theLocalMouse = m_Viewport.ToRectRelative(correctCoords); + } QT3DSF32 theRenderRectWidth = m_Viewport.m_Width; QT3DSF32 theRenderRectHeight = m_Viewport.m_Height; @@ -341,8 +364,32 @@ bool SLayerRenderHelper::isStereoscopic() const return m_StereoMode != StereoModes::Mono; } -void SLayerRenderHelper::copyCameraProperties(SCamera *sourceCamera, - SCamera *destinationCamera) +void SLayerRenderHelper::setViewport(const NVRenderRectF &viewport) +{ + m_Viewport = viewport; + m_Viewport.m_Width = NVMax(1.0f, m_Viewport.m_Width); + m_Viewport.m_Height = NVMax(1.0f, m_Viewport.m_Height); + // Now force the viewport to be a multiple of four in width and height. This is because + // when rendering to a texture we have to respect this and not forcing it causes scaling issues + // that are noticeable especially in situations where customers are using text. + QT3DSF32 originalWidth = m_Viewport.m_Width; + QT3DSF32 originalHeight = m_Viewport.m_Height; + + m_Viewport.m_Width = (QT3DSF32)ITextRenderer::NextMultipleOf4((QT3DSU32)m_Viewport.m_Width); + m_Viewport.m_Height = (QT3DSF32)ITextRenderer::NextMultipleOf4((QT3DSU32)m_Viewport.m_Height); + + // Now fudge the offsets to account for this slight difference + m_Viewport.m_X += (originalWidth - m_Viewport.m_Width) / 2.0f; + m_Viewport.m_Y += (originalHeight - m_Viewport.m_Height) / 2.0f; +} + +NVRenderRectF SLayerRenderHelper::getOriginalLayerToPresentationViewport() const +{ + return m_originalViewport; +} + +void SLayerRenderHelper::copyCameraStereoProperties(SCamera *sourceCamera, + SCamera *destinationCamera) { if (!sourceCamera || !destinationCamera) return; @@ -360,33 +407,27 @@ void SLayerRenderHelper::copyCameraProperties(SCamera *sourceCamera, destinationCamera->m_Pivot = sourceCamera->m_Pivot; destinationCamera->m_Scale = sourceCamera->m_Scale; destinationCamera->m_DFSIndex = sourceCamera->m_DFSIndex; - destinationCamera->m_Position = sourceCamera->m_Position; - destinationCamera->m_Rotation = sourceCamera->m_Rotation; - destinationCamera->m_UserData = sourceCamera->m_UserData; - destinationCamera->m_LocalOpacity = sourceCamera->m_LocalOpacity; - destinationCamera->m_GlobalOpacity = sourceCamera->m_GlobalOpacity; destinationCamera->m_RotationOrder = sourceCamera->m_RotationOrder; - destinationCamera->m_LocalTransform = sourceCamera->m_LocalTransform; - destinationCamera->m_GlobalTransform = sourceCamera->m_GlobalTransform; } void SLayerRenderHelper::adjustCameraStereoSeparation() { - if (!m_CameraLeftEye) - m_CameraLeftEye = new SCamera(); - if (!m_CameraRightEye) - m_CameraRightEye = new SCamera(); - // Copy m_Camera properties into left & right cameras - copyCameraProperties(m_Camera, m_CameraLeftEye); - copyCameraProperties(m_Camera, m_CameraRightEye); + copyCameraStereoProperties(m_Camera, &m_CameraLeftEye); + copyCameraStereoProperties(m_Camera, &m_CameraRightEye); // Adjust left & right camera positions by eye separation - m_CameraLeftEye->m_Position.x -= m_StereoEyeSeparation; - m_CameraLeftEye->m_Flags.SetTransformDirty(true); - m_CameraRightEye->m_Position.x += m_StereoEyeSeparation; - m_CameraRightEye->m_Flags.SetTransformDirty(true); - - m_CameraLeftEye->MarkDirty(); - m_CameraRightEye->MarkDirty(); + QT3DSVec3 eyeMove(m_StereoEyeSeparation, 0, 0); + m_CameraLeftEye.m_Position = -eyeMove; + m_CameraLeftEye.m_Flags.SetTransformDirty(true); + m_CameraRightEye.m_Position = eyeMove; + m_CameraRightEye.m_Flags.SetTransformDirty(true); + + // Adjust left & right camera rotations + QT3DSVec3 eyeRotation(0, m_StereoEyeRotation, 0); + m_CameraLeftEye.m_Rotation = eyeRotation; + m_CameraRightEye.m_Rotation = -eyeRotation; + + m_CameraLeftEye.MarkDirty(); + m_CameraRightEye.MarkDirty(); } diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h index 19fd3f5..2c64569 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h @@ -60,10 +60,11 @@ namespace render { QT3DSVec2 m_PresentationDesignDimensions; SLayer *m_Layer; SCamera *m_Camera; - SCamera *m_CameraLeftEye; - SCamera *m_CameraRightEye; + SCamera m_CameraLeftEye; + SCamera m_CameraRightEye; bool m_Offscreen; + NVRenderRectF m_originalViewport; NVRenderRectF m_Viewport; NVRenderRectF m_Scissor; @@ -72,6 +73,7 @@ namespace render { StereoModes::Enum m_StereoMode = StereoModes::Mono; StereoViews::Enum m_StereoView = StereoViews::Mono; QT3DSF32 m_StereoEyeSeparation = 0.4f; + QT3DSF32 m_StereoEyeRotation = 0.0f; QT3DSVec2 m_ScaleFactor; @@ -85,6 +87,7 @@ namespace render { qt3ds::render::StereoModes::Enum inStereoMode, qt3ds::render::StereoViews::Enum inStereoView, double inStereoEyeSeparation, + double inStereoEyeRotation, qt3ds::QT3DSVec2 inScaleFactor); NVRenderRectF GetPresentationViewport() const { return m_PresentationViewport; } @@ -102,13 +105,18 @@ namespace render { // Get/set eye (camera) separation. QT3DSF32 getEyeSeparation() const { return m_StereoEyeSeparation; } void setEyeSeparation(QT3DSF32 separation) { m_StereoEyeSeparation = separation; } + // Get/set eye (camera) rotation. + QT3DSF32 getEyeRotation() const { return m_StereoEyeRotation; } + void setEyeRotation(QT3DSF32 rotation) { m_StereoEyeRotation = rotation; } + void setViewport(const NVRenderRectF &viewport); // Does not differ whether offscreen or not, simply states how this layer maps to the // presentation - NVRenderRectF GetLayerToPresentationViewport() const; + NVRenderRectF getOriginalLayerToPresentationViewport() const; + NVRenderRectF GetLayerToPresentationViewport(bool noStereo = false) const; // Does not differ whether offscreen or not, scissor rect of how this layer maps to // presentation. - NVRenderRectF GetLayerToPresentationScissorRect() const; + NVRenderRectF GetLayerToPresentationScissorRect(bool noStereo = false) const; QSize GetTextureDimensions() const; @@ -130,7 +138,7 @@ namespace render { // different than the layer to presentation viewport. NVRenderRectF GetLayerRenderViewport() const; - void copyCameraProperties(SCamera *sourceCamera, SCamera *destinationCamera); + void copyCameraStereoProperties(SCamera *sourceCamera, SCamera *destinationCamera); void adjustCameraStereoSeparation(); }; } diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp index df60f64..c8c287c 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp @@ -72,18 +72,29 @@ namespace render { namespace { void MaybeQueueNodeForRender(SNode &inNode, nvvector<SRenderableNodeEntry> &outRenderables, - nvvector<SNode *> &outCamerasAndLights, QT3DSU32 &ioDFSIndex) + nvvector<SRenderableNodeEntry> &outGroups, + nvvector<SNode *> &outCamerasAndLights, QT3DSU32 &ioDFSIndex, + QT3DSU32 groupNode = 0) { ++ioDFSIndex; inNode.m_DFSIndex = ioDFSIndex; - if (GraphObjectTypes::IsRenderableType(inNode.m_Type)) + inNode.m_GroupIndex = groupNode; + if (GraphObjectTypes::IsRenderableType(inNode.m_Type)) { outRenderables.push_back(inNode); - else if (GraphObjectTypes::IsLightCameraType(inNode.m_Type)) + } else if (GraphObjectTypes::IsLightCameraType(inNode.m_Type)) { outCamerasAndLights.push_back(&inNode); + } else if (GraphObjectTypes::IsNodeType(inNode.m_Type) && inNode.m_ordered + && !groupNode) { + outGroups.push_back(inNode); + groupNode = outGroups.size(); + inNode.m_GroupIndex = groupNode; + } for (SNode *theChild = inNode.m_FirstChild; theChild != NULL; - theChild = theChild->m_NextSibling) - MaybeQueueNodeForRender(*theChild, outRenderables, outCamerasAndLights, ioDFSIndex); + theChild = theChild->m_NextSibling) { + MaybeQueueNodeForRender(*theChild, outRenderables, outGroups, outCamerasAndLights, + ioDFSIndex, groupNode); + } } bool HasValidLightProbe(SImage *inLightProbeImage) @@ -113,6 +124,8 @@ namespace render { "SLayerRenderPreparationData::m_RenderableNodes")) , m_RenderableNodes(inRenderer.GetContext().GetAllocator(), "SLayerRenderPreparationData::m_RenderableNodes") + , m_GroupNodes(inRenderer.GetContext().GetAllocator(), + "SLayerRenderPreparationData::m_GroupNodes") , m_LightToNodeMap(inRenderer.GetContext().GetAllocator(), "SLayerRenderPreparationData::m_LightToNodeMap") , m_CamerasAndLights(inRenderer.GetContext().GetAllocator(), @@ -123,6 +136,8 @@ namespace render { "SLayerRenderPreparationData::m_OpaqueObjects") , m_TransparentObjects(inRenderer.GetContext().GetAllocator(), "SLayerRenderPreparationData::m_TransparentObjects") + , m_GroupObjects(inRenderer.GetContext().GetAllocator(), + "SLayerRenderPreparationData::m_GroupObjects") , m_RenderedOpaqueObjects(inRenderer.GetContext().GetAllocator(), "SLayerRenderPreparationData::m_RenderedOpaqueObjects") , m_RenderedTransparentObjects(inRenderer.GetContext().GetAllocator(), @@ -140,6 +155,7 @@ namespace render { , m_FeaturesDirty(true) , m_FeatureSetHash(0) , m_TooManyLightsError(false) + , m_StereoMode(StereoModes::Mono) { } @@ -246,10 +262,12 @@ namespace render { { if (m_RenderedOpaqueObjects.empty() == false || m_Camera == NULL) return m_RenderedOpaqueObjects; - if (m_Layer.m_Flags.IsLayerEnableDepthTest() && m_OpaqueObjects.empty() == false) { + if (m_Layer.m_Flags.IsLayerEnableDepthTest() + && (!m_OpaqueObjects.empty() || !m_GroupObjects.empty())) { QT3DSVec3 theCameraDirection(GetCameraDirection()); QT3DSVec3 theCameraPosition = m_Camera->GetGlobalPos(); m_RenderedOpaqueObjects.assign(m_OpaqueObjects.begin(), m_OpaqueObjects.end()); + // Setup the object's sorting information for (QT3DSU32 idx = 0, end = m_RenderedOpaqueObjects.size(); idx < end; ++idx) { SRenderableObject &theInfo = *m_RenderedOpaqueObjects[idx]; @@ -273,10 +291,19 @@ namespace render { m_RenderedTransparentObjects.assign(m_TransparentObjects.begin(), m_TransparentObjects.end()); + m_RenderedTransparentObjects.insert(m_RenderedTransparentObjects.end(), m_GroupObjects.begin(), + m_GroupObjects.end()); + + // Set position for group objects + for (int i = 0; i < m_GroupObjects.size(); i++) + static_cast<SOrderedGroupRenderable *>(m_GroupObjects[i])->update(); - if (m_Layer.m_Flags.IsLayerEnableDepthTest() == false) + if (m_Layer.m_Flags.IsLayerEnableDepthTest() == false) { m_RenderedTransparentObjects.insert(m_RenderedTransparentObjects.end(), m_OpaqueObjects.begin(), m_OpaqueObjects.end()); + m_RenderedTransparentObjects.insert(m_RenderedTransparentObjects.end(), + m_GroupObjects.begin(), m_GroupObjects.end()); + } if (m_RenderedTransparentObjects.empty() == false) { QT3DSVec3 theCameraDirection(GetCameraDirection()); @@ -287,7 +314,11 @@ namespace render { SRenderableObject &theInfo = *m_RenderedTransparentObjects[idx]; QT3DSVec3 difference = theInfo.m_WorldCenterPoint - theCameraPosition; theInfo.m_CameraDistanceSq = difference.dot(theCameraDirection); + + if (m_Layer.m_Flags.IsLayerEnableDepthTest() == false) + theInfo.m_RenderableFlags.setAlphaTest(0); } + ForwardingAllocator alloc(m_Renderer.GetPerFrameAllocator(), "SortAllocations"); // render furthest to nearest. eastl::merge_sort(m_RenderedTransparentObjects.begin(), @@ -365,7 +396,8 @@ namespace render { bool SLayerRenderPreparationData::PrepareTextForRender( SText &inText, const QT3DSMat44 &inViewProjection, - QT3DSF32 inTextScaleFactor, SLayerRenderPreparationResultFlags &ioFlags) + QT3DSF32 inTextScaleFactor, SLayerRenderPreparationResultFlags &ioFlags, + qt3ds::render::SOrderedGroupRenderable *group) { ITextTextureCache *theTextRenderer = m_Renderer.GetQt3DSContext().GetTextureCache(); if (theTextRenderer == nullptr && !IQt3DSRenderContextCore::distanceFieldEnabled()) @@ -424,8 +456,12 @@ namespace render { // After preparation, do not push object back to queue if it is not // active, because we prepare text elements regardless of their // visibility (=active status). - if (inText.m_Flags.IsGloballyActive()) - m_TransparentObjects.push_back(theRenderable); + if (inText.m_Flags.IsGloballyActive()) { + if (group) + group->m_renderables.push_back(theRenderable); + else + m_TransparentObjects.push_back(theRenderable); + } } return retval; } @@ -459,7 +495,8 @@ namespace render { bool SLayerRenderPreparationData::PreparePathForRender( SPath &inPath, const QT3DSMat44 &inViewProjection, - const Option<SClippingFrustum> &inClipFrustum, SLayerRenderPreparationResultFlags &ioFlags) + const Option<SClippingFrustum> &inClipFrustum, SLayerRenderPreparationResultFlags &ioFlags, + SOrderedGroupRenderable *group) { SRenderableObjectFlags theSharedFlags; theSharedFlags.SetPickable(true); @@ -603,7 +640,10 @@ namespace render { IOffscreenRenderManager &theOffscreenRenderManager( qt3dsContext.GetOffscreenRenderManager()); IRenderPluginManager &theRenderPluginManager(qt3dsContext.GetRenderPluginManager()); - if (inImage.ClearDirty(bufferManager, theOffscreenRenderManager, theRenderPluginManager)) + if (inImage.ClearDirty(bufferManager, theOffscreenRenderManager, theRenderPluginManager, + m_Layer.m_Scene->m_Presentation->m_preferKTX, + inImage.m_MappingMode == ImageMappingModes::LightProbe, + m_Layer.m_Scene->m_Presentation->m_flipCompressedTextures)) ioFlags |= RenderPreparationResultFlagValues::Dirty; // All objects with offscreen renderers are pickable so we can pass the pick through to the @@ -790,7 +830,8 @@ namespace render { // Enable alpha test, but only if the whole object opacity is full // so parts of the object might be fully opaque if (renderableFlags & RenderPreparationResultFlagValues::HasTransparency - && subsetOpacity >= 1.0f && transparencyImagesHaveOpaquePixels) { + && subsetOpacity >= 1.0f && transparencyImagesHaveOpaquePixels + && theMaterial->m_BlendMode != DefaultMaterialBlendMode::Screen) { m_Renderer.DefaultMaterialShaderKeyProperties() .m_AlphaTestEnabled.SetValue(theGeneratedKey, true); renderableFlags.setAlphaTest(true); @@ -825,7 +866,10 @@ namespace render { // If the custom material uses subpresentations, those have to be rendered before // the custom material itself - m_Renderer.GetQt3DSContext().GetCustomMaterialSystem().renderSubpresentations(inMaterial); + if (m_Renderer.GetQt3DSContext().GetCustomMaterialSystem() + .renderSubpresentations(inMaterial)) { + retval.m_Dirty = true; + } // set wireframe mode m_Renderer.DefaultMaterialShaderKeyProperties().m_WireframeMode.SetValue( @@ -862,17 +906,17 @@ namespace render { CHECK_IMAGE_AND_PREPARE(inMaterial.m_Lightmaps.m_LightmapShadow, ImageMapTypes::LightmapShadow, SShaderDefaultMaterialKeyProperties::LightmapShadow); - if (inMaterial.m_imageMaps && inMaterial.m_imageMaps->size() > 0) { - auto iter = inMaterial.m_imageMaps->begin(); - auto end = inMaterial.m_imageMaps->end(); + if (inMaterial.m_images.size() > 0) { + auto iter = inMaterial.m_images.begin(); + auto end = inMaterial.m_images.end(); for (; iter != end; iter++) { - CHECK_IMAGE_AND_PREPARE(iter->second, + CHECK_IMAGE_AND_PREPARE(*iter, ImageMapTypes::Unknown, SShaderDefaultMaterialKeyProperties::ImageMapCount); } } #undef CHECK_IMAGE_AND_PREPARE - + retval.m_Dirty |= renderableFlags.IsDirty(); retval.m_FirstImage = firstImage; if (retval.m_Dirty || alreadyDirty) m_Renderer.addMaterialDirtyClear(&inMaterial); @@ -881,7 +925,8 @@ namespace render { bool SLayerRenderPreparationData::PrepareModelForRender( SModel &inModel, const QT3DSMat44 &inViewProjection, - const Option<SClippingFrustum> &inClipFrustum, TNodeLightEntryList &inScopedLights) + const Option<SClippingFrustum> &inClipFrustum, TNodeLightEntryList &inScopedLights, + SOrderedGroupRenderable *group) { IQt3DSRenderContext &qt3dsContext(m_Renderer.GetQt3DSContext()); IBufferManager &bufferManager = qt3dsContext.GetBufferManager(); @@ -1011,6 +1056,7 @@ namespace render { subsetOpacity, subsetDirty)); SShaderDefaultMaterialKey theGeneratedKey = theMaterialPrepResult.m_MaterialKey; subsetOpacity = theMaterialPrepResult.m_Opacity; + subsetDirty |= theMaterialPrepResult.m_Dirty; SRenderableImage *firstImage(theMaterialPrepResult.m_FirstImage); renderableFlags = theMaterialPrepResult.m_RenderableFlags; @@ -1037,12 +1083,26 @@ namespace render { theRenderableObject->m_ScopedLights = inScopedLights; // set tessellation theRenderableObject->m_TessellationMode = inModel.m_TessellationMode; - - if (theRenderableObject->m_RenderableFlags.HasTransparency() - || theRenderableObject->m_RenderableFlags.HasRefraction()) { - m_TransparentObjects.push_back(theRenderableObject); + bool transparentObject = theRenderableObject->m_RenderableFlags.HasTransparency() + || theRenderableObject->m_RenderableFlags.HasRefraction(); + bool alphaTestObject = theRenderableObject->m_RenderableFlags.hasAlphaTest(); + + // Only put transparent object into ordered group if depth test is on + // Put object into both lists if it is alpha-test object + // object must have transparency on if it is alpha-test object + if (group && (!m_Layer.m_Flags.IsLayerEnableDepthTest() || transparentObject)) { + group->m_renderables.push_back(theRenderableObject); + if (alphaTestObject) + m_OpaqueObjects.push_back(theRenderableObject); } else { - m_OpaqueObjects.push_back(theRenderableObject); + if (transparentObject && alphaTestObject) { + m_TransparentObjects.push_back(theRenderableObject); + m_OpaqueObjects.push_back(theRenderableObject); + } else if (transparentObject) { + m_TransparentObjects.push_back(theRenderableObject); + } else { + m_OpaqueObjects.push_back(theRenderableObject); + } } } } @@ -1055,24 +1115,43 @@ namespace render { QT3DSF32 inTextScaleFactor, SLayerRenderPreparationResultFlags &ioFlags) { QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), - "SLayerRenderData::PrepareRenderablesForRender") + "LayerRenderData: PrepareRenderablesForRender") m_ViewProjection = inViewProjection; QT3DSF32 theTextScaleFactor = inTextScaleFactor; bool wasDataDirty = false; bool hasTextRenderer = m_Renderer.GetQt3DSContext().getDistanceFieldRenderer() != nullptr || m_Renderer.GetQt3DSContext().GetTextRenderer() != nullptr; + for (QT3DSU32 idx = 0, end = m_GroupNodes.size(); idx < end; ++idx) { + SRenderableNodeEntry &theNodeEntry(m_GroupNodes[idx]); + SRenderableObjectFlags flags; + QT3DSVec3 inWorldCenterPt; + QT3DSMat44 inGlobalTransform; + NVBounds3 inBounds; + SOrderedGroupRenderable *renderable + = RENDER_FRAME_NEW(SOrderedGroupRenderable)( + flags, inWorldCenterPt, inGlobalTransform, inBounds, + m_Renderer.GetPerFrameAllocator()); + m_GroupObjects.push_back(renderable); + } + for (QT3DSU32 idx = 0, end = m_RenderableNodes.size(); idx < end; ++idx) { SRenderableNodeEntry &theNodeEntry(m_RenderableNodes[idx]); SNode *theNode = theNodeEntry.m_Node; wasDataDirty = wasDataDirty || theNode->m_Flags.IsDirty(); + SOrderedGroupRenderable *group = nullptr; + if (theNode->m_GroupIndex) { + group = static_cast<SOrderedGroupRenderable *>( + m_GroupObjects[theNode->m_GroupIndex - 1]); + } + switch (theNode->m_Type) { case GraphObjectTypes::Model: { SModel *theModel = static_cast<SModel *>(theNode); theModel->CalculateGlobalVariables(); if (theModel->m_Flags.IsGloballyActive()) { bool wasModelDirty = PrepareModelForRender( - *theModel, inViewProjection, inClipFrustum, theNodeEntry.m_Lights); + *theModel, inViewProjection, inClipFrustum, theNodeEntry.m_Lights, group); wasDataDirty = wasDataDirty || wasModelDirty; } } break; @@ -1085,7 +1164,7 @@ namespace render { // large delay for distance field text items becoming active // mid-animation. bool wasTextDirty = PrepareTextForRender(*theText, inViewProjection, - theTextScaleFactor, ioFlags); + theTextScaleFactor, ioFlags, group); wasDataDirty = wasDataDirty || wasTextDirty; } @@ -1095,7 +1174,8 @@ namespace render { thePath->CalculateGlobalVariables(); if (thePath->m_Flags.IsGloballyActive()) { bool wasPathDirty = - PreparePathForRender(*thePath, inViewProjection, inClipFrustum, ioFlags); + PreparePathForRender(*thePath, inViewProjection, inClipFrustum, ioFlags, + group); wasDataDirty = wasDataDirty || wasPathDirty; } } break; @@ -1112,7 +1192,9 @@ namespace render { IQt3DSRenderContext &theContext(m_Renderer.GetQt3DSContext()); return inLightProbe.ClearDirty(theContext.GetBufferManager(), theContext.GetOffscreenRenderManager(), - theContext.GetRenderPluginManager(), true); + theContext.GetRenderPluginManager(), + m_Layer.m_Scene->m_Presentation->m_preferKTX, true, + m_Layer.m_Scene->m_Presentation->m_flipCompressedTextures); } struct SLightNodeMarker @@ -1161,12 +1243,187 @@ namespace render { } }; - void SLayerRenderPreparationData::PrepareForRender(const QSize &inViewportDimensions) + void SLayerRenderPreparationData::calculateDynamicLayerSize( + SLayerRenderPreparationResult &prepResult) + { + m_boundPoints.clear(); + if (m_Layer.m_DynamicCombine) { + // Combine all bounds of the layer objects to one spanning the whole active scene + // Only needs 8 projections but has low accuracy + NVBounds3 layerBounds; + layerBounds.setEmpty(); + for (SNode *child = m_Layer.m_FirstChild; child; child = child->m_NextSibling) { + if (child->m_Flags.IsActive()) { + auto &context = m_Renderer.GetQt3DSContext(); + qt3ds::NVBounds3 childBounds = child->GetActiveBounds( + context.GetBufferManager(), context.GetPathManager()); + if (childBounds.isEmpty() == false) { + childBounds.transform(child->m_GlobalTransform); + layerBounds.include(childBounds); + } + } + } + + m_boundPoints += QT3DSVec3(layerBounds.minimum.x, layerBounds.minimum.y, + layerBounds.minimum.z); + m_boundPoints += QT3DSVec3(layerBounds.maximum.x, layerBounds.minimum.y, + layerBounds.minimum.z); + m_boundPoints += QT3DSVec3(layerBounds.maximum.x, layerBounds.maximum.y, + layerBounds.minimum.z); + m_boundPoints += QT3DSVec3(layerBounds.minimum.x, layerBounds.maximum.y, + layerBounds.minimum.z); + m_boundPoints += QT3DSVec3(layerBounds.minimum.x, layerBounds.minimum.y, + layerBounds.maximum.z); + m_boundPoints += QT3DSVec3(layerBounds.maximum.x, layerBounds.minimum.y, + layerBounds.maximum.z); + m_boundPoints += QT3DSVec3(layerBounds.maximum.x, layerBounds.maximum.y, + layerBounds.maximum.z); + m_boundPoints += QT3DSVec3(layerBounds.minimum.x, layerBounds.maximum.y, + layerBounds.maximum.z); + } else { + // Add 8 points for each active object to the point list + // Provides accurate 2d bounds, but causes a lot of projections for large scenes + for (SNode *child = m_Layer.m_FirstChild; child; child = child->m_NextSibling) { + if (child->m_Flags.IsActive()) { + auto &context = m_Renderer.GetQt3DSContext(); + child->GetActiveBoundsList(m_boundPoints, context.GetBufferManager(), + context.GetPathManager(), child->m_GlobalTransform); + } + } + } + + auto layerViewport = prepResult.GetLayerToPresentationViewport(); + + QT3DSVec2 projectedMinimum(std::numeric_limits<float>::max(), + std::numeric_limits<float>::max()); + QT3DSVec2 projectedMaximum(std::numeric_limits<float>::lowest(), + std::numeric_limits<float>::lowest()); + + for (const auto &point : qAsConst(m_boundPoints)) { + QT3DSVec4 projectedPoint = m_ViewProjection.transform(QT3DSVec4(point, 1.0f)); + projectedPoint.x /= projectedPoint.w; + projectedPoint.y /= projectedPoint.w; + projectedPoint.x += 1.0f; + projectedPoint.y += 1.0f; + projectedPoint.x *= 0.5f; + projectedPoint.y *= 0.5f; + + QT3DSVec2 dims(QT3DSF32(layerViewport.m_Width), + QT3DSF32(layerViewport.m_Height)); + projectedPoint.x *= dims.x; + projectedPoint.y *= dims.y; + projectedPoint.x += layerViewport.m_X; + projectedPoint.y += layerViewport.m_Y; + + if (projectedPoint.x < projectedMinimum.x) + projectedMinimum.x = projectedPoint.x; + if (projectedPoint.y < projectedMinimum.y) + projectedMinimum.y = projectedPoint.y; + if (projectedPoint.x > projectedMaximum.x) + projectedMaximum.x = projectedPoint.x; + if (projectedPoint.y > projectedMaximum.y) + projectedMaximum.y = projectedPoint.y; + } + + float boundsLeft = projectedMinimum.x; + float boundsBottom = projectedMinimum.y; + float boundsWidth = qAbs(projectedMaximum.x - projectedMinimum.x); + float boundsHeight = qAbs(projectedMaximum.y - projectedMinimum.y); + + float paddedBoundsLeft = boundsLeft; + float paddedBoundsBottom = boundsBottom; + float paddedBoundsWidth = boundsWidth; + float paddedBoundsHeight = boundsHeight; + + if (m_Layer.m_DynamicPadding > 0) { + float unpaddedBoundsLeft; + float unpaddedBoundsBottom; + float unpaddedBoundsWidth; + float unpaddedBoundsHeight; + + if (m_Layer.m_DynamicPaddingUnits == LayerUnitTypes::Pixels) { + paddedBoundsLeft = boundsLeft - m_Layer.m_DynamicPadding; + paddedBoundsBottom = boundsBottom - m_Layer.m_DynamicPadding; + paddedBoundsWidth = boundsWidth + m_Layer.m_DynamicPadding * 2; + paddedBoundsHeight = boundsHeight + m_Layer.m_DynamicPadding * 2; + + unpaddedBoundsLeft = boundsLeft + m_Layer.m_DynamicPadding; + unpaddedBoundsBottom = boundsBottom + m_Layer.m_DynamicPadding; + unpaddedBoundsWidth = boundsWidth - m_Layer.m_DynamicPadding * 2; + unpaddedBoundsHeight = boundsHeight - m_Layer.m_DynamicPadding * 2; + } else { + const float leftPadding = boundsWidth * m_Layer.m_DynamicPadding * 0.01f; + const float bottomPadding = boundsHeight * m_Layer.m_DynamicPadding * 0.01f; + const float widthPadding = m_Layer.m_DynamicPadding * 0.02f; + const float heightPadding = m_Layer.m_DynamicPadding * 0.02f; + + paddedBoundsLeft = boundsLeft - leftPadding; + paddedBoundsBottom = boundsBottom - bottomPadding; + paddedBoundsWidth = boundsWidth * (1.0f + widthPadding); + paddedBoundsHeight = boundsHeight * (1.0f + heightPadding); + + unpaddedBoundsLeft = boundsLeft + leftPadding; + unpaddedBoundsBottom = boundsBottom + bottomPadding; + unpaddedBoundsWidth = boundsWidth * (1.0f - widthPadding); + unpaddedBoundsHeight = boundsHeight * (1.0f - heightPadding); + } + + // Both the padded and unpadded bounds are calculated + // Padded provides the upper bound when size has to be recalculated + // Unpadded provides the lower bound + // If the newly calculated bounds fit between the padded and unpadded ones + // use the previous calculations instead + if (m_Layer.m_DynamicPadding == m_lastDynamicPadding + && m_Layer.m_DynamicPaddingUnits == m_lastDynamicPaddingUnits + && m_unpaddedDynamicSize.m_X >= boundsLeft + && m_unpaddedDynamicSize.m_Y >= boundsBottom + && m_unpaddedDynamicSize.m_X + m_unpaddedDynamicSize.m_Width + <= boundsLeft + boundsWidth + && m_unpaddedDynamicSize.m_Y + m_unpaddedDynamicSize.m_Height + <= boundsBottom + boundsHeight + && m_dynamicSize.m_X <= boundsLeft + && m_dynamicSize.m_Y <= boundsBottom + && m_dynamicSize.m_X + m_dynamicSize.m_Width + >= boundsLeft + boundsWidth + && m_dynamicSize.m_Y + m_dynamicSize.m_Height + >= boundsBottom + boundsHeight) { + paddedBoundsLeft = m_dynamicSize.m_X; + paddedBoundsBottom = m_dynamicSize.m_Y; + paddedBoundsWidth = m_dynamicSize.m_Width; + paddedBoundsHeight = m_dynamicSize.m_Height; + } else { + m_unpaddedDynamicSize = NVRenderRectF(unpaddedBoundsLeft, + unpaddedBoundsBottom, + unpaddedBoundsWidth, + unpaddedBoundsHeight); + m_dynamicSize = NVRenderRectF(paddedBoundsLeft, + paddedBoundsBottom, + paddedBoundsWidth, + paddedBoundsHeight); + } + m_lastDynamicPadding = m_Layer.m_DynamicPadding; + m_lastDynamicPaddingUnits = m_Layer.m_DynamicPaddingUnits; + } + + if (paddedBoundsLeft < layerViewport.m_X) + paddedBoundsLeft = layerViewport.m_X; + if (paddedBoundsBottom < layerViewport.m_Y) + paddedBoundsBottom = layerViewport.m_Y; + if (paddedBoundsWidth > layerViewport.m_Width) + paddedBoundsWidth = layerViewport.m_Width; + if (paddedBoundsHeight > layerViewport.m_Height) + paddedBoundsHeight = layerViewport.m_Height; + + prepResult.setViewport(NVRenderRectF(paddedBoundsLeft, paddedBoundsBottom, + paddedBoundsWidth, paddedBoundsHeight)); + } + + bool SLayerRenderPreparationData::PrepareForRender(const QSize &inViewportDimensions) { QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), - "SLayerRenderData::PrepareForRender") + "LayerRenderData: PrepareForRender") if (m_LayerPrepResult.hasValue()) - return; + return false; m_Features.clear(); m_FeatureSetHash = 0; @@ -1176,7 +1433,7 @@ namespace render { NVRenderRect theViewport(theGraph.GetViewport()); NVRenderRect theScissor(theGraph.GetViewport()); if (theGraph.IsScissorTestEnabled()) - theScissor = m_Renderer.GetContext().GetScissorRect(); + theScissor = theGraph.GetScissor(); bool wasDirty = false; bool wasDataDirty = false; wasDirty = m_Layer.m_Flags.IsDirty(); @@ -1189,10 +1446,10 @@ namespace render { // Uncomment the line below to disable all progressive AA. // maxNumAAPasses = 0; - SLayerRenderPreparationResult thePrepResult; bool hasOffscreenRenderer = GetOffscreenRenderer(); - bool SSAOEnabled = (m_Layer.m_AoStrength > 0.0f && m_Layer.m_AoDistance > 0.0f); + bool SSAOEnabled = (m_Layer.m_AoStrength > 0.0f && m_Layer.m_AoDistance > 0.0f + && m_Layer.m_AoEnabled); bool SSDOEnabled = (m_Layer.m_ShadowStrength > 0.0f && m_Layer.m_ShadowDist > 0.0f); SetShaderFeature("QT3DS_ENABLE_SSAO", SSAOEnabled); SetShaderFeature("QT3DS_ENABLE_SSDO", SSDOEnabled); @@ -1217,20 +1474,18 @@ namespace render { && theEffectSystem.DoesEffectRequireDepthTexture(theEffect->m_ClassName)) requiresDepthPrepass = true; - if (theEffect->m_imageMaps && theEffect->m_imageMaps->size() > 0) { + if (theEffect->m_images.size() > 0) { SRenderableImage *firstImage = nullptr; SRenderableImage *nextImage = nullptr; SShaderDefaultMaterialKey key; SRenderableObjectFlags flags; - auto iter = theEffect->m_imageMaps->begin(); - auto end = theEffect->m_imageMaps->end(); + auto iter = theEffect->m_images.begin(); + auto end = theEffect->m_images.end(); for (; iter != end; iter++) { - if (iter->second) { - PrepareImageForRender(*iter->second, ImageMapTypes::Unknown, - firstImage, nextImage, flags, key, - SShaderDefaultMaterialKeyProperties::ImageMapCount, - nullptr); - } + PrepareImageForRender(**iter, ImageMapTypes::Unknown, + firstImage, nextImage, flags, key, + SShaderDefaultMaterialKeyProperties::ImageMapCount, + nullptr); } } } @@ -1250,22 +1505,23 @@ namespace render { maxNumAAPasses = 0; } - thePrepResult = SLayerRenderPreparationResult(SLayerRenderHelper( + m_LayerPrepResult = SLayerRenderPreparationResult(SLayerRenderHelper( theViewport, theScissor, m_Layer.m_Scene->m_Presentation->m_PresentationDimensions, m_Layer, shouldRenderToTexture, m_Renderer.GetQt3DSContext().GetScaleMode(), m_Renderer.GetQt3DSContext().GetStereoMode(), m_Renderer.GetQt3DSContext().GetStereoView(), m_Renderer.GetQt3DSContext().GetStereoEyeSeparation(), + m_Renderer.GetQt3DSContext().GetStereoEyeRotation(), m_Renderer.GetQt3DSContext().GetPresentationScaleFactor())); - thePrepResult.m_LastEffect = theLastEffect; - thePrepResult.m_MaxAAPassIndex = maxNumAAPasses; - thePrepResult.m_Flags.SetRequiresDepthTexture(requiresDepthPrepass + m_LayerPrepResult->m_LastEffect = theLastEffect; + m_LayerPrepResult->m_MaxAAPassIndex = maxNumAAPasses; + m_LayerPrepResult->m_Flags.SetRequiresDepthTexture(requiresDepthPrepass || NeedsWidgetTexture()); - thePrepResult.m_Flags.SetShouldRenderToTexture(shouldRenderToTexture); + m_LayerPrepResult->m_Flags.SetShouldRenderToTexture(shouldRenderToTexture); if (m_Renderer.GetContext().GetRenderContextType() != NVRenderContextValues::GLES2) - thePrepResult.m_Flags.SetRequiresSsaoPass(SSAOEnabled); + m_LayerPrepResult->m_Flags.SetRequiresSsaoPass(SSAOEnabled); - if (thePrepResult.IsLayerVisible()) { + if (m_LayerPrepResult->IsLayerVisible()) { if (shouldRenderToTexture) { m_Renderer.GetQt3DSContext().GetRenderList().AddRenderTask( CreateRenderToTextureRunnable()); @@ -1274,6 +1530,12 @@ namespace render { m_Renderer.PrepareImageForIbl(*m_Layer.m_LightProbe); wasDataDirty = true; } + if (m_StereoMode != m_LayerPrepResult->getStereoMode()) { + // When stereo mode changes we need to mark data dirty + // for e.g. temporalAA to render correctly. + m_StereoMode = m_LayerPrepResult->getStereoMode(); + wasDataDirty = true; + } bool lightProbeValid = HasValidLightProbe(m_Layer.m_LightProbe); @@ -1292,11 +1554,12 @@ namespace render { // Push nodes in reverse depth first order if (m_RenderableNodes.empty()) { m_CamerasAndLights.clear(); + m_GroupNodes.clear(); QT3DSU32 dfsIndex = 0; for (SNode *theChild = m_Layer.m_FirstChild; theChild; theChild = theChild->m_NextSibling) - MaybeQueueNodeForRender(*theChild, m_RenderableNodes, m_CamerasAndLights, - dfsIndex); + MaybeQueueNodeForRender(*theChild, m_RenderableNodes, m_GroupNodes, + m_CamerasAndLights, dfsIndex); reverse(m_CamerasAndLights.begin(), m_CamerasAndLights.end()); reverse(m_RenderableNodes.begin(), m_RenderableNodes.end()); m_LightToNodeMap.clear(); @@ -1320,10 +1583,10 @@ namespace render { // SetupCameraForRender() sets the camera used for picking and // updates global state e.g. IsGloballyActive() SCameraGlobalCalculationResult theResult = - thePrepResult.SetupCameraForRender(*theCamera); + m_LayerPrepResult->SetupCameraForRender(*theCamera); wasDataDirty = wasDataDirty || theResult.m_WasDirty; if (theCamera->m_Flags.IsGloballyActive()) - m_Camera = thePrepResult.GetCamera(); + m_Camera = m_LayerPrepResult->GetCamera(); if (theResult.m_ComputeFrustumSucceeded == false) { qCCritical(INTERNAL_ERROR, "Failed to calculate camera frustum"); } @@ -1363,7 +1626,7 @@ namespace render { m_Lights.size() - 1, mapSize, mapSize, NVRenderTextureFormats::R16F, 1, mapMode, ShadowFilterValues::NONE); - thePrepResult.m_Flags.SetRequiresShadowMapPass(true); + m_LayerPrepResult->m_Flags.SetRequiresShadowMapPass(true); SetShaderFeature("QT3DS_ENABLE_SSM", true); } } @@ -1430,9 +1693,13 @@ namespace render { QT3DSF32 theTextScaleFactor = 1.0f; if (m_Camera) { m_Camera->CalculateViewProjectionMatrix(m_ViewProjection); + + if (m_Layer.m_DynamicResize) + calculateDynamicLayerSize(*m_LayerPrepResult); + theTextScaleFactor = m_Camera->GetTextScaleFactor( - thePrepResult.GetLayerToPresentationViewport(), - thePrepResult.GetPresentationDesignDimensions()); + m_LayerPrepResult->GetLayerToPresentationViewport(), + m_LayerPrepResult->GetPresentationDesignDimensions()); if (m_Camera->m_EnableFrustumCulling) { SClipPlane nearPlane; QT3DSMat33 theUpper33(m_Camera->m_GlobalTransform.getUpper3x3InverseTranspose()); @@ -1464,16 +1731,16 @@ namespace render { bool renderablesDirty = PrepareRenderablesForRender(m_ViewProjection, m_ClippingFrustum, - theTextScaleFactor, thePrepResult.m_Flags); + theTextScaleFactor, m_LayerPrepResult->m_Flags); wasDataDirty = wasDataDirty || renderablesDirty; - if (thePrepResult.m_Flags.RequiresStencilBuffer()) - thePrepResult.m_Flags.SetShouldRenderToTexture(true); + if (m_LayerPrepResult->m_Flags.RequiresStencilBuffer()) + m_LayerPrepResult->m_Flags.SetShouldRenderToTexture(true); } else { NVRenderRect theViewport = - thePrepResult.GetLayerToPresentationViewport().ToIntegerRect(); + m_LayerPrepResult->GetLayerToPresentationViewport().ToIntegerRect(); bool theScissor = true; NVRenderRect theScissorRect = - thePrepResult.GetLayerToPresentationScissorRect().ToIntegerRect(); + m_LayerPrepResult->GetLayerToPresentationScissorRect().ToIntegerRect(); // This happens here because if there are any fancy render steps IRenderList &theRenderList(m_Renderer.GetQt3DSContext().GetRenderList()); NVRenderContext &theContext(m_Renderer.GetContext()); @@ -1503,12 +1770,13 @@ namespace render { wasDataDirty = wasDataDirty || theResult.m_HasChangedSinceLastFrame; } } + } else { + // m_LayerPrepResult must always be set. + m_LayerPrepResult = SLayerRenderPreparationResult(); } wasDirty = wasDirty || wasDataDirty; - thePrepResult.m_Flags.SetWasDirty(wasDirty); - thePrepResult.m_Flags.SetLayerDataDirty(wasDataDirty); - - m_LayerPrepResult = thePrepResult; + m_LayerPrepResult->m_Flags.SetWasDirty(wasDirty); + m_LayerPrepResult->m_Flags.SetLayerDataDirty(wasDataDirty); // Per-frame cache of renderable objects post-sort. GetOpaqueRenderableObjects(); @@ -1516,12 +1784,14 @@ namespace render { GetTransparentRenderableObjects(); GetCameraDirection(); + return wasDirty; } void SLayerRenderPreparationData::ResetForFrame() { m_TransparentObjects.clear_unsafe(); m_OpaqueObjects.clear_unsafe(); + m_GroupObjects.clear_unsafe(); m_LayerPrepResult.setEmpty(); // The check for if the camera is or is not null is used // to figure out if this layer was rendered at all. diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h index eae29f6..fd9b86e 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h @@ -253,6 +253,7 @@ namespace render { TNodeLightEntryPoolType m_RenderableNodeLightEntryPool; nvvector<SRenderableNodeEntry> m_RenderableNodes; + nvvector<SRenderableNodeEntry> m_GroupNodes; TLightToNodeMap m_LightToNodeMap; // map of lights to nodes to cache if we have looked up a // given scoped light yet. // Built at the same time as the renderable nodes map. @@ -265,6 +266,12 @@ namespace render { nvvector<SLight *> m_Lights; // Only contains lights that are global. TRenderableObjectList m_OpaqueObjects; TRenderableObjectList m_TransparentObjects; + TRenderableObjectList m_GroupObjects; + QVector<QT3DSVec3> m_boundPoints; + NVRenderRectF m_dynamicSize; + NVRenderRectF m_unpaddedDynamicSize; + float m_lastDynamicPadding = 0; + LayerUnitTypes::Enum m_lastDynamicPaddingUnits = LayerUnitTypes::Percent; // Sorted lists of the rendered objects. There may be other transforms applied so // it is simplest to duplicate the lists. TRenderableObjectList m_RenderedOpaqueObjects; @@ -294,6 +301,7 @@ namespace render { bool m_FeaturesDirty; size_t m_FeatureSetHash; bool m_TooManyLightsError; + StereoModes::Enum m_StereoMode; // shadow mapps NVScopedRefCounted<Qt3DSShadowMap> m_ShadowMapManager; @@ -323,23 +331,28 @@ namespace render { bool PrepareModelForRender(SModel &inModel, const QT3DSMat44 &inViewProjection, const Option<SClippingFrustum> &inClipFrustum, - TNodeLightEntryList &inScopedLights); + TNodeLightEntryList &inScopedLights, + SOrderedGroupRenderable *group); bool PrepareTextForRender(SText &inText, const QT3DSMat44 &inViewProjection, QT3DSF32 inTextScaleFactor, - SLayerRenderPreparationResultFlags &ioFlags); + SLayerRenderPreparationResultFlags &ioFlags, + SOrderedGroupRenderable *group); bool PreparePathForRender(SPath &inPath, const QT3DSMat44 &inViewProjection, const Option<SClippingFrustum> &inClipFrustum, - SLayerRenderPreparationResultFlags &ioFlags); + SLayerRenderPreparationResultFlags &ioFlags, + SOrderedGroupRenderable *group); // Helper function used during PRepareForRender and PrepareAndRender bool PrepareRenderablesForRender(const QT3DSMat44 &inViewProjection, const Option<SClippingFrustum> &inClipFrustum, QT3DSF32 inTextScaleFactor, SLayerRenderPreparationResultFlags &ioFlags); + void calculateDynamicLayerSize(SLayerRenderPreparationResult &prepResult); + // returns true if this object will render something different than it rendered the last // time. - virtual void PrepareForRender(const QSize &inViewportDimensions); + virtual bool PrepareForRender(const QSize &inViewportDimensions); bool CheckLightProbeDirty(SImage &inLightProbe); void AddRenderWidget(IRenderWidget &inWidget); void SetShaderFeature(const char *inName, bool inValue); |