唯杰地图 logo唯杰地图
VJMAP
EN

创建应用

vjmap3d/references/guide/createapp.md 9.7 KB242 行
原文

创建3D应用

通过 vjmap3d 中的 App 来创建一个3d应用。App需要设置container与一个div容器相关联。

示例如下:

// 创建一个服务类,与服务连接
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    // 渲染参数
    render: {
        alpha: true,
        antialias: true
    },
    // 是否显示性能统计面板
    stat: {
        show: true,
        left: "0"
    },
    // 场景设置
    scene: {
        // 是否显示坐标网格
        gridHelper: {
            visible: true
        }
    },
    // 相机设置
    camera: {
        // 是否显示视角指示器
        viewHelper: {
            enable: true
        }
    }
})

提示

免费试用版不提供私有化部署,直接连官网的服务进行试用,有水印。如果需要正式版本私有化部署,请联系客服。

选择渲染引擎(WebGL / WebGPU)

vjmap3d v2 起支持 WebGPU 渲染引擎。创建应用时通过渲染参数 render.engine 选择:"webgl"(默认,WebGLRenderer)或 "webgpu"(WebGPURenderer)。浏览器不支持 WebGPU 时,three 的 WebGPURenderer 会自动降级为 WebGL2 后端(仍属 webgpu 引擎:app.renderer.isWebGPURenderer === true、仍走 TSL 材质,GLSL ShaderMaterial 依旧不可用);只有 three/webgpu/three/tsl 动态加载失败(如 importmap 缺映射)或渲染器 init() 抛错时,才回退到 webgl 引擎(WebGLRenderer)。

版本要求

webgpu 引擎与 app.whenReady() 均为 v2.0.0 起的 API——旧版 vjmap3d@1.0.23(webgl-only,peer three@^0.165)的 dist 中没有。1.x 用户请直接使用默认 webgl 引擎并跳过下例的 await app.whenReady()(webgl 渲染器同步就绪)。版本分界详见 WebGPU 渲染引擎。

let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map",
    render: {
        engine: "webgpu", // 渲染引擎: 'webgl'(默认) 或 'webgpu'
        // forceWebGL: true, // 可选: webgpu 引擎强制使用 WebGL2 后端(兼容不支持 WebGPU 的环境)
        antialias: true
    }
})
// webgpu 引擎的渲染器为异步初始化:访问 app.renderer 前先等待就绪
// (webgl 引擎下立即返回;v2.0.0 起提供,旧版 1.x 无此方法可省略)
await app.whenReady();
console.log(app.renderer.isWebGPURenderer
    ? (app.renderer.backend?.isWebGPUBackend ? "WebGPU" : "WebGL2 后端(WebGPURenderer)")
    : "WebGL(webgl 引擎)");

提示

webgpu 引擎下,内置特效材质与后期处理(辉光/描边等)会自动切换为 TSL / WebGPU 实现,用法不变。详细说明(浏览器要求、回退规则、自定义材质注意事项)见 WebGPU 渲染引擎。

注意:vjmap3d 做为唯杰地图的三维图层使用时(见下文),因需共享 2D 地图的 WebGL 上下文,不支持 webgpu 引擎。

创建CAD为底图的3D应用

通过 vjmap3d 中的 MapViewEntity 来创建一个地图实体。

// 创建一个服务类,与服务连接
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    camera: {  // 相机设置
        viewHelper: { enable: true } // 是否显示视角指示器
    }
})
let res = await app.svc.openMap({
        mapid: env.exampleMapId, // 地图ID,(请确保此ID已存在,可上传新图形新建ID)
        mapopenway: vjmap3d.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
        style: vjmap3d.openMapDarkStyle()
});
if (res.error) {
    showError(res.error);
    return;
}
// 获取当前地图的可视范围
let clipPolygon = vjmap3d.GeoBounds.fromString(res.drawBounds).toPointArray();
let provider = new vjmap3d.MapProvider(
    [
        {
            url: app.svc.rasterTileUrl()
        }
    ],
    {
        transparent: true
    }
);
let mapBounds = vjmap3d.GeoBounds.fromString(res.bounds)
let scale = 100;
let mapviewEnt = new vjmap3d.MapViewEntity({
    provider,
    baseScale: scale,
    mapBounds: mapBounds.toArray(),
    clipPolygon //  如果透明的话,不能使用裁剪区载
});
mapviewEnt.addTo(app);
//
// 在CAD图中心上方创建一个Mesh
let cadLen = mapBounds.width() / 50; // 取cad图长度的1/50
// toDist 的 app 形参默认值是"当前全局 App"(new App 之后才有)——必须在 App 创建后调用,否则崩溃
let len = vjmap3d.toDist(cadLen); // cad长度转世界坐标长度
let box = new THREE.BoxGeometry(len, len, len)
const material = new THREE.MeshStandardMaterial({
    color: "#f00",
    side: THREE.DoubleSide
});
let mesh = new THREE.Mesh(box, material);
let cadPos = [mapBounds.center().x, mapBounds.center().y, cadLen]; // mesh在cad中坐标
//
let worldPos = vjmap3d.toWorld(cadPos);// cad坐标转世界坐标
mesh.position.copy(worldPos);
//app.scene.add(mesh) // 可以直接把 mesh 加进场景中不与实体相关联
// 创建一个实体与mesh相关联
let entity = vjmap3d.Entity.fromObject3d(mesh);
entity.addTo(app);
// 增加一个事件模块,用来高亮提示
entity.add(vjmap3d.EventModule, {
    hoverSelect: true,
    hoverHtmlText: '我是用vjmap3d创建的Box',
    popupOptions: {
        anchor: "bottom"
    }
});

