> 文章列表 > openDriver开源插件main.js源码分析

openDriver开源插件main.js源码分析

openDriver开源插件main.js源码分析

资源分享

链接: https://pan.baidu.com/s/1o9HtGzEuSxsaKVPRp-RENw

提取码: 2k5y

jsView

这个项目是java后台资源服务,启动该项目,前端通过请求获取xodr资源

opendriver

开源插件,用于渲染xodr,浏览器访问html即可在本地渲染3D效果

xodr文件格式讲解

自动驾驶场景仿真标准(一)- OpenDRIVE - 知乎

《OpenDRIVE1.6规格文档》3_opendrive1.6 收费站_YMWM_的博客-CSDN博客

main.js

/* globals */

var ModuleOpenDrive = null;

var OpenDriveMap = null;

var refline_lines = null;

var road_network_mesh = null;

var roadmarks_mesh = null;

var lane_outline_lines = null;

var roadmark_outline_lines = null;

var ground_grid = null;

var disposable_objs = [];

var mouse = new THREE.Vector2();

var spotlight_info = document.getElementById('spotlight_info');

//相交车道ID

var INTERSECTED_LANE_ID = 0xffffffff;

var INTERSECTED_ROADMARK_ID = 0xffffffff;

//聚集光是否暂停

var spotlight_paused = false;

const COLORS = {

    road: 1.0,

    roadmark: 1.0,

    road_object: 0.9,

    lane_outline: 0xae52d4,

    roadmark_outline: 0xffffff,

    ref_line: 0x69f0ae,

    background: 0x444444,

    lane_highlight: 0x0000CD,

    roadmark_highlight: 0xff0000,

};

//自适应大小

window.addEventListener('resize', onWindowResize, false);

//监听鼠标位置改变

window.addEventListener('mousemove', onDocumentMouseMove, false);

window.addEventListener('dblclick', onDocumentMouseDbClick, false);

/* notifactions */

const notyf = new Notyf({

    duration: 3000,

    position: { x: 'left', y: 'bottom' },

    types: [{ type: 'info', background: '#607d8b', icon: false }]

});

 

//创建渲染器

const renderer = new THREE.WebGLRenderer(

    {

        antialias: true, //抗锯齿,防失真

        sortObjects: false //定义渲染器是否应对对象进行排序

    });

//开启投影阴影

renderer.shadowMap.enabled = true;

//设置渲染器渲染区域

renderer.setSize(window.innerWidth, window.innerHeight);

//渲染

document.getElementById('ThreeJS').appendChild(renderer.domElement);

//创建场景

const scene = new THREE.Scene();

//创建透视相机

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

//让Z轴朝上+

camera.up.set(0, 0, 1); /* Coordinate system with Z pointing up */

//创建控制器

const controls = new THREE.MapControls(camera, renderer.domElement);

controls.addEventListener('start', () => {

    /**

     * 拖动开始停止开启聚集光和停止旋转

     */

    spotlight_paused = true; //聚集光暂停

    controls.autoRotate = false; //是否旋转

});

controls.addEventListener('end', () => {

    //拖动结束聚集光关闭并且开启旋转

    spotlight_paused = false;//聚集光开始

    //将其设为true,以自动围绕目标旋转。请注意,如果它被启用,你必须在你的动画循环里调用

    // controls.autoRotate = true;//开启旋转

});

controls.autoRotate = true;//开启旋转

//创建平行光

const light = new THREE.DirectionalLight(0xffffff, 1.0);

scene.add(light);

//平行光方向指向原点(0,0,0)

scene.add(light.target);

//添加坐标轴辅助器

const axesHepler = new THREE.AxesHelper(5)

scene.add(axesHepler)

//选择车道线场景

const lane_picking_scene = new THREE.Scene();

//车道线场景背景颜色

lane_picking_scene.background = new THREE.Color(0xffffff);

//路标场景

const roadmark_picking_scene = new THREE.Scene();

//路标场景背景颜色

roadmark_picking_scene.background = new THREE.Color(0xffffff);

//坐标场景

const xyz_scene = new THREE.Scene();

//坐标场景背景颜色

xyz_scene.background = new THREE.Color(0xffffff);

const st_scene = new THREE.Scene();

st_scene.background = new THREE.Color(0xffffff);

//创建渲染器

const lane_picking_texture = new THREE.WebGLRenderTarget(1, 1, { type: THREE.FloatType });

const roadmark_picking_texture = new THREE.WebGLRenderTarget(1, 1, { type: THREE.FloatType });

const xyz_texture = new THREE.WebGLRenderTarget(1, 1, { type: THREE.FloatType });

const st_texture = new THREE.WebGLRenderTarget(1, 1, { type: THREE.FloatType });

//获取顶点着色器

const idVertexShader = document.getElementById('idVertexShader').textContent;

const idFragmentShader = document.getElementById('idFragmentShader').textContent;

const xyzVertexShader = document.getElementById('xyzVertexShader').textContent;

const xyzFragmentShader = document.getElementById('xyzFragmentShader').textContent;

const stVertexShader = document.getElementById('stVertexShader').textContent;

const stFragmentShader = document.getElementById('stFragmentShader').textContent;

//设置车道中轴线颜色

const refline_material = new THREE.LineBasicMaterial({

    //color: COLORS.ref_line,

    color: 0x0000FF

});

const road_network_material = new THREE.MeshPhongMaterial({

    vertexColors: THREE.VertexColors,

    wireframe: PARAMS.wireframe,//显示现况

    shininess: 20.0,

    transparent: true,

    opacity: 0.4

});

 

//道路线

const lane_outlines_material = new THREE.LineBasicMaterial({

    color: COLORS.lane_outline,

    //color: 0xCD3278,

});

//外侧线

const roadmark_outlines_material = new THREE.LineBasicMaterial({

    color: COLORS.roadmark_outline,

});

const id_material = new THREE.ShaderMaterial({

    vertexShader: idVertexShader,

    fragmentShader: idFragmentShader,

});

const xyz_material = new THREE.ShaderMaterial({

    vertexShader: xyzVertexShader,

    fragmentShader: xyzFragmentShader,

});

const st_material = new THREE.ShaderMaterial({

    vertexShader: stVertexShader,

    fragmentShader: stFragmentShader,

});

const roadmarks_material = new THREE.MeshBasicMaterial({

    vertexColors: THREE.VertexColors,

});

const road_objects_material = new THREE.MeshBasicMaterial({

    vertexColors: THREE.VertexColors,

    side: THREE.DoubleSide,

    wireframe: true,

});

/* load WASM + odr map */

libOpenDrive().then(Module => {

    console.log(Module)

    ModuleOpenDrive = Module;

    fetch("http://localhost:8080/upload/factory_v3.1.2.xodr").then((file_data) => {

        file_data.text().then((file_text) => {

            //加载数据文件

            loadFile(file_text, false);

        });

    });

});

function onFileSelect(file) {

    let file_reader = new FileReader();

    file_reader.onload = () => { loadFile(file_reader.result, true); };

    file_reader.readAsText(file);

}

function loadFile(file_text, clear_map) {

    //清除文件系统中保存的文件节点

    if (clear_map)

        ModuleOpenDrive['FS_unlink']('./data.xodr');

    //将文件数据转为节点保存到文件系统本地指定的文件目录,支持读写

    ModuleOpenDrive['FS_createDataFile'](".", "data.xodr", file_text, true, true);

    //OpenDriveMap不为null,则已经打开过,需要删除地图重新尝试打开

    if (OpenDriveMap)

        OpenDriveMap.delete()

    //打开驱动地图

    OpenDriveMap = new ModuleOpenDrive.OpenDriveMap("./data.xodr", PARAMS.lateralProfile, PARAMS.laneHeight, true);

    loadOdrMap(clear_map);

}

function reloadOdrMap() {

    if (OpenDriveMap)

        OpenDriveMap.delete();

    OpenDriveMap = new ModuleOpenDrive.OpenDriveMap("./data.xodr", PARAMS.lateralProfile, PARAMS.laneHeight, true);

    loadOdrMap(true, false);

}

