Class TCastleScreenEffects

Unit

Declaration

type TCastleScreenEffects = class(TCastleUserInterface)

Description

Screen effects are shaders that post-process the rendered screen. The effects may be defined using X3D node ScreenEffect.

This control applies screen effects (post-processing) on the rendering done by children and (when this class is used as an ancestor) it's descendants.

It can be used to apply screen effects over any UI control, like TCastleViewport, TCastleButton, TCastleImageControl and so on. Simply place the desired control as child of this control.

To make it easier to apply effects on TCastleViewport, it already descends from this class. So, while you can, you don't need to wrap TCastleViewport instance inside another TCastleScreenEffects instance. You can instead directly call AddScreenEffect on your TCastleViewport instance.

Note that the UI controls rendered for the screen effects (our children and descendants) must always initialize and fill colors of the entire rectangle (RenderRect) of this control. Otherwise, the results are undefined, as an internal texture that is used for screen effects is initially undefined. You may use e.g. TCastleRectangleControl to fill the background with a solid color from TCastleRectangleControl.Color. Or use TCastleViewport with TCastleViewport.Transparent = False (default) which fills background with TCastleViewport.BackgroundColor.

Hierarchy

Overview

Fields

Protected RenderScreenEffects: Boolean;

Methods

Protected procedure RenderWithoutScreenEffects; virtual;
Public constructor Create(AOwner: TComponent); override;
Public destructor Destroy; override;
Public procedure AddScreenEffect(const Node: TAbstractChildNode);
Public procedure RemoveScreenEffect(const Node: TAbstractChildNode);
Public procedure BeforeRender; override;
Public procedure Render; override;
Public procedure RenderOverChildren; override;
Public procedure Update(const SecondsPassed: Single; var HandleInput: boolean); override;
Public procedure GLContextClose; override;
Public procedure PrepareResources;

Properties

Public property ScreenEffectsTimeScale: Single read FScreenEffectsTimeScale write FScreenEffectsTimeScale default 1;
Public property ScreenEffectsEnable: Boolean read FScreenEffectsEnable write FScreenEffectsEnable default true;

Description

Fields

Protected RenderScreenEffects: Boolean;

Valid only between Render and RenderOverChildren calls. Tells whether we actually use screen effects, thus RenderWithoutScreenEffects renders to texture. Read-only in descendants.

Methods

Protected procedure RenderWithoutScreenEffects; virtual;

Descendants with special rendering code should override this, and never override Render or RenderOverChildren (as those two methods have special implementation in this class).

This rendering method will be called regardless if we have or not some screen effects. When no screen effects are actually used (e.g. AddScreenEffect wasn't used, InternalExtraScreenEffectsCount is zero), then our Render trivially calls this method without doing anything else.

Public constructor Create(AOwner: TComponent); override;

This item has no description.

Public destructor Destroy; override;

This item has no description.

Public procedure AddScreenEffect(const Node: TAbstractChildNode);

Add or remove a ScreenEffect node that defines new shader screen effect. See https://castle-engine.io/x3d_extensions_screen_effects.php .

In the simple case, you can pass here an instance of TScreenEffectNode. In a general case, you can passs here any X3D node you want, just remember that only the TScreenEffectNode inside will be rendered. You can e.g. pass a TGroupNode with TScreenEffectNode and TTimeSensorNode as children, and use TTimeSensorNode to provide time to your shader uniform parameter. Or you can e.g. pass an X3D graph loaded from X3D file using X3DLoad.LoadNode, this way you can define effects inside an external X3D file, e.g. like this:

ScreenEffects.AddScreenEffect(
  LoadNode('castle-data:/screen_effects_scene.x3dv'));

If you're looking for inspirations what to put in screen_effects_scene.x3dv, see https://github.com/castle-engine/demo-models/tree/master/screen_effects . See also CGE example in "examples/screen_effects_demo/" directory ( https://github.com/castle-engine/castle-engine/tree/master/examples/screen_effects_demo ) that shows more screen effects code, and shows how to load or construct X3D node graph with ScreenEffect.

The memory management of the node added here is automatic: the added screen effect becomes owned by the internal X3D Group node. It's reference-count is increased at AddScreenEffect, and decreased at RemoveScreenEffect, and it is automatically freed when reference-count drops to zero.

This means that, if you create the provided Node by code, and don't add it anywhere else, then the node will be freed automatically at our destructor (if you call AddScreenEffect and do not call RemoveScreenEffect on it), or at RemoveScreenEffect call. If you don't want this, use TX3DNode.KeepExistingBegin to manage the node destruction yourself.

Note that the given Node should not be used by other TCastlScene instances. In general, a node should not be present in more than one TCastlScene instance, and we already insert the node into an internal TCastlScene instance. Use TX3DNode.DeepCopy if necessary to duplicate node into multiple scenes.

Note that you can enable/disable the effect using TScreenEffectNode.Enabled, or enable/disable all using ScreenEffectsEnable. You do not need to remove the node by RemoveScreenEffect if you only want to disable it temporarily.

Public procedure RemoveScreenEffect(const Node: TAbstractChildNode);

This item has no description.

Public procedure BeforeRender; override;

This item has no description. Showing description inherited from TCastleUserInterface.BeforeRender.

Prepare your resources, right before drawing. Called only when Exists and GLInitialized.

Do not explicitly call this method. Instead, render controls by adding them to the TCastleContainer.Controls list, or render them explicitly (for off-screen rendering) by TCastleContainer.RenderControl.

Public procedure Render; override;

This item has no description. Showing description inherited from TCastleUserInterface.Render.

Render a control. Called only when Exists and render context is initialized.

Do not call this method. It will be automatically called by the engine when needed. It will be called when UI is part of TCastleContainer.Controls list or rendered (e.g. for off-screen rendering) by TCastleContainer.RenderControl.

You should only override this method.

See https://castle-engine.io/manual_2d_ui_custom_drawn.php for examples what you can put here.

You can depend on some OpenGL state being set before calling this method. You can depend on it being set, and you can carelessly change it. This state we set:

  • Viewport is set to include whole container.

  • Depth test is off.

  • For ancient fixed-function pipeline (see TGLFeatures.RequestCapabilities):

    • The 2D orthographic projection is always set at the beginning. Useful for 2D controls.

    • The modelview matrix is set to identity. The matrix mode is always modelview.

    • The raster position is set to (0,0). The (deprecated) WindowPos is also set to (0,0).

    • Texturing, lighting, fog is off.

Beware that GLSL RenderContext.CurrentProgram has undefined value when this is called. You should always set it, before making direct OpenGL drawing calls (all the engine drawing routines do it already, this is only a concern if you make direct OpenGL / OpenGLES calls).

Public procedure RenderOverChildren; override;

This item has no description. Showing description inherited from TCastleUserInterface.RenderOverChildren.

Render a control contents over the children controls. This is analogous to Render, but it executes after children are drawn. You should usually prefer to override Render instead of this method, as the convention is that the parent is underneath children.

You should only override this method (do not call it, it will be called by the engine).

See https://castle-engine.io/manual_2d_ui_custom_drawn.php for examples what you can put here.

Public procedure Update(const SecondsPassed: Single; var HandleInput: boolean); override;

This item has no description. Showing description inherited from TCastleUserInterface.Update.

Control may do here anything that must be continuously repeated. E.g. camera handles here falling down due to gravity, rotating model in Examine mode, and many more.

This method may be used, among many other things, to continuously react to the fact that user pressed some key (or mouse button). For example, if holding some key should move some 3D object, you should do something like:

if HandleInput then
begin
  if Container.Pressed[keyArrowRight] then
    Transform.Position := Transform.Position + Vector3(SecondsPassed * 10, 0, 0);
  HandleInput := false;
end;

Instead of directly using a key code, consider also using TInputShortcut that makes the input key nicely configurable. See engine tutorial about handling inputs.

Multiplying movement by SecondsPassed makes your operation frame-rate independent. Object will move by 10 units in a second, regardless of how many FPS your game has.

The code related to HandleInput is important if you write a generally-useful control that should nicely cooperate with all other controls, even when placed on top of them or under them. The correct approach is to only look at pressed keys/mouse buttons if HandleInput is True. Moreover, if you did check that HandleInput is True, and you did actually handle some keys, then you have to set HandleInput := false. This will prevent the other controls (behind the current control) from handling the keys (they will get HandleInput = False). And this is important to avoid doubly-processing the same key press, e.g. if two controls react to the same key, only the one on top should process it.

Note that to handle a single press / release (like "switch light on when pressing a key") you should rather use Press and Release methods. Use this method only for continuous handling (like "holding this key makes the light brighter and brighter").

To understand why such HandleInput approach is needed, realize that the "Update" events are called differently than simple mouse and key events like "Press" and "Release". "Press" and "Release" events return whether the event was somehow "handled", and the container passes them only to the controls under the mouse (decided by TCastleUserInterface.CapturesEventsAtPosition). And as soon as some control says it "handled" the event, other controls (even if under the mouse) will not receive the event.

This approach is not suitable for Update events. Some controls need to do the Update job all the time, regardless of whether the control is under the mouse and regardless of what other controls already did. So all controls (well, all controls that exist, in case of TCastleUserInterface, see TCastleUserInterface.Exists) receive Update calls.

So the "handled" status is passed through HandleInput. If a control is not under the mouse, it will receive HandleInput = False. If a control is under the mouse, it will receive HandleInput = True as long as no other control on top of it didn't already change it to False.

Public procedure GLContextClose; override;

This item has no description. Showing description inherited from TCastleUserInterface.GLContextClose.

Destroy your OpenGL resources.

Called when OpenGL context of the container is destroyed. Also called when controls is removed from the container Controls list. Also called from the destructor.

You should release here any resources that are tied to the OpenGL context. In particular, the ones created in GLContextOpen.

As an exception, this is called regardless of the Exists value. This way a control can release it's resources, regardless if it exists now.

Public procedure PrepareResources;

Make the screen effects rendering resources ready (e.g. link shaders).

Properties

Public property ScreenEffectsTimeScale: Single read FScreenEffectsTimeScale write FScreenEffectsTimeScale default 1;

Scale time passing inside TimeSensor nodes you add as part of AddScreenEffect. May be 0 to stop time passing. This has deliberately long name, instead of simple TimeScale, to make it clear that it's completely independent from TCastleAbstractRootTransform.TimeScale.

Public property ScreenEffectsEnable: Boolean read FScreenEffectsEnable write FScreenEffectsEnable default true;

Enable or disable all screen effects added by AddScreenEffect. When this is True, particular screen effects can still be enabled/disabled using TScreenEffectNode.Enabled. When this is False, all effects are disabled, regardless of TScreenEffectNode.Enabled.


Generated by PasDoc 0.16.0-snapshot.