diff options
author | Antti Määttä <antti.maatta@qt.io> | 2019-12-17 18:22:59 +0200 |
---|---|---|
committer | Antti Määttä <antti.maatta@qt.io> | 2020-01-13 13:27:28 +0200 |
commit | 49fba62dfff3166e44a4b85f99180c27f2bba69e (patch) | |
tree | b7d1d2efb96115e30b44354f0f2e2eaa494aef60 | |
parent | 9f9c5497ac52b40ef336a0931cbac6068f6035e9 (diff) |
Implement ordered group
Add ordered property to group, which disables automatic depth sorting for
that group and all it's children. The group as a whole gets sorted with
other objects as if it was one object.
Task-number: QT3DS-3820
Change-Id: Iea71917fc78f4c543aa944d851c77b6794bd7d80
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
18 files changed, 417 insertions, 199 deletions
diff --git a/res/DataModelMetadata/en-us/MetaData.xml b/res/DataModelMetadata/en-us/MetaData.xml index e249d22..a4d6d45 100644 --- a/res/DataModelMetadata/en-us/MetaData.xml +++ b/res/DataModelMetadata/en-us/MetaData.xml @@ -227,6 +227,8 @@ </Component> <Group> + <!-- Basic Properties --> + <Property name="ordered" formalName="Ordered" type="Boolean" default="False" category="Basic Properties" description="The group is ordered. Draw objects in the group order (disables dynamic depth sorting). " /> <!-- Variant Tags --> <Property name="variants" type="String" animatable="False" category="Variant Tags" /> diff --git a/src/dm/systems/Qt3DSDMComposerTypeDefinitions.cpp b/src/dm/systems/Qt3DSDMComposerTypeDefinitions.cpp index c1c0071..c529515 100644 --- a/src/dm/systems/Qt3DSDMComposerTypeDefinitions.cpp +++ b/src/dm/systems/Qt3DSDMComposerTypeDefinitions.cpp @@ -317,6 +317,7 @@ struct DataConstructor<SObjectRefType> #define QT3DS_WCHAR_T_lightmapshadow L"lightmapshadow" #define QT3DS_WCHAR_T_controlledproperty L"controlledproperty" #define QT3DS_WCHAR_T_variants L"variants" +#define QT3DS_WCHAR_T_ordered L"ordered" const wchar_t *ComposerObjectTypes::Convert(ComposerObjectTypes::Enum inType) { diff --git a/src/dm/systems/Qt3DSDMComposerTypeDefinitions.h b/src/dm/systems/Qt3DSDMComposerTypeDefinitions.h index ce49f07..0e0ada5 100644 --- a/src/dm/systems/Qt3DSDMComposerTypeDefinitions.h +++ b/src/dm/systems/Qt3DSDMComposerTypeDefinitions.h @@ -243,6 +243,7 @@ class IPropertySystem; HANDLE_COMPOSER_PROPERTY_DUPLICATE(controlledproperty, m_ControlledProperty, TDataStrPtr, L"") #define ITERATE_COMPOSER_GROUP_PROPERTIES \ + HANDLE_COMPOSER_PROPERTY(ordered, m_ordered, bool, false) \ HANDLE_COMPOSER_PROPERTY_DUPLICATE(variants, m_variants, TDataStrPtr, L"") \ #define ITERATE_COMPOSER_LIGHT_PROPERTIES \ diff --git a/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp b/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp index c40dd42..998fedb 100644 --- a/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp +++ b/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp @@ -493,6 +493,7 @@ struct SRuntimePropertyParser #define Node_LocalOpacity ATTRIBUTE_OPACITY #define Node_RotationOrder ATTRIBUTE_ROTATIONORDER #define Node_LeftHanded ATTRIBUTE_ORIENTATION +#define Group_ordered ATTRIBUTE_ORDERED #define Layer_TemporalAAEnabled ATTRIBUTE_TEMPORALAA #define Layer_LayerEnableDepthTest ATTRIBUTE_DISABLEDEPTHTEST #define Layer_LayerEnableDepthPrePass ATTRIBUTE_DISABLEDEPTHPREPASS diff --git a/src/runtime/Qt3DSAttributeHashes.cpp b/src/runtime/Qt3DSAttributeHashes.cpp index 9d248b7..da74931 100644 --- a/src/runtime/Qt3DSAttributeHashes.cpp +++ b/src/runtime/Qt3DSAttributeHashes.cpp @@ -285,6 +285,7 @@ const char *GetAttributeString(const EAttribute inAttribute) case ATTRIBUTE_LIFETIME: return "lifetime"; case ATTRIBUTE_CONTROLLEDPROPERTY: return "controlledproperty"; case ATTRIBUTE_OBSERVEDPROPERTY: return "observedproperty"; + case ATTRIBUTE_ORDERED: return "ordered"; case ATTRIBUTE_QT_IO: return "qt.io"; default: { static char s_UnknownHash[16]; diff --git a/src/runtime/Qt3DSAttributeHashes.h b/src/runtime/Qt3DSAttributeHashes.h index 3f53541..f8f7bec 100644 --- a/src/runtime/Qt3DSAttributeHashes.h +++ b/src/runtime/Qt3DSAttributeHashes.h @@ -276,6 +276,7 @@ enum EAttribute { ATTRIBUTE_LIFETIME = 0x0033D297, // lifetime ATTRIBUTE_CONTROLLEDPROPERTY = 0x022C0A1D, // controlledproperty ATTRIBUTE_OBSERVEDPROPERTY = 0x02D1CE03, // observedproperty + ATTRIBUTE_ORDERED = 0x038AEAD3, // ordered ATTRIBUTE_QT_IO = 0x010EF2CF, // qt.io }; // enum EAttribute diff --git a/src/runtime/Qt3DSAttributeHashes.txt b/src/runtime/Qt3DSAttributeHashes.txt index b8e2a7f..21b9646 100644 --- a/src/runtime/Qt3DSAttributeHashes.txt +++ b/src/runtime/Qt3DSAttributeHashes.txt @@ -249,3 +249,5 @@ lifetime controlledproperty observedproperty + +ordered diff --git a/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.cpp b/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.cpp index 51e3d70..462cca8 100644 --- a/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.cpp +++ b/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.cpp @@ -447,9 +447,11 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator << " = getTransformedUVCoords( environment_map_reflection, uTransform, " "vTransform );" << Endl; - if (image.m_Image.m_TextureData.m_TextureFlags.IsInvertUVCoords()) + + if (image.m_Image.m_TextureData.m_TextureFlags.IsInvertUVCoords()) { fragmentShader << " " << m_ImageFragCoords << ".y = 1.0 - " << m_ImageFragCoords << ".y;" << Endl; + } } } diff --git a/src/runtimerender/Qt3DSRenderUIPLoader.cpp b/src/runtimerender/Qt3DSRenderUIPLoader.cpp index df02e78..9433b50 100644 --- a/src/runtimerender/Qt3DSRenderUIPLoader.cpp +++ b/src/runtimerender/Qt3DSRenderUIPLoader.cpp @@ -716,6 +716,7 @@ struct SRenderUIPLoader : public IDOMReferenceResolver #define Node_LocalOpacity "opacity" #define Node_RotationOrder "rotationorder" #define Node_LeftHanded "orientation" +#define Group_ordered "ordered" #define Layer_Variants "variants" #define Layer_TemporalAAEnabled "temporalaa" #define Layer_LayerEnableDepthTest "disabledepthtest" @@ -928,6 +929,7 @@ struct SRenderUIPLoader : public IDOMReferenceResolver inItem.m_Flags.SetActive(eyeball); ITERATE_QT3DS_RENDER_NODE_PROPERTIES ParseProperty(inParser, "boneid", inItem.m_SkeletonId); + ParseProperty(inParser, "ordered", inItem.m_ordered); bool ignoreParent = false; if (ParseProperty(inParser, "ignoresparent", ignoreParent)) inItem.m_Flags.SetIgnoreParentTransform(ignoreParent); diff --git a/src/runtimerender/graphobjects/Qt3DSRenderNode.cpp b/src/runtimerender/graphobjects/Qt3DSRenderNode.cpp index bf47bb8..9d42aa5 100644 --- a/src/runtimerender/graphobjects/Qt3DSRenderNode.cpp +++ b/src/runtimerender/graphobjects/Qt3DSRenderNode.cpp @@ -47,11 +47,13 @@ SNode::SNode(GraphObjectTypes::Enum inGraphObjectType) , m_LocalOpacity(1.0f) , m_GlobalOpacity(1.0f) , m_SkeletonId(-1) + , m_ordered(false) , m_Parent(NULL) , m_NextSibling(NULL) , m_PreviousSibling(NULL) , m_FirstChild(NULL) , m_DFSIndex(0) + , m_GroupIndex(0) { m_Flags.SetDirty(true); m_Flags.SetTransformDirty(true); @@ -72,11 +74,13 @@ SNode::SNode(const SNode &inCloningObject, NVAllocatorCallback &inAllocator) , m_GlobalTransform(inCloningObject.m_GlobalTransform) , m_GlobalOpacity(inCloningObject.m_GlobalOpacity) , m_SkeletonId(inCloningObject.m_SkeletonId) + , m_ordered(inCloningObject.m_ordered) , m_Parent(NULL) , m_NextSibling(NULL) , m_PreviousSibling(NULL) , m_FirstChild(NULL) , m_DFSIndex(0) + , m_GroupIndex(0) { m_Flags.SetDirty(true); m_Flags.SetTransformDirty(true); diff --git a/src/runtimerender/graphobjects/Qt3DSRenderNode.h b/src/runtimerender/graphobjects/Qt3DSRenderNode.h index 87a1500..751ed27 100644 --- a/src/runtimerender/graphobjects/Qt3DSRenderNode.h +++ b/src/runtimerender/graphobjects/Qt3DSRenderNode.h @@ -201,6 +201,7 @@ namespace render { QT3DSMat44 m_GlobalTransform; QT3DSF32 m_GlobalOpacity; QT3DSI32 m_SkeletonId; + bool m_ordered; // node graph members. SNode *m_Parent; @@ -210,6 +211,8 @@ namespace render { // Property maintained solely by the render system. // Depth-first-search index assigned and maintained by render system. QT3DSU32 m_DFSIndex; + // Index to the group of the node + QT3DSU32 m_GroupIndex; SNode(GraphObjectTypes::Enum inType = GraphObjectTypes::Node); SNode(const SNode &inCloningObject, NVAllocatorCallback &inAllocator); diff --git a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp index 712214a..2705b18 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp @@ -600,5 +600,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..0484390 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp @@ -1405,61 +1405,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/Qt3DSRendererImplLayerRenderData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp index 9c92bda..c43ed1a 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp @@ -674,8 +674,9 @@ namespace render { 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; } @@ -832,7 +833,7 @@ namespace render { // Avoid running this method if possible. if ((inEnableTransparentDepthWrite == false - && ((m_OpaqueObjects.size() == 0 && m_TransparentObjects.size() == 0) + && ((m_GroupObjects.empty() && m_OpaqueObjects.empty() && m_TransparentObjects.empty()) || m_Layer.m_Flags.IsLayerEnableDepthPrepass() == false)) || m_Layer.m_Flags.IsLayerEnableDepthTest() == false) return; @@ -895,79 +896,156 @@ 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); - - // 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())) { + 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. - // 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); + // 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 - 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); +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())) { #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); - } + // 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 + 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); +#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 } } - // 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); @@ -996,76 +1074,83 @@ 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(); + 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; - 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); - } - } - { - QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), - "LayerRenderData: Render transparent pass1") + theRenderContext.SetDepthTestEnabled(opaqueDepthTest); + theRenderContext.SetDepthWriteEnabled(opaqueDepthWrite); - 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]); + for (QT3DSU32 idx = 0, end = theOpaqueObjects.size(); idx < end; ++idx) { + SRenderableObject &theObject(*theOpaqueObjects[idx]); + + if (theObject.m_RenderableFlags.isOrderedGroup()) { + renderOrderedGroup(theObject, inRenderFn, inEnableBlending, inEnableDepthWrite, + inEnableTransparentDepthWrite, indexLight, inCamera, theFB); + } else { + 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); inRenderFn(*this, theObject, theCameraProps, GetShaderFeatureSet(), indexLight, inCamera); } } + } + { + QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), + "LayerRenderData: Render transparent pass1") - { - QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), - "LayerRenderData: Render transparent pass2") - 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 pass3") - m_Renderer.setAlphaTest(false, 1.0, 1.0); - // transparent objects without alpha test - renderTransparentObjectsPass(inRenderFn, inEnableBlending, inEnableTransparentDepthWrite, - indexLight, inCamera, theFB); + 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]); + 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); } } + { + QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), + "LayerRenderData: Render transparent pass2") + 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, + inEnableDepthWrite, indexLight, inCamera, theFB); + } + { + QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), + "LayerRenderData: Render transparent pass3") + m_Renderer.setAlphaTest(false, 1.0, 1.0); + // transparent objects without alpha test + renderTransparentObjectsPass(inRenderFn, inEnableBlending, inEnableTransparentDepthWrite, + inEnableDepthWrite, indexLight, inCamera, theFB); + } +} + void SLayerRenderData::Render(CResourceFrameBuffer *theFB) { QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), @@ -1546,7 +1631,8 @@ 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(), @@ -1834,13 +1920,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; diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h index 0f0a838..aa4d456 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h @@ -125,6 +125,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 +183,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/Qt3DSRendererImplLayerRenderPreparationData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp index 45839e0..b6cd2a0 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(), @@ -246,10 +261,18 @@ 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()); + m_RenderedOpaqueObjects.insert(m_RenderedOpaqueObjects.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(); + // Setup the object's sorting information for (QT3DSU32 idx = 0, end = m_RenderedOpaqueObjects.size(); idx < end; ++idx) { SRenderableObject &theInfo = *m_RenderedOpaqueObjects[idx]; @@ -274,9 +297,12 @@ namespace render { m_RenderedTransparentObjects.assign(m_TransparentObjects.begin(), m_TransparentObjects.end()); - if (m_Layer.m_Flags.IsLayerEnableDepthTest() == false) + if (!m_Layer.m_Flags.IsLayerEnableDepthTest()) { 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()); @@ -365,7 +391,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 +451,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 +490,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); @@ -882,7 +914,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(); @@ -1039,11 +1072,15 @@ namespace render { // set tessellation theRenderableObject->m_TessellationMode = inModel.m_TessellationMode; - if (theRenderableObject->m_RenderableFlags.HasTransparency() - || theRenderableObject->m_RenderableFlags.HasRefraction()) { - m_TransparentObjects.push_back(theRenderableObject); + if (group) { + group->m_renderables.push_back(theRenderableObject); } else { - m_OpaqueObjects.push_back(theRenderableObject); + if (theRenderableObject->m_RenderableFlags.HasTransparency() + || theRenderableObject->m_RenderableFlags.HasRefraction()) { + m_TransparentObjects.push_back(theRenderableObject); + } else { + m_OpaqueObjects.push_back(theRenderableObject); + } } } } @@ -1063,17 +1100,36 @@ namespace render { 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; @@ -1086,7 +1142,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; } @@ -1096,7 +1152,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; @@ -1293,11 +1350,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(); @@ -1523,6 +1581,7 @@ namespace render { { 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..53b60f2 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,7 @@ namespace render { nvvector<SLight *> m_Lights; // Only contains lights that are global. TRenderableObjectList m_OpaqueObjects; TRenderableObjectList m_TransparentObjects; + TRenderableObjectList m_GroupObjects; // Sorted lists of the rendered objects. There may be other transforms applied so // it is simplest to duplicate the lists. TRenderableObjectList m_RenderedOpaqueObjects; @@ -323,14 +325,17 @@ 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, |