Changing colors in TCastleScene

How can I easily change colors in TCastleScene?

In my old code with TSprite I could change color with:
var rgb1, rgb2, rgb3: single;
Location.BackGround.Color := Vector4(rgb1, rgb2, rgb3, 1); // fade background to night

if Event.IsKey(keySpace)then
begin
rgb1 := rgb1-0.004;
rgb2 := rgb2-0.004;
rgb3 := rgb3-0.004;

As TCastleScene can contain a lot of stuff inside, it’s not so easy to change “its color”. You will have to find all components inside (even if there is only one), and change each of their colors. See e.g. Castle Game Engine: X3DNodes: Class TMaterialNode

However, in your case you most likely wouldn’t want to do that - a better idea would be changing the color (tint) of the whole construction through shader. See examples\3d_rendering_processing\shader_effects. It practically does exactly what you need.

I just experimented with this example but found it still too difficult to implement in my 2D setup.
I only want to gradually darken all colors so eventually it becomes “night”. This should apply to all my scenes (background, player and npc).

The other path might look simpler (manipulating color for every texture) because it uses the same logic as “just images”, but actually it isn’t simple. So, I’d still highly recommend you to invest some time and learn how to work with shaders - later that will enable you to implement much more sophisticated effects than just changing the screen tint.

However, if you want just “fade all the screen” - you can try a bit simpler approach - examples\screen_effects_demo - you can apply those to groups of UI elements - i.e. this way you can dim both Player, Background and objects on the screen in one go. But in the end those are the same GLSL shaders, just a little bit differently formatted.

In case of sprite sheets, it is a bit easier, as you actually have only one material instance inside, and all sprite sheets should have exactly 1 material, no more no less. So you can do

var
  MyMaterial: TUnlitMateriaNode;
begin
  Scene.Load('some-sprite-sheet.castle-sprite-sheet');
  MyMaterial := Scene.RootNode.FindNode(TUnlitMaterialNode, false); // will raise exception if not found
  MyMaterial.EmissiveColor := Vector3(1, 1, 0); // change color to yellow
end;
1 Like

That would be great.
However I get an error trying this?

Make a typecast:

MyMaterial := Scene.RootNode.FindNode(TUnlitMaterialNode, false) as TUnlitMaterialNode;

Wow, this is really spectacular!
:slight_smile:

Now that this works for the background I can apply it to all character scenes also.
Thanks!

Update: At least… that’s what I thought, but I can get the effect only for 1 scene.
So:
If I, for instance, want to fade all scenes that are within the viewport at once, is this possible? Maybe by placing a ‘filtering’ rectangle over the world?
Because when I eventually have a background with objects and 20 sprites walking around it would be very much work to apply the effect one by one for all scenes.
:wink:

There are screen effects: Screen Effects | Castle Game Engine , demo e.g. in examples/screen_effects_demo/. While I heavily advise learning to use them, it requires understanding GLSL a bit. If this is too much then you can use simpler solution instead and just iterate over your TCastleScenes.