function loadOdrMap(clear_map = true, fit_view = true) {

    //web浏览器内置api,精度微秒级,performance.now是浏览器(Web API)提供的方法,不同浏览器获取到的精度不同。Date.now是Javascript内置方法,差异主要在于浏览器遵循的ECMAScript规范。

    const t0 = performance.now();

    //是否清除地图

    if (clear_map) {

        road_network_mesh.userData.odr_road_network_mesh.delete();

        scene.remove(road_network_mesh, roadmarks_mesh, road_objects_mesh, refline_lines, lane_outline_lines, roadmark_outline_lines, ground_grid);

        lane_picking_scene.remove(...lane_picking_scene.children);

        roadmark_picking_scene.remove(...roadmark_picking_scene.children);

        xyz_scene.remove(...xyz_scene.children);

        st_scene.remove(...st_scene.children);

        for (let obj of disposable_objs)

            obj.dispose();

    }

 

    /**

     * 道路中间s方向的线

     */

    //获取参考线矩形几何体

    const reflines_geom = new THREE.BufferGeometry();

    //获取驱动中参考线数据信息

    const odr_refline_segments = OpenDriveMap.get_refline_segments(parseFloat(PARAMS.resolution));

    //设置参考线坐标点

    reflines_geom.setAttribute('position', new THREE.Float32BufferAttribute(getStdVecEntries(odr_refline_segments.vertices).flat(), 3));

    //设置参考线坐标点索引

    reflines_geom.setIndex(getStdVecEntries(odr_refline_segments.indices, true));

    //创建参考线物体

    refline_lines = new THREE.LineSegments(reflines_geom, refline_material);

    refline_lines.renderOrder = 10;

    //设置是否可见

    refline_lines.visible = PARAMS.ref_line;

    refline_lines.matrixAutoUpdate = false;

    disposable_objs.push(reflines_geom);

    //将参考线加入场景中

    //scene.add(refline_lines);

 

    /*

     *道路面

     */

    //根据细节级别获取道路网格物体PARAMS.resolution 默认0.3中等级别

    const odr_road_network_mesh = OpenDriveMap.get_mesh(parseFloat(PARAMS.resolution));

    //获取所有路段的车道(车道id为 -2, -1, 0, 1, 2)

    const odr_lanes_mesh = odr_road_network_mesh.lanes_mesh;

    //获取所有路段车道点集构建道路物体

    const road_network_geom = get_geometry(odr_lanes_mesh);

    //设置道路颜色

    road_network_geom.attributes.color.array.fill(COLORS.road);

    //获取所有路段的车道的起始位置索引

    //将索引作为车道开始和结束信息

    for (const [vert_start_idx, _] of getStdMapEntries(odr_lanes_mesh.lane_start_indices)) {

        //  console.log(vert_start_idx)

        //根据起始位置索引获取车道信息

        const vert_idx_interval = odr_lanes_mesh.get_idx_interval_lane(vert_start_idx);

        //console.log(vert_idx_interval)

        //结束索引减去起始索引的长度就是该路段该车道的长度

        const vert_count = vert_idx_interval[1] - vert_idx_interval[0];

        //索引数据压缩

        const vert_start_idx_encoded = encodeUInt32(vert_start_idx)

        // console.log(vert_start_idx, vert_start_idx_encoded,vert_idx_interval)

        const attr_arr = new Float32Array(vert_count * 4);

        for (let i = 0; i < vert_count; i++)

            attr_arr.set(

                vert_start_idx_encoded, //存入的数据集合,批量存入,底层会打散

                i * 4 //数组起始索引位置

            );

        road_network_geom.attributes.id.array.set(attr_arr, vert_idx_interval[0] * 4);

    }

    disposable_objs.push(road_network_geom);

    road_network_mesh = new THREE.Mesh(road_network_geom, road_network_material);

    road_network_mesh.renderOrder = 0;

    road_network_mesh.userData = { odr_road_network_mesh };

    road_network_mesh.matrixAutoUpdate = false;

    road_network_mesh.visible = !(PARAMS.view_mode == 'Outlines');

    scene.add(road_network_mesh);

 

    /**

     * 选中被选中的车道进行离屏渲染

     */

    const lane_picking_mesh = new THREE.Mesh(road_network_geom, id_material);

    lane_picking_mesh.matrixAutoUpdate = false;

    lane_picking_scene.add(lane_picking_mesh);

    /* xyz coords road network mesh */

    const xyz_mesh = new THREE.Mesh(road_network_geom, xyz_material);

    xyz_mesh.matrixAutoUpdate = false;

    xyz_scene.add(xyz_mesh);

    /* st coords road network mesh */

    const st_mesh = new THREE.Mesh(road_network_geom, st_material);

    st_mesh.matrixAutoUpdate = false;

    st_scene.add(st_mesh);

    /**

     * 车道线宽度区域填充,由于车道线有宽度,宽度区域颜色填充

     */

    const odr_roadmarks_mesh = odr_road_network_mesh.roadmarks_mesh;

    const roadmarks_geom = get_geometry(odr_roadmarks_mesh);

    roadmarks_geom.attributes.color.array.fill(COLORS.roadmark);

    for (const [vert_start_idx, _] of getStdMapEntries(odr_roadmarks_mesh.roadmark_type_start_indices)) {

        const vert_idx_interval = odr_roadmarks_mesh.get_idx_interval_roadmark(vert_start_idx);

        const vert_count = vert_idx_interval[1] - vert_idx_interval[0];

        const vert_start_idx_encoded = encodeUInt32(vert_start_idx);

        const attr_arr = new Float32Array(vert_count * 4);

        for (let i = 0; i < vert_count; i++)

            attr_arr.set(

                vert_start_idx_encoded, //数组

                i * 4 //偏移量,每次偏移step:数组大小

            );

        roadmarks_geom.attributes.id.array.set(attr_arr, vert_idx_interval[0] * 4);

    }

    disposable_objs.push(roadmarks_geom);

    /* roadmarks mesh */

    roadmarks_mesh = new THREE.Mesh(roadmarks_geom, roadmarks_material);

    roadmarks_mesh.matrixAutoUpdate = false;

    roadmarks_mesh.visible = !(PARAMS.view_mode == 'Outlines') && PARAMS.roadmarks;

    scene.add(roadmarks_mesh);

    //离屏渲染车道线宽度区域

    const roadmark_picking_mesh = new THREE.Mesh(roadmarks_geom, id_material);

    roadmark_picking_mesh.matrixAutoUpdate = false;

    roadmark_picking_scene.add(roadmark_picking_mesh);

    /* road objects geometry */

    const odr_road_objects_mesh = odr_road_network_mesh.road_objects_mesh;

    const road_objects_geom = get_geometry(odr_road_objects_mesh);

    road_objects_geom.attributes.color.array.fill(COLORS.road_object);

    for (const [vert_start_idx, _] of getStdMapEntries(odr_road_objects_mesh.road_object_start_indices)) {

        const vert_idx_interval = odr_roadmarks_mesh.get_idx_interval_roadmark(vert_start_idx);

        //console.log(vert_idx_interval)

        const vert_count = vert_idx_interval[1] - vert_idx_interval[0];

        const vert_start_idx_encoded = encodeUInt32(vert_start_idx);

        const attr_arr = new Float32Array(vert_count * 4);

        for (let i = 0; i < vert_count; i++)

            attr_arr.set(vert_start_idx_encoded, i * 4);

        roadmarks_geom.attributes.id.array.set(attr_arr, vert_idx_interval[0] * 4);

    }

    disposable_objs.push(road_objects_geom);

    /* road objects mesh */

    road_objects_mesh = new THREE.Mesh(road_objects_geom, road_objects_material);

    road_objects_mesh.matrixAutoUpdate = false;

    scene.add(road_objects_mesh);

    /**

     * 车道轮廓线

     * 道路轮廓线包含车道线,由于每条车道线有宽度,车道轮廓线即为车道线的中心线

     * id为0的车道轮廓线和参考线s重合

     */

    const lane_outlines_geom = new THREE.BufferGeometry();

    lane_outlines_geom.setAttribute('position', road_network_geom.attributes.position);

    lane_outlines_geom.setIndex(getStdVecEntries(odr_lanes_mesh.get_lane_outline_indices(), true));

    lane_outline_lines = new THREE.LineSegments(lane_outlines_geom, lane_outlines_material);

    lane_outline_lines.renderOrder = 9;

    disposable_objs.push(lane_outlines_geom);

    //scene.add(lane_outline_lines);

    /**

     * 道路轮廓线

     */

    const roadmark_outlines_geom = new THREE.BufferGeometry();

    roadmark_outlines_geom.setAttribute('position', roadmarks_geom.attributes.position);

    roadmark_outlines_geom.setIndex(getStdVecEntries(odr_roadmarks_mesh.get_roadmark_outline_indices(), true));

    roadmark_outline_lines = new THREE.LineSegments(roadmark_outlines_geom, roadmark_outlines_material);

    roadmark_outline_lines.renderOrder = 8;

    roadmark_outline_lines.matrixAutoUpdate = false;

    disposable_objs.push(roadmark_outlines_geom);

    roadmark_outline_lines.visible = PARAMS.roadmarks;

    scene.add(roadmark_outline_lines);

    /* fit view and camera */

    const bbox_reflines = new THREE.Box3().setFromObject(refline_lines);

    const max_diag_dist = bbox_reflines.min.distanceTo(bbox_reflines.max);

    camera.far = max_diag_dist * 1.5;

    controls.autoRotate = fit_view;

    if (fit_view)

        fitViewToBbox(bbox_reflines);

    /**

     * 网格

     */

    let bbox_center_pt = new THREE.Vector3();

    bbox_reflines.getCenter(bbox_center_pt);

    ground_grid = new THREE.GridHelper(max_diag_dist, max_diag_dist / 10, 0x2f2f2f, 0x2f2f2f);

    ground_grid.geometry.rotateX(Math.PI / 2);

    ground_grid.position.set(bbox_center_pt.x, bbox_center_pt.y, bbox_reflines.min.z - 0.1);

    disposable_objs.push(ground_grid.geometry);

    scene.add(ground_grid);

    /**

     * 灯光

     */

    light.position.set(bbox_reflines.min.x, bbox_reflines.min.y, bbox_reflines.max.z + max_diag_dist);

    light.target.position.set(bbox_center_pt.x, bbox_center_pt.y, bbox_center_pt.z);

    light.position.needsUpdate = true;

    light.target.position.needsUpdate = true;

    light.target.updateMatrixWorld();

    const t1 = performance.now();

    console.log("Heap size: " + ModuleOpenDrive.HEAP8.length / 1024 / 1024 + " mb");

    //renderer.info.render.triangles简单地显示渲染引擎当前处理的多边形(三角形)数量

    const info_msg = `

        <div class=popup_info>

        <h3>加载完成</h3>

        <table>

            <tr><th>加载用时</th><th>${((t1 - t0) / 1e3).toFixed(2)}s</th></tr>

            <tr><th>路段数量</th><th>${OpenDriveMap.roads.size()}</th></tr>

            <tr><th>节点数量</th><th>${renderer.info.render.triangles}</th></tr>

        </table>

        </div>`;

    notyf.open({ type: 'info', message: info_msg });

    //删除数据冗余,避免造成内存泄漏

    odr_roadmarks_mesh.delete();

    odr_lanes_mesh.delete();

    //左上角信息提示

    spotlight_info.style.display = "none";

    console.log(camera.position)

    animate();

}

function animate() {

    //控制电脑帧频,防止刷屏过快导致的页面刷3D数据刷新过快 控制每秒30次

    setTimeout(function () {

        requestAnimationFrame(animate);

    }, 1000 / 30);

    controls.update();

    //spotlight_paused 如果时true怎开始拖动

    if (PARAMS.spotlight && !spotlight_paused) {

        //camera.setViewOffset(renderer.domElement.width, renderer.domElement.height, mouse.x * window.devicePixelRatio | 0, mouse.y * window.devicePixelRatio | 0, 1, 1);

        //改造

        camera.setViewOffset(

            renderer.domElement.width, //画布的宽度

            renderer.domElement.height,//画布的高度

            mouse.x | 0, //画布坐标系中,相机的x坐标位置

            mouse.y | 0, //画布坐标系中,相机的y坐标位置

            1,//副相机的宽度

            1 //副相机的高度

        );

        //离屏渲染

        renderer.setRenderTarget(lane_picking_texture);

        renderer.render(lane_picking_scene, camera);

        renderer.setRenderTarget(roadmark_picking_texture);

        renderer.render(roadmark_picking_scene, camera);

        renderer.setRenderTarget(xyz_texture);

        renderer.render(xyz_scene, camera);

        renderer.setRenderTarget(st_texture);

        renderer.render(st_scene, camera);

        const lane_id_pixel_buffer = new Float32Array(4);

        // console.log(mouse)

        //拾取颜色

        //console.log(mouse.x, window.innerHeight - mouse.y)

        renderer.readRenderTargetPixels(

            lane_picking_texture,

            0, //相机截图左上角为坐标原点,相对于截图左上角而言的渲染起始点x坐标

            0,//相机截图左上角为坐标原点,相对于截图左上角而言的渲染起始点y坐标

            1, //渲染宽度范围

            1, //渲染高度范围

            lane_id_pixel_buffer);

 

        const roadmark_id_pixel_buffer = new Float32Array(4);

        renderer.readRenderTargetPixels(roadmark_picking_texture, 0, 0, 1, 1, roadmark_id_pixel_buffer);

        const xyz_pixel_buffer = new Float32Array(4);

        renderer.readRenderTargetPixels(xyz_texture, 0, 0, 1, 1, xyz_pixel_buffer);

        xyz_pixel_buffer[0] += OpenDriveMap.x_offs;

        xyz_pixel_buffer[1] += OpenDriveMap.y_offs;

        const st_pixel_buffer = new Float32Array(4);

        renderer.readRenderTargetPixels(st_texture, 0, 0, 1, 1, st_pixel_buffer);

        camera.clearViewOffset();

        renderer.setRenderTarget(null);

        /**

         * 选中车道离屏渲染

         */

        //选取颜色是否有效,(道路以外的点视为无效)

        if (isValid(lane_id_pixel_buffer)) {

            //根据颜色值解码成车道ID

            const decoded_lane_id = decodeUInt32(lane_id_pixel_buffer);

            //自定义数据中获取所有车段中的所有车道数据

            const odr_lanes_mesh = road_network_mesh.userData.odr_road_network_mesh.lanes_mesh;

            //本次选中的区域车道ID是否和上次一样

            if (INTERSECTED_LANE_ID != decoded_lane_id) {

 

                //当前是否是初始化状态,如果不是则进行初始化,防止重复初始化

                if (INTERSECTED_LANE_ID != 0xffffffff) {

                    //根据车道ID索引获取车道信息

                    const prev_lane_vert_idx_interval = odr_lanes_mesh.get_idx_interval_lane(INTERSECTED_LANE_ID);

                    road_network_mesh.geometry.attributes.color.array.fill(COLORS.road);

                }

                //保存选中车道ID

                INTERSECTED_LANE_ID = decoded_lane_id;

                //根据车道ID获取车道信息

                const lane_vert_idx_interval = odr_lanes_mesh.get_idx_interval_lane(INTERSECTED_LANE_ID);

                //获取该车道长度

                const vert_count = (lane_vert_idx_interval[1] - lane_vert_idx_interval[0]);

                //修改离屏渲染场景中该车道的背景颜色

                applyVertexColors(road_network_mesh.geometry.attributes.color, new THREE.Color(COLORS.lane_highlight), lane_vert_idx_interval[0], vert_count);

                //手动更新颜色值

                road_network_mesh.geometry.attributes.color.needsUpdate = true;

                //显示左上角信息展示

                spotlight_info.style.display = "block";

            }

            //使用过后删除数据冗余,避免造成内存泄漏

            odr_lanes_mesh.delete();

        } else {//鼠标拾取无效色素

            //恢复初始化数据

            //当前是否已经是初始化状态如果不是则进行初始化

            if (INTERSECTED_LANE_ID != 0xffffffff) {

                console.log("重叠了")

                const odr_lanes_mesh = road_network_mesh.userData.odr_road_network_mesh.lanes_mesh;

                const lane_vert_idx_interval = odr_lanes_mesh.get_idx_interval_lane(INTERSECTED_LANE_ID);

                road_network_mesh.geometry.attributes.color.array.fill(COLORS.road);

                road_network_mesh.geometry.attributes.color.needsUpdate = true;

                odr_lanes_mesh.delete();

                INTERSECTED_LANE_ID = 0xffffffff;

                spotlight_info.style.display = "none";

            }

        }

        /**

         * 选中车道线-车道线宽度区域离屏渲染

         */

        if (isValid(roadmark_id_pixel_buffer)) {

            //获取

            const decoded_roadmark_id = decodeUInt32(roadmark_id_pixel_buffer);

            const odr_roadmarks_mesh = road_network_mesh.userData.odr_road_network_mesh.roadmarks_mesh;

            if (INTERSECTED_ROADMARK_ID != decoded_roadmark_id) {

                if (INTERSECTED_ROADMARK_ID != 0xffffffff) {

                    const prev_roadmark_vert_idx_interval = odr_roadmarks_mesh.get_idx_interval_roadmark(INTERSECTED_ROADMARK_ID);

                    roadmarks_mesh.geometry.attributes.color.array.fill(COLORS.roadmark, prev_roadmark_vert_idx_interval[0] * 3, prev_roadmark_vert_idx_interval[1] * 3);

                }

                INTERSECTED_ROADMARK_ID = decoded_roadmark_id;

                const roadmark_vert_idx_interval = odr_roadmarks_mesh.get_idx_interval_roadmark(INTERSECTED_ROADMARK_ID);

                const vert_count = (roadmark_vert_idx_interval[1] - roadmark_vert_idx_interval[0]);

                applyVertexColors(roadmarks_mesh.geometry.attributes.color, new THREE.Color(COLORS.roadmark_highlight), roadmark_vert_idx_interval[0], vert_count);

                roadmarks_mesh.geometry.attributes.color.needsUpdate = true;

            }

            odr_roadmarks_mesh.delete();

        } else {

            if (INTERSECTED_ROADMARK_ID != 0xffffffff) {

                const odr_roadmarks_mesh = road_network_mesh.userData.odr_road_network_mesh.roadmarks_mesh;

                const roadmark_vert_idx_interval = odr_roadmarks_mesh.get_idx_interval_lane(INTERSECTED_ROADMARK_ID);

                roadmarks_mesh.geometry.attributes.color.array.fill(COLORS.roadmark, roadmark_vert_idx_interval[0] * 3, roadmark_vert_idx_interval[1] * 3);

                roadmarks_mesh.geometry.attributes.color.needsUpdate = true;

                INTERSECTED_ROADMARK_ID = 0xffffffff;

                odr_roadmarks_mesh.delete();

            }

        }

        if (INTERSECTED_LANE_ID != 0xffffffff) {

            const odr_lanes_mesh = road_network_mesh.userData.odr_road_network_mesh.lanes_mesh;

            const road_id = odr_lanes_mesh.get_road_id(INTERSECTED_LANE_ID);

            const lanesec_s0 = odr_lanes_mesh.get_lanesec_s0(INTERSECTED_LANE_ID);

            const lane_id = odr_lanes_mesh.get_lane_id(INTERSECTED_LANE_ID);

            const lane_type = OpenDriveMap.roads.get(road_id).s_to_lanesection.get(lanesec_s0).id_to_lane.get(lane_id).type;

            odr_lanes_mesh.delete();

            spotlight_info.innerHTML = `

                    <table>

                        <tr><th>路段编号</th><th>${road_id}</th></tr>

                        <tr><th>横断面</th><th>${lanesec_s0.toFixed(2)}</th></tr>

                        <tr><th>车道</th><th>${lane_id} <span style="color:gray;">${lane_type}</span></th></tr>

                        <tr><th>s/t</th><th>[${st_pixel_buffer[0].toFixed(2)}, ${st_pixel_buffer[1].toFixed(2)}]</th>

                        <tr><th>世界坐标</th><th>[${xyz_pixel_buffer[0].toFixed(2)}, ${xyz_pixel_buffer[1].toFixed(2)}, ${xyz_pixel_buffer[2].toFixed(2)}]</th></tr>

                    </table>`;

        }

    }

    renderer.render(scene, camera);

}

//集合体

function get_geometry(odr_meshunion) {

    const geom = new THREE.BufferGeometry();

    geom.setAttribute('position', new THREE.Float32BufferAttribute(getStdVecEntries(odr_meshunion.vertices, true).flat(), 3));

    //获取uv坐标

    geom.setAttribute('st', new THREE.Float32BufferAttribute(getStdVecEntries(odr_meshunion.st_coordinates, true).flat(), 2));

    //设置点颜色

    geom.setAttribute('color', new THREE.Float32BufferAttribute(new Float32Array(geom.attributes.position.count * 3), 3));

    //设置几何体唯一编号

    geom.setAttribute('id', new THREE.Float32BufferAttribute(new Float32Array(geom.attributes.position.count * 4), 4));

    // geom.setAttribute('ids', new THREE.Float32BufferAttribute(new Float32Array(geom.attributes.position.count * 4), 4));

    //设置几何体索引数据

    geom.setIndex(getStdVecEntries(odr_meshunion.indices, true));

    geom.computeVertexNormals();

    return geom;

}

//奇幻照相机视角

function fitViewToBbox(bbox, restrict_zoom = true) {

    let center_pt = new THREE.Vector3();

    //返回盒子的中心点

    bbox.getCenter(center_pt);

    const l2xy = 0.5 * Math.sqrt(Math.pow(bbox.max.x - bbox.min.x, 2.0) + Math.pow(bbox.max.y - bbox.min.y, 2));

    const fov2r = (camera.fov * 0.5) * (Math.PI / 180.0);

    const dz = l2xy / Math.tan(fov2r);

    camera.position.set(bbox.min.x, center_pt.y, bbox.max.z + dz);

    controls.target.set(center_pt.x, center_pt.y, center_pt.z);

    if (restrict_zoom)

        controls.maxDistance = center_pt.distanceTo(bbox.max) * 1.2;

    controls.update();

}

