3D particle system (Now with full support for 2D and castle-editor)

Previous thread

Thanks to castle-editor’s recent developments, now it is possible to edit particle effects directly inside castle-editor!

This release also introduce several new features:

  • You can now use MiddleParticleSize, which allows to change particle size by performing linear interpolation to certain point (defined by MiddleAnchor) during it’s lifetime.
  • New SourceType property, allows to define the type of emitter source (Box or Spheroid).
  • New Burst property, allows to create burst-type emitter, useful for creating explosion effect.
  • New AllowsUpdateWhenCulled property, very useful if you want to optimize particle’s performance, by stopping it’s updating when particle emitter’s bounding box is outside of view frustum.
  • New AllowsInstancing property. If this is set to True, then you can use the same particle emitter on different transform nodes. Particles are calculated in local space, which mean if you move the emitter, then it’s particles will also move with it. If you want particles to be calculated in world space, then set this property to False, which also disable the ability of instancing.
  • Despite it’s name, you can also use it in 2D, which mean cge-2d-particle-emitter is now deprecated :slight_smile:

Download: https://github.com/Kagamma/cge-3d-particle-emitter

2 Likes

Tested! This is great. And in general I feel this is a great approach – particle effects done this way look completely native to CGE, and are configurable in editor.

As a bonus, this proves that you can implement new CGE components outside of CGE codebase too, and they integrate nicely, look as proper part of editor. So I’m also happy with the editor improvements this has caused :slight_smile:

Notes:

  1. Descending TCastle3DParticleEmitterGPU from TCastleSceneCore is not ideal. It exposes properties like Spatial, code can also access ancestor TCastleSceneCore.URL that is probably confusing on the emitter. I would propose to remake it as TCastleTransform descendant – attaching a patch, it seems rather straightforward.

    Unless you have future plans that justify that TCastle3DParticleEmitterGPU should remain descending from TCastleSceneCore.

    emitter_descend_from_castletransform.patch (1.7 KB)

  2. I’d expose more properties on “Basic” tab, of both the emitter and effect classes, by overriding PropertySections. At least the TCastle3DParticleEmitterGPU.Effect. Like this:

    function TCastle3DParticleEmitterGPU.PropertySections(const PropertyName: String): TPropertySections;
    begin
      case PropertyName of
        'Effect':
          Result := [psBasic];
        else
          Result := inherited PropertySections(PropertyName);
      end;
    end;
    

    This is the basic way to “emphasize” most important properties that user’s may want to tweak to create a particle system.

  3. I’d consider renaming TCastle3DParticleEmitterGPU to something more general, to avoid breaking compatibility later. Like TCastleParticleEmitter. The 3D and GPU name parts can be dropped – as you say it is for 2D too, and the “GPU” is an implementation detail (that ideally should be hidden from users, and have a fallback rendering without transform feedback; though I know that implementing this would be a beast).

  4. A code convention note – at least in CGE code we generally do not write Self.Xxx, we write just Xxx (probably with some justified exceptions).

    It’s not a problem for me when this is a component outside of CGE codebase, I understand it’s a matter of code style and you may want to just prefer writing Self. explicitly. There are languages where writing self/this is a convention (or necessity) and it makes sense. So I’m just noting it here – I will very much want to merge your work at some point into “CGE core” to have particle effects available out-of-the-box in CGE, and then this code style will be important, to be consistent with rest of CGE.

  5. You mention in REDME “The editor source code is licensed under GNU v2 due to some of its code is borrowed from view3dscene.” – which parts? If they are some small parts, that I’m the sole author/copyright owner, then I will possibly be 100% OK with relicensing these bits for you on MIT, and make the licensing of cge-3d-particle-emitter simpler.

  6. I see you depend on user defining bounding box explicitly. This is visible in demos/gallery/ where only one emitter shows bbox. Hm, and that’s actually OK.

    From what I see, we have here some CGE bug. Because even when you have a bounding box non-empty (on the “Box” emitter in demos/gallery/), the emitter is still not pickable by CGE editor “Select Scene” (it should actually allow to select any TCastleTransform that is the leaf of tree in Viewport.Items, so it should highlight/select emitter too when you mouse over/click) or “Move Transform” tools. From a first glance, seems like a problem on CGE side, I’ll look into it soon.

  7. I see you have alternative ways of assigning the effect – by assigning Effect, or by setting URL. I would say to simplify it, and force the user to explicitly create TCastle3DParticleEffect instance in all cases, and assign it to emitter Effect explicitly. This is more consistent, and it is then clear what is the memory management.

    E.g. now calling TCastle3DParticleEmitterGPU.LoadEffect(const AURL: String) multiple times on a long-living TCastle3DParticleEmitterGPU is not optimal. The application will not have memory leaks, but it will internally create more and more effects that are owned by TCastle3DParticleEmitterGPU, while actually only the last one is used and accessible.

    Maybe you want to have 2 effect descendants, one that allows to customize all values , and another one that allows to load particle effect from various formats, without customizing the values (thus it would only publish a URL).

    Or maybe just drop loading of the effects from special file formats, and depend entirely on designing / serializing particle effects by CGE.

    Or maybe support only .castle-component format to define a particle effect, by having alternative effect class like TCastleParticleEffectDesign similar to TCastleTransformDesign that would refer to another .castle-component file, and require that as root it contains TCastle3DParticleEffect.

    In any case, keep the simple rule: to have emitter work, one has to assign TCastle3DParticleEmitterGPU.Effect. There is no shortcut TCastle3DParticleEmitterGPU.URL. This would simplify IMHO a bit the relation effects<->emitters in code.

1 Like
  1. Applied. Yes TCastleTransform is better than TCastleSceneCore.
  2. Applied. I also add Burst to the basic tab.
  3. I guess it’s fine to rename them, to avoid trouble later (I think I am the only one who’s using it extensively at the moment).
  4. This is mainly because of GDB. As I doesn’t use Lazarus to debug (which add a lot of glues to make GDB happy with Pascal), GDB without Lazarus isn’t really happy with instance’s members without Self, as it tried to look for this instead. That said since I made a move to fpdebug, this isn’t necessary anymore, although I still keep this habit because I can tell which one belongs to class just by a glance.
  5. This is for the bounding box visualization code. Yes it’s small and I can easily create it myself (in fact I did it with the new bounding box visualization code for castle-editor). Still it doesn’t change the fact it’s something that belongs to view3dscene, thus the mention in README.md :slight_smile:
  6. I still want to keep the URL way (although I will change it so it won’t appear in castle-editor anymore), as my own editor still depend on it to load effects. That said URL now use FreePascal’s built-in deserialization underneath so it can load .castle-component created by castle-editor just fine :slight_smile:

Btw I think castle-editor should be able to “Export” a component/non-visual component directly from the Hierarchy. I am relying on copy to copy particle’s effect and save to file manually at the moment, and it would be great if there’s an Export option to do that work.

Great, thank you for the updates. I am now setting up CGE news posts for the weekend, and I will announce your work with links and videos. This is fantastic.

AD 5 - Oh, you mean the one using fixed-function pipeline to visualize bbox? I’d suggest to do this in more “modern” way now – use TCastleScene with TBoxNode inside with rendering set as shWireframe. See e.g. CastleDebugTransform implementation of TDebugBox. Hm, or you can just use TDebugBox :slight_smile:

In any case, you can also hereby officially consider the bbox rendering bits of view3dscene as being under MIT license too. This is old code that only I authored I think. So you can simplify https://github.com/Kagamma/cge-3d-particle-emitter licensing (of course if you want).

Agreed, ability to “Export” a piece of hierarchy would be useful, and should be trivial to add.

I haven’t tried it myself. But isn’t it will “pollute” the hierarchy tree if one component try to add another TCastleScene instance manually into the tree? And that TCastleScene instance will appear on the hierarchy tree?

You can call SetTransient to keep a component (like TCastleScene or TCastleTransform or TCastleUserInterface) not serialized and hidden in the hierarchy. This is suitable for internal components that are automatically managed by other components, and should be hidden for both users and for serialization system.

E.g. TCastleText actually uses a full-blown TCastleScene children inside. It is set up at TCastleAbstractPrimitive (ancestor of TCastleText) by

constructor TCastleAbstractPrimitive.Create(AOwner: TComponent);
begin
  inherited;

  { internal stuff create }
  FScene := TCastleScene.Create(nil);
  FScene.SetTransient;
  Add(FScene);
...
1 Like

If that’s the case then I think it would be nice if castle-editor support some kind of Proxy component, which allows to refer to another component in the tree, for optimization. This will be very useful for world designing, and of course particle emitter will also benefit from it with AllowsInstancing property :slight_smile:

Indeed. Internally we can already do this, i.e. you can insert the same TCastleTransform or any of its descendants into the Viewport.Items many times. It should be possible at some point to leverage this in the editor too. I was thinking of doing it without any additional “proxy” component, although it then complicates the hierarchy code…

I like your idea. Indeed we could add a class like TCastleTransformProxy to implement it simpler. Just like TCastleTransformDesign that loads an internal transform from another file, TCastleTransformProxy could just expose a property like Proxy: TCastleTransform (it will be serialized as just a component name) and insert this proxy as a child (using an intermediate child with SetTransient to hide it).

Hm. I’ll think about it. Such TCastleTransformProxy would be an easy solution.

I’ve removed “3D” and “GPU” from unit & class name.
I’ve also removed the use of emitter’s URL to load effects and made some changes in my own editor instead. Now users have to assign effect instance to emitter as the only way. Of course we can still load effects from file via TCastleParticleEffect.Load() method.