Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OGC3DTilesLayer loading 3dtiles model position adjustment and scaling adjustment? #2406

Open
liangyuan1 opened this issue Sep 13, 2024 · 8 comments
Assignees
Labels

Comments

@liangyuan1
Copy link

Manual modeling of data fbx is required to slice and convert it into 3dtiles. Use cesiumLab (download link: https://www.bjxbsj.cn/downcenter.html )This tool can be converted to 3dtiles1.1 (gltf) and 3dtiles1.0 (b3dm), where 3dtiles1.1 cannot load with an error message, while 3dtiles1.0 can load normally, but cannot change the model display position and scaling ratio as Cesium does, resulting in incorrect model position and scale after loading. What do I need to do to correctly place the model in the specified position(需要人工建模数据fbx 进行切片转化成3dtiles。使用cesiumLab(下载地址:https://www.bjxbsj.cn/downcenter.html),该工具可以转成3dtiles1.1(gltf)和3dtiles1.0(b3dm),其中3dtiles1.1无法加载报错,3dtiles1.0可以正常加载,但是无法像cesium加载完成更改模型显示位置和以及缩放比例,导致我加载后的模型位置和比例不对,我需要怎么做可以正确放到指定位置上)

##result
image

@AnthonyGlt
Copy link
Contributor

AnthonyGlt commented Sep 16, 2024

Are you using OGC3DTilesLayer to load it ?
Example : 3dtiles_loader.html
You should be able to edit the position using something like:

view.addLayer(layer).then((layer) => {
     layer.object3d.position.set( X, X, X );
                    layer.object3d.updateMatrixWorld( true );

})

@liangyuan1
Copy link
Author

 layer.object3d.position.set( X, X, X );

export function add3dTilesData(view) {
const source = new itowns.OGC3DTilesSource({
url: '/2/tileset.json',
})
console.log(source)

const layer = new itowns.OGC3DTilesLayer('3DTiles', {
source,
})

// Add the layer to our view
view.addLayer(layer).then((layer) => {
console.log('-000000000000000', layer, layer.object3d)
// 等待图层加载完成
layer.object3d.scale.set(3, 3, 3)
// layer.object3d.position.set(113.249257, 28.408089, 0)
layer.object3d.updateMatrixWorld(true)
// 更新视图以反映更改
view.notifyChange()
zoomToLayer(view, layer)
})
}
The above is my implementation method. When I scale, I use layer.ort3d.scale. set (3, 3, 3)
When layer. object3d. updateMatrixWorld (true) is set, the model cannot find where it is, but layer. object3d. scale. set (1, 1, 1) is the same as before. In addition, when I only set layer. object3d. position. set (113.249257, 28.408089, 0), the zoom ToLayer (view, layer) is still executed in its original position, and the model cannot be found when changing the coordinate position

@jailln
Copy link
Contributor

jailln commented Sep 25, 2024

You need to set the layer position in the same coordinate system as the view (that you can access with view.referenceCrs. If you are using a GlobeView for instance, the position must be in the EPSG:4978 coordinate system.

113.249257, 28.408089, 0 seems like EPSG:4326 coordinates. If that's the case, you must convert them first. To do that, you can use the Coordinates class:

var geographicPos = new itowns.Coordinates('EPSG:4326', 113.249257, 28.408089, 0);
var viewerCrsPos = geographicPos.as(view.referenceCrs);
layer.object3d.position.copy(viewerCrsPos.toVector3());
layer.object3d.updateMatrixWorld():

@jailln jailln self-assigned this Oct 14, 2024
@jailln
Copy link
Contributor

jailln commented Oct 14, 2024

@liangyuan1 have you been able to test the solution from my previous comment ?

@liangyuan1
Copy link
Author

liangyuan1 commented Oct 16, 2024

@liangyuan1 have you been able to test the solution from my previous comment ?

<title>Itowns - 3D Tiles loader</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="stylesheet" type="text/css" href="css/example.css" />
    <link rel="stylesheet" type="text/css" href="css/LoadingScreen.css" />

    <style type="text/css">
        #description {
            z-index: 2;
            right: 10px;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
</head>
<body>
    <div id="viewerDiv"></div>
    <div id="description">
        Specify the URL of a tileset to load:
        <input type="text" id="url" />
        <button onclick="setURL(document.getElementById('url').value)">
            Load
        </button>
        <hr />
        <p><b>Feature Information:</b></p>
        <div id="featureInfo"></div>
    </div>

    <script src="js/GUI/GuiTools.js"></script>
    <script src="../dist/itowns.js"></script>
    <script src="js/GUI/LoadingScreen.js"></script>
    <script src="../dist/debug.js"></script>

    <script type="importmap">
        {
            "imports": {
                "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
                "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/"
            }
        }
    </script>

    <script type="module">
        import { AmbientLight } from "three";
        import {
            zoomToLayer,
            fillHTMLWithPickingInfo,
        } from "./jsm/OGC3DTilesHelper.js";

        const {
            TMSSource,
            WMTSSource,
            OGC3DTilesSource,
            ColorLayer,
            ElevationLayer,
            OGC3DTilesLayer,
            GlobeView,
            Coordinates,
            Fetcher,
        } = itowns;

        const uri = new URL(location);
        const state = {
            // URL to tileset JSON
            tileset: uri.searchParams.get("tileset"),
            // Cesium ION /
            assetId: uri.searchParams.get("assetId"),
        };

        function setURL(url) {
            if (!url) return;

            uri.searchParams.set("tileset", url);
            history.pushState(null, "", `?${uri.searchParams.toString()}`);

            location.reload();
        }

        // ---- CREATE A GlobeView FOR SUPPORTING DATA VISUALIZATION ----

        // Define camera initial position
        const placement = {
            coord: new Coordinates("EPSG:4326", 2.351323, 48.856712),
            range: 12500000,
        };

        // `viewerDiv` will contain iTowns' rendering area (`<canvas>`)
        const viewerDiv = document.getElementById("viewerDiv");

        // Create a GlobeView
        const view = new GlobeView(viewerDiv, placement, {});

        // Add ambient light to globally illuminates all objects
        const light = new AmbientLight(0x404040, 15);
        view.scene.add(light);

        // Setup loading screen
        setupLoadingScreen(viewerDiv, view);

        // Setup debug menu
        const menuGlobe = new GuiTools("menuDiv", view, 300);
        debug.createTileDebugUI(menuGlobe.gui, view, view.tileLayer);

        // ---- ADD A BASEMAP ----

        // Add one imagery layer to the scene. This layer's properties are
        // defined in a json file, but it cou   ld be defined as a plain js
        // object. See `Layer` documentation for more info.
        Fetcher.json("./layers/JSONLayers/OPENSM.json").then((config) => {
            const layer = new ColorLayer("Ortho", {
                ...config,
                source: new TMSSource(config.source),
            });
            view.addLayer(layer).then(
                menuGlobe.addLayerGUI.bind(menuGlobe)
            );
        });

        // ---- ADD 3D TILES TILESET ----

        // Enable various compression support for 3D Tiles tileset:
        // - `KHR_draco_mesh_compression` mesh compression extension
        // - `KHR_texture_basisu` texture compresion extension
        itowns.enableDracoLoader("./libs/draco/");
        itowns.enableKtx2Loader("./lib/basis/", view.renderer);

        if (state.tileset) {
            const source = new OGC3DTilesSource({ url: state.tileset });
            const layer = new OGC3DTilesLayer("3DTiles", {
                source,
            });

            // Add an event for picking the 3D Tiles layer and displaying
            // information about the picked feature in an html div
            const pickingArgs = {
                htmlDiv: document.getElementById("featureInfo"),
                view,
                layer,
            };

            // Add the layer to our view
            view.addLayer(layer).then((layer) => {
                // 模型放大
                layer.object3d.scale.set(2, 2, 2);
                layer.object3d.updateMatrixWorld();
                view.notifyChange();
                zoomToLayer(view, layer);
                window.addEventListener(
                    "click",
                    (event) => fillHTMLWithPickingInfo(event, pickingArgs),
                    false
                );
            });

            debug.createOGC3DTilesDebugUI(menuGlobe.gui, view, layer);
        }

        window.setURL = setURL;
    </script>
</body>

@liangyuan1
Copy link
Author

@liangyuan1 have you been able to test the solution from my previous comment ?

@jailln https://github.com/hiwxy95/Hanged-brother.git ,3dtiles model

@jailln
Copy link
Contributor

jailln commented Oct 16, 2024

@liangyuan1 I managed to display it:

image

There was three reasons why it was hard to see your tileset:

  • It is underneath the terrain: in the 3dtiles_loader.html example we add a world 3D terrain with the following lines:
            function addElevationLayerFromConfig(config) {
                config.source = new itowns.WMTSSource(config.source);
                var elevationLayer = new itowns.ElevationLayer(config.id, config);
                view.addLayer(elevationLayer);
            }
            itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig);
            itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig);