function fitViewToObj(obj) {

    const bbox = new THREE.Box3().setFromObject(obj);

    fitViewToBbox(bbox);

}

//改变颜色

function applyVertexColors(buffer_attribute, color, offset, count) {

    //buffer_attribute.itemSize颜色宽度

    const colors = new Float32Array(count * buffer_attribute.itemSize);

    for (let i = 0; i < (count * buffer_attribute.itemSize); i += buffer_attribute.itemSize) {

        colors[i] = color.r;

        colors[i + 1] = color.g;

        colors[i + 2] = color.b;

        // colors[i] =0;

        // colors[i + 1] = 0;

        // colors[i + 2] = 255;

    }

    //根据颜色偏移设置改变颜色值

    buffer_attribute.array.set(colors, offset * buffer_attribute.itemSize);

}

function getStdMapKeys(std_map, delete_map = false) {

    let map_keys = [];

    const map_keys_vec = std_map.keys();

    for (let idx = 0; idx < map_keys_vec.size(); idx++)

        map_keys.push(map_keys_vec.get(idx));

    map_keys_vec.delete();

    if (delete_map)

        std_map.delete();

    return map_keys;

}

function getStdMapEntries(std_map) {

    let map_entries = [];

    //key路段索引 , std_map.get(key)车道编号

    for (let key of getStdMapKeys(std_map)) {

        //console.log(key, std_map.get(key))

        map_entries.push([key, std_map.get(key)]);

    }

    // console.log("总数量", map_entries.length)

    return map_entries;

}

