Render to Texture Background

Good morning everyone,

To keep UI simple I’ve opted to use fill-mode-KEEP_ASPECT. Of course this means if the window is out of aspect ratio there will be bars surrounding the canvas. Currently, I’ve settled with just making the html and body tags have a nice radial gradient background to soften everything, but I think I could do better.

I’m currently thinking about using Render to Texture to push out a low res image of the current scene out of the canvas to be used as the background surrounding the canvas and blur it using either mipmaps or CSS.

I think if I keep the texture small, 256 or 512, I won’t be taking too much of a hit to performance.

The most informative project I seen is this one by @yaustar. I see the data being created and harvested, but I think I’m getting logically lost on how I would push that data outside of the canvas to act as a source for thhe background image:

https://playcanvas.com/editor/code/605131?tabs=17966832

Of course, this might also be a terrible idea, and I should just stick to my gradient, but any insight or thoughts would be greatly appreciated.

this.canvas.toDataURL('image/png'); returns a base64 URL that can be used as an image source in CSS.

Not sure if that’s something you should be doing every frame though. Would just the once would work well enough?

1 Like

Since the idea is still pretty nebulous, once might work, but I’m thinking that sine the user can look around that it might be better for the background to update as the scene changes, but that’s what testing is for!

I think if I keep the image small enough the hit to performance might not be so bad. Thank you very much for the insight @yaustar !

The issue is that you are still rendering the scene twice and there’s a not insignificant cost involved getting the image from the texture.

You could do something like this where instead of having the canvas resized, you do it all within PlayCanvas: Resolution Scaling | Learn PlayCanvas

That project renders the scene to a texture and then uses the texture in the UI as a full screen image.

You can do potentially do something similar but to a fixed aspect ratio and use another render texture for your ‘background’?

That’s a good point. At least I have a simple gradient to fall back on if I have to, but I’m not ready to give up quite yet. The resolution scaling sound Like I might have to rework a lot of the layout of the UI.

Hmmmm…What are your thoughts on using CanvasRenderingContext2D.getImageData() from a 2nd, fully extended, canvas behind the main PlayCanvas just to color it with the specified area?

Afraid I haven’t used that API

No problem. I’ll keep looking and start experimenting. Thank you!

So I actually got this working by creating a global script and a 2nd canvas that is rendered behind application-canvas. I then call the the 2nd canvas to be updated in an update function. This require preserving the drawing buffer. There was a noticeable hit to performance, but I think the result looked ok. Overall, I think I will just stick to the simple gradient, as I’m not sure the performance hit is worth the look I’m going for, even if I only updated every other frame.

Here’s what I did in case someone else wants to do something similar:

index.html:

...

<body>

    <script src="__modules__.js"></script>
    <script src="__start__.js"></script>
    <script src="__loading__.js"></script>
    <canvas id="bgCanvas"></canvas>
    <script src="bg.js"></script>
</body>
...

bg.js

var pcCanvas = document.getElementById('application-canvas');
var pcCtx = pcCanvas.getContext('webgl2');

var bgCanvas = document.getElementById('bgCanvas');
var bgCtx = bgCanvas.getContext('2d');

bgCtx.imageSmoothingEnabled = true;
bgCtx.webkitImageSmoothingEnabled = true;
bgCtx.msImageSmoothingEnabled = true;
bgCtx.filter = "blur(1.5rem)";

var bgUpdate = function(ctx) {

  ctx.drawImage(pcCtx.canvas, 200, 100, 1920, 1080, 0, 0, 480, 270);
}

function bgInit() {
  bgUpdate(bgCtx);
}

window.onload = bgInit;

css:

canvas#bgCanvas {
  display: block;
  position: absolute;
  z-index: -1;
  height: 100%;
  width: 100%;
}
RandomScript.prototype.update = function(dt) {
bgInit();
}
3 Likes