Three js object to render in matterport scene with code

I have a website where I need to create a 3d plane object which have provided image as texture on two sides. Then I want to render that object into matterport scene/space.

Note: I cannot export the glb file as the object has to be created on the website and rendered on the matterport scene. The glb file isnot stored anywhere on the database, It is created from the provided image.

I have implemented the logic of creating plane 3d object and exporting to glb file having image as texture using three js as:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Loading 3d models</title>
    <style>
      body {
        margin: 0;
      }
      canvas {
        display: block;
      }
    </style>
  </head>
  <body>
    <p>
      <span><button class="export-glb">Export</button></span>
    </p>
    <script type="module">
      import * as THREE from "three";
      import { OrbitControls } from "three/addons/controls/OrbitControls.js";
      import { GLTFExporter } from "three/addons/exporters/GLTFExporter.js";

      const exportBtn = document.querySelector(".export-glb"); // Create export button dynamically

      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      );

      const renderer = new THREE.WebGLRenderer({ antialias: true });
      renderer.setSize(window.innerWidth, window.innerHeight);
      document.body.appendChild(renderer.domElement);

      // Load the water texture
      const textureLoader = new THREE.TextureLoader();
      const texture = textureLoader.load("test-3.png");
      texture.wrapS = THREE.RepeatWrapping;
      texture.wrapT = THREE.RepeatWrapping;

      // Create a plane geometry and apply the texture as material
      const geometry = new THREE.PlaneGeometry(1, 1);
      const material = new THREE.MeshBasicMaterial({
        map: texture,
        side: THREE.DoubleSide, // Makes the texture visible from both sides
        transparent: true,
      });
      const plane = new THREE.Mesh(geometry, material);
      scene.add(plane);

      // OrbitControls for better interaction
      const controls = new OrbitControls(camera, renderer.domElement);

      camera.position.z = 5;

      function animate() {
        renderer.render(scene, camera);
        controls.update();
      }

      renderer.setAnimationLoop(animate);

      // Function to download the scene as a GLB file
      function download() {
        const exporter = new GLTFExporter();
        exporter.parse(
          scene,
          function (result) {
            if (result instanceof ArrayBuffer) {
              console.log("result", result);
              saveArrayBuffer(result, "scene.glb");
            } else {
              console.error(
                "GLTFExporter did not return an ArrayBuffer. Converting to GLB format..."
              );
              const json = JSON.stringify(result);
              console.log(result);
              const buffer = new TextEncoder().encode(json);
              saveArrayBuffer(buffer, "scene.glb"); // Save as .glb but it will be in JSON format
            }
          },
          { binary: true }
        );
      }

      // Function to save the ArrayBuffer as a file
      function saveArrayBuffer(buffer, filename) {
        const blob = new Blob([buffer], { type: "application/octet-stream" });
        const link = document.createElement("a");
        link.style.display = "none";
        document.body.appendChild(link); // Firefox workaround
        link.href = URL.createObjectURL(blob);
        link.download = filename;
        link.click();
      }

      // Add event listener for the export button
      exportBtn.addEventListener("click", download);
    </script>
  </body>
</html>

And I know to render the glb files in matterport too.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>load</title>
    <link rel="stylesheet" />
  </head>

  <body>
    <iframe
      id="showcase"
      width="100%"
      height="700"
      src="./bundle/showcase.html?m=gMDfBc11wvm&applicationKey=<YOUR_MATTERPORT_SDK_KEY>&play=1"
      frameborder="”0”"
      allowfullscreen
      allow="vr"
    ></iframe>

    <script>
      const bundleIframe = document.getElementById("showcase");
      const showcaseWindow = bundleIframe.contentWindow;

      let mpSdk;
      let mattertagID;

      showcase.addEventListener("load", async function () {
        try {
          mpSdk = await showcaseWindow.MP_SDK.connect(showcaseWindow);
          console.log("mpSdk", mpSdk);

          const [sceneObject] = await mpSdk.Scene.createObjects(1);
          const lights = sceneObject.addNode();
          lights.addComponent("mp.lights");
          lights.start();

          const modelNode = sceneObject.addNode();

          // Store the glb component since we will need to adjust it in the next step.
          const fbxComponent = modelNode.addComponent(
            mpSdk.Scene.Component.GLTF_LOADER,
            {
              url: "water.glb",
            }
          );

          fbxComponent.inputs.localScale = {
            x: 0.2,
            y: 0.2,
            z: 0.2,
          };
          modelNode.obj3D.position.set(-1, 1, 0); // drop ~3 feet
          modelNode.start();

          const tick = function () {
            requestAnimationFrame(tick);
            modelNode.obj3D.rotation.y += 0.02;
          };
          tick();
        } catch (e) {
          console.log("error", e);
        }
      });
    </script>
  </body>