function getStdVecEntries(std_vec, delete_vec = false, ArrayType = null) {

    //获取道路网格三位坐标点数据

    let entries = ArrayType ? new ArrayType(std_vec.size()) : new Array(std_vec.size());

    for (let idx = 0; idx < std_vec.size(); idx++)

        entries[idx] = std_vec.get(idx);

    if (delete_vec)

        std_vec.delete();

    return entries;

}

//判断当前拾取颜色是否是道路范围的颜色,否则视为无效拾取

function isValid(rgba) {

    return !(rgba[0] == 1 && rgba[1] == 1 && rgba[2] == 1 && rgba[3] == 1);

}

//数据压缩

function encodeUInt32(ui32) {

    rgba = new Float32Array(4);

    rgba[0] = (Math.trunc(ui32) % 256) / 255.;

    rgba[1] = (Math.trunc(ui32 / 256) % 256) / 255.;

    rgba[2] = (Math.trunc(ui32 / 256 / 256) % 256) / 255.;

    rgba[3] = (Math.trunc(ui32 / 256 / 256 / 256) % 256) / 255.;

    return rgba;

}

//数据还原

function decodeUInt32(rgba) {

    return Math.round(rgba[0] * 255) + Math.round(rgba[1] * 255) * 256 + Math.round(rgba[2] * 255) * 256 * 256 + Math.round(rgba[3] * 255) * 256 * 256 * 256;

}

 