做为唯杰地图的三维图层

vjmap3d既可做为一个单独的3D引擎, 也可以基于唯杰地图VJMAP做为一个3D图层,能够在保留二维图形信息的直观性同时,融入三维空间的深度感知和交互性,为用户带来更丰富、立体和沉浸式的视觉体验及数据分析能力。

其步骤为:

示例如下:

let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// 打开地图
let res = await svc.openMap({
    mapid: env.exampleMapId, // 地图ID
    // @ts-ignore
    mapopenway: vjmap.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
    style: vjmap.openMapLightStyle() // div为深色背景颜色时,这里也传深色背景样式
})
if (res.error) {
    // 如果打开出错
    showError(res.error)
    return;
}
// 获取地图范围
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
// 根据地图范围建立几何投影坐标系
let prj = new vjmap.GeoProjection(mapBounds);
//
// 地图对象
let map = new vjmap.Map({
    container: 'map', // DIV容器ID
    style: svc.rasterStyle(), // 样式,这里是栅格样式
    center: prj.toLngLat(mapBounds.center()), // 设置地图中心点
    zoom: 2, // 设置地图缩放级别
    pitch: 45,
    antialias: true, // 反锯齿
    renderWorldCopies: false // 不显示多屏地图
});
//
// 关联服务对象和投影对象
map.attach(svc, prj);
await map.onLoad();
//
// 创建3d图层
let mapLayer = new vjmap3d.MapThreeLayer(map, {
    stat: {
        show: true,
        left: "0"
    }
});
map.addLayer(new vjmap.ThreeLayer({ context: mapLayer }))
let app = mapLayer.app;
//
// 在CAD图中心上方创建一个Mesh
let cadLen = mapBounds.width() / 50; // 取cad图长度的1/50
// toDist 的 app 形参默认值是"当前全局 App"(new App 之后才有)——必须在 App 创建后调用,否则崩溃
let len = vjmap3d.toDist(cadLen); // cad长度转世界坐标长度
let box = new THREE.BoxGeometry(len, len, len)
const material = new THREE.MeshStandardMaterial({
    color: "#f00",
    side: THREE.DoubleSide
});
let mesh = new THREE.Mesh(box, material);
let cadPos = [mapBounds.center().x, mapBounds.center().y, cadLen]; // mesh在cad中坐标
//
let worldPos = vjmap3d.toWorld(cadPos);// cad坐标转世界坐标
mesh.position.copy(worldPos);
//app.scene.add(mesh) // 可以直接把 mesh 加进场景中不与实体相关联
// 创建一个实体与mesh相关联
let entity = vjmap3d.Entity.fromObject3d(mesh);
entity.addTo(app);
// 增加一个事件模块,用来高亮提示
entity.add(vjmap3d.EventModule, {
    hoverSelect: true,
    hoverHtmlText: '我是用vjmap3d创建的Box',
    popupOptions: {
        anchor: "bottom"
    }
});

总结

使用vjmap3d创建3d应用 和 做为唯杰地图的三维图层 使用,除了初始化代码不同外,业务代码基本上可复用,做到同一套代码用在不同的框架上。但要注意坐标轴差异:独立 App 为 Y 轴向上,三维图层模式(app.isMapMode)为 Z 轴向上(高度在 .z、地面为 XY 平面、旋转轴用 (0,0,1)),涉及高度/朝向的代码需按 app.isMapMode 分支,详见 坐标转换。

需要说明的是:当vjmap3d做为唯杰地图的三维图层使用时,其相机是由唯杰地图控制的,vjmap3d的相机会和唯杰地图相机保持同步。因此在这种模式下,不能直接操作vjmap3d的相机。同时因为唯杰地图暂不支持后期处理,所以在这种模式下,vjmap3d的后期处理功能会自动禁用。