1

I wrote a function (a bit of vibe coding too) that exports the users current canvas as an image.

Reference Images

User’s View:

enter image description here

Please ignore the toolbar in the user’s view image that is not a part of canvas its just an overlay.

Exported Image:

enter image description here

Issue:

If you see users view the object is centered while inside the exported image the object is not in the center and is bit more towards the top-right corner side.

I’ve trying to fix this for quite sometime now, I think it’s got something to do with how the viewport is being set but I’m not an expert. Here’s the function to export the canvas:

  exportImageWithBg(bgType, resolution = '8K') {
    const resolutions = {
      '1K': { width: 1280, height: 720 },
      '2K': { width: 2048, height: 1080 },
      '4K': { width: 3840, height: 2160 },
      '8K': { width: 7680, height: 4320 },
    };

    const { width, height } = resolutions[resolution];
    const fileName = `export_${resolution}_${Date.now()}.png`;

    const renderer = this.renderer;
    const scene = this.scene;
    const originalCamera = this.camera;

    // Preserve original settings
    const originalBg = scene.background;
    const originalRenderTarget = renderer.getRenderTarget();
    const originalViewport = renderer.getViewport(new THREE.Vector4());

    // Set background
    switch (bgType) {
      case 'white':
        scene.background = new THREE.Color(0xffffff);
        break;
      case 'dark':
        scene.background = new THREE.Color(0x000000);
        break;
      case 'transparent':
        scene.background = null;
        renderer.setClearColor(0x000000, 0);
        break;
    }

    // Clone and configure camera for correct aspect ratio
    const exportCamera = originalCamera.clone();
    exportCamera.aspect = width / height;
    exportCamera.updateProjectionMatrix();
    exportCamera.position.copy(originalCamera.position);
    exportCamera.quaternion.copy(originalCamera.quaternion);
    exportCamera.updateMatrixWorld(true);

    // Render target
    const renderTarget = new THREE.WebGLRenderTarget(width, height, {
      format: THREE.RGBAFormat,
      type: THREE.UnsignedByteType,
      colorSpace: THREE.SRGBColorSpace,
    });

    // Render offscreen
    renderer.setRenderTarget(renderTarget);
    console.log(renderTarget);
    // renderer.setViewport(0, 0, width, height);
    // renderer.setViewport(0, 0, width * 2, height * 2);
    renderer.setViewport(0, 0, width, height);
    renderer.render(scene, exportCamera);

    // Extract pixels
    const buffer = new Uint8Array(width * height * 4);
    renderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, buffer);

    // Copy to canvas
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d');
    const imageData = ctx.createImageData(width, height);

    for (let y = 0; y < height; y++) {
      for (let x = 0; x < width; x++) {
        const srcIdx = (y * width + x) * 4;
        const dstIdx = ((height - y - 1) * width + x) * 4;
        imageData.data[dstIdx] = buffer[srcIdx];
        imageData.data[dstIdx + 1] = buffer[srcIdx + 1];
        imageData.data[dstIdx + 2] = buffer[srcIdx + 2];
        imageData.data[dstIdx + 3] = buffer[srcIdx + 3];
      }
    }

    ctx.putImageData(imageData, 0, 0);

    // Trigger download
    const link = document.createElement('a');
    link.href = canvas.toDataURL('image/png');
    link.download = fileName;
    link.click();

    // Cleanup and restore
    renderTarget.dispose();
    scene.background = originalBg;
    renderer.setRenderTarget(originalRenderTarget);
    renderer.setViewport(originalViewport);
  }

I tried but nothing seems to work

1
  • 2
    Perhaps your threeJS scene is displayed in a different resolution than one of the four presets in your code. Your first screenshot is not 16:9 but the resolutions in your code ARE all 16:9. Commented Jul 16 at 9:31

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.