Add second instance of Renderer to manage transparent background.#949
Add second instance of Renderer to manage transparent background.#949nicolas-daures wants to merge 12 commits intogoogle:masterfrom nicolas-daures:master
Conversation
|
Thanks for the change suggestion @nicolas-daures ! Would it be possible to structure this so that the transparent renderer is created on-demand? This way folks only pay a cost in the case that they actually want to use transparency. Also for the sake of cross-referencing things, we have had issues with transparent rendering in the past (see #381 ). |
| const widthDPR = width * dpr; | ||
| const heightDPR = height * dpr; | ||
| if (this.isTransparent) { | ||
| context.clearRect(0, 0, widthDPR, heightDPR); |
There was a problem hiding this comment.
Why is it necessary to clear both the context and three's renderer color?
There was a problem hiding this comment.
|
@cdata The renderer is now created on-demand. About transparency issues, I have the same rendering as on this comment: #381 (comment) @elalish I added an example in customize-ui with a linear gradient background to see the transparency. |
elalish
left a comment
There was a problem hiding this comment.
Thanks for bringing the rendering issue to my attention. I don't see a reason to hold this back due to a Three.js bug, especially since it works for most cases. I want to test this a bit more before merging, but I really like it! Thanks for taking the initiative!
|
|
||
| static get singleton(): Renderer { | ||
| let singleton = this[$singleton]; | ||
| if (!singleton) { |
There was a problem hiding this comment.
nit: in this project's style we prefer to say explicitly x == null rather than !x. Also, is the temporary variable necessary here? Same comment for the changes below.
There was a problem hiding this comment.
I modified the code to adapt to the project's style. I deleted the temporary variable. It just used to avoid the cast of Renderer.
| </div> | ||
| <example-snippet stamp-to="demo-container-2" highlight-as="html"> | ||
| <template> | ||
| <model-viewer ar camera-controls ios-src="assets/Astronaut.usdz" src="assets/Astronaut.glb" background-color="transparent" alt="A 3D model of an astronaut"> |
There was a problem hiding this comment.
nit: Everything inside the <template> should be indented starting over from the left. If you look at this page in your browser you'll see why. Also, can we add an image or some text or something behind this so that it's clear the transparency is working? These dev pages serve as manual regression tests for this project.
There was a problem hiding this comment.
Ah, I just saw the linear gradient; the trouble is that it's not inside the <template>, so it's not a visible part of the demo code.
There was a problem hiding this comment.
I modified the example to integrate the gradient and a text in the template. Thanks for all the feedback.
| if (this[$singleton] != null) { | ||
| (this[$singleton] as Renderer).dispose(); | ||
| } | ||
| this[$singleton] = new Renderer({debug: isDebugMode()}); |
There was a problem hiding this comment.
Should this be created only if the previous value was defined (aka inside the if statement)? Same for the singleton with transparency below.
There was a problem hiding this comment.
Good remark, thank you.
|
@nicolas-daures thanks so much for your diligent work on this change. I want to give you a friendly heads up that we are trying to start the year off on the right foot by landing a major source restructuring change (see #962 ). Your changes are still good, but I will likely ask you to reconcile before this lands and everything will have been moved two directories deep. Anyway, I am happy to help you reconcile the changes when that time comes. Just wanted to let you know what is going on. |
|
@nicolas-daures This seems to work, except when switching between the renderers. You can repro by scrolling up and down on the customize-ui page. It seems to switch back and forth between rendering transparently and non each time it comes into view. Can you repro? |
|
@nicolas-daures Thanks! That big change @cdata was talking about just landed, so once you merge or rebase I'll take another look. Note the build instructions have changed too, so check out the updated READMEs. |
…-viewer # Conflicts: # packages/modelviewer.dev/examples/customizing-ui.html
|
@elalish It's merged. |
cdata
left a comment
There was a problem hiding this comment.
Thanks for keeping this in sync with master, I know there has been a lot of change happening on the side 🍻
Ideally we would also have at least one test that confirms that setting backgroundColor to "transparent" causes the canvas to render with alpha transparency.
|
|
||
| // Update background color before to get texture utils because renderer singleton depends on background transparency | ||
| if (skyboxImage == null) | ||
| { |
There was a problem hiding this comment.
clang-format needs to be run on this change
| if (backgroundColor === 'transparent') { | ||
| if (this[$scene].background != null) { | ||
| this.disconnectedCallback(); | ||
| delete this[$scene].background; |
There was a problem hiding this comment.
If this isn't significantly different from assigning null, prefer to assign null instead
There was a problem hiding this comment.
ok, that's fixed.
| { | ||
| if (backgroundColor === 'transparent') { | ||
| if (this[$scene].background != null) { | ||
| this.disconnectedCallback(); |
There was a problem hiding this comment.
These (connectedCallback/disconnectedCallback) are custom element lifecycle methods, and are meant to be invoked by the browser based on the semantics defined in the custom element spec. If we are calling them manually, then it's a sign that we may need to factor out part of their implementation to discrete methods.
Why are we invoking these methods manually?
There was a problem hiding this comment.
These callbacks are called to unregister the scene from the renderer and to unsubscribe from the contextlost event. I change the code to call only what is necessary.
|
|
||
| static get singleton() { | ||
| return this[$singleton]; | ||
| static get singleton(): Renderer { |
There was a problem hiding this comment.
It seems weird to call this a singleton now that we are creating up to two of them. Maybe we should just call them opaqueRenderer and transparentRenderer?
There was a problem hiding this comment.
ok, that's renamed.
| } | ||
| else { | ||
| const mustUpdateRenderer = this[$scene].background == null; | ||
| mustUpdateRenderer && this.disconnectedCallback(); |
There was a problem hiding this comment.
If these lifecycle methods are being invoked in order to get the renderer to update, then we could use this[$needsRender]() to provoke a re-render and skip calling the lifecycle methods.
There was a problem hiding this comment.
The objective is not really to update the rendering but to unsubscribe listeners and unregister the scene from the old renderer before switching to the new renderer. So the accessor $renderer must return the old renderer to unsubscribe the listener, then the same accessor must return the new renderer to subscribe the listener. This is why there is the test to null on the background performed in the accessor.
|
|
||
| get[$renderer]() { | ||
| return Renderer.singleton; | ||
| return this[$scene].background ? Renderer.singleton : Renderer.singletonWithTransparency; |
There was a problem hiding this comment.
It seems like we should only use the transparent renderer if the background color is, in fact, "transparent". One way to accomplish this would be to specialize the [$renderer] accessor for the EnvironmentMixin implementation, so that it overrides the default ("always use opaque renderer") with a version that returns a renderer based on the value of the backgroundColor property.
|
hi guys, great work! :) I have a small question: I've noticed that if the it would be really awesome if the transparency would still work even when having the |
… Assign null to background instead of using delete.
|
@nicolas-daures @valdrinkoshi @koch-crsd I have an alternative PR that I'd love feedback on: #975. It draws heavily from this one, but also simplifies our API. |
|
Closing in favor of #975. Thank you @nicolas-daures for pushing us on this and contributing to the landed change! |

Reference Issue
Fixes #874
Management of the "transparent" value for the background-color property.
To allow the property value to change (transparent -> opaque, opaque -> transparent), we create two instances of the Renderer class. The first to manage a background color, the second to manage transparency.