diff --git a/Resources/Engine/Materials/Atmosphere.ovmat b/Resources/Engine/Materials/Atmosphere.ovmat index 7d41edc8f..42904e3a3 100644 --- a/Resources/Engine/Materials/Atmosphere.ovmat +++ b/Resources/Engine/Materials/Atmosphere.ovmat @@ -1,6 +1,8 @@ :Shaders\Atmosphere.ovfx + false + true false false true diff --git a/Resources/Engine/Materials/Default.ovmat b/Resources/Engine/Materials/Default.ovmat index d489dcc32..41114c442 100644 --- a/Resources/Engine/Materials/Default.ovmat +++ b/Resources/Engine/Materials/Default.ovmat @@ -1,6 +1,8 @@ :Shaders\StandardPBR.ovfx + true + true false true false diff --git a/Resources/Engine/Materials/Skysphere.ovmat b/Resources/Engine/Materials/Skysphere.ovmat index 7e973be4b..94f333781 100644 --- a/Resources/Engine/Materials/Skysphere.ovmat +++ b/Resources/Engine/Materials/Skysphere.ovmat @@ -1,6 +1,8 @@ :Shaders\Skysphere.ovfx + false + true false false true diff --git a/Resources/Engine/Shaders/Common/Utils.ovfxh b/Resources/Engine/Shaders/Common/Utils.ovfxh index c576547a3..c2cfd330b 100644 --- a/Resources/Engine/Shaders/Common/Utils.ovfxh +++ b/Resources/Engine/Shaders/Common/Utils.ovfxh @@ -12,6 +12,13 @@ vec2 TileAndOffsetTexCoords(vec2 texCoords, vec2 tiling, vec2 offset) return vec2(mod(texCoords.x * tiling.x, 1), mod(texCoords.y * tiling.y, 1)) + offset; } +bool IsOrthographic(mat4 projectionMatrix) +{ + // In an orthographic projection matrix, the [3][3] element is 1.0 + // In a perspective projection matrix, it's 0.0 + return projectionMatrix[3][3] > 0.5; +} + // Expects a height map with values in the range [0, 1]. // 1.0 means the height is at the maximum depth, 0.0 means the height is at the minimum depth. vec2 ApplyParallaxOcclusionMapping(vec2 texCoords, sampler2D heightMap, vec3 tangentViewPos, vec3 tangentFragPos, float heightScale) @@ -58,6 +65,13 @@ vec2 ApplyParallaxOcclusionMapping(vec2 texCoords, sampler2D heightMap, vec3 tan return finalTexCoords; } +bool IsParallaxOutOfBounds(vec2 texCoords, mat4 projectionMatrix) +{ + return + !IsOrthographic(projectionMatrix) && // No clipping in orthographic projection (not supported) + (texCoords.x < 0.0 || texCoords.x > 1.0 || texCoords.y < 0.0 || texCoords.y > 1.0); +} + // [Deprecated] Kept for backward compatibility. Prefer using `ApplyParallaxOcclusionMapping()` instead. vec2 ApplyParallaxMapping(vec2 texCoords, sampler2D heightMap, vec3 tangentViewPos, vec3 tangentFragPos, float heightScale) { diff --git a/Resources/Engine/Shaders/Standard.ovfx b/Resources/Engine/Shaders/Standard.ovfx index e9bb9cc4b..d185da0fe 100644 --- a/Resources/Engine/Shaders/Standard.ovfx +++ b/Resources/Engine/Shaders/Standard.ovfx @@ -84,6 +84,7 @@ uniform float u_AlphaClippingThreshold = 0.1; #endif #if defined(SHADOW_PASS) +#undef PARALLAX_MAPPING // Disable parallax mapping in shadow pass uniform float u_ShadowClippingThreshold = 0.5; #endif @@ -98,7 +99,7 @@ void main() #if defined(PARALLAX_MAPPING) texCoords = ApplyParallaxOcclusionMapping(texCoords, u_HeightMap, fs_in.TangentViewPos, fs_in.TangentFragPos, u_HeightScale); - if (u_ParallaxClipEdges && (texCoords.x < 0.0 || texCoords.x > 1.0 || texCoords.y < 0.0 || texCoords.y > 1.0)) + if (u_ParallaxClipEdges && IsParallaxOutOfBounds(texCoords, ubo_Projection)) { discard; } diff --git a/Resources/Engine/Shaders/StandardPBR.ovfx b/Resources/Engine/Shaders/StandardPBR.ovfx index 5e754a97e..15695896e 100644 --- a/Resources/Engine/Shaders/StandardPBR.ovfx +++ b/Resources/Engine/Shaders/StandardPBR.ovfx @@ -86,6 +86,7 @@ uniform float u_AlphaClippingThreshold = 0.1; #endif #if defined(SHADOW_PASS) +#undef PARALLAX_MAPPING // Disable parallax mapping in shadow pass uniform float u_ShadowClippingThreshold = 0.5; #endif @@ -100,7 +101,7 @@ void main() #if defined(PARALLAX_MAPPING) texCoords = ApplyParallaxOcclusionMapping(texCoords, u_HeightMap, fs_in.TangentViewPos, fs_in.TangentFragPos, u_HeightScale); - if (u_ParallaxClipEdges && (texCoords.x < 0.0 || texCoords.x > 1.0 || texCoords.y < 0.0 || texCoords.y > 1.0)) + if (u_ParallaxClipEdges && IsParallaxOutOfBounds(texCoords, ubo_Projection)) { discard; } diff --git a/Sources/Overload/OvCore/src/OvCore/Resources/Material.cpp b/Sources/Overload/OvCore/src/OvCore/Resources/Material.cpp index f4c78498b..7acde7cf5 100644 --- a/Sources/Overload/OvCore/src/OvCore/Resources/Material.cpp +++ b/Sources/Overload/OvCore/src/OvCore/Resources/Material.cpp @@ -20,6 +20,8 @@ void OvCore::Resources::Material::OnSerialize(tinyxml2::XMLDocument& p_doc, tiny tinyxml2::XMLNode* settingsNode = p_doc.NewElement("settings"); p_node->InsertEndChild(settingsNode); + Serializer::SerializeBoolean(p_doc, settingsNode, "support_orthographic", m_supportOrthographic); + Serializer::SerializeBoolean(p_doc, settingsNode, "support_perspective", m_supportPerspective); Serializer::SerializeBoolean(p_doc, settingsNode, "blendable", m_blendable); Serializer::SerializeBoolean(p_doc, settingsNode, "backface_culling", m_backfaceCulling); Serializer::SerializeBoolean(p_doc, settingsNode, "frontface_culling", m_frontfaceCulling); @@ -125,6 +127,8 @@ void OvCore::Resources::Material::OnDeserialize(tinyxml2::XMLDocument& p_doc, ti if (settingsNode) { + Serializer::DeserializeBoolean(p_doc, settingsNode, "support_orthographic", m_supportOrthographic); + Serializer::DeserializeBoolean(p_doc, settingsNode, "support_perspective", m_supportPerspective); Serializer::DeserializeBoolean(p_doc, settingsNode, "blendable", m_blendable); Serializer::DeserializeBoolean(p_doc, settingsNode, "backface_culling", m_backfaceCulling); Serializer::DeserializeBoolean(p_doc, settingsNode, "frontface_culling", m_frontfaceCulling); diff --git a/Sources/Overload/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp b/Sources/Overload/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp index 3c1d6aeb5..06b6cb9ea 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp @@ -335,6 +335,8 @@ void OvEditor::Panels::MaterialEditor::GenerateMaterialSettingsContent() GUIDrawer::DrawBoolean(*m_materialSettingsColumns, "Shadow Casting", std::bind(&OvCore::Resources::Material::IsShadowCaster, m_target), std::bind(&OvCore::Resources::Material::SetCastShadows, m_target, std::placeholders::_1)); GUIDrawer::DrawBoolean(*m_materialSettingsColumns, "Shadow Receiving", std::bind(&OvCore::Resources::Material::IsShadowReceiver, m_target), std::bind(&OvCore::Resources::Material::SetReceiveShadows, m_target, std::placeholders::_1)); GUIDrawer::DrawBoolean(*m_materialSettingsColumns, "User Interface", std::bind(&OvCore::Resources::Material::IsUserInterface, m_target), std::bind(&OvCore::Resources::Material::SetUserInterface, m_target, std::placeholders::_1)); + GUIDrawer::DrawBoolean(*m_materialSettingsColumns, "Orthographic Support", std::bind(&OvCore::Resources::Material::SupportsOrthographic, m_target), std::bind(&OvCore::Resources::Material::SetOrthographicSupport, m_target, std::placeholders::_1)); + GUIDrawer::DrawBoolean(*m_materialSettingsColumns, "Perspective Support", std::bind(&OvCore::Resources::Material::SupportsPerspective, m_target), std::bind(&OvCore::Resources::Material::SetPerspectiveSupport, m_target, std::placeholders::_1)); GUIDrawer::DrawScalar(*m_materialSettingsColumns, "GPU Instances", std::bind(&OvCore::Resources::Material::GetGPUInstances, m_target), std::bind(&OvCore::Resources::Material::SetGPUInstances, m_target, std::placeholders::_1), 1.0f, 0, 100000); GUIDrawer::DrawScalar(*m_materialSettingsColumns, "Draw Order", std::bind(&OvCore::Resources::Material::GetDrawOrder, m_target), std::bind(&OvCore::Resources::Material::SetDrawOrder, m_target, std::placeholders::_1), 1.0f, 0, 100000); } diff --git a/Sources/Overload/OvRendering/include/OvRendering/Data/Material.h b/Sources/Overload/OvRendering/include/OvRendering/Data/Material.h index 411260d34..fb1c7bcaf 100644 --- a/Sources/Overload/OvRendering/include/OvRendering/Data/Material.h +++ b/Sources/Overload/OvRendering/include/OvRendering/Data/Material.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace OvRendering::Data { @@ -132,6 +133,18 @@ namespace OvRendering::Data */ bool IsValid() const; + /** + * Sets the shader support for orthographic projection + * @param p_supportOrthographic + */ + void SetOrthographicSupport(bool p_supportOrthographic); + + /** + * Sets the shader support for perspective projection + * @param p_supportPerspective + */ + void SetPerspectiveSupport(bool p_supportPerspective); + /** * Sets the draw order of the material * @param p_order @@ -150,7 +163,6 @@ namespace OvRendering::Data */ void SetUserInterface(bool p_userInterface); - /** * Defines if the material has backface culling * @param p_backfaceCulling @@ -293,11 +305,30 @@ namespace OvRendering::Data */ bool SupportsFeature(const std::string& p_feature) const; + /** + * Returns true if the material supports orthopgraphic projection + */ + bool SupportsOrthographic() const; + + /** + * Returns true if the material supports perspective projection + */ + bool SupportsPerspective() const; + + /** + * Returns true if the material supports the given projection mode + * @param p_projectionMode + */ + bool SupportsProjectionMode(OvRendering::Settings::EProjectionMode p_projectionMode) const; + protected: OvRendering::Resources::Shader* m_shader = nullptr; PropertyMap m_properties; Data::FeatureSet m_features; + bool m_supportOrthographic = true; + bool m_supportPerspective = true; + bool m_userInterface = false; bool m_blendable = false; bool m_backfaceCulling = true; diff --git a/Sources/Overload/OvRendering/src/OvRendering/Core/ABaseRenderer.cpp b/Sources/Overload/OvRendering/src/OvRendering/Core/ABaseRenderer.cpp index f601cfc04..7a12d9d7d 100644 --- a/Sources/Overload/OvRendering/src/OvRendering/Core/ABaseRenderer.cpp +++ b/Sources/Overload/OvRendering/src/OvRendering/Core/ABaseRenderer.cpp @@ -185,9 +185,12 @@ void OvRendering::Core::ABaseRenderer::DrawEntity( auto material = p_drawable.material; auto mesh = p_drawable.mesh; - const auto gpuInstances = material.value().GetGPUInstances(); + OVASSERT(material.has_value(), "Missing material instance!"); - if (mesh && material && material->IsValid() && gpuInstances > 0) + const auto gpuInstances = material->GetGPUInstances(); + const auto projectionMode = m_frameDescriptor.camera->GetProjectionMode(); + + if (mesh && material->IsValid() && material->SupportsProjectionMode(projectionMode) && gpuInstances > 0) { p_pso.depthWriting = p_drawable.stateMask.depthWriting; p_pso.colorWriting.mask = p_drawable.stateMask.colorWriting ? 0xFF : 0x00; diff --git a/Sources/Overload/OvRendering/src/OvRendering/Data/Material.cpp b/Sources/Overload/OvRendering/src/OvRendering/Data/Material.cpp index e61d1a757..3a80ca7a6 100644 --- a/Sources/Overload/OvRendering/src/OvRendering/Data/Material.cpp +++ b/Sources/Overload/OvRendering/src/OvRendering/Data/Material.cpp @@ -284,6 +284,16 @@ bool OvRendering::Data::Material::IsValid() const return HasShader(); } +void OvRendering::Data::Material::SetOrthographicSupport(bool p_supportOrthographic) +{ + m_supportOrthographic = p_supportOrthographic; +} + +void OvRendering::Data::Material::SetPerspectiveSupport(bool p_supportPerspective) +{ + m_supportPerspective = p_supportPerspective; +} + void OvRendering::Data::Material::SetDrawOrder(int p_order) { m_drawOrder = p_order; @@ -437,3 +447,26 @@ bool OvRendering::Data::Material::SupportsFeature(const std::string& p_feature) { return m_shader->GetFeatures().contains(p_feature); } + +bool OvRendering::Data::Material::SupportsOrthographic() const +{ + return m_supportOrthographic; +} + +bool OvRendering::Data::Material::SupportsPerspective() const +{ + return m_supportPerspective; +} + +bool OvRendering::Data::Material::SupportsProjectionMode(OvRendering::Settings::EProjectionMode p_projectionMode) const +{ + using enum OvRendering::Settings::EProjectionMode; + + switch (p_projectionMode) + { + case ORTHOGRAPHIC: return SupportsOrthographic(); + case PERSPECTIVE: return SupportsPerspective(); + } + + return true; +}