[SOLVED] Render UI to texture

Looking for an advice or a recommendation on how to approach rendering a long list of UI elements in a scroll view. The list could have a few items per row and could span a few screen heights (depending on device).

The issue is that each item from the scroll view is a multi-element item, which may contain shared sprites/images among all of items, as well as unique ones only belonging to that item. Consider a long list of menu dishes in a restaurant, where you could have decoration elements on each item that all of them share, while the dish image is unique to that item.

One option I consider is that the shared images/sprites could go all together in single atlas map, while the unique ones, not available on runtime would be requested and rendered when ready. This will tank the draw calls, as each dish would then add a draw call (or more if there are more unique elements).

To mitigate it perhaps an option is to use an offscreen camera that would render these items into a tall texture. Then that texture would be used as a background for the scrollview content and would only take a single draw call. However, I am not sure how to render a tall texture of screen elements, if they can go over the screen height. Can I change some properties of the offscreen camera so that it would be able to see the whole list? Or do I need to somehow break the stack into smaller ones and then stitch them?

@mvaligursky @slimbuck @yaustar if you have any ideas, feel free to chip in :slight_smile:

1 Like

One idea that may work is to set the render camera to a custom aspect ratio and fill mode that matches the render target. And after the render is complete you set it back to the original settings.

That should work given you are able to calculate the right render target resolution for the UI elements (I haven’t tried it though and potentially if the render is slow it may glitch momentarily).

Something like this:

renderCamera.camera.aspectRatioMode = pc.ASPECT_MANUAL;
renderCamera.camera.aspectRatio = this.renderTexture.width / this.renderTexture.height;

this.app.setCanvasFillMode(pc.FILLMODE_NONE, this.renderTexture.width, this.renderTexture.height);

If the issue is drawcalls, can you disable/enable list item entities if they are in view or not? Or won’t that be enough?

1 Like

aspect ration is by default automatically calculated based on the render target dimensions … so that part should just work. Ideally you create a render target with texture, create a camera for rendering to it, and just render it it (by using a new layer on geometry as well as the camera. Something along this script:

used here


Thank you, everyone for the inputs!

@yaustar yeah, in some cases there can be like 10-30 extra elements that are hard to batch, unfortunately.

@mvaligursky, right, so as @Leonidas mentioned I had to adjust the ratio. As you mentioned camera is fine, it grabs whatever texture resolution is set there, so it just works. The issue comes afterwards, when that texture is added to some existing UI element, skewing it, depending on the ratio differences. I had to adjust the element’s ratio, so there would be no distortion. I also had to flip on Y the UI element, as the render is upside down (and flipY flag on texture in this case doesn’t work for some reason).

For anyone interested, here is a result with an example of 20 UI images packing into a single draw call:


The flipY option is on the RenderTarget, not the texture :slight_smile:

Hmm, are you sure? I think it is on texture:

Hmm… It’s also on the render target RenderTarget | PlayCanvas API Reference

1 Like

Interesting… Anyhow, I just tried to use the flag on render target, but it doesn’t seem to change anything. My guess is that the texture is first flipped, then we render to it, which cancels any flipping? Not sure.

Very odd :thinking: May have to have a poke at it myself

1 Like

Found the issue, the UI layer doesn’t render on a flipY render target.

I will report it as a bug

Edit: Bug report: https://github.com/playcanvas/engine/issues/4097


Thank you! I remember I had that issue with not being able to render it. Thought I was doing something wrong.