brianzinn / react-babylonjs

React for Babylon 3D engine
https://brianzinn.github.io/react-babylonjs/
824 stars 105 forks source link

How to add postprocess effects? #124

Closed j-fan closed 3 years ago

j-fan commented 3 years ago

First of all, thanks for creating this project! It has been really useful to me so far.

I have checked the storybook and saw examples for glow and highlight layers, but I am not sure how to use the other effects in the default render pipeline like in this demo: https://playground.babylonjs.com/#Y3C0HQ#146

The other post process effects don't have JSX representations so I tried to initialise them like this, but there was no effect to the scene. When I debugged, I found that scene.cameras was an empty array.

  const onSceneMounted = ({ scene }: SceneEventArgs) => {
    const defaultPipeline = new DefaultRenderingPipeline(
      "default",
      true,
      scene,
      scene.cameras
    );
    defaultPipeline.chromaticAberrationEnabled = true;
    defaultPipeline.chromaticAberration.aberrationAmount = -100;
    defaultPipeline.chromaticAberration.radialIntensity = 0.2;

    defaultPipeline.grainEnabled = true;
    defaultPipeline.grain.intensity = 50;
  };

This function was provided to the Scene component like so:

<Scene
    onSceneMount={onSceneMounted}
    ...other props
/>

Any suggestion on how else I can use post process effects?

j-fan commented 3 years ago

Seems that I answered my own question just after posting, despite trying for a while. 😅 It works when I attach it to the onReadyObservable prop like this:

  const onReady = (scene) => {
    const defaultPipeline = new DefaultRenderingPipeline(
      "default",
      true,
      scene,
      scene.cameras
    );
    defaultPipeline.chromaticAberrationEnabled = true;
    defaultPipeline.chromaticAberration.aberrationAmount = -100;
    defaultPipeline.chromaticAberration.radialIntensity = 0.2;

    defaultPipeline.grainEnabled = true;
    defaultPipeline.grain.intensity = 50;
  };

<Scene
    onReadyObservable={onReady}
    ...other props
/>

Shame that there are no types for onReadyObservable prop though, so it needed some trial and error.

brianzinn commented 3 years ago

Good question and answer, too! I could change how I handle the "onReady". If you look at the babylon.js Scene object I think what it does is call that after a setTimeout, so it goes to the event queue and runs after the camera is added (I would not say that is deterministic). Whereas what I do is check if the scene is ready (and it seems to always be, but otherwise I used to hand off to the scene ready observable.

What I found in practice is that the scene is always "ready": https://github.com/brianzinn/react-babylonjs/blob/master/src/Scene.tsx#L65

I would be open to make a change there, but not sure how that would affect backwards compatibility as it would now run after the first render.

One perhaps better way would be on the camera creation, if it's just one camera to create a default rendering pipeline for that camera. Also, with a useEffect you would be able to dispose. You can do it from 'onCreated' callback or a useRef on the camera in that case. There is a useScene hook available as well.

It wouldn't take much to get these Post Process render pipelines supported declaratively as well. Would maybe need some kind of lifecycle events for if cameras are added to the scene after creation or can be children elements of a Camera to use that camera. The default is already scene.cameras. Let me know if you would provide feedback if it was added. Cheers.

j-fan commented 3 years ago

Thanks, I didn't consider doing it on camera creation, with the combination of useEffect and useScene. I would love to be able to use the post-process effects declaratively, since that is one of the main appeals of using this library. I'd be happy to provide feedback or help (add a storybook example perhaps?).

brianzinn commented 3 years ago

hi @j-fan thanks for the idea. I'll update the project to support declarative post processing! It was a feature that I had already wanted, but never made the time 😄 I need to fix something first for the react-spring downstream project and then will work on this. I'm pretty busy right now, but will try for early next week. Cheers.

j-fan commented 3 years ago

That is much appreciated @brianzinn! Honestly there is no hurry so long as some method to do post-processing exists.

brianzinn commented 3 years ago

hi @j-fan - it's been added - hopefully that works for you. Still need to do a bit of clean-up and eventually some documentation, because I'm probably the only person that can figure it out! image

<defaultRenderingPipeline hdr chromaticAberrationEnabled grainEnabled>
  <chromaticAberrationPostProcess assignFrom='chromaticAberration' aberrationAmount={-100} radialIntensity={0.2} />
  <grainPostProcess assignFrom='grain' intensity={50} />
</defaultRenderingPipeline>

I added a storybook for that and also one for scene image processing - they're here: https://github.com/brianzinn/react-babylonjs/tree/master/stories/babylonjs/PostProcess

There's no NPM yet, but if you yarn build and yarn storybook then it should work (or you can link it to your project). I'll try to get it out later in the week after some testing. Cheers 😃

j-fan commented 3 years ago

This is much appreciated, thank you! I will give this a spin soon.