</html>

Any suggestions or example of such implementation would be helpful.
Thanks in advance <3 .

Guys, I did it. I created the blob url to simulate a link to file and then used that url in matterport’s GLTF_LOADER as:

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Loading 3D Models</title>
    <style>
      body {
        margin: 0;
      }
      canvas {
        display: block;
      }
    </style>

    <script type="importmap">
      {
        "imports": {
          "three": "https://cdn.jsdelivr.net/npm/three@0.168.0/build/three.module.js",
          "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.168.0/examples/jsm/"
        }
      }
    </script>
  </head>
  <body>
    <script async type="module" src="script.js"></script>

    <!-- Add your Matterport iframe here -->
    <iframe
      id="showcase"
      width="100%"
      height="700"
      src="./bundle/showcase.html?m=gMDfBc11wvm&applicationKey=<YOUR_MATTERPORT_APPLICATION_KEY>&play=1"
      frameborder="”0”"
      allowfullscreen
      allow="vr"
    ></iframe>
  </body>
</html>

script.js

import * as THREE from "three";
import { GLTFExporter } from "three/addons/exporters/GLTFExporter.js";

// Create Three.js scene
const scene = new THREE.Scene();
const geometry = new THREE.PlaneGeometry(1, 1);

// Load the texture and wait until it's fully loaded
const textureLoader = new THREE.TextureLoader();
textureLoader.load("water.jpeg", (texture) => {
  // Texture is fully loaded, create material and mesh
  const material = new THREE.MeshBasicMaterial({
    map: texture,
    side: THREE.DoubleSide,
    transparent: true,
  });
  const plane = new THREE.Mesh(geometry, material);
  scene.add(plane);

  // Now that the texture is loaded, export the scene as GLTF
  const exporter = new GLTFExporter();
  exporter.parse(
    scene,
    (gltf) => {
      // Convert the GLTF data into a Blob
      const blob = new Blob([JSON.stringify(gltf)], {
        type: "application/json",
      });

      // Create a Blob URL to simulate a file
      const blobUrl = URL.createObjectURL(blob);

      console.log("GLTF Blob URL:", blobUrl);

      // Pass the Blob URL to the Matterport loader
      renderToMatterport(blobUrl);
    },
    { binary: false } // Use binary: true for binary GLB export
  );
});

// Matterport rendering logic
async function renderToMatterport(gltfUrl) {
  const showcaseIframe = document.getElementById("showcase");
  const showcaseWindow = showcaseIframe.contentWindow;

  showcaseIframe.addEventListener("load", async function () {
    try {
      const mpSdk = await showcaseWindow.MP_SDK.connect(showcaseWindow);

      const [sceneObject] = await mpSdk.Scene.createObjects(1);
      const modelNode = sceneObject.addNode();

      // Use the GLTF URL here
      const gltfComponent = modelNode.addComponent(
        mpSdk.Scene.Component.GLTF_LOADER,
        { url: gltfUrl }
      );
      modelNode.obj3D.position.set(2, 1, 2);
      modelNode.start();
    } catch (error) {
      console.error("Error rendering in Matterport", error);
    }
  });
}

I am expecting the best practice if there are any except for this.