You can comment these lines to remove the terrain (or update the altitude of your model, similarly to what is done here)

view.addLayer(window.layer).then((layer) => {
                    layer.addEventListener('load-model', (m) => {
                        m.scene.scale.set(10, 10, 10);
                        m.scene.updateMatrixWorld();
                    });
                    zoomToLayer(view, layer);
                    window.addEventListener('click',
                        (event) => fillHTMLWithPickingInfo(event, pickingArgs), false);
                });

Note that the zoomToLayer util zooms to the 3D Tiles tileset bounding box which does not consider the position/rotation/scale updates applied to the model after loading, so zooming might be broken when you update the position or rotation or scale. To fix that, you can zoom to the layer.object3d bounding box that you can for instance compute with Box3.setFromObject.

  • Finally, note that the globeControls have a min distance configured (you cannot zoom passed this distance). Depending on your use case, you can update that value (set to 250m by default) by configuring the view creation as follow:
            const view = new GlobeView(viewerDiv, placement, {
                controls: {
                    minDistance: 10, // Update the value here
                }
            });

@jailln jailln closed this as completed Oct 16, 2024
@liangyuan1
Copy link
Author

@jailln Thank you very much, but I still want to modify the model position. I tried using the following code, but I was not successful. In addition, how to automatically locate the model after I modify the model position? I don't quite understand what you said about Box3. setFromObject. Can you provide a demo? Thank you

code

const source = new itowns.C3DTilesSource({
url: '/data/2/tileset.json'
// url: 'https://raw.githubusercontent.com/CesiumGS/3d-tiles-samples/master/1.0/TilesetWithRequestVolume/tileset.json'
});
const layer = new itowns.OGC3DTilesLayer('3DTiles', {
source
});

    // Add the layer to our view
    view.addLayer(layer).then(layer => {
      console.log('-0-0-0-0-0-0-0-0', layer);
      layer.addEventListener('load-model', m => {
        m.scene.scale.set(100, 100, 100);
        m.scene.rotation.z = Math.PI;
        const coord = new itowns.Coordinates(
          'EPSG:4326',
          113.052834960937517,
          28.466879577636721,
          0
        );
        m.scene.position.copy(coord.as(view.referenceCrs));
        console.log('-----坐标转化--dsdssssss--', m.scen);
        m.scene.updateMatrixWorld();
      });
    });

@jailln jailln reopened this Oct 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants