1

I am developing an augmented reality application using Three.js, WebXR, and Vue.js version 3. My goal is to add a button that, when pressed, captures a snapshot of the current scene. However, I am facing issues while attempting to take the snapshot. On a mobile device, the captured image is blank, while in the WebXR environment (I am using firefox and chrome with the webxrapi extension to simulate a galax s8 phone) on desktop, I can only see the 3D model with a white background.

Here is the code for my Vue component template:

<template>
    <canvas ref="canvas" id="canvas"></canvas>
    <div ref="overlay" id="overlay">
        <button  ref="picture" class="picture-button" v-show="arSessionStarted">
        TA BILD
        </button>
        <button ref="rotate" class="rotation-button" v-show="arSessionStarted">
        ROTERA 
        </button>
    </div>
</template>

This is the main function:

init() {
    // Create a THREE scene
    this.scene = new THREE.Scene()
    this.camera = new THREE.PerspectiveCamera(
        70,
        window.innerWidth / window.innerHeight,
        0.1,
        20
    );
    this.camera.position.z = 1;
   // CreatE a THREE WebGLRenderer
    this.canvas = this.$refs.canvas;
    this.gl = this.canvas.getContext('webgl', {xrCompatible: true});
    this.renderer = new THREE.WebGLRenderer({
        canvas: this.canvas,
        context: this.gl,
        antialias: true,
        alpha: true,
        powerPreference: 'high-performance', 
        xrCompatible: true,
        preserveDrawingBuffer: true
    });
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(window.innerWidth, window.innerHeight);
    this.renderer.xr.enabled = true;

    // Create a THREE light object
    const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1);
    light.position.set(0.5, 1, 0.25);
    this.scene.add(light);
    
    // Load the model and reticle to the scene
    this.addReticleToScene();
    this.addModelToScene(); 
    // Create THREE controller to place the container
    this.controller = this.renderer.xr.getController(0);
    this.controller.addEventListener("select", this.onSelect);
    this.scene.add(this.controller);
    
    // Create a button to enter  a AR session 
    this.overlay = this.$refs.overlay;
    const button = ARButton.createButton(this.renderer, {
        requiredFeatures: ["hit-test"],
        optionalFeatures: [
            "dom-overlay",
            "dom-overlay-for-handheld-ar",
        ],
        domOverlay: {
            root: this.overlay,
        },
    });
    this.overlay.appendChild(button);
    // Add an id to the ar button
    button.id = "my-id";
    //Initiate the event listeners for the rotate and take picture buttons
    this.rotationButton = this.$refs.rotate;
    this.takePictureButton = this.$refs.picture;
    this.rotationButton.addEventListener('beforexrselect', ev => ev.preventDefault());
    this.takePictureButton.addEventListener('beforexrselect', ev => ev.preventDefault());
    
    this.rotationButton.addEventListener('click', () => {
        this.rotate();
    });
    
    this.takePictureButton.addEventListener('click', () => {
        this.takePicture();
    });
    // Add event listener to adjust the size of the window
    window.addEventListener("resize", this.onWindowResize, false);
}

This is thetakePicture function:

takePicture() {
    //Take Picture
    this.screenshoot = this.renderer.domElement.toDataURL();
    console.log(this.screenshoot);
    alert("Work in Progress!");
},

This is therenderer:

render(timestamp, frame) {
    if (frame) {
        if (!this.hitTestSourceInitialized) {
            this.initializeHitTestSource();
        }
        if (this.hitTestSourceInitialized) {
            const hitTestResults = frame.getHitTestResults(
                this.hitTestSource
            );
            if (hitTestResults.length > 0) {
                const hit = hitTestResults[0];
                const pose = hit.getPose(this.localSpace);
                this.reticle.visible = true;
                this.reticle.matrix.fromArray(pose.transform.matrix);
            } else {
                this.reticle.visible = false;
            }
        }
        this.renderer.render(this.scene, this.camera);
    }
}
animate() {
    this.renderer.setAnimationLoop(this.render);
}

I have tried the following:

takePicture() {
    //Take Picture
    this.screenshoot = this.renderer.domElement.toDataURL();
    console.log(this.screenshoot);
    alert("Work in Progress!");
},

Thread from stackoverflow: How to capture an image of THREE.Scene uning THREE.PerspectiveCamera?

Thread from stackoverflow: Three.js: How can I make a 2D SnapShot of a Scene as a JPG Image?

nazariisme
  • 11
  • 1

1 Answers1

0

We have a solution to screen capture using MindAR. It involves creating an additional canvas for a copy of the AR feed, getting hold of the rendering canvas, sizing the copy canvas to match the rendering canvas, capturing the copied canvas WebGL 2D context, and then taking the video feed and the rendering canvas and drawing them to the copied canvas via the 2D WebGL context. Then you save the copy canvas using toDataURL. Please see the code example here:

https://github.com/dvbridges/ar-projects/blob/main/mind-ar-threejs-image-tracker/script.js

Bridges
  • 21
  • 3