//监听画面变化,更新渲染画面,(自适应的大小)

function onWindowResize() {

    camera.aspect = window.innerWidth / window.innerHeight;

    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);

    renderer.setPixelRatio(window.devicePixelRatio);

}

//记录鼠标位置

function onDocumentMouseMove(event) {

    event.preventDefault();

    console.log()

    // let middleX = window.innerWidth / 2

    // let middleY = window.innerHeight / 2

    // let x = 0

    // let y = 0

    // x = (event.clientX - middleX) / middleX

    // y = (middleY - event.clientY) / middleY

    mouse.x = event.clientX;

    mouse.y = event.clientY;

}

//双击切换选中视角

function onDocumentMouseDbClick(e) {

    //判断是否是初始换状态

    if (INTERSECTED_LANE_ID != 0xffffffff) {

        console.log("双击")

        //获取车道线

        const odr_lanes_mesh = road_network_mesh.userData.odr_road_network_mesh.lanes_mesh;

        const lane_vert_idx_interval = odr_lanes_mesh.get_idx_interval_lane(INTERSECTED_LANE_ID);

        //根据索引获取坐标

        const vertA = odr_lanes_mesh.vertices.get(lane_vert_idx_interval[0]);

        const vertB = odr_lanes_mesh.vertices.get(lane_vert_idx_interval[1] - 1);

        console.log(vertA, vertB)

        odr_lanes_mesh.delete();

        const bbox = new THREE.Box3();

        //flat, 将数组所有元素都降维(一维)

        bbox.setFromArray([vertA, vertB].flat());

        fitViewToBbox(bbox, false);

    }

}

 效果图: