Skip to content

Instantly share code, notes, and snippets.

@w0wca7a
Last active September 26, 2025 21:55
Show Gist options
  • Select an option

  • Save w0wca7a/e2eb6f25940d7c017e5b5074b6054833 to your computer and use it in GitHub Desktop.

Select an option

Save w0wca7a/e2eb6f25940d7c017e5b5074b6054833 to your computer and use it in GitHub Desktop.
Simple menu with blur in Stride. In this example we not using Depth of field effect in game. If you already using Depth of field, you must save DoF configuration before showing UI, and restore after hiding.
using Stride.Core;
using Stride.Core.Annotations;
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Games;
using Stride.Input;
using Stride.Rendering.Compositing;
using Stride.Rendering.Images;
using Stride.UI;
[Display("DoF Effect Menu")]
[ComponentCategory("UI")]
public class DoFEffectMenu : SyncScript
{
[DataMember(1, "DOF Level")]
[DataMemberRange(0, 1, 0.05, 0.15, 2)]
public float Level { get; set; } = 0.3f;
[DataMember(2, "Menu key")]
public Keys MenuKey { get; set; } = Keys.Space;
[DataMember(-1)]
public UIComponent UIPage { get; set; }
private PostProcessingEffects PostEffects;
private DepthOfField doF;
private bool isDofEnabled = false;
private bool isMenuShow = false;
// should be global game variable
//bool isPaused;
public override void Start()
{
base.Start();
var compositor = SceneSystem.GraphicsCompositor.Game;
// We have SceneRendererCollection with 2 children SceneCameraRenderers (CameraRenderer in Game Studio)
// 0 - Main camera
// https://doc.stride3d.net/latest/en/manual/graphics/graphics-compositor/render-textures.html#5-set-up-the-graphics-compositor
// 2 - UI configured like in video https://www.youtube.com/watch?v=cazIR97VPcg&ab_channel=MarianDziubiak
var rendererCollection = ((SceneRendererCollection)compositor).Children;
for (var i = 0; i < rendererCollection.Count; i++) // 2 SceneCameraRenderers
{
//var child
if (rendererCollection[i] is SceneCameraRenderer renderer)
{
var child = renderer.Child;
if (child == null) return;
if (child is ForwardRenderer forwardRenderer)
{
PostEffects = forwardRenderer.PostEffects as PostProcessingEffects;
}
}
}
ConfigureDoF(PostEffects);
UIPage ??= Entity.Get<UIComponent>();
UIPage.Page.RootElement.Visibility = Visibility.Hidden;
}
private void ConfigureDoF(PostProcessingEffects postProcessing)
{
// get Depth of Field and disable it
doF = postProcessing.DepthOfField;
doF.Enabled = isDofEnabled;
// try to play with enabled DepthOfField in Post Effects in Game Studio for better quality
doF.MaxBokehSize = Level;
doF.DOFAreas = new Vector4(0.1f, 0.1f, 0.1f, 2f);
doF.QualityPreset = 0.5f;
doF.Technique = BokehTechnique.CircularGaussian;
doF.AutoFocus = false;
}
public override void Update()
{
if (Input.Keyboard.IsKeyReleased(MenuKey))
{
if (!isMenuShow) Show();
else Hide();
}
}
private void Show()
{
isMenuShow = true;
doF.Enabled = true;
UIPage.Page.RootElement.Visibility = Visibility.Visible;
// gameplay pause logic
// pause will only work with animations, particles and physics.
Services.GetService<IGame>().UpdateTime.Factor = 0;
/*
for working in sync and async scripts you must have global game bool variable,
and do in every Update() and Execute() methods in all script
if(isPaused) return;
*/
// isPaused = true;
}
private void Hide()
{
isMenuShow = false;
doF.Enabled = false;
UIPage.Page.RootElement.Visibility = Visibility.Hidden;
// gameplay resume logic
Services.GetService<IGame>().UpdateTime.Factor = 1;
// isPaused = false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment