NodeMaterials, Env Maps, Tonemapping and Exposure

Finding some really strange behaviour in how NME materials behave with HDR environment maps right now. I think there are elements of the Babylon rendering pipeline I don’t fully understand, within which NME materials are being treated differently from PBRMaterials in a way that doesn’t make sense to me.

Observation #1:
NME Materials don’t respect imageProcessingConfiguration.exposure.

PBR left, PBR NME with a Reflection node right. At exposure 1.0 they look about the same, but lowering exposure darkens the reflection in the PBR material while NME material looks unchanged. This is odd as I would expect both materials to be rendering to an HDR rendertarget and for global tonemapping to affect them equally.

Observation #2:
Okay, so I guess the NME material is forward rendered and just isn’t aware of the exposure value. Perhaps I can override this by adding a scalar multiply to the PBR output?

Unfortunately, this doesn’t have the desired effect:

PG can be found here:

So it seems like tonemapping in the NME happens inside the PBR node, but there is no direct way to influence the reflection strength. The closest I could get to is to multiply the reflection colour in this PG:
But even this doesn’t result in the same behaviour as changing exposure:

Observation #3:
I suspect something similar is happening when PBR glass is used in combination with NME materials. I don’t have a PG for this yet, but I suspect that when overlaps with bright HDR materials, something gets messed up in the tonemapping pipe, though I’m wondering if this applies to just NME materials:

Adding @Evgeni_Popov

1 Like

Quick note: you need to add the image processing block to support exposure, etc…

1 Like

That’s good to know! Are there any good examples of the image processing block in action?

Nothing specific: simply drop it at the end like that:

Hmm, it’s giving me some odd behaviour. If I use a material like this one in the PG, it errors out. In my local scene it does work as a material, but doesn’t seem to be affected by exposure changes, and strongly burns colours in an odd way.

Here’s the updated PG with that material:

Adding @Evgeni_Popov


The PBR block already supported image processing but not fully. After the PR is merged, it will support the full image processing feature set and you won’t need a ImageProcessing block: just link the lighting output to the FragmentOutput rgb input.


Thanks @Evgeni_Popov! Is there a way currently to work around it in the NME material in this PG using the ImageProcessing node, or do we need to wait for the new build to come through?

No, I don’t see a way to make it work in the current state, but the changes have been merged so they will be available from the next nightly build (which should be in a few hours).

1 Like

It’s now available in the preview CDN / on the Playground.

1 Like

Looks good on PG! Will grab and test latest npm when it’s available :slight_smile: (not sure if there’s an easy way of running preview build except running a local build?)

The packages are available on the preview CDN: for eg for the core package.

1 Like

Sorry for all the questions, is there a way to npm install the above or update package.json ? I was doing some poking and did not find

1 Like

I think you need to install the preview by doing: npm install babylonjs@preview

However, npm packages are built infrequently, I don’t know when the latest build has been done…

Thank you for the fix, solves reflections beautifully :slight_smile:

The glass issue mentioned in my first post still persists - I’m looking at trying to repro it in a PG.

I think the problem might be in part due to the fact that we’re using emissive maps in our node-based PBR materials. As there is no emissive input into the PBR node, we’ve been adding emissive onto the lighting output, prior to piping the colour out. But given that there is some of the image processing happening inside the PBR node, obviously any emissive added in that way would be excluded from e.g. exposure controls.

What would be the best way of handling emissive contribution in a way that is consistent with the rest of the tonemapping operations and the PBR node material?

Yes, the problem comes from the fact the emissive color is not factored in before applying image processing.

What you can do is handling the computation in linear space instead: that’s what all the outputs above lighting are for. You need to sum them all, add the emissive color (in linear space too!) and plug this into an ImageProcessing block:

You will notice some black parts in the sphere: that’s because the ImageProcessing is expecting its input to be in gamma space (because it is applying a linear space conversion to what we link to the input), so there’s a conversion to gamma space and it happens it is this conversion that produces this artifact. We should not need this conversion in the first place (as the ImageProcessing code is doing the computation in linear space anyway), so here’s a PR that add a switch to the ImageProcessing block to disable the conversion to linear space:

Once the PR is merged, this PG will work as expected:


Ah! Thank you for demonstrating that, this makes sense now - I was not expecting at all for imageProcessing to want an input in gamma space, so that’s something that was stumping me :slight_smile: And I missed, initially, that Lighting returns the sum output in gamma, while the other outputs are linear. That’s so much clearer now.

I’m sure this is on the roadmap for the node material editor, but it would be great to have that behaviour flagged slightly more visibly in the future. Looking at Node Material | Babylon.js Documentation I can see that it does talk about the PBR node materials, some being linear and Lighting being in gamma space, but this does not get mentioned e.g. for the imageProcessing node.

Adding @PirateJC for the doc update :wink:

Docs have been updated with a note about this! Awesome callout @Valentine!

Should be live in a couple minutes here: