Fixed entity position with orbit camera

Hello, All.

I’m trying to add an entity which doesn’t move around as the orbit camera moves.

For that, I’ve created a layer named as ‘backplate’ then assigned an entity to it.
A camera for the backplate only sees the backplate layer and orbit camera sees the rest layers.

Below is the code.
Somehow the backplate camera overrides everything.

Is there anything I missed?

<!DOCTYPE html>
<html>
<head>
    <title>PlayCanvas Layers</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <link rel="icon" type="image/png" href="../playcanvas-favicon.png" />
    <script src="../../build/playcanvas.js"></script>
    <script src="../../build/playcanvas-extras.js"></script>
    <style>
        body {
            margin: 0;
            overflow-y: hidden;
        }
    </style>
</head>

<body>
    <!-- The canvas element -->
    <canvas id="application-canvas"></canvas>
    <a onclick="javascript:toggleBackplateCamera()">Backplate Camera</a>
    <!-- The script -->
    <script>

        var canvas = document.getElementById("application-canvas");
        var canvasWidth = 1024;
        var canvasHeight = 768;

        // Create the app and start the update loop
        // Create the app and start the update loop
        var app = new pc.Application(canvas, {
            mouse: new pc.Mouse(document.body),
            touch: new pc.TouchDevice(document.body)
        });

        app.start();

        // Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
        app.setCanvasFillMode(pc.FILLMODE_NONE);
        app.setCanvasResolution(pc.RESOLUTION_FIXED, canvasWidth, canvasHeight);

        // window.addEventListener("resize", function () {
        app.resizeCanvas(canvasWidth, canvasHeight);
        // });


        var miniStats = new pcx.MiniStats(app);

        app.scene.ambientLight = new pc.Color(0.2, 0.2, 0.2);

        var entity, light, camera;

        // Create a new layer to put in front of everything
        var frontLayer = new pc.Layer({
            name: "Front Layer"
        });

        var topLayer = new pc.Layer({
            name: "Top Layer"
        });


        var backplateLayer = new pc.Layer({ name: 'Backplate Layer'})

        // get the world layer index
        var worldLayer = app.scene.layers.getLayerByName("World");
        var worldLayerIdx = app.scene.layers.getTransparentIndex(worldLayer);

        // insert the backplate layer after the world layer
        app.scene.layers.insert(backplateLayer, worldLayerIdx + 1);

        // insert the front layer after the backplate layer
        app.scene.layers.insert(frontLayer, worldLayerIdx + 2);

        // insert the top layer after the front layer
        app.scene.layers.insert(topLayer, worldLayerIdx + 99);

        // Create an Entity with a camera component
        // Make sure it renders both World and Front Layer
        var camera = new pc.Entity();
        camera.name = 'backplateCamera';
        camera.addComponent("camera", {
            clearColor: new pc.Color(0.4, 0.45, 0.5),
            layers: [ backplateLayer.id]
        });
        camera.translate(0, 0, 24);
        app.root.addChild(camera);

        // Create an Entity with a point light component
        // Make sure it lights both World and Front Layer
        var light = new pc.Entity();
        light.addComponent("light", {
            type: "point",
            color: new pc.Color(1, 1, 1),
            range: 100,
            layers: [worldLayer.id, frontLayer.id, topLayer.id]
        });
        light.translate(5, 0, 15);
        app.root.addChild(light);

        // red material is semi-transparent
        var red = new pc.StandardMaterial();
        red.diffuse.set(1, 0, 0);
        red.blendType = pc.BLEND_NORMAL;
        red.opacity = 0.5;
        red.update();

        // blue material does not test the existing depth buffer
        var blue = new pc.StandardMaterial();
        blue.diffuse.set(0, 0, 1);
        blue.depthTest = false;
        blue.update();

        // red box is rendered first in World layer
        var redBox = new pc.Entity();
        redBox.addComponent('model', {
            type: 'box',
            layers: [frontLayer.id]
        });
        redBox.model.material = red;
        redBox.setLocalScale(5, 5, 5);
        app.root.addChild(redBox);

        // blue box is rendered in the Front Layer which is after World
        // because it does not test for depth
        // and is in a later layer
        // it is visible even though it should be inside the red box
        var blueBox = new pc.Entity();
        blueBox.addComponent('model', {
            type: 'box',
            layers: [topLayer.id] // try removing this line, the blue box will appear inside the red one
        });
        blueBox.model.material = blue;
        blueBox.setLocalScale(2.5, 2.5, 2.5);
        app.root.addChild(blueBox);

        app.on("update", function (dt) {
            if (redBox) {
                redBox.rotate(0, 10 * dt, 0);
            }
            if (blueBox) {
                blueBox.rotate(0, -10 * dt, 0);
            }

            blueBox.model.meshInstances[0].layer = 10;
        });



        var backplateEntity = new pc.Entity();
        backplateEntity.name = 'backplateEntity';
        backplateEntity.setPosition(0, 0, -100);
        backplateEntity.enabled = true;
        backplateEntity.setLocalScale(0.1, 0.1, 0.1);
        app.root.addChild(backplateEntity);

        var backplate = new pc.Asset('backplate', 'texture', {
            url: '../assets/textures/GIPS_TEST_2.jpg'
            // url: '/app/configurator/plate/plateImage.do?plateId=30'
        });


        app.assets.add(backplate);
        backplate.ready((backplateAsset) => {
            console.log(backplateAsset);
            var backplateAssetWidth = backplateAsset.resources[0].width;
            var backplateAssetHeight = backplateAsset.resources[0].height;

            var widthRatio = Math.abs(canvasWidth - backplateAssetWidth) / canvasWidth;
            var heightRatio = Math.abs(canvasHeight - backplateAssetHeight) / canvasHeight;
            console.log('backplate is ready', backplate);


            if (widthRatio < heightRatio) {

                backplateEntity.element.width = canvasWidth;
                backplateEntity.element.height = (backplateAssetHeight * canvasWidth) / backplateAssetWidth;

                if (backplateEntity.element.height < canvasHeight) {
                    backplateEntity.element.width = (backplateAssetWidth * canvasHeight) / backplateAssetHeight;
                    backplateEntity.element.height = canvasHeight;
                }
            } else {
                backplateEntity.element.width = (backplateAssetWidth * canvasHeight) / backplateAssetHeight;
                backplateEntity.element.height = canvasHeight;

                if (backplateEntity.element.width < canvasWidth) {
                    backplateEntity.element.width = canvasWidth;
                    backplateEntity.element.height = (backplateAssetHeight * canvasWidth) / backplateAssetWidth;
                }
            }

        });

        backplateEntity.addComponent('element', {
            type: 'image',
            textureAsset: backplate,
            anchor: [0.5, 0.5, 0.5, 0.5],
            pivot: [0.5, 0.5]
        });

        // console.log('backplate layer id : ' + backplateLayer.id);
        backplateEntity.element.layers = [backplateLayer.id];


        var assetManifest = [
            {
                type: "script",
                url: "../../scripts/camera/orbit-camera.js"
            }
        ];

        // Load all assets and then run the example
        var assetsToLoad = assetManifest.length;
        assetManifest.forEach(function (entry) {
            app.assets.loadFromUrl(entry.url, entry.type, function (err, asset) {
                if (!err && asset) {
                    assetsToLoad--;
                    entry.asset = asset;
                    if (assetsToLoad === 0) {
                        // run();

                        // Create a camera with an orbit camera script
                        var orbitCamera = new pc.Entity();
                        orbitCamera.addComponent("camera", {
                            clearColor: new pc.Color(0.4, 0.45, 0.5),
                            layers: [topLayer.id, frontLayer.id, worldLayer.id]
                        });
                        orbitCamera.addComponent("script");
                        orbitCamera.script.create("orbitCamera", {
                            attributes: {
                                inertiaFactor: 0.2 // Override default of 0 (no inertia)
                            }
                        });
                        orbitCamera.script.create("orbitCameraInputMouse");
                        orbitCamera.script.create("orbitCameraInputTouch");
                        app.root.addChild(orbitCamera);
                    }
                }
            });
        });

        function toggleBackplateCamera() {
            console.log(app.root.findByName('backplateCamera'));
            app.root.findByName('backplateCamera').enabled = !app.root.findByName('backplateCamera').enabled;
        }
    </script>
</body>
</html>


Doesn’t move in camera space or doesn’t move in world space?

The backplate looks to be an UI element. This is usually on the UI layer which clears the depth buffer before rendering so it renders ‘over’ everything that was on a previous layer.

Without looking too deeply in your code, try putting it on the World layer.

The UI element is alway over other entity, isn’t it?
The backplate should be behind of everything…

Can you invide me to discord?

Can you give more detail about this?

Is this the kind of thing that you are looking for? https://playcanvas.com/editor/scene/1110697

yes…I think it is…

Have a look at the layer setup in the project settings. I’ve added a new layer (backplate) that renders before the world and after the skybox. The UI element is on this layer so it renders behind everything but remains fixed in world space

I was trying to find out how to config the same setting via playcanvas engine but I couldn’t.

Is there any way to set up the order of layers only via engine?

thanks.

Yes, there’s an example here https://playcanvas.github.io/#graphics/layers.html