pixi-essentials
pixi-essentials copied to clipboard
[SVG] Cannot export the SVGScene into image
We are trying to export the canvas to png using add.renderer.generateTexture
and app.renderer.extract
, but the svg object isn't showing in the image.
After digging into the source code and found out this line is causing the issue
https://github.com/ShukantPal/pixi-essentials/blob/0c61c083b7e1bd5206b015699c8d13a0c1e948b5/packages/svg/src/SVGScene.ts#L177
By removing this line, the svg object now can export as expected
- this._cull.cull(renderer.renderTexture.sourceFrame, true);
Although the app works fine without this line, we are not sure wether if there's side effect or not.
Hi @rnike, this is a performance optimization that culls out elements that are off-screen. If you try to render the SVG into a texture without updating the culling, it will not render the previously culled items.
@ShukantPal Thanks for the reply, I found out there is a transform in renderer while using the add.renderer.generateTexture
method, this cause the cull be culling with the incorrect area.
https://github.com/pixijs/pixijs/blob/c04c09c50874fef9296555af23e25fe58cc808a9/packages/core/src/renderTexture/GenerateTextureSystem.ts#L83C1-L96C1
Shall we also handle the renderer.projection.transform
when culling the object?
For example adjust the xy of the cull rectangle with the transform from renderer, the following workaround fix our case.
this.tempSourceFrame.copyFrom(renderer.renderTexture.sourceFrame);
if(renderer.projection.transform){
this.tempSourceFrame.x -= renderer.projection.transform.tx
this.tempSourceFrame.y -= renderer.projection.transform.ty
}
// Cull the SVG scene graph
this._cull.cull(this.tempSourceFrame, true);
The transform is to map (x, y) to (0, 0) in the texture (aka the top left of the texture). But the culling should be done in world space, without discounting the projection transform.
What may be happening is that skipUpdateTransform
is being set (since I assume the Transformer
is mounted in your scene graph somewhere). That will make the children of the Transformer
not update their world bounds. I suggest removing the transformer from your scene, rendering it into a texture, and then re-adding it back.
Unfortunately, removing Transformer
isn't solving our problem.
What we are trying to do is to export the specific area of the stage to image.
// this is what pixi do while calling `add.renderer.generateTexture`
const texture = RenderTexture.create({
width: region.width,
height: region.height,
});
app.renderer.render(app.stage, {
renderTexture: texture,
transform: new Matrix().translate(-region.x, -region.y),
skipUpdateTransform: false,
blit: true,
});
output
If increase the size of the texture and don't set the transform, the svg will display but the output image size will be greater than expected
const texture = RenderTexture.create({
width: region.width + region.x, // add region.x to width
height: region.height + region.y, // add region.y to height
});
app.renderer.render(app.stage, {
renderTexture: texture,
// transform: new Matrix().translate(-region.x, -region.y), don't set the transform
skipUpdateTransform: false,
blit: true,
});
output
If don't increase the size of texture and don't set the transform for render, the svg graphics will not be draw in the image because of the incorrect export area and culling.
const texture = RenderTexture.create({
width: region.width,
height: region.height,
});
app.renderer.render(app.stage, {
renderTexture: texture,
// transform: new Matrix().translate(-region.x, -region.y), don't set the transform
skipUpdateTransform: false,
blit: true,
});
output