Skip to content

Instantly share code, notes, and snippets.

@unitycoder
Created January 13, 2026 09:04
Show Gist options
  • Select an option

  • Save unitycoder/55b8f4ad960773430656154794aff9ef to your computer and use it in GitHub Desktop.

Select an option

Save unitycoder/55b8f4ad960773430656154794aff9ef to your computer and use it in GitHub Desktop.
How to take a screenshot with Unity WebGPU?
// https://discussions.unity.com/t/how-to-take-a-screenshot-with-unity-webgpu/1681498/2
using System.Runtime.InteropServices;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Rendering;
public sealed class AsyncCapture : MonoBehaviour
{
// ProcessCapture is defined in ASyncCapture.jslib
[DllImport("__Internal")]
private static extern void ProcessCapture(byte[] pngPtr, int pngLength);
int frameCount = 0;
void Update()
{
// Capture on the 10th frame, an arbitrarily picked frame
frameCount++;
if (frameCount == 10)
{
var (w, h) = (Screen.width, Screen.height);
var (scale, offs) = (new Vector2(1, -1), new Vector2(0, 1));
var grabRT = new RenderTexture(w, h, 0);
var flipRT = new RenderTexture(w, h, 0);
var rtFormat = grabRT.graphicsFormat;
// Capture the screen to grabRT. This will be upside down, so we'll need to flip it.
ScreenCapture.CaptureScreenshotIntoRenderTexture(grabRT);
// Flip grabRT by blit'ing it to flipRT with a -1 y scale
Graphics.Blit(grabRT, flipRT, scale, offs); // flip Y
// Read the contents of flipRT to CPU memory. WebGPU does not support synchronous
// readback, so we need to use async readback.
AsyncGPUReadback.Request(flipRT, 0, TextureFormat.RGBA32, (req) =>
{
// We don't need these textures anymore.
DestroyImmediate(grabRT);
DestroyImmediate(flipRT);
// Get the image memory we just read
var imageData = req.GetData<byte>().ToArray();
// Encode the image to a PNG
byte[] pngData = ImageConversion.EncodeArrayToPNG(imageData, UnityEngine.Experimental.Rendering.GraphicsFormat.R8G8B8A8_UNorm, (uint)w, (uint)h);
// Send the PNG data to JavaScript to do something with it
ProcessCapture(pngData, pngData.Length);
});
}
}
}
mergeInto(LibraryManager.library, {
ProcessCapture: function(pngPtr, pngLength) {
// Get the JS view of the Wasm memory
const pngBytes = new Uint8Array(Module.HEAPU8.buffer, pngPtr, pngLength);
// Create a PNG Blob for the png data
const imageBlob = new Blob([pngBytes], { type: 'image/png' });
// Create an Object URL from the PNG blob
const imageUrl = URL.createObjectURL(imageBlob);
// Create an Image element to display the PNG Object URL and add it to the page
const imageElement = document.createElement('img');
imageElement.src = imageUrl;
document.body.appendChild(imageElement);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment