Assistance Needed with iFrame on 3D Plane Display Issues

Hello everyone,

I am currently encountering a problem while embedding an iFrame on a plane within my 3D scene. Specifically:

  1. When I move behind the plane (positioned in mid-air), the video on the plane becomes visible in reverse from the backside.
  2. When the player/character stands in front of the plane, the plane’s rendering appears to be at a higher display level, causing the character to appear behind the plane—even though the character is logically in front of it.

These issues do not manifest in the editor itself, but appear once I test or play the scene in an actual runtime environment while using engine in code with react.

I would greatly appreciate any guidance on how to fix these rendering or depth-sorting discrepancies. If you have experience with similar iFrame, your suggestions or best practices would be extremely helpful.

This is the example I used: PlayCanvas 3D HTML5 Game Engine

let beforeWorld = app.scene.layers.getLayerByName("Before World");
        if (!beforeWorld) {
          beforeWorld = new extendedPc.Layer({ name: "Before World" });
          app.scene.layers.insert(beforeWorld, 0);
        }

        const immediateLayer = app.scene.layers.getLayerByName("Immediate");
        immediateLayer.opaqueSortMode = extendedPc.SORTMODE_NONE;

        const uiLayer = app.scene.layers.getLayerByName("UI");
        uiLayer.opaqueSortMode = extendedPc.SORTMODE_MANUAL;
        uiLayer.transparentSortMode = extendedPc.SORTMODE_MANUAL;

        const skyboxLayer = app.scene.layers.getLayerByName("Skybox");
        skyboxLayer.opaqueSortMode = extendedPc.SORTMODE_NONE;

 const childPlane = new extendedPc.Entity("ChildPlane");

        childPlane.setLocalPosition(0, 3, -1.4391355514526367); // Position relative to the parent
        childPlane.setLocalScale(1.492, 1, 1.305);
        childPlane.setEulerAngles(90, 0, 0);

        childPlane.addComponent("render", {
          type: "plane",
        });

        childPlane.render.castShadows = true;
        childPlane.render.castShadowsLightmap = true;
        childPlane.render.receiveShadows = true;
        childPlane.render.layers = [beforeWorld.id];

        app.root.addChild(childPlane);

childPlane.addComponent("script");
          childPlane.script.create("iframePlane", {
            attributes: {
              iframeUrl: URL,
              pixelsPerUnit: 320,
            },
          });

Thank you in advance for your time and assistance.

Kind regards,

I’ve helped this user in private so here were the issues:

It’s important here to understand how the whole effect works in order to debug this.

The two main DOM elements that are rendering to the document are the canvas (where PlayCanvas is rendering to) and the iframe DOM element for the YouTube video. The iframe isn’t part of the PlayCanvas rendering, there’s just some clever trickery to make it look like the iframe is part of the scene.

For the effect to work, the iframe element has to be BEHIND the canvas and in PlayCanvas, we ensure we don’t render the area where the iframe is behind the canvas.

You can see it in the example PlayCanvas project for the TV models when you capture the render in SpectorJS

The checkerboard pattern is where we don’t render. The Iframe script does this by creating a material that doesn’t write to the color buffer but writes to the depth buffer

And as it’s on the opaque sub layer of the world where meshes are rendered front to back order, this is what happens in the example project

  • The canvas has been set in the project options to be transparent

  • In each frame render, the camera clears the color buffer with a transparent clear color so the whole canvas is made transparent

  • The plane is rendered first so it writes to the depth buffer. But as it’s not rendering to the color buffer, where it’s ‘rendered’ is still transparent on the canvas

  • No objects behind the plane, render to the color buffer because when they depth test, it will show that there was something rendered there that was closer to camera

  • Final result is that we have an area in the canvas that is transparent and can see the iframe DOM element through.

To sum it up: for all this to work, there’s a number of constraints for setup:

  • The canvas has to be set as transparent
  • The camera has to have it’s clear color have an alpha value of 0
  • The z index of the canvas has to be higher than the z index of the iframe DOM elements
  • The canvas and iframe DOM element style has to have it’s ‘position’ not to be ‘static’

To fix this in your project:

  • Set the canvas to be transparent (when you create the graphics device)

  • Style the canvas to have it’s position to be something other than ‘static’ and ensure that it’s z-index is higher than the iframe DOM elements
  • Set the clear color of the camera to have the alpha as 0

1 Like