Conversation
|
Hitting that CI Chrome error I think: |
We may want to expose... eh.. |
cdata
left a comment
There was a problem hiding this comment.
Tonemapping is an opinionated change. I don't think chasing Filament's GLTF Viewer is worthwhile for pixel perfect comparison
For the time being, this is our standard for comparison. If we aren't chasing that, we need alternatives to consider (a custom Filament configuration, a selection of ray traced samples etc). But, keep in mind that <model-viewer> can afford to be more opinionated than Three.js so the Filament GLTF viewer is probably as good as anything for the time being.
It may be best to just stick to linear tonemapping for now until we expose knobs.
We need to pick a reasonable default. In time, we will expose knobs at some level. A conservative default is probably better so that we don't surprise users down the line when our opinions change.
General feedback follows:
Offline PMREM generation
Some of the qualities of this change (significant payload burden, high cost for realtime changes) suggest that PMREM generation would be well suited to a build time tool. Does this seem reasonable to you?
Script execution time
The script execution time cost of runtime PMREM generation seems high. On Chrome desktop, I measured an added cost in excess of 150ms for the PBR Spheres fidelity test with background-image. Even without a background-image, PMREM is still a cost factor and adds almost 100ms in script execution time. See timeline screenshots below (and note that in the no-background-image case pmremPass is actually invoked twice). Is it necessary to levy this cost on users by default? Should PMREM be opt-in?
<model-viewer> |
<model-viewer> + PMREM |
|---|---|
with background-image |
with background-image |
![]() |
![]() |
without background-image |
without background-image |
![]() |
![]() |
Fidelity tests
Given the strong effect this change has on rendering, it would be nice to see a contribution to the fidelity tests as part of this change. On the one hand, PBR Spheres looks subjectively worse to me ("what happened to the skybox?"). On the other hand, it looks more like Filament, which is... good? My takeaway is that we aren't consciously measuring the right things.
See screenshots below for a sense of the delta we are talking about.
<model-viewer> <-> <model-viewer> + PMREM |
|---|
![]() |
<model-viewer> + PMREM <-> Filament |
|---|
![]() |
src/three-components/TextureUtils.js
Outdated
| environmentMap = this.pmremPass( | ||
| skybox.texture, this.config.pmremSamples, this.config.pmremSize); | ||
|
|
||
| equirect.dispose(); |
There was a problem hiding this comment.
Orthogonal to this change, but it seems like this belongs in a finally clause.
Any opinion then on tonemapping for this change? Current one is used to match Filament (ACES Filmic Tonemapping, seems darker, more saturated colors), but the default (linear) will of course reduce visual delta.
Quick overview of the PMREM texture generator: Generating radiance maps is inherently a computationally intensive task -- each map represents the amount of light a facet receives from a given direction, essentially averaging all light sources for each texel(ish), and scaled down/blurred for various roughness values. I think I'm more accurately describing the process for importance sampling PR in OP, but that's the idea, computationally costly. I can't imagine any production pipelines generating this at runtime unless for good reason (e.g. dynamic indirect lighting). The value/justification for this within three I think is:
For production use cases, this should certainly be generated offline, no doubt. This also assumes having 3D resources available and supporting pipelines. I'm not sure how well three handles that in general (I should look into what it'd take to use cmgen to output a texture that can be used directly in three, it should be possible, just a matter of matching up the 'format'). For more casual/prototype use cases, it seems more likely that they won't know what PMREM is, why its needed, or how to make it. It seems valuable to just handle this for developers. But of course, the costs!
Some strategies for mitigating the computing cost:
These changes shock me and not sure why the skybox is changing.. |
|
Also note that cmgen is a part of Filament, and requires compiling the project -- even if cmgen is the perfect tool for the job, building the project can be a tall order for web devs unfamiliar with using a native build pipeline. |
|
cmgen does not handle creating a single file with multiple mips AFAICT, would need to stitch that outside. Still doable, can stitch with Similarly, the reason why equirectangular images are used for background images is that it's a single image, whereas cubemaps require 6 different images (or a single image in a cross, but again, arbitrary), which faces a similar issue (in terms of "formats", not in terms of jank/computational costs) |
|
Thanks for the thorough walk-through @jsantell Some additional thoughts:
Not suggesting we should do it in this change, but it seems like this is an area where we could help the community a bit while helping ourselves. If we document the format and socialize it a bit I'm sure we could come up with something that others would make use of. OTOH if we could somehow leverage I've filed #341 to track work on an offline map generation strategy.
Runtime generation definitely makes it easier to experiment. I think the other main advantage of runtime generation is for scenarios when the map might change frequently and generating the maps in advance is complicated. It's not that much harder for someone to wield by specifying a URL in the
Let's investigate / address this if we can before landing this change.
I agree, I didn't notice this as much on my laptop. However, 100ms could easily be 1s on a less capable device. And, if I have more than one For the future, I've filed #342 to track moving this work off of the main thread. I've also filed #343 to track generating the map lazily and progressively enhancing so as not to block rendering something while the map is being generated.
Good call. This is probably the best option to mitigate performance concerns for now.
Agreed, let's try to understand this better before we land the change. |
|
SGTM, I'll check out:
|
|
My bikeshed on attribute name is that we should avoid acronyms and also pick something that conveys both the breadth of the technical concept and the visual effect at the same time. Surely it will be easy to find a single word that satisfies these requirements. Surely. |
Tracked down to #344, filed (edit I think I fixed it in this patch now)
Yup, tonemapping explains it.
Gating on an For example, here's the helmet with default environment map without, and with, PMREM: And again without, and with, PMREM: The white spheres we use often are way brighter as well -- which could be unexpected -- but, these are pure white albedo spheres that are lit on all sides by a whiteish environment, it's going to be a rather well lit sphere that absorbs all light. Above without PMREM, below with: All images here have been tonemapped, although that affects the output much less than whether or not PMREM is enabled. Remaining TODO: tests |
Saw this after my post and push, but with a name like |
|
I have filed #346 to cover future work on naming. For now, let's just stick to |
|
Also fixes #344 |
cdata
left a comment
There was a problem hiding this comment.
I filed #347 to track the various optimization issues related to this change in aggregate, since there are a few of them now.
I would still like to see a contribution to the fidelity tests. LMK if you would be willing to accept a contribution to this PR and I'll add one!
| } | ||
|
|
||
| /** | ||
| * @param {THREE.Texture} environmentMap |
There was a problem hiding this comment.
Above, you invoke this method with null as the argument. Can we document what this is intended to do?
src/three-components/TextureUtils.js
Outdated
| generateDefaultEnvironmentMap(size) { | ||
| const mapSize = size || this.config.synthesizedEnvmapSize; | ||
| generateDefaultEnvironmentMap(config={}) { | ||
| const mapSize = config.size || this.config.synthesizedEnvmapSize; |
There was a problem hiding this comment.
Is config.size ever actually used anywhere?
| cubemap.userData = { | ||
| let environmentMap; | ||
|
|
||
| if (config.pmrem) { |
|
I've opened a PR against this change that includes a fidelity test for HDR/PMREM. PTAL: #361 |
cdata
left a comment
There was a problem hiding this comment.
Amazing work on this. <model-viewer> looks so beautiful now...
LGTM!
😄 thrilled to click merge |










Part two of #323, adding radiance map generation to the default environment map as well as provided environment maps.
Currently, both sRGB (left) and HDR images are supported as environment maps. Radiance is approximated (?) for LDR and HDR environment maps. LDR maps blur roughness better, but HDR preserves light better.
(LDR left, HDR right, tip of master)
Computing the radiance for each vector via PMREMGenerator gives a nicer, more accurate environment map, especially for rough, metal objects.
(LDR left, HDR right, with PMREM)
Using the Damaged Helmet model, here are the current renderings for LDR/HDR:
And after this patch, with applied tonemapping below. Notice slightly rougher reflections (the surface is mostly smooth, so)
Tonemapping was chosen to match Filament's GLTF Viewer (below), with roughly similar environments.
Fixes #215.
Fixes #344