diff options
Diffstat (limited to 'src')
32 files changed, 1039 insertions, 333 deletions
diff --git a/src/engine/Qt3DSRenderRuntimeBinding.cpp b/src/engine/Qt3DSRenderRuntimeBinding.cpp index 33f9f5c..038fd8f 100644 --- a/src/engine/Qt3DSRenderRuntimeBinding.cpp +++ b/src/engine/Qt3DSRenderRuntimeBinding.cpp @@ -1110,7 +1110,9 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, if (theSourcePathStr.size() > 4) { CRegisteredString theObjectPath = m_SourcePaths[idx].first; if (qt3ds::runtime::isImagePath(theSourcePathStr.c_str())) { - theManager.SetImageHasTransparency(theObjectPath, hasTransparency); + theManager.SetImageHasTransparency( + theObjectPath, hasTransparency, + theManager.GetImageHasOpaquePixels(theObjectPath)); if (isIbl) iblImagePathList.push_back(theObjectPath); else diff --git a/src/render/Qt3DSRenderShaderProgram.h b/src/render/Qt3DSRenderShaderProgram.h index ed8c677..5ad3f06 100644 --- a/src/render/Qt3DSRenderShaderProgram.h +++ b/src/render/Qt3DSRenderShaderProgram.h @@ -106,7 +106,7 @@ namespace render { NVConstDataRef<QT3DSI8> fragmentShaderSource, bool binaryProgram = false); /** - * @brief create tesselation control shader + * @brief create tessellation control shader * * @param[in] context Pointer to render context * @param[in] tessControlShaderSource Tessellation control shader source code @@ -120,7 +120,7 @@ namespace render { bool binaryProgram = false); /** - * @brief create tesselation evaluation shader + * @brief create tessellation evaluation shader * * @param[in] context Pointer to render context * @param[in] tessEvaluationShaderSource Tessellation evaluation shader source code diff --git a/src/render/backends/Qt3DSRenderBackend.h b/src/render/backends/Qt3DSRenderBackend.h index 4e9e177..226e0b7 100644 --- a/src/render/backends/Qt3DSRenderBackend.h +++ b/src/render/backends/Qt3DSRenderBackend.h @@ -73,10 +73,10 @@ namespace render { typedef struct _NVRenderBackendVertexShaderObject *NVRenderBackendVertexShaderObject; /// opaque fragment shader object handle typedef struct _NVRenderBackendFragmentShaderObject *NVRenderBackendFragmentShaderObject; - /// opaque tesselation control shader object handle + /// opaque tessellation control shader object handle typedef struct _NVRenderBackendTessControlShaderObject *NVRenderBackendTessControlShaderObject; - /// opaque tesselation evaluation shader object handle + /// opaque tessellation evaluation shader object handle typedef struct _NVRenderBackendTessEvaluationShaderObject *NVRenderBackendTessEvaluationShaderObject; /// opaque geometry shader object handle diff --git a/src/render/backends/gl/Q3DSRenderBackendGLES2.cpp b/src/render/backends/gl/Q3DSRenderBackendGLES2.cpp index 1db51ef..54d8d5d 100644 --- a/src/render/backends/gl/Q3DSRenderBackendGLES2.cpp +++ b/src/render/backends/gl/Q3DSRenderBackendGLES2.cpp @@ -42,13 +42,13 @@ #if defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2_ANGLE) #define GL_CALL_TIMER_EXT(x) m_qt3dsExtensions->x; RENDER_LOG_ERROR_PARAMS(x); -#define GL_CALL_TESSELATION_EXT(x) m_qt3dsExtensions->x; RENDER_LOG_ERROR_PARAMS(x); +#define GL_CALL_TESSELLATION_EXT(x) m_qt3dsExtensions->x; RENDER_LOG_ERROR_PARAMS(x); #define GL_CALL_MULTISAMPLE_EXT(x) m_qt3dsExtensions->x; RENDER_LOG_ERROR_PARAMS(x); #define GL_CALL_EXTRA_FUNCTION(x) m_glExtraFunctions->x; RENDER_LOG_ERROR_PARAMS(x); #define GL_CALL_EXTENSION_FUNCTION(x) m_qt3dsExtensions->x; RENDER_LOG_ERROR_PARAMS(x); #else #define GL_CALL_TIMER_EXT(x) -#define GL_CALL_TESSELATION_EXT(x) +#define GL_CALL_TESSELLATION_EXT(x) #define GL_CALL_MULTISAMPLE_EXT(x) #define GL_CALL_EXTRA_FUNCTION(x) m_glExtraFunctions->x; RENDER_LOG_ERROR_PARAMS(x); #define GL_CALL_EXTENSION_FUNCTION(x) diff --git a/src/render/backends/gl/Qt3DSOpenGLExtensions.h b/src/render/backends/gl/Qt3DSOpenGLExtensions.h index c9ba76a..e79fe1b 100644 --- a/src/render/backends/gl/Qt3DSOpenGLExtensions.h +++ b/src/render/backends/gl/Qt3DSOpenGLExtensions.h @@ -134,7 +134,7 @@ class Qt3DSOpenGLES2Extensions : public Qt3DSOpenGLExtensions public: Qt3DSOpenGLES2Extensions(); - // tesselation shader + // tessellation shader void glPatchParameteriEXT(GLenum pname, GLint value); // timer diff --git a/src/render/backends/gl/Qt3DSOpenGLUtil.h b/src/render/backends/gl/Qt3DSOpenGLUtil.h index 32f7dad..47f4230 100644 --- a/src/render/backends/gl/Qt3DSOpenGLUtil.h +++ b/src/render/backends/gl/Qt3DSOpenGLUtil.h @@ -1757,7 +1757,7 @@ namespace render { return NVRenderClearFlags(retval); } - static GLenum fromDrawModeToGL(NVRenderDrawMode::Enum value, bool inTesselationSupported) + static GLenum fromDrawModeToGL(NVRenderDrawMode::Enum value, bool inTessellationSupported) { switch (value) { case NVRenderDrawMode::Points: @@ -1775,7 +1775,7 @@ namespace render { case NVRenderDrawMode::Triangles: return GL_TRIANGLES; case NVRenderDrawMode::Patches: - return (inTesselationSupported) ? GL_PATCHES : GL_TRIANGLES; + return (inTessellationSupported) ? GL_PATCHES : GL_TRIANGLES; default: break; } diff --git a/src/render/backends/gl/Qt3DSRenderBackendGL3.cpp b/src/render/backends/gl/Qt3DSRenderBackendGL3.cpp index e5caf5e..4e637da 100644 --- a/src/render/backends/gl/Qt3DSRenderBackendGL3.cpp +++ b/src/render/backends/gl/Qt3DSRenderBackendGL3.cpp @@ -43,10 +43,10 @@ #if defined(QT_OPENGL_ES) #define GL_CALL_TIMER_EXT(x) m_qt3dsExtensions->x; RENDER_LOG_ERROR_PARAMS(x); -#define GL_CALL_TESSELATION_EXT(x) m_qt3dsExtensions->x; RENDER_LOG_ERROR_PARAMS(x); +#define GL_CALL_TESSELLATION_EXT(x) m_qt3dsExtensions->x; RENDER_LOG_ERROR_PARAMS(x); #else #define GL_CALL_TIMER_EXT(x) m_timerExtension->x; RENDER_LOG_ERROR_PARAMS(x); -#define GL_CALL_TESSELATION_EXT(x) m_tessellationShader->x; RENDER_LOG_ERROR_PARAMS(x); +#define GL_CALL_TESSELLATION_EXT(x) m_tessellationShader->x; RENDER_LOG_ERROR_PARAMS(x); #define GL_CALL_MULTISAMPLE_EXT(x) m_multiSample->x; RENDER_LOG_ERROR_PARAMS(x); #endif @@ -408,9 +408,9 @@ namespace render { && m_pCurrentMiscState->m_PatchVertexCount != inputAssembler->m_PatchVertexCount) { m_pCurrentMiscState->m_PatchVertexCount = inputAssembler->m_PatchVertexCount; #if defined(QT_OPENGL_ES) - GL_CALL_TESSELATION_EXT(glPatchParameteriEXT(GL_PATCH_VERTICES, inputAssembler->m_PatchVertexCount)); + GL_CALL_TESSELLATION_EXT(glPatchParameteriEXT(GL_PATCH_VERTICES, inputAssembler->m_PatchVertexCount)); #else - GL_CALL_TESSELATION_EXT(glPatchParameteri(GL_PATCH_VERTICES, inputAssembler->m_PatchVertexCount)); + GL_CALL_TESSELLATION_EXT(glPatchParameteri(GL_PATCH_VERTICES, inputAssembler->m_PatchVertexCount)); #endif } diff --git a/src/runtimerender/Qt3DSRenderCustomMaterialShaderGenerator.cpp b/src/runtimerender/Qt3DSRenderCustomMaterialShaderGenerator.cpp index 1391565..1b0b304 100644 --- a/src/runtimerender/Qt3DSRenderCustomMaterialShaderGenerator.cpp +++ b/src/runtimerender/Qt3DSRenderCustomMaterialShaderGenerator.cpp @@ -755,7 +755,8 @@ struct SShaderGenerator : public ICustomMaterialShaderGenerator NVRenderTexture2D *inDepthTexture, NVRenderTexture2D *inSSaoTexture, SImage *inLightProbe, SImage *inLightProbe2, QT3DSF32 inProbeHorizon, QT3DSF32 inProbeBright, QT3DSF32 inProbe2Window, QT3DSF32 inProbe2Pos, - QT3DSF32 inProbe2Fade, QT3DSF32 inProbeFOV) + QT3DSF32 inProbe2Fade, QT3DSF32 inProbeFOV, + const QT3DSVec2 &alphaOpRef) { ICustomMaterialSystem &theMaterialSystem(m_RenderContext.GetCustomMaterialSystem()); SShaderGeneratorGeneratedShader &theShader(GetShaderForProgram(inProgram)); @@ -858,12 +859,13 @@ struct SShaderGenerator : public ICustomMaterialShaderGenerator } void SetMaterialProperties(NVRenderShaderProgram &inProgram, - const SGraphObject &inMaterial, const QT3DSVec2 &inCameraVec, - const QT3DSMat44 &inModelViewProjection, - const QT3DSMat33 &inNormalMatrix, - const QT3DSMat44 &inGlobalTransform, - SRenderableImage *inFirstImage, QT3DSF32 inOpacity, - SLayerGlobalRenderProperties inRenderProperties) override + const SGraphObject &inMaterial, const QT3DSVec2 &inCameraVec, + const QT3DSMat44 &inModelViewProjection, + const QT3DSMat33 &inNormalMatrix, + const QT3DSMat44 &inGlobalTransform, + SRenderableImage *inFirstImage, QT3DSF32 inOpacity, + SLayerGlobalRenderProperties inRenderProperties, + const QT3DSVec2 &alphaOpRef) override { const SCustomMaterial &theCustomMaterial( reinterpret_cast<const SCustomMaterial &>(inMaterial)); @@ -880,7 +882,8 @@ struct SShaderGenerator : public ICustomMaterialShaderGenerator inRenderProperties.m_LightProbe, inRenderProperties.m_LightProbe2, inRenderProperties.m_ProbeHorizon, inRenderProperties.m_ProbeBright, inRenderProperties.m_Probe2Window, inRenderProperties.m_Probe2Pos, - inRenderProperties.m_Probe2Fade, inRenderProperties.m_ProbeFOV); + inRenderProperties.m_Probe2Fade, inRenderProperties.m_ProbeFOV, + alphaOpRef); } void GenerateLightmapIndirectFunc(IShaderStageGenerator &inFragmentShader, @@ -1207,7 +1210,8 @@ struct SShaderGenerator : public ICustomMaterialShaderGenerator m_GeneratedShaderString.assign(nonNull(inShaderPrefix)); m_GeneratedShaderString.append(inCustomMaterialName); SShaderDefaultMaterialKey theKey(Key()); - theKey.ToString(m_GeneratedShaderString, m_DefaultMaterialShaderKeyProperties); + theKey.ToString(m_GeneratedShaderString, m_DefaultMaterialShaderKeyProperties, + SShaderDefaultMaterialKeyProperties::DefaultKey); // Add hash of the shader code to the cache key so that custom materials with the same name // can have different shaders and the shaders are recompiled when the code is changed diff --git a/src/runtimerender/Qt3DSRenderCustomMaterialShaderGenerator.h b/src/runtimerender/Qt3DSRenderCustomMaterialShaderGenerator.h index 44e2c06..29c31ff 100644 --- a/src/runtimerender/Qt3DSRenderCustomMaterialShaderGenerator.h +++ b/src/runtimerender/Qt3DSRenderCustomMaterialShaderGenerator.h @@ -58,7 +58,8 @@ namespace render { const QT3DSVec2 &inCameraVec, const QT3DSMat44 &inModelViewProjection, const QT3DSMat33 &inNormalMatrix, const QT3DSMat44 &inGlobalTransform, SRenderableImage *inFirstImage, QT3DSF32 inOpacity, - SLayerGlobalRenderProperties inRenderProperties) override = 0; + SLayerGlobalRenderProperties inRenderProperties, + const QT3DSVec2 &alphaOpRef) override = 0; static ICustomMaterialShaderGenerator & CreateCustomMaterialShaderGenerator(IQt3DSRenderContext &inRenderContext); diff --git a/src/runtimerender/Qt3DSRenderCustomMaterialSystem.cpp b/src/runtimerender/Qt3DSRenderCustomMaterialSystem.cpp index 470014f..62d9805 100644 --- a/src/runtimerender/Qt3DSRenderCustomMaterialSystem.cpp +++ b/src/runtimerender/Qt3DSRenderCustomMaterialSystem.cpp @@ -662,8 +662,8 @@ typedef eastl::pair<CRegisteredString, NVScopedRefCounted<SCustomMaterialTexture */ struct SCustomMaterialsTessellationProperties { - NVRenderCachedShaderProperty<QT3DSF32> m_EdgeTessLevel; ///< tesselation value for the edges - NVRenderCachedShaderProperty<QT3DSF32> m_InsideTessLevel; ///< tesselation value for the inside + NVRenderCachedShaderProperty<QT3DSF32> m_EdgeTessLevel; ///< tessellation value for the edges + NVRenderCachedShaderProperty<QT3DSF32> m_InsideTessLevel; ///< tessellation value for the inside NVRenderCachedShaderProperty<QT3DSF32> m_PhongBlend; ///< blending between linear and phong component NVRenderCachedShaderProperty<QT3DSVec2> @@ -1684,7 +1684,7 @@ struct SMaterialSystem : public ICustomMaterialSystem *inShader.m_Shader, inRenderContext.m_Material, QT3DSVec2(1.0, 1.0), inRenderContext.m_ModelViewProjection, inRenderContext.m_NormalMatrix, inRenderContext.m_ModelMatrix, inRenderContext.m_FirstImage, inRenderContext.m_Opacity, - GetLayerGlobalRenderProperties(inRenderContext)); + GetLayerGlobalRenderProperties(inRenderContext), QT3DSVec2()); NVRenderContext &theContext(m_Context->GetRenderContext()); theContext.SetRenderTarget(inFrameBuffer); @@ -1702,7 +1702,7 @@ struct SMaterialSystem : public ICustomMaterialSystem // for this frame NVRenderDrawMode::Enum theDrawMode = inAssembler.GetPrimitiveType(); - // tesselation + // tessellation if (inRenderContext.m_Subset.m_PrimitiveType == NVRenderDrawMode::Patches) { QT3DSVec2 camProps(inRenderContext.m_Camera.m_ClipNear, inRenderContext.m_Camera.m_ClipFar); diff --git a/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.cpp b/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.cpp index cf276e7..4a1f6e3 100644 --- a/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.cpp +++ b/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.cpp @@ -170,6 +170,7 @@ struct SShaderGeneratorGeneratedShader NVRenderCachedShaderProperty<NVRenderTexture2D *> m_LightProbe2; NVRenderCachedShaderProperty<QT3DSVec4> m_LightProbe2Props; NVRenderCachedShaderProperty<QT3DSVec2> m_LightProbe2Size; + NVRenderCachedShaderProperty<QT3DSVec2> m_alphaTestOp; NVRenderCachedShaderBuffer<qt3ds::render::NVRenderShaderConstantBuffer *> m_AoShadowParams; NVRenderCachedShaderBuffer<qt3ds::render::NVRenderShaderConstantBuffer *> m_LightsBuffer; @@ -216,9 +217,10 @@ struct SShaderGeneratorGeneratedShader , m_LightProbe2("light_probe2", inShader) , m_LightProbe2Props("light_probe2_props", inShader) , m_LightProbe2Size("light_probe2_size", inShader) + , m_alphaTestOp("alphaOpRef", inShader) , m_AoShadowParams("cbAoShadow", inShader) , m_LightsBuffer("cbBufferLights", inShader) - , m_lightConstantProperties(NULL) + , m_lightConstantProperties(nullptr) , m_Images(inContext.GetAllocator(), "SShaderGeneratorGeneratedShader::m_Images") , m_Lights(inContext.GetAllocator(), "SShaderGeneratorGeneratedShader::m_Lights") , m_ShadowMaps(inContext.GetAllocator(), "SShaderGeneratorGeneratedShader::m_ShadowMaps") @@ -316,11 +318,11 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator SShaderGenerator(IQt3DSRenderContext &inRc) : m_RenderContext(inRc) , m_ProgramGenerator(m_RenderContext.GetShaderProgramGenerator()) - , m_CurrentMaterial(NULL) - , m_CurrentKey(NULL) - , m_ShadowMapManager(NULL) - , m_CurrentPipeline(NULL) - , m_FirstImage(NULL) + , m_CurrentMaterial(nullptr) + , m_CurrentKey(nullptr) + , m_ShadowMapManager(nullptr) + , m_CurrentPipeline(nullptr) + , m_FirstImage(nullptr) , m_LightsAsSeparateUniforms(false) , m_ProgramToShaderMap(inRc.GetAllocator(), "m_ProgramToShaderMap") , m_ConstantBuffers(inRc.GetAllocator(), "m_ConstantBuffers") @@ -546,7 +548,7 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator void AddTranslucencyIrradiance(IShaderStageGenerator &infragmentShader, SRenderableImage *image, TStrType inLightPrefix, bool areaLight) { - if (image == NULL) + if (image == nullptr) return; addFunction(infragmentShader, "diffuseReflectionWrapBSDF"); @@ -792,7 +794,7 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator // we only create if if we have lights if (!inLightCount || !theContext.GetConstantBufferSupport()) - return NULL; + return nullptr; CRegisteredString theName = theContext.GetStringTable().RegisterStr("cbBufferLights"); NVRenderConstantBuffer *pCB = theContext.GetConstantBuffer(theName); @@ -807,7 +809,7 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator (sizeof(SLightSourceShader) * QT3DS_MAX_NUM_LIGHTS) + (4 * sizeof(QT3DSI32)), cBuffer); if (!pCB) { QT3DS_ASSERT(false); - return NULL; + return nullptr; } // init first set memset(&s[0], 0x0, sizeof(SLightSourceShader)); @@ -888,10 +890,10 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator { // vertex displacement QT3DSU32 imageIdx = 0; - SRenderableImage *displacementImage = NULL; + SRenderableImage *displacementImage = nullptr; QT3DSU32 displacementImageIdx = 0; - for (SRenderableImage *img = m_FirstImage; img != NULL; + for (SRenderableImage *img = m_FirstImage; img != nullptr; img = img->m_NextImage, ++imageIdx) { if (img->m_MapType == ImageMapTypes::Displacement) { displacementImage = img; @@ -910,7 +912,7 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator bool vertexColorsEnabled = Material().IsVertexColorsEnabled(); bool hasLighting = Material().HasLighting(); - bool hasImage = m_FirstImage != NULL; + bool hasImage = m_FirstImage != nullptr; bool hasIblProbe = m_DefaultMaterialShaderKeyProperties.m_HasIbl.GetValue(inKey); bool hasSpecMap = false; @@ -918,30 +920,30 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator bool hasEmissiveMap = false; bool hasLightmaps = false; // Pull the bump out as - SRenderableImage *bumpImage = NULL; + SRenderableImage *bumpImage = nullptr; QT3DSU32 imageIdx = 0; QT3DSU32 bumpImageIdx = 0; - SRenderableImage *specularAmountImage = NULL; + SRenderableImage *specularAmountImage = nullptr; QT3DSU32 specularAmountImageIdx = 0; - SRenderableImage *roughnessImage = NULL; + SRenderableImage *roughnessImage = nullptr; QT3DSU32 roughnessImageIdx = 0; // normal mapping - SRenderableImage *normalImage = NULL; + SRenderableImage *normalImage = nullptr; QT3DSU32 normalImageIdx = 0; // translucency map - SRenderableImage *translucencyImage = NULL; + SRenderableImage *translucencyImage = nullptr; QT3DSU32 translucencyImageIdx = 0; // lightmaps - SRenderableImage *lightmapIndirectImage = NULL; + SRenderableImage *lightmapIndirectImage = nullptr; QT3DSU32 lightmapIndirectImageIdx = 0; - SRenderableImage *lightmapRadiosityImage = NULL; + SRenderableImage *lightmapRadiosityImage = nullptr; QT3DSU32 lightmapRadiosityImageIdx = 0; - SRenderableImage *lightmapShadowImage = NULL; + SRenderableImage *lightmapShadowImage = nullptr; QT3DSU32 lightmapShadowImageIdx = 0; const bool supportStandardDerivatives = m_RenderContext.GetRenderContext().IsStandardDerivativesSupported(); - for (SRenderableImage *img = m_FirstImage; img != NULL; + for (SRenderableImage *img = m_FirstImage; img != nullptr; img = img->m_NextImage, ++imageIdx) { hasSpecMap = img->m_MapType == ImageMapTypes::Specular; if (img->m_MapType == ImageMapTypes::Bump) { @@ -983,6 +985,8 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator bool enableSSDO = false; bool enableShadowMaps = false; bool enableBumpNormal = normalImage || bumpImage; + bool enableAlphaTest + = m_DefaultMaterialShaderKeyProperties.m_AlphaTestEnabled.GetValue(inKey); for (QT3DSU32 idx = 0; idx < FeatureSet().size(); ++idx) { eastl::string name(FeatureSet()[idx].m_Name.c_str()); @@ -1051,7 +1055,7 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator fragmentShader.Append("\tvec3 vertColor = vec3(1.0);"); // You do bump or normal mapping but not both - if (bumpImage != NULL) { + if (bumpImage != nullptr) { GenerateImageUVCoordinates(bumpImageIdx, *bumpImage); fragmentShader.AddUniform("bumpAmount", "float"); @@ -1065,7 +1069,7 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator fragmentShader << "\tbinormal = normalize(cross(world_normal, tangent) );\n"; fragmentShader << "\ttangent = normalize(cross(binormal, world_normal) );\n"; - } else if (normalImage != NULL) { + } else if (normalImage != nullptr) { GenerateImageUVCoordinates(normalImageIdx, *normalImage); fragmentShader.AddInclude("defaultMaterialFileNormalTexture.glsllib"); @@ -1098,7 +1102,7 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator fragmentShader.AddUniform("material_properties", "vec4"); } - if (lightmapIndirectImage != NULL) { + if (lightmapIndirectImage != nullptr) { GenerateImageUVCoordinates(lightmapIndirectImageIdx, *lightmapIndirectImage, 1); fragmentShader << "\tvec4 indirect_light = texture2D( " << m_ImageSampler << ", " << m_ImageFragCoords << ");" << Endl; @@ -1110,7 +1114,7 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator } } - if (lightmapRadiosityImage != NULL) { + if (lightmapRadiosityImage != nullptr) { GenerateImageUVCoordinates(lightmapRadiosityImageIdx, *lightmapRadiosityImage, 1); fragmentShader << "\tvec4 direct_light = texture2D( " << m_ImageSampler << ", " << m_ImageFragCoords << ");" << Endl; @@ -1122,7 +1126,7 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator } } - if (translucencyImage != NULL) { + if (translucencyImage != nullptr) { fragmentShader.AddUniform("translucentFalloff", "float"); fragmentShader.AddUniform("diffuseLightWrap", "float"); @@ -1478,6 +1482,14 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator } } + // Alpha test + if (enableAlphaTest) { + fragmentShader.AddUniform("alphaOpRef", "vec2"); + fragmentShader.Append( + "\tif (dot(vec2(global_diffuse_light.a, 1.0), alphaOpRef) <= 0.0)\n" + "\t\tdiscard;"); + } + if (hasEmissiveMap) { fragmentShader.Append("\tglobal_diffuse_light.rgb += global_emission.rgb;"); } @@ -1498,6 +1510,343 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator } } + // generate default material shader for depth only pass + NVRenderShaderProgram *GenerateDepthPassShader( + const SGraphObject &inMaterial, SShaderDefaultMaterialKey inShaderDescription, + IShaderStageGenerator &inVertexPipeline, TShaderFeatureSet inFeatureSet, + SRenderableImage *inFirstImage, bool inHasTransparency, + const char8_t *inVertexPipelineName, const char8_t *inCustomMaterialName = "") override + { + QT3DS_ASSERT(inMaterial.m_Type == GraphObjectTypes::DefaultMaterial); + m_CurrentMaterial = static_cast<const SDefaultMaterial *>(&inMaterial); + m_CurrentKey = &inShaderDescription; + m_CurrentPipeline = static_cast<IDefaultMaterialVertexPipeline *>(&inVertexPipeline); + m_CurrentFeatureSet = inFeatureSet; + m_FirstImage = inFirstImage; + m_HasTransparency = inHasTransparency; + + ProgramGenerator().BeginProgram(); + + bool enableAlphaTest = m_DefaultMaterialShaderKeyProperties + .m_AlphaTestEnabled.GetValue(inShaderDescription); + + QT3DS_ASSERT(m_FirstImage != nullptr); + if (!enableAlphaTest) + return nullptr; + QT3DS_ASSERT(enableAlphaTest); + + m_GeneratedShaderString.clear(); + m_GeneratedShaderString.assign(nonNull(inVertexPipelineName)); + m_GeneratedShaderString.append("depth--"); + + SShaderDefaultMaterialKey theKey(Key()); + theKey.ToString(m_GeneratedShaderString, m_DefaultMaterialShaderKeyProperties, + SShaderDefaultMaterialKeyProperties::DepthKey); + + m_LightsAsSeparateUniforms = !m_RenderContext.GetRenderContext().GetConstantBufferSupport(); + + VertexGenerator().BeginFragmentGeneration(); + IShaderStageGenerator &fragmentShader(FragmentGenerator()); + IDefaultMaterialVertexPipeline &vertexShader(VertexGenerator()); + + vertexShader.AddIncoming("attr_pos", "vec3"); + vertexShader.AddUniform("model_view_projection", "mat4"); + vertexShader.Append("void main() {"); + vertexShader.Append("\tgl_Position = model_view_projection * vec4( attr_pos, 1.0 );"); + vertexShader.Append("\tvec3 uTransform;"); + vertexShader.Append("\tvec3 vTransform;"); + + fragmentShader << "\tfloat global_opacity = object_opacity;" << Endl; + + fragmentShader.Append("\tvec4 texture_color;"); + QT3DSU32 idx = 0; + for (SRenderableImage *image = m_FirstImage; image; image = image->m_NextImage, ++idx) { + // Various maps are handled on a different locations + if (image->m_MapType == ImageMapTypes::Bump + || image->m_MapType == ImageMapTypes::Normal + || image->m_MapType == ImageMapTypes::Displacement + || image->m_MapType == ImageMapTypes::SpecularAmountMap + || image->m_MapType == ImageMapTypes::Roughness + || image->m_MapType == ImageMapTypes::Translucency + || image->m_MapType == ImageMapTypes::LightmapIndirect + || image->m_MapType == ImageMapTypes::LightmapRadiosity + || image->m_MapType == ImageMapTypes::Emissive) { + continue; + } + + eastl::basic_string<char8_t> texSwizzle, lookupSwizzle, texLodStr; + + GenerateImageUVCoordinates(idx, *image, 0); + + GenerateTextureSwizzle( + image->m_Image.m_TextureData.m_Texture->GetTextureSwizzleMode(), texSwizzle, + lookupSwizzle); + + if (texLodStr.empty()) { + fragmentShader << "\ttexture_color" << texSwizzle.c_str() << " = texture2D( " + << m_ImageSampler << ", " << m_ImageFragCoords << ")" + << lookupSwizzle.c_str() << ";" << Endl; + } else { + fragmentShader << "\ttexture_color" << texSwizzle.c_str() << "= textureLod( " + << m_ImageSampler << ", " << m_ImageFragCoords << ", " + << texLodStr.c_str() << " )" << lookupSwizzle.c_str() << ";" + << Endl; + } + + switch (image->m_MapType) { + case ImageMapTypes::Diffuse: // assume images are premultiplied. + case ImageMapTypes::LightmapShadow: + case ImageMapTypes::Specular: + case ImageMapTypes::Opacity: + fragmentShader.Append("\tglobal_opacity *= texture_color.a;"); + break; + default: + break; + } + } + + fragmentShader.AddUniform("alphaOpRef", "vec2"); + fragmentShader.Append("\tif (dot(vec2(global_opacity, 1.0), alphaOpRef) <= 0.0)\n" + "\t\tdiscard;"); + fragmentShader.Append("\tfragOutput = vec4(0.0);"); + fragmentShader.Append("}"); + vertexShader.Append("}"); + + return ProgramGenerator().CompileGeneratedShader(m_GeneratedShaderString.c_str(), + SShaderCacheProgramFlags(), FeatureSet()); + + } + + // generate default material shader cube depth shader + NVRenderShaderProgram *GenerateCubeDepthShader( + const SGraphObject &inMaterial, SShaderDefaultMaterialKey inShaderDescription, + IShaderStageGenerator &inVertexPipeline, TShaderFeatureSet inFeatureSet, + SRenderableImage *inFirstImage, bool inHasTransparency, + const char8_t *inVertexPipelineName, const char8_t *inCustomMaterialName = "") override + { + QT3DS_ASSERT(inMaterial.m_Type == GraphObjectTypes::DefaultMaterial); + m_CurrentMaterial = static_cast<const SDefaultMaterial *>(&inMaterial); + m_CurrentKey = &inShaderDescription; + m_CurrentPipeline = static_cast<IDefaultMaterialVertexPipeline *>(&inVertexPipeline); + m_CurrentFeatureSet = inFeatureSet; + m_FirstImage = inFirstImage; + m_HasTransparency = inHasTransparency; + + ProgramGenerator().BeginProgram(); + + bool enableAlphaTest = m_DefaultMaterialShaderKeyProperties + .m_AlphaTestEnabled.GetValue(inShaderDescription); + + QT3DS_ASSERT(m_FirstImage != nullptr); + if (!enableAlphaTest) + return nullptr; + QT3DS_ASSERT(enableAlphaTest); + + m_GeneratedShaderString.clear(); + m_GeneratedShaderString.assign(nonNull(inVertexPipelineName)); + m_GeneratedShaderString.append("shadowcube--"); + + SShaderDefaultMaterialKey theKey(Key()); + theKey.ToString(m_GeneratedShaderString, m_DefaultMaterialShaderKeyProperties, + SShaderDefaultMaterialKeyProperties::DepthKey); + + m_LightsAsSeparateUniforms = !m_RenderContext.GetRenderContext().GetConstantBufferSupport(); + + VertexGenerator().BeginFragmentGeneration(); + IShaderStageGenerator &fragmentShader(FragmentGenerator()); + IDefaultMaterialVertexPipeline &vertexShader(VertexGenerator()); + + vertexShader.AddIncoming("attr_pos", "vec3"); + vertexShader.AddUniform("model_matrix", "mat4"); + vertexShader.AddUniform("model_view_projection", "mat4"); + vertexShader.AddOutgoing("raw_pos", "vec4"); + vertexShader.AddOutgoing("world_pos", "vec4"); + + vertexShader.Append("void main() {"); + vertexShader.Append("\tvec3 uTransform;"); + vertexShader.Append("\tvec3 vTransform;"); + vertexShader.Append("\tworld_pos = model_matrix * vec4( attr_pos, 1.0 );"); + vertexShader.Append("\tworld_pos /= world_pos.w;"); + vertexShader.Append("\tgl_Position = model_view_projection * vec4( attr_pos, 1.0 );"); + vertexShader.Append("\traw_pos = vec4( attr_pos, 1.0 );"); + + fragmentShader << "\tfloat global_opacity = object_opacity;" << Endl; + + fragmentShader.Append("\tvec4 texture_color;"); + QT3DSU32 idx = 0; + for (SRenderableImage *image = m_FirstImage; image; image = image->m_NextImage, ++idx) { + // Various maps are handled on different locations + if (image->m_MapType == ImageMapTypes::Bump + || image->m_MapType == ImageMapTypes::Normal + || image->m_MapType == ImageMapTypes::Displacement + || image->m_MapType == ImageMapTypes::SpecularAmountMap + || image->m_MapType == ImageMapTypes::Roughness + || image->m_MapType == ImageMapTypes::Translucency + || image->m_MapType == ImageMapTypes::LightmapIndirect + || image->m_MapType == ImageMapTypes::LightmapRadiosity + || image->m_MapType == ImageMapTypes::Emissive) { + continue; + } + + eastl::basic_string<char8_t> texSwizzle, lookupSwizzle, texLodStr; + + GenerateImageUVCoordinates(idx, *image, 0); + + GenerateTextureSwizzle( + image->m_Image.m_TextureData.m_Texture->GetTextureSwizzleMode(), texSwizzle, + lookupSwizzle); + + if (texLodStr.empty()) { + fragmentShader << "\ttexture_color" << texSwizzle.c_str() << " = texture2D( " + << m_ImageSampler << ", " << m_ImageFragCoords << ")" + << lookupSwizzle.c_str() << ";" << Endl; + } else { + fragmentShader << "\ttexture_color" << texSwizzle.c_str() << "= textureLod( " + << m_ImageSampler << ", " << m_ImageFragCoords << ", " + << texLodStr.c_str() << " )" << lookupSwizzle.c_str() << ";" + << Endl; + } + + switch (image->m_MapType) { + case ImageMapTypes::Diffuse: // assume images are premultiplied. + case ImageMapTypes::LightmapShadow: + case ImageMapTypes::Specular: + case ImageMapTypes::Opacity: + fragmentShader.Append("\tglobal_opacity *= texture_color.a;"); + break; + default: + break; + } + } + + fragmentShader.AddUniform("camera_position", "vec3"); + fragmentShader.AddUniform("camera_properties", "vec2"); + fragmentShader.Append("\tvec3 camPos = vec3(camera_position.x, camera_position.y, " + "-camera_position.z);"); + fragmentShader.Append("\tfloat dist = length(world_pos.xyz - camPos);"); + fragmentShader.Append("\tdist = max((dist - 1.0) / (camera_properties.y - 1.0), 0.0);"); + fragmentShader.AddUniform("alphaOpRef", "vec2"); + fragmentShader.Append("\tif (dot(vec2(global_opacity, 1.0), alphaOpRef) <= 0.0)\n" + "\t\tdist = 1.0;"); + fragmentShader.Append("\tfragOutput = vec4(dist);"); + fragmentShader.Append("}"); + + vertexShader.Append("}"); + + return ProgramGenerator().CompileGeneratedShader(m_GeneratedShaderString.c_str(), + SShaderCacheProgramFlags(), FeatureSet()); + } + + // generate default material shader orthographic depth shader + NVRenderShaderProgram *GenerateOrthoDepthShader( + const SGraphObject &inMaterial, SShaderDefaultMaterialKey inShaderDescription, + IShaderStageGenerator &inVertexPipeline, TShaderFeatureSet inFeatureSet, + SRenderableImage *inFirstImage, bool inHasTransparency, + const char8_t *inVertexPipelineName, const char8_t *inCustomMaterialName = "") override + { + QT3DS_ASSERT(inMaterial.m_Type == GraphObjectTypes::DefaultMaterial); + m_CurrentMaterial = static_cast<const SDefaultMaterial *>(&inMaterial); + m_CurrentKey = &inShaderDescription; + m_CurrentPipeline = static_cast<IDefaultMaterialVertexPipeline *>(&inVertexPipeline); + m_CurrentFeatureSet = inFeatureSet; + m_FirstImage = inFirstImage; + m_HasTransparency = inHasTransparency; + + ProgramGenerator().BeginProgram(); + + bool enableAlphaTest = m_DefaultMaterialShaderKeyProperties + .m_AlphaTestEnabled.GetValue(inShaderDescription); + + QT3DS_ASSERT(m_FirstImage != nullptr); + if (!enableAlphaTest) + return nullptr; + QT3DS_ASSERT(enableAlphaTest); + + m_GeneratedShaderString.clear(); + m_GeneratedShaderString.assign(nonNull(inVertexPipelineName)); + m_GeneratedShaderString.append("shadowmap--"); + + SShaderDefaultMaterialKey theKey(Key()); + theKey.ToString(m_GeneratedShaderString, m_DefaultMaterialShaderKeyProperties, + SShaderDefaultMaterialKeyProperties::DepthKey); + + m_LightsAsSeparateUniforms = !m_RenderContext.GetRenderContext().GetConstantBufferSupport(); + + VertexGenerator().BeginFragmentGeneration(); + IShaderStageGenerator &fragmentShader(FragmentGenerator()); + IDefaultMaterialVertexPipeline &vertexShader(VertexGenerator()); + + vertexShader.AddIncoming("attr_pos", "vec3"); + vertexShader.AddUniform("model_view_projection", "mat4"); + vertexShader.AddOutgoing("outDepth", "vec3"); + + vertexShader.Append("void main() {"); + vertexShader.Append("\tvec3 uTransform;"); + vertexShader.Append("\tvec3 vTransform;"); + vertexShader.Append("\tgl_Position = model_view_projection * vec4( attr_pos, 1.0 );"); + vertexShader.Append("\toutDepth.x = gl_Position.z / gl_Position.w;"); + + fragmentShader << "\tfloat global_opacity = object_opacity;" << Endl; + + fragmentShader.Append("\tvec4 texture_color;"); + QT3DSU32 idx = 0; + for (SRenderableImage *image = m_FirstImage; image; image = image->m_NextImage, ++idx) { + // Various maps are handled on different locations + if (image->m_MapType == ImageMapTypes::Bump + || image->m_MapType == ImageMapTypes::Normal + || image->m_MapType == ImageMapTypes::Displacement + || image->m_MapType == ImageMapTypes::SpecularAmountMap + || image->m_MapType == ImageMapTypes::Roughness + || image->m_MapType == ImageMapTypes::Translucency + || image->m_MapType == ImageMapTypes::LightmapIndirect + || image->m_MapType == ImageMapTypes::LightmapRadiosity + || image->m_MapType == ImageMapTypes::Emissive) { + continue; + } + + eastl::basic_string<char8_t> texSwizzle, lookupSwizzle, texLodStr; + + GenerateImageUVCoordinates(idx, *image, 0); + + GenerateTextureSwizzle( + image->m_Image.m_TextureData.m_Texture->GetTextureSwizzleMode(), texSwizzle, + lookupSwizzle); + + if (texLodStr.empty()) { + fragmentShader << "\ttexture_color" << texSwizzle.c_str() << " = texture2D( " + << m_ImageSampler << ", " << m_ImageFragCoords << ")" + << lookupSwizzle.c_str() << ";" << Endl; + } else { + fragmentShader << "\ttexture_color" << texSwizzle.c_str() << "= textureLod( " + << m_ImageSampler << ", " << m_ImageFragCoords << ", " + << texLodStr.c_str() << " )" << lookupSwizzle.c_str() << ";" + << Endl; + } + + switch (image->m_MapType) { + case ImageMapTypes::Diffuse: // assume images are premultiplied. + case ImageMapTypes::LightmapShadow: + case ImageMapTypes::Specular: + case ImageMapTypes::Opacity: + fragmentShader.Append("\tglobal_opacity *= texture_color.a;"); + break; + default: + break; + } + } + + fragmentShader.AddUniform("alphaOpRef", "vec2"); + fragmentShader.Append("\tfloat depth = (outDepth.x + 1.0) * 0.5;"); + fragmentShader.Append("\tif (dot(vec2(global_opacity, 1.0), alphaOpRef) <= 0.0)\n" + "\t\tdepth = 1.0;"); + fragmentShader.Append("\tfragOutput = vec4(depth);"); + fragmentShader.Append("}"); + vertexShader.Append("}"); + + return ProgramGenerator().CompileGeneratedShader(m_GeneratedShaderString.c_str(), + SShaderCacheProgramFlags(), FeatureSet()); + } + NVRenderShaderProgram *GenerateMaterialShader(const char8_t *inShaderPrefix) { // build a string that allows us to print out the shader we are generating to the log. @@ -1509,7 +1858,8 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator m_GeneratedShaderString.assign(nonNull(inShaderPrefix)); SShaderDefaultMaterialKey theKey(Key()); - theKey.ToString(m_GeneratedShaderString, m_DefaultMaterialShaderKeyProperties); + theKey.ToString(m_GeneratedShaderString, m_DefaultMaterialShaderKeyProperties, + SShaderDefaultMaterialKeyProperties::DefaultKey); m_LightsAsSeparateUniforms = !m_RenderContext.GetRenderContext().GetConstantBufferSupport(); @@ -1545,7 +1895,7 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator { eastl::pair<TProgramToShaderMap::iterator, bool> inserter = m_ProgramToShaderMap.insert(eastl::make_pair( - &inProgram, NVScopedRefCounted<SShaderGeneratorGeneratedShader>(NULL))); + &inProgram, NVScopedRefCounted<SShaderGeneratorGeneratedShader>(nullptr))); if (inserter.second) { NVAllocatorCallback &alloc(m_RenderContext.GetRenderContext().GetAllocator()); inserter.first->second = QT3DS_NEW(alloc, SShaderGeneratorGeneratedShader)( @@ -1671,7 +2021,8 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator NVRenderTexture2D *inDepthTexture, NVRenderTexture2D *inSSaoTexture, SImage *inLightProbe, SImage *inLightProbe2, QT3DSF32 inProbeHorizon, QT3DSF32 inProbeBright, QT3DSF32 inProbe2Window, QT3DSF32 inProbe2Pos, - QT3DSF32 inProbe2Fade, QT3DSF32 inProbeFOV) + QT3DSF32 inProbe2Fade, QT3DSF32 inProbeFOV, + const QT3DSVec2 &alphaOpRef) { NVRenderContext &context(m_RenderContext.GetRenderContext()); @@ -1776,6 +2127,7 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator shader.m_MaterialSpecular.Set(material_specular); shader.m_CameraProperties.Set(inCameraVec); shader.m_FresnelPower.Set(inMaterial.m_FresnelPower); + shader.m_alphaTestOp.Set(alphaOpRef); if (context.GetConstantBufferSupport()) { NVRenderConstantBuffer *pLightCb = GetLightConstantBuffer(shader.m_Lights.size()); @@ -1885,12 +2237,13 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator context.SetBlendEquation(blendEqua); } void SetMaterialProperties(NVRenderShaderProgram &inProgram, - const SGraphObject &inMaterial, const QT3DSVec2 &inCameraVec, - const QT3DSMat44 &inModelViewProjection, - const QT3DSMat33 &inNormalMatrix, - const QT3DSMat44 &inGlobalTransform, - SRenderableImage *inFirstImage, QT3DSF32 inOpacity, - SLayerGlobalRenderProperties inRenderProperties) override + const SGraphObject &inMaterial, const QT3DSVec2 &inCameraVec, + const QT3DSMat44 &inModelViewProjection, + const QT3DSMat33 &inNormalMatrix, + const QT3DSMat44 &inGlobalTransform, + SRenderableImage *inFirstImage, QT3DSF32 inOpacity, + SLayerGlobalRenderProperties inRenderProperties, + const QT3DSVec2 &alphaOpRef) override { const SDefaultMaterial &theMaterial(static_cast<const SDefaultMaterial &>(inMaterial)); QT3DS_ASSERT(inMaterial.m_Type == GraphObjectTypes::DefaultMaterial); @@ -1905,7 +2258,8 @@ struct SShaderGenerator : public IDefaultMaterialShaderGenerator inRenderProperties.m_LightProbe, inRenderProperties.m_LightProbe2, inRenderProperties.m_ProbeHorizon, inRenderProperties.m_ProbeBright, inRenderProperties.m_Probe2Window, inRenderProperties.m_Probe2Pos, - inRenderProperties.m_Probe2Fade, inRenderProperties.m_ProbeFOV); + inRenderProperties.m_Probe2Fade, inRenderProperties.m_ProbeFOV, + alphaOpRef); } SLightConstantProperties<SShaderGeneratorGeneratedShader> *GetLightConstantProperties(SShaderGeneratorGeneratedShader &shader) diff --git a/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.h b/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.h index 7453e1d..871ab1b 100644 --- a/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.h +++ b/src/runtimerender/Qt3DSRenderDefaultMaterialShaderGenerator.h @@ -103,13 +103,35 @@ namespace render { NVDataRef<SLight *> inLights, SRenderableImage *inFirstImage, bool inHasTransparency, const char8_t *inVertexPipelineName, const char8_t *inCustomMaterialName = "") override = 0; + // generate default material shader for depth only pass + virtual NVRenderShaderProgram *GenerateDepthPassShader( + const SGraphObject &inMaterial, SShaderDefaultMaterialKey inShaderDescription, + IShaderStageGenerator &inVertexPipeline, TShaderFeatureSet inFeatureSet, + SRenderableImage *inFirstImage, bool inHasTransparency, + const char8_t *inVertexPipelineName, const char8_t *inCustomMaterialName = "") = 0; + + // generate default material shader cube depth shader + virtual NVRenderShaderProgram *GenerateCubeDepthShader( + const SGraphObject &inMaterial, SShaderDefaultMaterialKey inShaderDescription, + IShaderStageGenerator &inVertexPipeline, TShaderFeatureSet inFeatureSet, + SRenderableImage *inFirstImage, bool inHasTransparency, + const char8_t *inVertexPipelineName, const char8_t *inCustomMaterialName = "") = 0; + + // generate default material shader orthographic depth shader + virtual NVRenderShaderProgram *GenerateOrthoDepthShader( + const SGraphObject &inMaterial, SShaderDefaultMaterialKey inShaderDescription, + IShaderStageGenerator &inVertexPipeline, TShaderFeatureSet inFeatureSet, + SRenderableImage *inFirstImage, bool inHasTransparency, + const char8_t *inVertexPipelineName, const char8_t *inCustomMaterialName = "") = 0; + // Also sets the blend function on the render context. virtual void SetMaterialProperties(NVRenderShaderProgram &inProgram, const SGraphObject &inMaterial, const QT3DSVec2 &inCameraVec, const QT3DSMat44 &inModelViewProjection, const QT3DSMat33 &inNormalMatrix, const QT3DSMat44 &inGlobalTransform, SRenderableImage *inFirstImage, QT3DSF32 inOpacity, - SLayerGlobalRenderProperties inRenderProperties) override = 0; + SLayerGlobalRenderProperties inRenderProperties, + const QT3DSVec2 &alphaOpRef) override = 0; static IDefaultMaterialShaderGenerator & CreateDefaultMaterialShaderGenerator(IQt3DSRenderContext &inRenderContext); diff --git a/src/runtimerender/Qt3DSRenderImageTextureData.h b/src/runtimerender/Qt3DSRenderImageTextureData.h index aaa73d7..a029451 100644 --- a/src/runtimerender/Qt3DSRenderImageTextureData.h +++ b/src/runtimerender/Qt3DSRenderImageTextureData.h @@ -48,6 +48,7 @@ namespace render { HasTransparency = 1, InvertUVCoords = 1 << 1, PreMultiplied = 1 << 2, + HasOpaquePixels = 1 << 3, }; }; @@ -55,7 +56,7 @@ namespace render { { bool HasTransparency() const { - return this->operator&(ImageTextureFlagValues::HasTransparency); + return *this & ImageTextureFlagValues::HasTransparency; } void SetHasTransparency(bool inValue) { @@ -64,7 +65,7 @@ namespace render { bool IsInvertUVCoords() const { - return this->operator&(ImageTextureFlagValues::InvertUVCoords); + return *this & ImageTextureFlagValues::InvertUVCoords; } void SetInvertUVCoords(bool inValue) { @@ -73,12 +74,21 @@ namespace render { bool IsPreMultiplied() const { - return this->operator&(ImageTextureFlagValues::PreMultiplied); + return *this & ImageTextureFlagValues::PreMultiplied; } void SetPreMultiplied(bool inValue) { clearOrSet(inValue, ImageTextureFlagValues::PreMultiplied); } + + bool HasOpaquePixels() const + { + return *this & ImageTextureFlagValues::HasOpaquePixels; + } + void setHasOpaquePixels(bool inValue) + { + clearOrSet(inValue, ImageTextureFlagValues::HasOpaquePixels); + } }; struct SImageTextureData diff --git a/src/runtimerender/Qt3DSRenderMaterialShaderGenerator.h b/src/runtimerender/Qt3DSRenderMaterialShaderGenerator.h index e8b9880..88858bd 100644 --- a/src/runtimerender/Qt3DSRenderMaterialShaderGenerator.h +++ b/src/runtimerender/Qt3DSRenderMaterialShaderGenerator.h @@ -144,7 +144,8 @@ namespace render { const QT3DSVec2 &inCameraVec, const QT3DSMat44 &inModelViewProjection, const QT3DSMat33 &inNormalMatrix, const QT3DSMat44 &inGlobalTransform, SRenderableImage *inFirstImage, QT3DSF32 inOpacity, - SLayerGlobalRenderProperties inRenderProperties) = 0; + SLayerGlobalRenderProperties inRenderProperties, + const QT3DSVec2 &alphaOpRef) = 0; }; } } diff --git a/src/runtimerender/Qt3DSRenderPathManager.cpp b/src/runtimerender/Qt3DSRenderPathManager.cpp index 5b2c51d..b845ead 100644 --- a/src/runtimerender/Qt3DSRenderPathManager.cpp +++ b/src/runtimerender/Qt3DSRenderPathManager.cpp @@ -1433,7 +1433,7 @@ struct SPathManager : public IPathManager inShader, inRenderContext.m_Material, inRenderContext.m_CameraVec, inRenderContext.m_ModelViewProjection, inRenderContext.m_NormalMatrix, inRenderContext.m_Path.m_GlobalTransform, inRenderContext.m_FirstImage, - inRenderContext.m_Opacity, inRenderProperties); + inRenderContext.m_Opacity, inRenderProperties, QT3DSVec2()); } void DoRenderGeometryPath(SPathGeneratedShader &inShader, SPathRenderContext &inRenderContext, diff --git a/src/runtimerender/Qt3DSRenderShaderKeys.h b/src/runtimerender/Qt3DSRenderShaderKeys.h index 5d02e41..298c198 100644 --- a/src/runtimerender/Qt3DSRenderShaderKeys.h +++ b/src/runtimerender/Qt3DSRenderShaderKeys.h @@ -558,6 +558,12 @@ namespace render { ImageMapCount }; + enum KeyMode + { + DefaultKey, + DepthKey, + }; + SShaderKeyBoolean m_HasLighting; SShaderKeyBoolean m_HasIbl; SShaderKeyUnsigned<3> m_LightCount; @@ -566,6 +572,7 @@ namespace render { SShaderKeyBoolean m_LightShadowFlags[LightCount]; SShaderKeyBoolean m_SpecularEnabled; SShaderKeyBoolean m_FresnelEnabled; + SShaderKeyBoolean m_AlphaTestEnabled; SShaderKeyBoolean m_VertexColorsEnabled; SShaderKeySpecularModel m_SpecularModel; SShaderKeyImageMap m_ImageMaps[ImageMapCount]; @@ -580,6 +587,7 @@ namespace render { , m_LightCount("lightCount") , m_SpecularEnabled("specularEnabled") , m_FresnelEnabled("fresnelEnabled") + , m_AlphaTestEnabled("alphaTestEnabled") , m_VertexColorsEnabled("vertexColorsEnabled") , m_SpecularModel("specularModel") , m_TessellationMode("tessellationMode") @@ -642,38 +650,50 @@ namespace render { SetPropertyOffsets(); } + bool isDepthKeyImage(QT3DSU32 idx) const + { + if (idx == DiffuseMap0 || idx == DiffuseMap1 || idx == DiffuseMap2 || idx == SpecularMap + || idx == OpacityMap || idx == LightmapShadow) { + return true; + } + return false; + } + template <typename TVisitor> - void VisitProperties(TVisitor &inVisitor) + void VisitProperties(TVisitor &inVisitor, KeyMode mode) { - inVisitor.Visit(m_HasLighting); - inVisitor.Visit(m_HasIbl); - inVisitor.Visit(m_LightCount); + if (mode == DefaultKey) { + inVisitor.Visit(m_HasLighting); + inVisitor.Visit(m_HasIbl); + inVisitor.Visit(m_LightCount); - for (QT3DSU32 idx = 0, end = LightCount; idx < end; ++idx) { - inVisitor.Visit(m_LightFlags[idx]); - } + for (QT3DSU32 idx = 0, end = LightCount; idx < end; ++idx) + inVisitor.Visit(m_LightFlags[idx]); - for (QT3DSU32 idx = 0, end = LightCount; idx < end; ++idx) { - inVisitor.Visit(m_LightAreaFlags[idx]); - } + for (QT3DSU32 idx = 0, end = LightCount; idx < end; ++idx) + inVisitor.Visit(m_LightAreaFlags[idx]); - for (QT3DSU32 idx = 0, end = LightCount; idx < end; ++idx) { - inVisitor.Visit(m_LightShadowFlags[idx]); - } + for (QT3DSU32 idx = 0, end = LightCount; idx < end; ++idx) + inVisitor.Visit(m_LightShadowFlags[idx]); - inVisitor.Visit(m_SpecularEnabled); - inVisitor.Visit(m_FresnelEnabled); - inVisitor.Visit(m_VertexColorsEnabled); - inVisitor.Visit(m_SpecularModel); + inVisitor.Visit(m_SpecularEnabled); + inVisitor.Visit(m_FresnelEnabled); + inVisitor.Visit(m_VertexColorsEnabled); + inVisitor.Visit(m_SpecularModel); + } + inVisitor.Visit(m_AlphaTestEnabled); for (QT3DSU32 idx = 0, end = ImageMapCount; idx < end; ++idx) { - inVisitor.Visit(m_ImageMaps[idx]); - inVisitor.Visit(m_TextureSwizzle[idx]); + if (mode == DefaultKey || isDepthKeyImage(idx)) { + inVisitor.Visit(m_ImageMaps[idx]); + inVisitor.Visit(m_TextureSwizzle[idx]); + } + } + if (mode == DefaultKey) { + inVisitor.Visit(m_TessellationMode); + inVisitor.Visit(m_HasSkinning); + inVisitor.Visit(m_WireframeMode); } - - inVisitor.Visit(m_TessellationMode); - inVisitor.Visit(m_HasSkinning); - inVisitor.Visit(m_WireframeMode); } struct SOffsetVisitor @@ -703,7 +723,7 @@ namespace render { void SetPropertyOffsets() { SOffsetVisitor visitor; - VisitProperties(visitor); + VisitProperties(visitor, DefaultKey); // If this assert fires, then the default material key needs more bits. QT3DS_ASSERT(visitor.m_Offset < 224); } @@ -779,10 +799,11 @@ namespace render { }; void ToString(eastl::string &ioString, - SShaderDefaultMaterialKeyProperties &inProperties) const + SShaderDefaultMaterialKeyProperties &inProperties, + SShaderDefaultMaterialKeyProperties::KeyMode mode) const { SStringVisitor theVisitor(ioString, *this); - inProperties.VisitProperties(theVisitor); + inProperties.VisitProperties(theVisitor, mode); } }; } diff --git a/src/runtimerender/Qt3DSRenderUIPLoader.cpp b/src/runtimerender/Qt3DSRenderUIPLoader.cpp index 4740839..3c8a0bf 100644 --- a/src/runtimerender/Qt3DSRenderUIPLoader.cpp +++ b/src/runtimerender/Qt3DSRenderUIPLoader.cpp @@ -1825,7 +1825,10 @@ struct SRenderUIPLoader : public IDOMReferenceResolver CRegisteredString imgPath = m_StrTable.RegisterStr(srcPath); bool hasTransparency = false; m_Reader.Att("hasTransparency", hasTransparency); - m_BufferManager.SetImageHasTransparency(imgPath, hasTransparency); + bool hasOpaque = false; + m_Reader.Att("hasOpaquePixels", hasOpaque); + m_BufferManager.SetImageHasTransparency(imgPath, hasTransparency, + hasOpaque); } } } diff --git a/src/runtimerender/Qt3DSRenderer.h b/src/runtimerender/Qt3DSRenderer.h index db3eee8..fb6c3de 100644 --- a/src/runtimerender/Qt3DSRenderer.h +++ b/src/runtimerender/Qt3DSRenderer.h @@ -100,6 +100,8 @@ namespace render { virtual void EnableLayerGpuProfiling(bool inEnabled) = 0; virtual bool IsLayerGpuProfilingEnabled() const = 0; + virtual void setAlphaTest(bool enable, float op, float ref) = 0; + // Get the camera that rendered this node last render virtual SCamera *GetCameraForNode(const SNode &inNode) const = 0; virtual Option<SCuboidRect> GetCameraBounds(const SGraphObject &inObject) = 0; diff --git a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp index fff7e32..e3b570d 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp @@ -96,8 +96,8 @@ namespace render { SShadowMapEntry *inShadowMapEntry) { NVRenderContext &context(m_Generator.GetContext()); - SRenderableDepthPrepassShader *shader = NULL; - NVRenderInputAssembler *pIA = NULL; + SRenderableDepthPrepassShader *shader = nullptr; + NVRenderInputAssembler *pIA = nullptr; /* if ( inLight->m_LightType == RenderLightTypes::Area ) @@ -114,7 +114,7 @@ namespace render { else shader = m_Generator.GetCubeShadowDepthShader(m_TessellationMode); - if (shader == NULL || inShadowMapEntry == NULL) + if (shader == nullptr || inShadowMapEntry == nullptr) return; // for phong and npatch tesselleation we need the normals too @@ -144,7 +144,7 @@ namespace render { shader->m_Projection.Set( inCamera.m_Projection ); */ - // tesselation + // tessellation if (m_TessellationMode != TessModeValues::NoTess) { // set uniforms we need shader->m_Tessellation.m_EdgeTessLevel.Set(m_Subset.m_EdgeTessFactor); @@ -166,17 +166,18 @@ namespace render { float inDisplacementAmount) { NVRenderContext &context(m_Generator.GetContext()); - SRenderableDepthPrepassShader *shader = NULL; - NVRenderInputAssembler *pIA = NULL; + SRenderableDepthPrepassShader *shader = nullptr; + NVRenderInputAssembler *pIA = nullptr; SRenderableImage *displacementImage = inDisplacementImage; - if (m_Subset.m_PrimitiveType != NVRenderDrawMode::Patches) - shader = m_Generator.GetDepthPrepassShader(displacementImage != NULL); - else + if (m_Subset.m_PrimitiveType != NVRenderDrawMode::Patches) { + shader = m_Generator.GetDepthPrepassShader(displacementImage != nullptr); + } else { shader = m_Generator.GetDepthTessPrepassShader(m_TessellationMode, - displacementImage != NULL); + displacementImage != nullptr); + } - if (shader == NULL) + if (shader == nullptr) return; // for phong and npatch tesselleation or displacement mapping we need the normals (and uv's) @@ -214,7 +215,7 @@ namespace render { displacementImage->m_Image.m_TextureData.m_Texture); } - // tesselation + // tessellation if (m_TessellationMode != TessModeValues::NoTess) { // set uniforms we need shader->m_GlobalTransform.Set(m_GlobalTransform); @@ -241,12 +242,18 @@ namespace render { // An interface to the shader generator that is available to the renderables - void SSubsetRenderable::Render(const QT3DSVec2 &inCameraVec, TShaderFeatureSet inFeatureSet) + void SSubsetRenderable::Render(const QT3DSVec2 &inCameraVec, TShaderFeatureSet inFeatureSet, + bool depth) { NVRenderContext &context(m_Generator.GetContext()); + SShaderGeneratorGeneratedShader *shader = nullptr; - SShaderGeneratorGeneratedShader *shader = m_Generator.GetShader(*this, inFeatureSet); - if (shader == NULL) + // Do not render if alpha test is enabled, but no alpha test in object or vice versa + if (m_Generator.alphaTestEnabled() ^ m_RenderableFlags.hasAlphaTest()) + return; + + shader = m_Generator.GetShader(*this, inFeatureSet, depth); + if (shader == nullptr) return; context.SetActiveShader(&shader->m_Shader); @@ -254,9 +261,10 @@ namespace render { m_Generator.GetQt3DSContext().GetDefaultMaterialShaderGenerator().SetMaterialProperties( shader->m_Shader, m_Material, inCameraVec, m_ModelContext.m_ModelViewProjection, m_ModelContext.m_NormalMatrix, m_ModelContext.m_Model.m_GlobalTransform, m_FirstImage, - m_Opacity, m_Generator.GetLayerGlobalRenderProperties()); + m_Opacity, m_Generator.GetLayerGlobalRenderProperties(), + QT3DSVec2(m_Generator.alphaOpRef())); - // tesselation + // tessellation if (m_Subset.m_PrimitiveType == NVRenderDrawMode::Patches) { shader->m_Tessellation.m_EdgeTessLevel.Set(m_Subset.m_EdgeTessFactor); shader->m_Tessellation.m_InsideTessLevel.Set(m_Subset.m_InnerTessFactor); @@ -287,11 +295,56 @@ namespace render { context.Draw(m_Subset.m_PrimitiveType, m_Subset.m_Count, m_Subset.m_Offset); } + void SSubsetRenderable::RenderShadow(const QT3DSVec2 &inCameraVec, + TShaderFeatureSet inFeatureSet, const SLight *inLight, + const SCamera &inCamera, SShadowMapEntry *inShadowMapEntry) + { + NVRenderContext &context(m_Generator.GetContext()); + SRenderableDepthPrepassShader *shader = nullptr; + + // Do not render if alpha test is enabled, but no alpha test in object or vice versa + if (m_Generator.alphaTestEnabled() ^ m_RenderableFlags.hasAlphaTest()) + return; + + shader = m_Generator.GetShadowShader(*this, inFeatureSet, inLight->m_LightType); + if (shader == nullptr || inShadowMapEntry == nullptr) + return; + + QT3DSMat44 theModelViewProjection = inShadowMapEntry->m_LightVP * m_GlobalTransform; + + context.SetActiveShader(&shader->m_Shader); + m_Generator.GetQt3DSContext().GetDefaultMaterialShaderGenerator().SetMaterialProperties( + shader->m_Shader, m_Material, inCameraVec, m_ModelContext.m_ModelViewProjection, + m_ModelContext.m_NormalMatrix, m_ModelContext.m_Model.m_GlobalTransform, m_FirstImage, + m_Opacity, m_Generator.GetLayerGlobalRenderProperties(), + QT3DSVec2(m_Generator.alphaOpRef())); + + shader->m_MVP.Set(theModelViewProjection); + shader->m_CameraPosition.Set(inCamera.m_Position); + shader->m_GlobalTransform.Set(m_GlobalTransform); + shader->m_CameraProperties.Set(inCameraVec); + + // tessellation + if (m_Subset.m_PrimitiveType == NVRenderDrawMode::Patches) { + shader->m_Tessellation.m_EdgeTessLevel.Set(m_Subset.m_EdgeTessFactor); + shader->m_Tessellation.m_InsideTessLevel.Set(m_Subset.m_InnerTessFactor); + // the blend value is hardcoded + shader->m_Tessellation.m_PhongBlend.Set(0.75); + // this should finally be based on some user input + shader->m_Tessellation.m_DistanceRange.Set(inCameraVec); + // enable culling + shader->m_Tessellation.m_DisableCulling.Set(0.0); + } + + context.SetInputAssembler(m_Subset.m_InputAssembler); + context.Draw(m_Subset.m_PrimitiveType, m_Subset.m_Count, m_Subset.m_Offset); + } + void SSubsetRenderable::RenderDepthPass(const QT3DSVec2 &inCameraVec) { - SRenderableImage *displacementImage = NULL; + SRenderableImage *displacementImage = nullptr; for (SRenderableImage *theImage = m_FirstImage; - theImage != NULL && displacementImage == NULL; theImage = theImage->m_NextImage) { + theImage != nullptr && displacementImage == nullptr; theImage = theImage->m_NextImage) { if (theImage->m_MapType == ImageMapTypes::Displacement) displacementImage = theImage; } @@ -302,11 +355,13 @@ namespace render { void STextRenderable::Render(const QT3DSVec2 &inCameraVec) { NVRenderContext &context(m_Generator.GetContext()); + if (m_Generator.alphaTestEnabled()) + return; if (!m_Text.m_PathFontDetails) { STextRenderHelper theInfo = m_Generator.GetShader(*this, false); - if (theInfo.m_Shader == NULL) + if (theInfo.m_Shader == nullptr) return; // All of our shaders produce premultiplied values. qt3ds::render::NVRenderBlendFunctionArgument blendFunc( @@ -330,7 +385,7 @@ namespace render { QT3DS_ASSERT(context.IsPathRenderingSupported() && context.IsProgramPipelineSupported()); STextRenderHelper theInfo = m_Generator.GetShader(*this, true); - if (theInfo.m_Shader == NULL) + if (theInfo.m_Shader == nullptr) return; // All of our shaders produce premultiplied values. @@ -357,7 +412,7 @@ namespace render { { NVRenderContext &context(m_Generator.GetContext()); STextDepthShader *theDepthShader = m_Generator.GetTextDepthShader(); - if (theDepthShader == NULL) + if (theDepthShader == nullptr || m_Generator.alphaTestEnabled()) return; if (!m_Text.m_PathFontDetails) { @@ -403,7 +458,7 @@ namespace render { theDepthFunction, false, theArg, theArg, theOpArg, theOpArg); - context.SetActiveShader(NULL); + context.SetActiveShader(nullptr); context.SetCullingEnabled(false); context.SetDepthStencilState(depthStencilState); @@ -451,6 +506,8 @@ namespace render { const NVRenderTexture2D *inSsaoTexture, TShaderFeatureSet inFeatureSet) { + if (m_Generator.alphaTestEnabled()) + return; IQt3DSRenderContext &qt3dsContext(m_Generator.GetQt3DSContext()); SCustomMaterialRenderContext theRenderContext( inLayer, inLayerData, inLights, inCamera, m_ModelContext.m_Model, m_Subset, @@ -468,13 +525,15 @@ namespace render { const SCamera & /*inCamera*/, const NVRenderTexture2D * /*inDepthTexture*/) { - + if (m_Generator.alphaTestEnabled()) + return; IQt3DSRenderContext &qt3dsContext(m_Generator.GetQt3DSContext()); if (!qt3dsContext.GetCustomMaterialSystem().RenderDepthPrepass( m_ModelContext.m_ModelViewProjection, m_Material, m_Subset)) { - SRenderableImage *displacementImage = NULL; + SRenderableImage *displacementImage = nullptr; for (SRenderableImage *theImage = m_FirstImage; - theImage != NULL && displacementImage == NULL; theImage = theImage->m_NextImage) { + theImage != nullptr && displacementImage == nullptr; + theImage = theImage->m_NextImage) { if (theImage->m_MapType == ImageMapTypes::Displacement) displacementImage = theImage; } diff --git a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h index 6924f9e..f79b169 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h +++ b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h @@ -62,6 +62,7 @@ namespace render { Path = 1 << 9, ShadowCaster = 1 << 10, DistanceField = 1 << 11, + HasAlphaTest = 1 << 12, }; }; @@ -70,7 +71,7 @@ namespace render { void ClearOrSet(bool value, RenderPreparationResultFlagValues::Enum enumVal) { if (value) - this->operator|=(enumVal); + *this |= enumVal; else clear(enumVal); } @@ -81,11 +82,11 @@ namespace render { } bool HasTransparency() const { - return this->operator&(RenderPreparationResultFlagValues::HasTransparency); + return *this & RenderPreparationResultFlagValues::HasTransparency; } bool HasRefraction() const { - return this->operator&(RenderPreparationResultFlagValues::HasRefraction); + return *this & RenderPreparationResultFlagValues::HasRefraction; } void SetCompletelyTransparent(bool inTransparent) { @@ -93,20 +94,20 @@ namespace render { } bool IsCompletelyTransparent() const { - return this->operator&(RenderPreparationResultFlagValues::CompletelyTransparent); + return *this & RenderPreparationResultFlagValues::CompletelyTransparent; } void SetDirty(bool inDirty) { ClearOrSet(inDirty, RenderPreparationResultFlagValues::Dirty); } - bool IsDirty() const { return this->operator&(RenderPreparationResultFlagValues::Dirty); } + bool IsDirty() const { return *this & RenderPreparationResultFlagValues::Dirty; } void SetPickable(bool inPickable) { ClearOrSet(inPickable, RenderPreparationResultFlagValues::Pickable); } bool GetPickable() const { - return this->operator&(RenderPreparationResultFlagValues::Pickable); + return *this & RenderPreparationResultFlagValues::Pickable; } // Mutually exclusive values @@ -116,7 +117,7 @@ namespace render { } bool IsDefaultMaterialMeshSubset() const { - return this->operator&(RenderPreparationResultFlagValues::DefaultMaterialMeshSubset); + return *this & RenderPreparationResultFlagValues::DefaultMaterialMeshSubset; } void SetCustomMaterialMeshSubset(bool inMeshSubset) @@ -125,11 +126,11 @@ namespace render { } bool IsCustomMaterialMeshSubset() const { - return this->operator&(RenderPreparationResultFlagValues::CustomMaterialMeshSubset); + return *this & RenderPreparationResultFlagValues::CustomMaterialMeshSubset; } void SetText(bool inText) { ClearOrSet(inText, RenderPreparationResultFlagValues::Text); } - bool IsText() const { return this->operator&(RenderPreparationResultFlagValues::Text); } + bool IsText() const { return *this & RenderPreparationResultFlagValues::Text; } void setDistanceField(bool inText) { @@ -138,17 +139,17 @@ namespace render { bool isDistanceField() const { - return this->operator&(RenderPreparationResultFlagValues::DistanceField); + return *this & RenderPreparationResultFlagValues::DistanceField; } void SetCustom(bool inCustom) { ClearOrSet(inCustom, RenderPreparationResultFlagValues::Custom); } - bool IsCustom() const { return this->operator&(RenderPreparationResultFlagValues::Custom); } + bool IsCustom() const { return *this & RenderPreparationResultFlagValues::Custom; } void SetPath(bool inPath) { ClearOrSet(inPath, RenderPreparationResultFlagValues::Path); } - bool IsPath() const { return this->operator&(RenderPreparationResultFlagValues::Path); } + bool IsPath() const { return *this & RenderPreparationResultFlagValues::Path; } void SetShadowCaster(bool inCaster) { @@ -156,7 +157,15 @@ namespace render { } bool IsShadowCaster() const { - return this->operator&(RenderPreparationResultFlagValues::ShadowCaster); + return *this & RenderPreparationResultFlagValues::ShadowCaster; + } + void setAlphaTest(bool set) + { + ClearOrSet(set, RenderPreparationResultFlagValues::HasAlphaTest); + } + bool hasAlphaTest() const + { + return *this & RenderPreparationResultFlagValues::HasAlphaTest; } }; @@ -311,8 +320,10 @@ namespace render { m_RenderableFlags.setDistanceField(false); } - void Render(const QT3DSVec2 &inCameraVec, TShaderFeatureSet inFeatureSet); - + void Render(const QT3DSVec2 &inCameraVec, TShaderFeatureSet inFeatureSet, bool depth); + void RenderShadow(const QT3DSVec2 &inCameraVec, TShaderFeatureSet inFeatureSet, + const SLight *inLight, const SCamera &inCamera, + SShadowMapEntry *inShadowMapEntry); void RenderDepthPass(const QT3DSVec2 &inCameraVec); DefaultMaterialBlendMode::Enum getBlendingMode() diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp index 466ac5c..db3697a 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp @@ -103,6 +103,9 @@ namespace render { , m_StringTable(ctx.GetStringTable()) , m_LayerShaders(ctx.GetAllocator(), "Qt3DSRendererImpl::m_LayerShaders") , m_Shaders(ctx.GetAllocator(), "Qt3DSRendererImpl::m_Shaders") + , m_DepthShaders(ctx.GetAllocator(), "Qt3DSRendererImpl::m_DepthShaders") + , m_ShadowMapShaders(ctx.GetAllocator(), "Qt3DSRendererImpl::m_ShadowMapShaders") + , m_ShadowCubeShaders(ctx.GetAllocator(), "Qt3DSRendererImpl::m_ShadowCubeShaders") , m_ConstantBuffers(ctx.GetAllocator(), "Qt3DSRendererImpl::m_ConstantBuffers") , m_TextShader(ctx.GetAllocator()) , m_TextPathShader(ctx.GetAllocator()) @@ -110,13 +113,13 @@ namespace render { , m_TextOnscreenShader(ctx.GetAllocator()) #ifdef ADVANCED_BLEND_SW_FALLBACK , m_LayerBlendTexture(ctx.GetResourceManager()) - , m_BlendFB(NULL) + , m_BlendFB(nullptr) #endif , m_InstanceRenderMap(ctx.GetAllocator(), "Qt3DSRendererImpl::m_InstanceRenderMap") , m_LastFrameLayers(ctx.GetAllocator(), "Qt3DSRendererImpl::m_LastFrameLayers") , mRefCount(0) , m_LastPickResults(ctx.GetAllocator(), "Qt3DSRendererImpl::m_LastPickResults") - , m_CurrentLayer(NULL) + , m_CurrentLayer(nullptr) , m_WidgetVertexBuffers(ctx.GetAllocator(), "Qt3DSRendererImpl::m_WidgetVertexBuffers") , m_WidgetIndexBuffers(ctx.GetAllocator(), "Qt3DSRendererImpl::m_WidgetIndexBuffers") , m_WidgetShaders(ctx.GetAllocator(), "Qt3DSRendererImpl::m_WidgetShaders") @@ -131,10 +134,25 @@ namespace render { { m_LayerShaders.clear(); for (TShaderMap::iterator iter = m_Shaders.begin(), end = m_Shaders.end(); iter != end; - ++iter) + ++iter) { NVDelete(m_Context->GetAllocator(), iter->second); - + } + for (TShaderMap::iterator iter = m_DepthShaders.begin(), end = m_DepthShaders.end(); + iter != end; ++iter) { + NVDelete(m_Context->GetAllocator(), iter->second); + } + for (TShadowShaderMap::iterator iter = m_ShadowMapShaders.begin(), + end = m_ShadowMapShaders.end(); iter != end; ++iter) { + NVDelete(m_Context->GetAllocator(), iter->second); + } + for (TShadowShaderMap::iterator iter = m_ShadowCubeShaders.begin(), + end = m_ShadowCubeShaders.end(); iter != end; ++iter) { + NVDelete(m_Context->GetAllocator(), iter->second); + } + m_ShadowMapShaders.clear(); + m_ShadowCubeShaders.clear(); m_Shaders.clear(); + m_DepthShaders.clear(); m_InstanceRenderMap.clear(); m_ConstantBuffers.clear(); } @@ -177,7 +195,7 @@ namespace render { { if (inLayer.m_NextSibling && inLayer.m_NextSibling->m_Type == GraphObjectTypes::Layer) return static_cast<SLayer *>(inLayer.m_NextSibling); - return NULL; + return nullptr; } static inline void MaybePushLayer(SLayer &inLayer, nvvector<SLayer *> &outLayerList) @@ -290,7 +308,7 @@ namespace render { m_LayerBlendTexture.EnsureTexture(viewport.m_Width + viewport.m_X, viewport.m_Height + viewport.m_Y, NVRenderTextureFormats::RGBA8); - if (m_BlendFB == NULL) + if (m_BlendFB == nullptr) m_BlendFB = theRenderContext.CreateFrameBuffer(); m_BlendFB->Attach(NVRenderFrameBufferAttachments::Color0, *m_LayerBlendTexture); theRenderContext.SetRenderTarget(m_BlendFB); @@ -333,7 +351,7 @@ namespace render { } if (inNode.m_Parent) return GetLayerForNode(*inNode.m_Parent); - return NULL; + return nullptr; } SLayerRenderData *Qt3DSRendererImpl::GetOrCreateLayerRenderDataForNode(const SNode &inNode, @@ -356,7 +374,7 @@ namespace render { return theRenderData; } - return NULL; + return nullptr; } SCamera *Qt3DSRendererImpl::GetCameraForNode(const SNode &inNode) const @@ -365,7 +383,7 @@ namespace render { const_cast<Qt3DSRendererImpl &>(*this).GetOrCreateLayerRenderDataForNode(inNode); if (theLayer) return theLayer->m_Camera; - return NULL; + return nullptr; } Option<SCuboidRect> Qt3DSRendererImpl::GetCameraBounds(const SGraphObject &inObject) @@ -552,8 +570,8 @@ namespace render { IResourceManager &theManager(m_qt3dsContext.GetResourceManager()); theManager.Release(*m_WidgetFBO); theManager.Release(*m_WidgetTexture); - m_WidgetTexture = NULL; - m_WidgetFBO = NULL; + m_WidgetTexture = nullptr; + m_WidgetFBO = nullptr; } } @@ -652,7 +670,7 @@ namespace render { // If picking against the sub object doesn't return a valid result *and* // the current object isn't globally pickable then we move onto the next object returned // by the pick query. - if (thePickResult.m_HitObject != NULL && thePickResult.m_FirstSubObject != NULL + if (thePickResult.m_HitObject != nullptr && thePickResult.m_FirstSubObject != nullptr && m_PickRenderPlugins) { QT3DSVec2 theUVCoords(thePickResult.m_LocalUVCoords.x, thePickResult.m_LocalUVCoords.y); @@ -686,7 +704,7 @@ namespace render { bool wasPickConsumed = theSubRenderer->Pick(theMouseCoords, theViewportDimensions, this); if (wasPickConsumed) { - thePickResult.m_HitObject = NULL; + thePickResult.m_HitObject = nullptr; foundValidResult = true; } } @@ -728,8 +746,8 @@ namespace render { if (inPickSiblings) theLayer = GetNextLayer(*theLayer); else - theLayer = NULL; - } while (theLayer != NULL); + theLayer = nullptr; + } while (theLayer != nullptr); return Qt3DSRenderPickResult(); } @@ -787,15 +805,15 @@ namespace render { SBasisPlanes::Enum inPlane) { SLayerRenderData *theLayerData = GetOrCreateLayerRenderDataForNode(inNode); - if (theLayerData == NULL) + if (theLayerData == nullptr) return Empty(); // 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. bool wasRenderToTarget(theLayerData->m_Layer.m_Flags.IsLayerRenderToTarget()); - if (wasRenderToTarget == false || theLayerData->m_Camera == NULL + if (wasRenderToTarget == false || theLayerData->m_Camera == nullptr || theLayerData->m_LayerPrepResult.hasValue() == false - || theLayerData->m_LastFrameOffscreenRenderer.mPtr != NULL) + || theLayerData->m_LastFrameOffscreenRenderer.mPtr != nullptr) return Empty(); QT3DSVec2 theMouseCoords(inMouseCoords); @@ -808,7 +826,7 @@ namespace render { // This is extremely counter intuitive but a good sign. } else if (currentObject.m_Type == GraphObjectTypes::Image) { SImage &theImage = static_cast<SImage &>(currentObject); - SModel *theParentModel = NULL; + SModel *theParentModel = nullptr; if (theImage.m_Parent && theImage.m_Parent->m_Type == GraphObjectTypes::DefaultMaterial) { SDefaultMaterial *theMaterial = @@ -817,7 +835,7 @@ namespace render { theParentModel = theMaterial->m_Parent; } } - if (theParentModel == NULL) { + if (theParentModel == nullptr) { QT3DS_ASSERT(false); return Empty(); } @@ -871,7 +889,7 @@ namespace render { // Translate mouse into layer's coordinates SLayerRenderData *theData = const_cast<Qt3DSRendererImpl &>(*this).GetOrCreateLayerRenderDataForNode(inNode); - if (theData == NULL || theData->m_Camera == NULL) { + if (theData == nullptr || theData->m_Camera == nullptr) { return QT3DSVec3(0, 0, 0); } // QT3DS_ASSERT( false ); return QT3DSVec3(0,0,0); } @@ -890,7 +908,7 @@ namespace render { // Translate mouse into layer's coordinates SLayerRenderData *theData = const_cast<Qt3DSRendererImpl &>(*this).GetOrCreateLayerRenderDataForNode(inNode); - if (theData == NULL || theData->m_Camera == NULL) { + if (theData == nullptr || theData->m_Camera == nullptr) { return QT3DSVec3(0, 0, 0); } // QT3DS_ASSERT( false ); return QT3DSVec3(0,0,0); } @@ -903,7 +921,7 @@ namespace render { SRay theRay = thePrepResult.GetPickRay( theMouse, QT3DSVec2((QT3DSF32)theWindow.width(), (QT3DSF32)theWindow.height()), true); QT3DSVec3 theTargetPosition = theRay.m_Origin + theRay.m_Direction * theDepth; - if (inNode.m_Parent != NULL && inNode.m_Parent->m_Type != GraphObjectTypes::Layer) + if (inNode.m_Parent != nullptr && inNode.m_Parent->m_Type != GraphObjectTypes::Layer) theTargetPosition = inNode.m_Parent->m_GlobalTransform.getInverse().transform(theTargetPosition); // Our default global space is right handed, so if you are left handed z means something @@ -918,7 +936,7 @@ namespace render { // Translate mouse into layer's coordinates SLayerRenderData *theData = const_cast<Qt3DSRendererImpl &>(*this).GetOrCreateLayerRenderDataForNode(inNode); - if (theData == NULL || theData->m_Camera == NULL) { + if (theData == nullptr || theData->m_Camera == nullptr) { return QT3DSVec3(0, 0, 0); } @@ -955,7 +973,7 @@ namespace render { const QSize &inPickDims) { SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inLayer); - if (theData == NULL || theData->m_Camera == NULL) { + if (theData == nullptr || theData->m_Camera == nullptr) { QT3DS_ASSERT(false); return Empty(); } @@ -968,7 +986,7 @@ namespace render { } SLayerRenderPreparationResult &thePrepResult(*theData->m_LayerPrepResult); - if (thePrepResult.GetCamera() == NULL) { + if (thePrepResult.GetCamera() == nullptr) { return Empty(); } // Perform gluPickMatrix and pre-multiply it into the view projection @@ -1009,7 +1027,7 @@ namespace render { Option<NVRenderRectF> Qt3DSRendererImpl::GetLayerRect(SLayer &inLayer) { SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inLayer); - if (theData == NULL || theData->m_Camera == NULL) { + if (theData == nullptr || theData->m_Camera == nullptr) { QT3DS_ASSERT(false); return Empty(); } @@ -1021,7 +1039,7 @@ namespace render { void Qt3DSRendererImpl::RunLayerRender(SLayer &inLayer, const QT3DSMat44 &inViewProjection) { SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inLayer); - if (theData == NULL || theData->m_Camera == NULL) { + if (theData == nullptr || theData->m_Camera == nullptr) { QT3DS_ASSERT(false); return; } @@ -1077,7 +1095,7 @@ namespace render { const QT3DSVec3 &inWorldPoint) { SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inLayer); - if (theData == NULL || theData->m_Camera == NULL) { + if (theData == nullptr || theData->m_Camera == nullptr) { QT3DS_ASSERT(false); return SScaleAndPosition(); } @@ -1141,7 +1159,7 @@ namespace render { m_CurrentLayer = &inLayer; } - void Qt3DSRendererImpl::EndLayerDepthPassRender() { m_CurrentLayer = NULL; } + void Qt3DSRendererImpl::EndLayerDepthPassRender() { m_CurrentLayer = nullptr; } void Qt3DSRendererImpl::BeginLayerRender(SLayerRenderData &inLayer) { @@ -1151,7 +1169,7 @@ namespace render { // shaders that are in the layer. m_LayerShaders.clear(); } - void Qt3DSRendererImpl::EndLayerRender() { m_CurrentLayer = NULL; } + void Qt3DSRendererImpl::EndLayerRender() { m_CurrentLayer = nullptr; } // Allocate an object that lasts only this frame. #define RENDER_FRAME_NEW(type) \ @@ -1170,7 +1188,7 @@ namespace render { bool NodeContainsBoneRoot(SNode &childNode, QT3DSI32 rootID) { - for (SNode *childChild = childNode.m_FirstChild; childChild != NULL; + for (SNode *childChild = childNode.m_FirstChild; childChild != nullptr; childChild = childChild->m_NextSibling) { if (childChild->m_SkeletonId == rootID) return true; @@ -1183,7 +1201,7 @@ namespace render { { if (childNode.m_SkeletonId >= 0) ioMap[childNode.m_SkeletonId] = &childNode; - for (SNode *childChild = childNode.m_FirstChild; childChild != NULL; + for (SNode *childChild = childNode.m_FirstChild; childChild != nullptr; childChild = childChild->m_NextSibling) FillBoneIdNodeMap(*childChild, ioMap); } @@ -1191,7 +1209,7 @@ namespace render { bool Qt3DSRendererImpl::PrepareTextureAtlasForRender() { ITextTextureAtlas *theTextureAtlas = m_qt3dsContext.GetTextureAtlas(); - if (theTextureAtlas == NULL) + if (theTextureAtlas == nullptr) return false; // this is a one time creation @@ -1344,13 +1362,13 @@ namespace render { // 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 != NULL) { + 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 == NULL) { + 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; @@ -1410,7 +1428,7 @@ namespace render { SRayIntersectionResult &theResult(*theIntersectionResultOpt); // Leave the coordinates relative for right now. - const SGraphObject *thePickObject = NULL; + const SGraphObject *thePickObject = nullptr; if (inRenderableObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) thePickObject = &static_cast<SSubsetRenderable *>(&inRenderableObject)->m_ModelContext.m_Model; @@ -1426,26 +1444,26 @@ namespace render { else if (inRenderableObject.m_RenderableFlags.IsPath()) thePickObject = &static_cast<SPathRenderable *>(&inRenderableObject)->m_Path; - if (thePickObject != NULL) { + if (thePickObject != nullptr) { outIntersectionResultList.push_back(Qt3DSRenderPickResult( *thePickObject, theResult.m_RayLengthSquared, theResult.m_RelXY)); // For subsets, we know we can find images on them which may have been the result // of rendering a sub-presentation. if (inRenderableObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) { - Qt3DSRenderPickSubResult *theLastResult = NULL; + Qt3DSRenderPickSubResult *theLastResult = nullptr; for (SRenderableImage *theImage = static_cast<SSubsetRenderable *>(&inRenderableObject)->m_FirstImage; - theImage != NULL; theImage = theImage->m_NextImage) { - if (theImage->m_Image.m_LastFrameOffscreenRenderer != NULL - && theImage->m_Image.m_TextureData.m_Texture != NULL) { + theImage != nullptr; theImage = theImage->m_NextImage) { + if (theImage->m_Image.m_LastFrameOffscreenRenderer != nullptr + && theImage->m_Image.m_TextureData.m_Texture != nullptr) { Qt3DSRenderPickSubResult *theSubResult = (Qt3DSRenderPickSubResult *)inTempAllocator.allocate( sizeof(Qt3DSRenderPickSubResult), "Qt3DSRenderPickSubResult", __FILE__, __LINE__); new (theSubResult) Qt3DSRenderPickSubResult(ConstructSubResult(*theImage)); - if (theLastResult == NULL) + if (theLastResult == nullptr) outIntersectionResultList.back().m_FirstSubObject = theSubResult; else theLastResult->m_NextSibling = theSubResult; @@ -1493,17 +1511,20 @@ namespace render { } SShaderGeneratorGeneratedShader *Qt3DSRendererImpl::GetShader(SSubsetRenderable &inRenderable, - TShaderFeatureSet inFeatureSet) + TShaderFeatureSet inFeatureSet, + bool depth) { - if (m_CurrentLayer == NULL) { + if (m_CurrentLayer == nullptr) { QT3DS_ASSERT(false); - return NULL; + return nullptr; } - TShaderMap::iterator theFind = m_Shaders.find(inRenderable.m_ShaderDescription); - SShaderGeneratorGeneratedShader *retval = NULL; - if (theFind == m_Shaders.end()) { + + SShaderGeneratorGeneratedShader *retval = nullptr; + TShaderMap &map = depth ? m_DepthShaders : m_Shaders; + TShaderMap::iterator theFind = map.find(inRenderable.m_ShaderDescription); + if (theFind == map.end()) { // Generate the shader. - NVRenderShaderProgram *theShader(GenerateShader(inRenderable, inFeatureSet)); + NVRenderShaderProgram *theShader(GenerateShader(inRenderable, inFeatureSet, depth)); if (theShader) { SShaderGeneratorGeneratedShader *theGeneratedShader = (SShaderGeneratorGeneratedShader *)m_Context->GetAllocator().allocate( @@ -1511,18 +1532,18 @@ namespace render { __FILE__, __LINE__); new (theGeneratedShader) SShaderGeneratorGeneratedShader( m_StringTable->RegisterStr(m_GeneratedShaderString.c_str()), *theShader); - m_Shaders.insert(make_pair(inRenderable.m_ShaderDescription, theGeneratedShader)); + map.insert(make_pair(inRenderable.m_ShaderDescription, theGeneratedShader)); retval = theGeneratedShader; } - // We still insert something because we don't to attempt to generate the same bad shader - // twice. + // We still insert something because we don't want to attempt to generate the same + // bad shader twice. else - m_Shaders.insert(make_pair(inRenderable.m_ShaderDescription, - (SShaderGeneratorGeneratedShader *)NULL)); + map.insert(make_pair(inRenderable.m_ShaderDescription, + (SShaderGeneratorGeneratedShader *)nullptr)); } else retval = theFind->second; - if (retval != NULL) { + if (retval != nullptr && !depth) { if (!m_LayerShaders.contains(*retval)) { m_LayerShaders.insert(*retval); } @@ -1534,6 +1555,45 @@ namespace render { } return retval; } + + SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetShadowShader( + SSubsetRenderable &inRenderable, TShaderFeatureSet inFeatureSet, + RenderLightTypes::Enum lightType) + { + if (m_CurrentLayer == nullptr) { + QT3DS_ASSERT(false); + return nullptr; + } + + SRenderableDepthPrepassShader *retval = nullptr; + TShadowShaderMap &map = lightType == RenderLightTypes::Point ? m_ShadowCubeShaders + : m_ShadowMapShaders; + TShadowShaderMap::iterator theFind = map.find(inRenderable.m_ShaderDescription); + if (theFind == map.end()) { + // Generate the shader. + NVRenderShaderProgram *theShader(GenerateShadowShader(inRenderable, inFeatureSet, + lightType)); + if (theShader) { + SRenderableDepthPrepassShader *theGeneratedShader = + (SRenderableDepthPrepassShader *)m_Context->GetAllocator().allocate( + sizeof(SRenderableDepthPrepassShader), "SRenderableDepthPrepassShader", + __FILE__, __LINE__); + new (theGeneratedShader) SRenderableDepthPrepassShader(*theShader, GetContext()); + map.insert(make_pair(inRenderable.m_ShaderDescription, theGeneratedShader)); + retval = theGeneratedShader; + } + // We still insert something because we don't want to attempt to generate the same + // bad shader twice. + else { + map.insert(make_pair(inRenderable.m_ShaderDescription, nullptr)); + } + } else { + retval = theFind->second; + } + + return retval; + } + static QT3DSVec3 g_fullScreenRectFace[] = { QT3DSVec3(-1, -1, 0), QT3DSVec3(-1, 1, 0), QT3DSVec3(1, 1, 0), QT3DSVec3(1, -1, 0), }; @@ -1613,7 +1673,7 @@ namespace render { QT3DSU32 strides = m_PointVertexBuffer->GetStride(); QT3DSU32 offsets = 0; m_PointInputAssembler = m_Context->CreateInputAssembler( - m_PointAttribLayout, toConstDataRef(&m_PointVertexBuffer.mPtr, 1), NULL, + m_PointAttribLayout, toConstDataRef(&m_PointVertexBuffer.mPtr, 1), nullptr, toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1)); } @@ -1666,7 +1726,7 @@ namespace render { QT3DSU32 strides = m_QuadStripVertexBuffer->GetStride(); QT3DSU32 offsets = 0; m_QuadStripInputAssembler = m_Context->CreateInputAssembler( - m_QuadStripAttribLayout, toConstDataRef(&m_QuadStripVertexBuffer.mPtr, 1), NULL, + m_QuadStripAttribLayout, toConstDataRef(&m_QuadStripVertexBuffer.mPtr, 1), nullptr, toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1)); } @@ -1796,7 +1856,7 @@ namespace render { TStrVertBufMap::iterator theIter = m_WidgetVertexBuffers.find(inStr); if (theIter != m_WidgetVertexBuffers.end()) return theIter->second; - return NULL; + return nullptr; } NVRenderIndexBuffer *Qt3DSRendererImpl::GetIndexBuffer(CRegisteredString &inStr) @@ -1804,7 +1864,7 @@ namespace render { TStrIndexBufMap::iterator theIter = m_WidgetIndexBuffers.find(inStr); if (theIter != m_WidgetIndexBuffers.end()) return theIter->second; - return NULL; + return nullptr; } NVRenderInputAssembler *Qt3DSRendererImpl::GetInputAssembler(CRegisteredString &inStr) @@ -1812,7 +1872,7 @@ namespace render { TStrIAMap::iterator theIter = m_WidgetInputAssembler.find(inStr); if (theIter != m_WidgetInputAssembler.end()) return theIter->second; - return NULL; + return nullptr; } NVRenderShaderProgram *Qt3DSRendererImpl::GetShader(CRegisteredString inStr) @@ -1820,7 +1880,7 @@ namespace render { TStrShaderMap::iterator theIter = m_WidgetShaders.find(inStr); if (theIter != m_WidgetShaders.end()) return theIter->second; - return NULL; + return nullptr; } NVRenderShaderProgram *Qt3DSRendererImpl::CompileAndStoreShader(CRegisteredString inStr) @@ -1838,7 +1898,7 @@ namespace render { STextDimensions Qt3DSRendererImpl::MeasureText(const STextRenderInfo &inText) { - if (m_qt3dsContext.GetTextRenderer() != NULL) + if (m_qt3dsContext.GetTextRenderer() != nullptr) return m_qt3dsContext.GetTextRenderer()->MeasureText(inText, 0); return STextDimensions(); } @@ -1846,14 +1906,14 @@ namespace render { void Qt3DSRendererImpl::RenderText(const STextRenderInfo &inText, const QT3DSVec3 &inTextColor, const QT3DSVec3 &inBackgroundColor, const QT3DSMat44 &inMVP) { - if (m_qt3dsContext.GetTextRenderer() != NULL) { + if (m_qt3dsContext.GetTextRenderer() != nullptr) { ITextRenderer &theTextRenderer(*m_qt3dsContext.GetTextRenderer()); NVRenderTexture2D *theTexture = m_qt3dsContext.GetResourceManager().AllocateTexture2D( 32, 32, NVRenderTextureFormats::RGBA8); STextTextureDetails theTextTextureDetails = theTextRenderer.RenderText(inText, *theTexture); STextRenderHelper theTextHelper(GetTextWidgetShader()); - if (theTextHelper.m_Shader != NULL) { + if (theTextHelper.m_Shader != nullptr) { m_qt3dsContext.GetRenderContext().SetBlendingEnabled(false); STextScaleAndOffset theScaleAndOffset(*theTexture, theTextTextureDetails, inText); theTextHelper.m_Shader->Render(*theTexture, theScaleAndOffset, @@ -1870,7 +1930,7 @@ namespace render { qt3ds::foundation::Option<qt3ds::QT3DSVec3> inColor, const char *text) { - if (m_qt3dsContext.GetOnscreenTextRenderer() != NULL) { + if (m_qt3dsContext.GetOnscreenTextRenderer() != nullptr) { GenerateXYQuadStrip(); if (PrepareTextureAtlasForRender()) { @@ -1892,7 +1952,7 @@ namespace render { if (theRenderTextDetails.first.m_Vertices.size()) { STextRenderHelper theTextHelper(GetOnscreenTextShader()); - if (theTextHelper.m_Shader != NULL) { + if (theTextHelper.m_Shader != nullptr) { // setup 2D projection SCamera theCamera; theCamera.m_ClipNear = -1.0; @@ -1900,7 +1960,8 @@ namespace render { theCamera.MarkDirty(NodeTransformDirtyFlag::TransformIsDirty); theCamera.m_Flags.SetOrthographic(true); - QT3DSVec2 theWindowDim((QT3DSF32)theWindow.width(), (QT3DSF32)theWindow.height()); + QT3DSVec2 theWindowDim((QT3DSF32)theWindow.width(), + (QT3DSF32)theWindow.height()); theCamera.CalculateGlobalVariables( NVRenderRect(0, 0, theWindow.width(), theWindow.height()), theWindowDim); @@ -1973,12 +2034,12 @@ namespace render { { SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inNode); SCamera *theCamera = theData->m_Camera; - if (theCamera == NULL || theData->m_LayerPrepResult.hasValue() == false) { + if (theCamera == nullptr || theData->m_LayerPrepResult.hasValue() == false) { QT3DS_ASSERT(false); return SWidgetRenderInformation(); } QT3DSMat44 theGlobalTransform(QT3DSMat44::createIdentity()); - if (inNode.m_Parent != NULL && inNode.m_Parent->m_Type != GraphObjectTypes::Layer + if (inNode.m_Parent != nullptr && inNode.m_Parent->m_Type != GraphObjectTypes::Layer && !inNode.m_Flags.IsIgnoreParentTransform()) theGlobalTransform = inNode.m_Parent->m_GlobalTransform; QT3DSMat44 theCameraInverse(theCamera->m_GlobalTransform.getInverse()); diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h index 6311a2d..cd104df 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h @@ -66,6 +66,7 @@ #include "Qt3DSRenderShaderCache.h" #include "Qt3DSRenderProfiler.h" #include "Qt3DSRenderDefaultMaterialShaderGenerator.h" +#include "Qt3DSRenderLight.h" namespace qt3ds { namespace render { @@ -150,9 +151,12 @@ namespace render { operator STextShader *() { return m_Shader; } }; - class QT3DS_AUTOTEST_EXPORT Qt3DSRendererImpl : public IQt3DSRenderer, public IRenderWidgetContext + class QT3DS_AUTOTEST_EXPORT Qt3DSRendererImpl : public IQt3DSRenderer, + public IRenderWidgetContext { typedef nvhash_map<SShaderDefaultMaterialKey, SShaderGeneratorGeneratedShader *> TShaderMap; + typedef nvhash_map<SShaderDefaultMaterialKey, SRenderableDepthPrepassShader *> + TShadowShaderMap; typedef nvhash_map<CRegisteredString, NVScopedRefCounted<NVRenderConstantBuffer>> TStrConstanBufMap; typedef nvhash_map<SRenderInstanceId, NVScopedRefCounted<SLayerRenderData>, @@ -210,11 +214,12 @@ namespace render { Option<NVScopedRefCounted<SLayerProgAABlendShader>> m_LayerProgAAShader; TShaderMap m_Shaders; + TShaderMap m_DepthShaders; + TShadowShaderMap m_ShadowMapShaders; + TShadowShaderMap m_ShadowCubeShaders; TStrConstanBufMap m_ConstantBuffers; ///< store the the shader constant buffers // Option is true if we have attempted to generate the shader. // This does not mean we were successul, however. - Option<NVScopedRefCounted<SDefaultMaterialRenderableDepthShader>> - m_DefaultMaterialDepthPrepassShader; Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_DepthPrepassShader; Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_DepthPrepassShaderDisplaced; Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_DepthTessLinearPrepassShader; @@ -295,6 +300,10 @@ namespace render { QHash<SLayer *, SLayerRenderData *> m_initialPrepareData; QSet<SGraphObject *> m_materialClearDirty; + bool m_alphaTest = false; + float m_alphaOp = 1.0f; + float m_alphaRef = 1.0f; + public: Qt3DSRendererImpl(IQt3DSRenderContext &ctx); virtual ~Qt3DSRendererImpl(); @@ -313,6 +322,23 @@ namespace render { void EnableLayerGpuProfiling(bool inEnabled) override; bool IsLayerGpuProfilingEnabled() const override { return m_LayerGPuProfilingEnabled; } + void setAlphaTest(bool enable, float op, float ref) override + { + m_alphaTest = enable; + m_alphaOp = op; + m_alphaRef = ref; + } + + bool alphaTestEnabled() const + { + return m_alphaTest; + } + + QT3DSVec2 alphaOpRef() const + { + return QT3DSVec2(m_alphaOp, m_alphaRef); + } + // Calls prepare layer for render // and then do render layer. bool PrepareLayerForRender(SLayer &inLayer, const QT3DSVec2 &inViewportDimensions, @@ -411,14 +437,19 @@ namespace render { const char8_t *inFrame); NVRenderShaderProgram *GenerateShader(SSubsetRenderable &inRenderable, - TShaderFeatureSet inFeatureSet); + TShaderFeatureSet inFeatureSet, bool depth); + NVRenderShaderProgram *GenerateShadowShader(SSubsetRenderable &inRenderable, + TShaderFeatureSet inFeatureSet, + RenderLightTypes::Enum lightType); SShaderGeneratorGeneratedShader *GetShader(SSubsetRenderable &inRenderable, - TShaderFeatureSet inFeatureSet); + TShaderFeatureSet inFeatureSet, bool depth); + SRenderableDepthPrepassShader *GetShadowShader(SSubsetRenderable &inRenderable, + TShaderFeatureSet inFeatureSet, + RenderLightTypes::Enum lightType); SDefaultAoPassShader *GetDefaultAoPassShader(TShaderFeatureSet inFeatureSet); SDefaultAoPassShader *GetFakeDepthShader(TShaderFeatureSet inFeatureSet); SDefaultAoPassShader *GetFakeCubeDepthShader(TShaderFeatureSet inFeatureSet); - SDefaultMaterialRenderableDepthShader *GetRenderableDepthShader(); SRenderableDepthPrepassShader *GetParaboloidDepthShader(TessModeValues::Enum inTessMode); SRenderableDepthPrepassShader *GetParaboloidDepthNoTessShader(); diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp index b99773b..2d11615 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp @@ -497,7 +497,7 @@ namespace render { } inline void RenderRenderableShadowMapPass(SLayerRenderData &inData, SRenderableObject &inObject, - const QT3DSVec2 &inCameraProps, TShaderFeatureSet, + const QT3DSVec2 &inCameraProps, TShaderFeatureSet set, QT3DSU32 lightIndex, const SCamera &inCamera) { if (!inObject.m_RenderableFlags.IsShadowCaster()) @@ -505,10 +505,15 @@ namespace render { SShadowMapEntry *pEntry = inData.m_ShadowMapManager->GetShadowMapEntry(lightIndex); - if (inObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) - static_cast<SSubsetRenderableBase &>(inObject).RenderShadowMapPass( - inCameraProps, inData.m_Lights[lightIndex], inCamera, pEntry); - else if (inObject.m_RenderableFlags.IsCustomMaterialMeshSubset()) { + if (inObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) { + auto &sub = static_cast<SSubsetRenderable &>(inObject); + if (sub.m_Generator.alphaTestEnabled()) { + sub.RenderShadow(inCameraProps, set, inData.m_Lights[lightIndex], inCamera, pEntry); + } else { + sub.RenderShadowMapPass(inCameraProps, inData.m_Lights[lightIndex], inCamera, + pEntry); + } + } else if (inObject.m_RenderableFlags.IsCustomMaterialMeshSubset()) { static_cast<SSubsetRenderableBase &>(inObject).RenderShadowMapPass( inCameraProps, inData.m_Lights[lightIndex], inCamera, pEntry); } else if (inObject.m_RenderableFlags.IsPath()) { @@ -667,8 +672,10 @@ namespace render { return; // Check if we have anything to render - if (m_OpaqueObjects.size() == 0 || m_Lights.size() == 0) + if ((m_OpaqueObjects.size() == 0 && GetTransparentRenderableObjects().size() == 0) + || m_Lights.size() == 0) { return; + } m_Renderer.BeginLayerDepthPassRender(*this); @@ -786,11 +793,15 @@ namespace render { } inline void RenderRenderableDepthPass(SLayerRenderData &inData, SRenderableObject &inObject, - const QT3DSVec2 &inCameraProps, TShaderFeatureSet, QT3DSU32, - const SCamera &inCamera) + const QT3DSVec2 &inCameraProps, TShaderFeatureSet set, + QT3DSU32, const SCamera &inCamera) { if (inObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) { - static_cast<SSubsetRenderable &>(inObject).RenderDepthPass(inCameraProps); + SSubsetRenderable &sub = static_cast<SSubsetRenderable &>(inObject); + if (sub.m_Generator.alphaTestEnabled()) + sub.Render(inCameraProps, set, true); + else + sub.RenderDepthPass(inCameraProps); } else if (inObject.m_RenderableFlags.IsText()) { static_cast<STextRenderable &>(inObject).RenderDepthPass(inCameraProps); #if QT_VERSION >= QT_VERSION_CHECK(5,12,2) @@ -817,7 +828,7 @@ namespace render { // Avoid running this method if possible. if ((inEnableTransparentDepthWrite == false - && (m_OpaqueObjects.size() == 0 + && ((m_OpaqueObjects.size() == 0 && m_TransparentObjects.size() == 0) || m_Layer.m_Flags.IsLayerEnableDepthPrepass() == false)) || m_Layer.m_Flags.IsLayerEnableDepthTest() == false) return; @@ -844,11 +855,11 @@ namespace render { } inline void RenderRenderable(SLayerRenderData &inData, SRenderableObject &inObject, - const QT3DSVec2 &inCameraProps, TShaderFeatureSet inFeatureSet, QT3DSU32, - const SCamera &inCamera) + const QT3DSVec2 &inCameraProps, TShaderFeatureSet inFeatureSet, + QT3DSU32, const SCamera &inCamera) { if (inObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) - static_cast<SSubsetRenderable &>(inObject).Render(inCameraProps, inFeatureSet); + static_cast<SSubsetRenderable &>(inObject).Render(inCameraProps, inFeatureSet, false); else if (inObject.m_RenderableFlags.IsText()) static_cast<STextRenderable &>(inObject).Render(inCameraProps); #if QT_VERSION >= QT_VERSION_CHECK(5,12,2) @@ -880,42 +891,18 @@ namespace render { } } - void SLayerRenderData::RunRenderPass(TRenderRenderableFunction inRenderFn, - bool inEnableBlending, bool inEnableDepthWrite, - bool inEnableTransparentDepthWrite, QT3DSU32 indexLight, - const SCamera &inCamera, CResourceFrameBuffer *theFB) + 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()); - theRenderContext.SetDepthFunction(qt3ds::render::NVRenderBoolOp::LessThanOrEqual); - theRenderContext.SetBlendingEnabled(false); QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar); - NVDataRef<SRenderableObject *> theOpaqueObjects = GetOpaqueRenderableObjects(); - bool usingDepthBuffer = - m_Layer.m_Flags.IsLayerEnableDepthTest() && theOpaqueObjects.size() > 0; - - if (usingDepthBuffer) { - theRenderContext.SetDepthTestEnabled(true); - theRenderContext.SetDepthWriteEnabled(inEnableDepthWrite); - } else { - theRenderContext.SetDepthWriteEnabled(false); - theRenderContext.SetDepthTestEnabled(false); - } - - 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); - } - - // transparent objects if (inEnableBlending || m_Layer.m_Flags.IsLayerEnableDepthTest() == false) { theRenderContext.SetBlendingEnabled(true && inEnableBlending); theRenderContext.SetDepthWriteEnabled(inEnableTransparentDepthWrite); - NVDataRef<SRenderableObject *> theTransparentObjects = GetTransparentRenderableObjects(); // 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) { @@ -953,7 +940,8 @@ namespace render { // restore blending status theRenderContext.SetBlendingEnabled(inEnableBlending); // restore depth test status - theRenderContext.SetDepthTestEnabled(usingDepthBuffer); + theRenderContext.SetDepthTestEnabled( + m_Layer.m_Flags.IsLayerEnableDepthTest()); theRenderContext.SetDepthWriteEnabled(inEnableTransparentDepthWrite); } #endif @@ -1004,6 +992,59 @@ namespace render { } } } + }; + + 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); + NVDataRef<SRenderableObject *> theOpaqueObjects = GetOpaqueRenderableObjects(); + + if (m_Layer.m_Flags.IsLayerEnableDepthTest()) { + theRenderContext.SetDepthTestEnabled(true); + theRenderContext.SetDepthWriteEnabled(inEnableDepthWrite); + } else { + theRenderContext.SetDepthWriteEnabled(false); + theRenderContext.SetDepthTestEnabled(false); + } + + 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]); + 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); + } + + 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); + + m_Renderer.setAlphaTest(false, 1.0, 1.0); + // transparent objects without alpha test + renderTransparentObjectsPass(inRenderFn, inEnableBlending, inEnableTransparentDepthWrite, + indexLight, inCamera, theFB); } void SLayerRenderData::Render(CResourceFrameBuffer *theFB) @@ -1483,7 +1524,7 @@ namespace render { // to that frame buffer. theFB.EnsureFrameBuffer(); - bool hasDepthObjects = m_OpaqueObjects.size() > 0; + bool hasDepthObjects = m_OpaqueObjects.size() > 0 || m_TransparentObjects.size() > 0; bool requiresDepthStencilBuffer = hasDepthObjects || thePrepResult.m_Flags.RequiresStencilBuffer(); NVRenderRect theNewViewport(0, 0, theLayerTextureDimensions.width(), @@ -1543,7 +1584,9 @@ namespace render { if (thePrepResult.m_Flags.RequiresShadowMapPass() && m_ProgressiveAAPassIndex == 0) { // shadow map path + StartProfiling("Shadow pass", false); RenderShadowMapPass(&theFB); + EndProfiling("Shadow pass"); } if (sampleCount > 1) { diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h index 8e5c694..0f0a838 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h @@ -178,6 +178,10 @@ struct AdvancedBlendModes void BlendAdvancedToFB(DefaultMaterialBlendMode::Enum blendMode, bool depthEnabled, CResourceFrameBuffer *theFB); #endif + void renderTransparentObjectsPass(TRenderRenderableFunction inRenderFn, + bool inEnableBlending, bool inEnableTransparentDepthWrite, + QT3DSU32 indexLight, const SCamera &inCamera, + CResourceFrameBuffer *theFB); }; } } diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp index bfd52d6..04bc4ae 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp @@ -595,7 +595,8 @@ namespace render { void SLayerRenderPreparationData::PrepareImageForRender( SImage &inImage, ImageMapTypes::Enum inMapType, SRenderableImage *&ioFirstImage, SRenderableImage *&ioNextImage, SRenderableObjectFlags &ioFlags, - SShaderDefaultMaterialKey &inShaderKey, QT3DSU32 inImageIndex) + SShaderDefaultMaterialKey &inShaderKey, QT3DSU32 inImageIndex, + bool *opaqueCheck) { IQt3DSRenderContext &qt3dsContext(m_Renderer.GetQt3DSContext()); IBufferManager &bufferManager = qt3dsContext.GetBufferManager(); @@ -619,6 +620,8 @@ namespace render { || inMapType == ImageMapTypes::Opacity || inMapType == ImageMapTypes::Translucency)) { ioFlags |= RenderPreparationResultFlagValues::HasTransparency; + if (opaqueCheck) + *opaqueCheck = inImage.m_TextureData.m_TextureFlags.HasOpaquePixels(); } // Textures used in general have linear characteristics. // PKC -- The filters are properly set already. Setting them here only overrides what @@ -683,6 +686,9 @@ namespace render { SRenderableImage *firstImage = NULL; + // Combined check for images for having opaque pixels + bool transparencyImagesHaveOpaquePixels = true; + // set wireframe mode m_Renderer.DefaultMaterialShaderKeyProperties().m_WireframeMode.SetValue( theGeneratedKey, m_Renderer.GetQt3DSContext().GetWireframeMode()); @@ -725,46 +731,47 @@ namespace render { // this may in fact set pickable on the renderable flags if one of the images // links to a sub presentation or any offscreen rendered object. SRenderableImage *nextImage = NULL; -#define CHECK_IMAGE_AND_PREPARE(img, imgtype, shadercomponent) \ +#define CHECK_IMAGE_AND_PREPARE(img, imgtype, shadercomponent, checkOpaque) \ if ((img)) \ PrepareImageForRender(*(img), imgtype, firstImage, nextImage, renderableFlags, \ - theGeneratedKey, shadercomponent); + theGeneratedKey, shadercomponent, \ + checkOpaque ? &transparencyImagesHaveOpaquePixels : nullptr); CHECK_IMAGE_AND_PREPARE(theMaterial->m_DiffuseMaps[0], ImageMapTypes::Diffuse, - SShaderDefaultMaterialKeyProperties::DiffuseMap0); + SShaderDefaultMaterialKeyProperties::DiffuseMap0, true); CHECK_IMAGE_AND_PREPARE(theMaterial->m_DiffuseMaps[1], ImageMapTypes::Diffuse, - SShaderDefaultMaterialKeyProperties::DiffuseMap1); + SShaderDefaultMaterialKeyProperties::DiffuseMap1, true); CHECK_IMAGE_AND_PREPARE(theMaterial->m_DiffuseMaps[2], ImageMapTypes::Diffuse, - SShaderDefaultMaterialKeyProperties::DiffuseMap2); + SShaderDefaultMaterialKeyProperties::DiffuseMap2, true); CHECK_IMAGE_AND_PREPARE(theMaterial->m_EmissiveMap, ImageMapTypes::Emissive, - SShaderDefaultMaterialKeyProperties::EmissiveMap); + SShaderDefaultMaterialKeyProperties::EmissiveMap, false); CHECK_IMAGE_AND_PREPARE(theMaterial->m_EmissiveMap2, ImageMapTypes::Emissive, - SShaderDefaultMaterialKeyProperties::EmissiveMap2); + SShaderDefaultMaterialKeyProperties::EmissiveMap2, false); CHECK_IMAGE_AND_PREPARE(theMaterial->m_SpecularReflection, ImageMapTypes::Specular, - SShaderDefaultMaterialKeyProperties::SpecularMap); + SShaderDefaultMaterialKeyProperties::SpecularMap, false); CHECK_IMAGE_AND_PREPARE(theMaterial->m_RoughnessMap, ImageMapTypes::Roughness, - SShaderDefaultMaterialKeyProperties::RoughnessMap); + SShaderDefaultMaterialKeyProperties::RoughnessMap, false); CHECK_IMAGE_AND_PREPARE(theMaterial->m_OpacityMap, ImageMapTypes::Opacity, - SShaderDefaultMaterialKeyProperties::OpacityMap); + SShaderDefaultMaterialKeyProperties::OpacityMap, true); CHECK_IMAGE_AND_PREPARE(theMaterial->m_BumpMap, ImageMapTypes::Bump, - SShaderDefaultMaterialKeyProperties::BumpMap); + SShaderDefaultMaterialKeyProperties::BumpMap, false); CHECK_IMAGE_AND_PREPARE(theMaterial->m_SpecularMap, ImageMapTypes::SpecularAmountMap, - SShaderDefaultMaterialKeyProperties::SpecularAmountMap); + SShaderDefaultMaterialKeyProperties::SpecularAmountMap, false); CHECK_IMAGE_AND_PREPARE(theMaterial->m_NormalMap, ImageMapTypes::Normal, - SShaderDefaultMaterialKeyProperties::NormalMap); + SShaderDefaultMaterialKeyProperties::NormalMap, false); CHECK_IMAGE_AND_PREPARE(theMaterial->m_DisplacementMap, ImageMapTypes::Displacement, - SShaderDefaultMaterialKeyProperties::DisplacementMap); + SShaderDefaultMaterialKeyProperties::DisplacementMap, false); CHECK_IMAGE_AND_PREPARE(theMaterial->m_TranslucencyMap, ImageMapTypes::Translucency, - SShaderDefaultMaterialKeyProperties::TranslucencyMap); + SShaderDefaultMaterialKeyProperties::TranslucencyMap, true); CHECK_IMAGE_AND_PREPARE(theMaterial->m_Lightmaps.m_LightmapIndirect, ImageMapTypes::LightmapIndirect, - SShaderDefaultMaterialKeyProperties::LightmapIndirect); + SShaderDefaultMaterialKeyProperties::LightmapIndirect, false); CHECK_IMAGE_AND_PREPARE(theMaterial->m_Lightmaps.m_LightmapRadiosity, ImageMapTypes::LightmapRadiosity, - SShaderDefaultMaterialKeyProperties::LightmapRadiosity); + SShaderDefaultMaterialKeyProperties::LightmapRadiosity, false); CHECK_IMAGE_AND_PREPARE(theMaterial->m_Lightmaps.m_LightmapShadow, ImageMapTypes::LightmapShadow, - SShaderDefaultMaterialKeyProperties::LightmapShadow); + SShaderDefaultMaterialKeyProperties::LightmapShadow, false); } #undef CHECK_IMAGE_AND_PREPARE @@ -780,6 +787,17 @@ namespace render { if (IsNotOne(subsetOpacity)) renderableFlags |= RenderPreparationResultFlagValues::HasTransparency; + // 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) { + m_Renderer.DefaultMaterialShaderKeyProperties() + .m_AlphaTestEnabled.SetValue(theGeneratedKey, true); + renderableFlags.setAlphaTest(true); + } else { + renderableFlags.setAlphaTest(false); + } + retval.m_FirstImage = firstImage; if (retval.m_RenderableFlags.IsDirty()) retval.m_Dirty = true; @@ -826,7 +844,7 @@ namespace render { #define CHECK_IMAGE_AND_PREPARE(img, imgtype, shadercomponent) \ if ((img)) \ PrepareImageForRender(*(img), imgtype, firstImage, nextImage, renderableFlags, \ - theGeneratedKey, shadercomponent); + theGeneratedKey, shadercomponent, nullptr); CHECK_IMAGE_AND_PREPARE(inMaterial.m_DisplacementMap, ImageMapTypes::Displacement, SShaderDefaultMaterialKeyProperties::DisplacementMap); @@ -1205,7 +1223,8 @@ namespace render { if (iter->second) { PrepareImageForRender(*iter->second, ImageMapTypes::Unknown, firstImage, nextImage, flags, key, - SShaderDefaultMaterialKeyProperties::ImageMapCount); + SShaderDefaultMaterialKeyProperties::ImageMapCount, + nullptr); } } } diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h index 1eb8766..eae29f6 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h @@ -310,7 +310,7 @@ namespace render { SRenderableImage *&ioFirstImage, SRenderableImage *&ioNextImage, SRenderableObjectFlags &ioFlags, SShaderDefaultMaterialKey &ioGeneratedShaderKey, - QT3DSU32 inImageIndex); + QT3DSU32 inImageIndex, bool *opaqueCheck); SDefaultMaterialPreparationResult PrepareDefaultMaterialForRender(SDefaultMaterial &inMaterial, diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp index 64de27d..c33aaeb 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp @@ -554,19 +554,23 @@ namespace render { }; NVRenderShaderProgram *Qt3DSRendererImpl::GenerateShader(SSubsetRenderable &inRenderable, - TShaderFeatureSet inFeatureSet) + TShaderFeatureSet inFeatureSet, + bool depth) { // build a string that allows us to print out the shader we are generating to the log. // This is time consuming but I feel like it doesn't happen all that often and is very - // useful to users - // looking at the log file. + // useful to users looking at the log file. QLatin1String logPrefix("mesh subset pipeline-- "); m_GeneratedShaderString.clear(); m_GeneratedShaderString.assign(logPrefix.data()); + if (depth) + m_GeneratedShaderString.append("depth--"); SShaderDefaultMaterialKey theKey(inRenderable.m_ShaderDescription); - theKey.ToString(m_GeneratedShaderString, m_DefaultMaterialShaderKeyProperties); + theKey.ToString(m_GeneratedShaderString, m_DefaultMaterialShaderKeyProperties, + depth ? SShaderDefaultMaterialKeyProperties::DepthKey + : SShaderDefaultMaterialKeyProperties::DefaultKey); IShaderCache &theCache = m_qt3dsContext.GetShaderCache(); CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(m_GeneratedShaderString.c_str()); @@ -577,6 +581,13 @@ namespace render { SSubsetMaterialVertexPipeline pipeline( *this, inRenderable, m_DefaultMaterialShaderKeyProperties.m_WireframeMode.GetValue(theKey)); + if (depth) { + return m_qt3dsContext.GetDefaultMaterialShaderGenerator().GenerateDepthPassShader( + inRenderable.m_Material, inRenderable.m_ShaderDescription, pipeline, inFeatureSet, + inRenderable.m_FirstImage, + inRenderable.m_RenderableFlags.HasTransparency(), + logPrefix.data()); + } return m_qt3dsContext.GetDefaultMaterialShaderGenerator().GenerateShader( inRenderable.m_Material, inRenderable.m_ShaderDescription, pipeline, inFeatureSet, m_CurrentLayer->m_Lights, inRenderable.m_FirstImage, @@ -584,6 +595,47 @@ namespace render { logPrefix.data()); } + NVRenderShaderProgram *Qt3DSRendererImpl::GenerateShadowShader(SSubsetRenderable &inRenderable, + TShaderFeatureSet inFeatureSet, + RenderLightTypes::Enum lightType) + { + // build a string that allows us to print out the shader we are generating to the log. + // This is time consuming but I feel like it doesn't happen all that often and is very + // useful to users looking at the log file. + QLatin1String logPrefix("mesh subset pipeline-- "); + + m_GeneratedShaderString.clear(); + m_GeneratedShaderString.assign(logPrefix.data()); + if (lightType == RenderLightTypes::Point) + m_GeneratedShaderString.append("shadowcube--"); + else + m_GeneratedShaderString.append("shadowmap--"); + + SShaderDefaultMaterialKey theKey(inRenderable.m_ShaderDescription); + theKey.ToString(m_GeneratedShaderString, m_DefaultMaterialShaderKeyProperties, + SShaderDefaultMaterialKeyProperties::DepthKey); + IShaderCache &theCache = m_qt3dsContext.GetShaderCache(); + CRegisteredString theCacheKey + = m_qt3dsContext.GetStringTable().RegisterStr(m_GeneratedShaderString.c_str()); + NVRenderShaderProgram *cachedProgram = theCache.GetProgram(theCacheKey, inFeatureSet); + if (cachedProgram) + return cachedProgram; + + SSubsetMaterialVertexPipeline pipeline( + *this, inRenderable, + m_DefaultMaterialShaderKeyProperties.m_WireframeMode.GetValue(theKey)); + if (lightType == RenderLightTypes::Point) { + return m_qt3dsContext.GetDefaultMaterialShaderGenerator().GenerateCubeDepthShader( + inRenderable.m_Material, inRenderable.m_ShaderDescription, pipeline, inFeatureSet, + inRenderable.m_FirstImage, inRenderable.m_RenderableFlags.HasTransparency(), + logPrefix.data()); + } + return m_qt3dsContext.GetDefaultMaterialShaderGenerator().GenerateOrthoDepthShader( + inRenderable.m_Material, inRenderable.m_ShaderDescription, pipeline, inFeatureSet, + inRenderable.m_FirstImage, inRenderable.m_RenderableFlags.HasTransparency(), + logPrefix.data()); + } + // -------------- Special cases for shadows ------------------- SRenderableDepthPrepassShader * diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.h index 1ac85db..9753256 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.h +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.h @@ -44,8 +44,8 @@ namespace render { */ struct SShaderTessellationProperties { - NVRenderCachedShaderProperty<QT3DSF32> m_EdgeTessLevel; ///< tesselation value for the edges - NVRenderCachedShaderProperty<QT3DSF32> m_InsideTessLevel; ///< tesselation value for the inside + NVRenderCachedShaderProperty<QT3DSF32> m_EdgeTessLevel; ///< tessellation value for the edges + NVRenderCachedShaderProperty<QT3DSF32> m_InsideTessLevel; ///< tessellation value for the inside NVRenderCachedShaderProperty<QT3DSF32> m_PhongBlend; ///< blending between linear and phong component NVRenderCachedShaderProperty<QT3DSVec2> @@ -98,34 +98,6 @@ namespace render { } }; - struct SDefaultMaterialRenderableDepthShader - { - NVAllocatorCallback &m_Allocator; - NVRenderShaderProgram &m_Shader; - NVRenderCachedShaderProperty<QT3DSMat44> m_MVP; - - QT3DSI32 m_RefCount; - SDefaultMaterialRenderableDepthShader(NVRenderShaderProgram &inShader, - NVRenderContext &inContext) - : m_Allocator(inContext.GetAllocator()) - , m_Shader(inShader) - , m_MVP("model_view_projection", inShader) - , m_RefCount(0) - { - m_Shader.addRef(); - } - - ~SDefaultMaterialRenderableDepthShader() { m_Shader.release(); } - - void addRef() { ++m_RefCount; } - void release() - { - --m_RefCount; - if (m_RefCount <= 0) - NVDelete(m_Allocator, this); - } - }; - /** * Cached texture property lookups, used one per texture so a shader generator for N * textures will have an array of N of these lookup objects. diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp index eb23f3d..b140e85 100644 --- a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp +++ b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp @@ -154,11 +154,13 @@ struct SBufferManager : public IBufferManager return m_StrTable->RegisterStr(m_PathBuilder.c_str()); } - void SetImageHasTransparency(CRegisteredString inImagePath, bool inHasTransparency) override + void SetImageHasTransparency(CRegisteredString inImagePath, bool inHasTransparency, + bool hasOpaque) override { pair<TImageMap::iterator, bool> theImage = m_ImageMap.insert(make_pair(inImagePath, SImageEntry())); theImage.first->second.m_TextureFlags.SetHasTransparency(inHasTransparency); + theImage.first->second.m_TextureFlags.setHasOpaquePixels(hasOpaque); } bool GetImageHasTransparency(CRegisteredString inSourcePath) const override @@ -169,6 +171,14 @@ struct SBufferManager : public IBufferManager return false; } + bool GetImageHasOpaquePixels(CRegisteredString inSourcePath) const override + { + TImageMap::const_iterator theIter = m_ImageMap.find(inSourcePath); + if (theIter != m_ImageMap.end()) + return theIter->second.m_TextureFlags.HasOpaquePixels(); + return false; + } + void SetImageTransparencyToFalseIfNotSet(CRegisteredString inSourcePath) override { pair<TImageMap::iterator, bool> theImage = @@ -512,9 +522,12 @@ struct SBufferManager : public IBufferManager if (theDecompressedImage.data) inLoadedImage.ReleaseDecompressedTexture(theDecompressedImage); } - if (wasInserted == true || inForceScanForTransparency) - theImage.first->second.m_TextureFlags.SetHasTransparency( - inLoadedImage.ScanForTransparency()); + if (wasInserted || inForceScanForTransparency) { + auto &flags = theImage.first->second.m_TextureFlags; + bool alsoOpaquePixels = false; + flags.SetHasTransparency(inLoadedImage.ScanForTransparency(alsoOpaquePixels)); + flags.setHasOpaquePixels(alsoOpaquePixels); + } theImage.first->second.m_Texture = theTexture; return theImage.first->second; } diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h index 070ab67..7930158 100644 --- a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h +++ b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h @@ -54,8 +54,9 @@ namespace render { virtual CRegisteredString CombineBaseAndRelative(const char8_t *inBase, const char8_t *inRelative) = 0; virtual void SetImageHasTransparency(CRegisteredString inSourcePath, - bool inHasTransparency) = 0; + bool inHasTransparency, bool alsoOpaque) = 0; virtual bool GetImageHasTransparency(CRegisteredString inSourcePath) const = 0; + virtual bool GetImageHasOpaquePixels(CRegisteredString inSourcePath) const = 0; virtual void SetImageTransparencyToFalseIfNotSet(CRegisteredString inSourcePath) = 0; virtual void SetInvertImageUVCoords(CRegisteredString inSourcePath, bool inShouldInvertCoords) = 0; diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp index 1176273..ff221f9 100644 --- a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp +++ b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp @@ -370,9 +370,10 @@ struct STextureDataWriter struct STextureAlphaScanner { bool &m_Alpha; + bool *m_alsoOpaque = nullptr; - STextureAlphaScanner(bool &inAlpha) - : m_Alpha(inAlpha) + STextureAlphaScanner(bool &inAlpha, bool *alsoOpaque) + : m_Alpha(inAlpha), m_alsoOpaque(alsoOpaque) { } @@ -381,12 +382,19 @@ struct STextureAlphaScanner Q_UNUSED(X) Q_UNUSED(Y) QT3DSU32 offset = 0; - for (QT3DSU32 yidx = 0; yidx < height; ++yidx) { - for (QT3DSU32 xidx = 0; xidx < width; ++xidx, offset += 4) { + bool opq = false; + bool exitLoop = false; + for (QT3DSU32 yidx = 0; yidx < height && !exitLoop; ++yidx) { + for (QT3DSU32 xidx = 0; xidx < width && !exitLoop; ++xidx, offset += 4) { if (pixelData[offset + 3] < 255) m_Alpha = true; + else + opq = true; + exitLoop = m_Alpha && (opq || !m_alsoOpaque); } } + if (m_alsoOpaque) + *m_alsoOpaque = opq; } // If we detect alpha we can stop right there. @@ -423,21 +431,27 @@ static void DecompressDDS(void *inSrc, QT3DSU32 inDataSize, QT3DSU32 inWidth, QT } } -bool ScanDDSForAlpha(Qt3DSDDSImage *dds) +bool ScanDDSForAlpha(Qt3DSDDSImage *dds, bool *alsoOpaquePixels = nullptr) { bool hasAlpha = false; switch (dds->format) { case qt3ds::render::NVRenderTextureFormats::RGBA_DXT1: DecompressDDS<DXT_BLOCKDECODER_1>(dds->data[0], dds->size[0], dds->mipwidth[0], - dds->mipheight[0], STextureAlphaScanner(hasAlpha)); + dds->mipheight[0], STextureAlphaScanner(hasAlpha, + alsoOpaquePixels) + ); break; case qt3ds::render::NVRenderTextureFormats::RGBA_DXT3: DecompressDDS<DXT_BLOCKDECODER_3>(dds->data[0], dds->size[0], dds->mipwidth[0], - dds->mipheight[0], STextureAlphaScanner(hasAlpha)); + dds->mipheight[0], STextureAlphaScanner(hasAlpha, + alsoOpaquePixels) + ); break; case qt3ds::render::NVRenderTextureFormats::RGBA_DXT5: DecompressDDS<DXT_BLOCKDECODER_5>(dds->data[0], dds->size[0], dds->mipwidth[0], - dds->mipheight[0], STextureAlphaScanner(hasAlpha)); + dds->mipheight[0], STextureAlphaScanner(hasAlpha, + alsoOpaquePixels) + ); break; default: QT3DS_ASSERT(false); @@ -447,10 +461,11 @@ bool ScanDDSForAlpha(Qt3DSDDSImage *dds) } bool ScanImageForAlpha(const void *inData, QT3DSU32 inWidth, QT3DSU32 inHeight, QT3DSU32 inPixelSizeInBytes, - QT3DSU8 inAlphaSizeInBits) + QT3DSU8 inAlphaSizeInBits, bool *alsoOpaque = nullptr) { const QT3DSU8 *rowPtr = reinterpret_cast<const QT3DSU8 *>(inData); bool hasAlpha = false; + bool hasOpaque = false; if (inAlphaSizeInBits == 0) return hasAlpha; if (inPixelSizeInBytes != 2 && inPixelSizeInBytes != 4) { @@ -476,8 +491,12 @@ bool ScanImageForAlpha(const void *inData, QT3DSU32 inWidth, QT3DSU32 inHeight, pixelValue = pixelValue >> alphaRightShift; if (pixelValue < maxAlphaValue) hasAlpha = true; + else + hasOpaque = true; } } + if (alsoOpaque) + *alsoOpaque = hasOpaque; return hasAlpha; } } @@ -505,7 +524,7 @@ void SLoadedTexture::release() theAllocator->deallocate(this); } -bool SLoadedTexture::ScanForTransparency() +bool SLoadedTexture::ScanForTransparency(bool &alsoOpaquePixels) { switch (format) { case NVRenderTextureFormats::SRGB8A8: @@ -513,7 +532,7 @@ bool SLoadedTexture::ScanForTransparency() if (!data) { // dds return true; } else { - return ScanImageForAlpha(data, width, height, 4, 8); + return ScanImageForAlpha(data, width, height, 4, 8, &alsoOpaquePixels); } break; // Scan the image. @@ -528,7 +547,7 @@ bool SLoadedTexture::ScanForTransparency() if (!data) { // dds return true; } else { - return ScanImageForAlpha(data, width, height, 2, 1); + return ScanImageForAlpha(data, width, height, 2, 1, &alsoOpaquePixels); } break; case NVRenderTextureFormats::Alpha8: @@ -551,7 +570,7 @@ bool SLoadedTexture::ScanForTransparency() case NVRenderTextureFormats::RGBA_DXT1: case NVRenderTextureFormats::RGBA_DXT5: if (dds) { - return ScanDDSForAlpha(dds); + return ScanDDSForAlpha(dds, &alsoOpaquePixels); } else { QT3DS_ASSERT(false); return false; diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h index f019400..10200ad 100644 --- a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h +++ b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h @@ -141,7 +141,8 @@ namespace render { void EnsureMultiplerOfFour(NVFoundationBase &inFoundation, const char *inPath); // Returns true if this image has a pixel less than 255. - bool ScanForTransparency(); + // If yes, then alsoOpaquePixels is true if some are not + bool ScanForTransparency(bool &alsoOpaquePixels); // Be sure to call this or risk leaking an enormous amount of memory void release() override; |