在cesium里加载three.js模型

 第一步,安装插件:

npm install cesium --save

第二步,移动文件:

        在node-modules中找到刚刚安装的cesium,在文件夹中里面有一个Build文件夹,把Build里面的Cesium复制出来丢到public中

第三步,在public/index.html中,引入cesium全局样式和cesium源码,这样前期工作就已经完成了

<link rel="stylesheet" href="./Cesium/Widgets/widgets.css"> //head部分
<script src="./Cesium/Cesium.js"></script> //script部分

 第四步,在官网申请一个token(可用默认token):

Cesium 官网:Cesium: The Platform for 3D Geospatial

第五步,开始写代码 (cesium部分)

一、初始化地球

 mounted() {
    this.init();
  },
 
 
 methods: {
    init() {
      this.viewer = new Cesium.Viewer("my-map", {
        homeButton: false,
        sceneModePicker: false,
        baseLayerPicker: false, // 影像切换
        animation: true, // 是否显示动画控件
        infoBox: false, // 是否显示点击要素之后显示的信息
        selectionIndicator: false, // 要素选中框
        geocoder: false, // 是否显示地名查找控件
        timeline: true, // 是否显示时间线控件
        fullscreenButton: false,
        shouldAnimate: false,
        navigationHelpButton: false, // 是否显示帮助信息控件
      });
    },
  },

二、优化(添加属性及其他)

  methods: {
    init() {
      (Cesium.Ion.defaultAccessToken = "你申请的cesium的token");
 
 
      this.viewer = new Cesium.Viewer("my-map", {
        homeButton: false,
        sceneModePicker: false,
        baseLayerPicker: false, // 影像切换
        animation: true, // 是否显示动画控件
        infoBox: false, // 是否显示点击要素之后显示的信息
        selectionIndicator: false, // 要素选中框
        geocoder: false, // 是否显示地名查找控件
        timeline: true, // 是否显示时间线控件
        fullscreenButton: false,
        shouldAnimate: false,
        navigationHelpButton: false, // 是否显示帮助信息控件
      });
 
      // 优化第一步
      //这是让你的画面以一个怎样的形式出现,相当于出场动画
      this.viewer.camera.flyTo({
        // fromDegrees()方法,将经纬度和高程转换为世界坐标,这里定位到中国
        destination: Cesium.Cartesian3.fromDegrees(101.8, 33.74, 5000000),
        orientation: {
          // 指向
          // heading:Cesium.Math.toRadians(90,0),
          // 视角
          // pitch:Cesium.Math.toRadians(-90),
          roll: 0.0,
        },
      });
 
      // 优化第二步
      //显示标注
      this.viewer.imageryLayers.addImageryProvider(
        new Cesium.WebMapTileServiceImageryProvider({
          url:
            "http://{s}.tianditu.gov.cn/cva_c/wmts?service=wmts&request=GetTile&version=1.0.0" +
            "&LAYER=cva&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
            "&style=default&format=tiles&tk=0a30a060a83ae06ba7a9dd5f70a3c203",
          layer: "tdtCva",
          style: "default",
          format: "tiles",
          tileMatrixSetID: "c",
          subdomains: ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"],
          tilingScheme: new Cesium.GeographicTilingScheme(),
          tileMatrixLabels: [
            "1",
            "2",
            "3",
            "4",
            "5",
            "6",
            "7",
            "8",
            "9",
            "10",
            "11",
            "12",
            "13",
            "14",
            "15",
            "16",
            "17",
            "18",
            "19",
          ],
          maximumLevel: 18,
          show: false,
        })
      );
    },
  },  

三、实现添加模型

addModel(viewer, url1, Cesium) {
    // 添加模型
    const position = Cesium.Cartesian3.fromDegrees(
        106.613922,
        29.53832,
        0.0
    );
    const heading = Cesium.Math.PI/2  // Cesium.Math.toRadians(135);
    const pitch = Cesium.Math.PI/2;
    const roll = Cesium.Math.PI/2;
    const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
    const orientation = Cesium.Transforms.headingPitchRollQuaternion(
        position,
        hpr
    );
    const entity = viewer.entities.add({
        name: 'MyName',
        position: position,
        orientation: orientation,
        model: {
            uri: url1,
            minimumPixelSize: 0,
            maximumScale: 20000,
            scale: 1, // 缩放比例
            incrementallyLoadTextures: true, // 加载模型后的纹理是否可以继续流入
            runAnimations: true, // 指定是否应运行 glTF 动画
            clampAnimations: true, // 指定 glTF 动画是否应在不带关键帧的持续时间内保持最后一个姿势
            shadows: Cesium.ShadowMode.ENABLED, // 指定模型是否 投射或接收来自光源的阴影
            // heightReference: Cesium.HeightReference.NONE, // 表示相对于地形的位置。NONE表示绝对位置
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 相对位置
        }
    });
    viewer.trackedEntity = entity;
},

 第六步,开始写代码 (three.js部分)

 一、初始化three.js

initthree(callback, callback1) {
    // 创建场景、相机和渲染
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    const renderer = new THREE.WebGLRenderer({
        antialiasing: true,
        alpha: true
    });
    renderer.setSize(window.innerWidth, window.innerHeight);
    const container = document.getElementById('id');
    container.appendChild(renderer.domElement);
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.addEventListener('change', () => {
        renderer.render(scene, camera) // 监听鼠标,键盘事件
    })
    // 创建灯光
    const ambientLight = new THREE.AmbientLight(0x404040);
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff);
    directionalLight.position.set(1, 1, 1).normalize();
    scene.add(directionalLight);

    function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
    }

    // 获取从父组件传来的模型文件
    const src = lodash.castArray(['Mypath'])
    // 创建加载器
    const loader = new PLYLoader();
    loader.load(src, geometry => {
        // 创建网格
        const color = geometry.color
        const material = new THREE.MeshStandardMaterial({color, roughness: 0.8, metalness: 0.2});
        const mesh = new THREE.Mesh(geometry, material);
          scene.add(mesh);
    })
    // 添加坐标轴
    const axesHelper = new THREE.AxesHelper(300); // 300是坐标轴的长度
    scene.add(axesHelper);
     camera.position.z = 5;
     animate();
}

二、给three增加打点、连线功能

methods: {
        showpointsThree(pointslist, color, scene) {
            if (pointslist == null) {
                return
            }
            // 打点
            pointslist.forEach(point => {
                const sphereGeometry = new THREE.SphereGeometry(1, 32, 32); // 半径为5,细分度32x32
                const sphereMaterial = new THREE.MeshBasicMaterial({color: color}); // 红色
                const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
                sphere.position.set(...point); // 设置球体的位置
                scene.add(sphere); // 将             球体添加到场景中
            });
            // 计算并添加两点之间的线段
            if (pointslist.length % 2 == 0) {
                for (let i = 0; i < pointslist.length - 1; i += 2) {
                    const startPoint = pointslist[i];
                    const endPoint = pointslist[i + 1];
                    // 创建线段的几何体
                    const geometry = new THREE.BufferGeometry().setFromPoints([
                        new THREE.Vector3(...startPoint),
                        new THREE.Vector3(...endPoint)
                    ]);

                    // 创建线段的材料(这里使用LineBasicMaterial)
                    const material = new THREE.LineBasicMaterial({color: color}); // 蓝色

                    // 创建线段并添加到场景中
                    const line = new THREE.Line(geometry, material);
                    scene.add(line);
                }
            }
            //    做标记
        },
       
       
// 构建three场景,打包scene
        initthree(callback, callback1) {
            // 创建场景、相机和渲染
            const scene = new THREE.Scene();
            const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            const renderer = new THREE.WebGLRenderer({
                antialiasing: true,
                alpha: true
            });
            renderer.setSize(window.innerWidth, window.innerHeight);
            const container = document.getElementById('id');
            container.appendChild(renderer.domElement);
            const controls = new OrbitControls(camera, renderer.domElement);
            controls.addEventListener('change', () => {
                renderer.render(scene, camera) // 监听鼠标,键盘事件
            })
            // 创建灯光
            const ambientLight = new THREE.AmbientLight(0x404040);
            scene.add(ambientLight);

            const directionalLight = new THREE.DirectionalLight(0xffffff);
            directionalLight.position.set(1, 1, 1).normalize();
            scene.add(directionalLight);

            function animate() {
                requestAnimationFrame(animate);
                renderer.render(scene, camera);
            }
            // 获取从父组件传来的模型文件
            const src = lodash.castArray(['Mypath'])
            // 创建加载器
            const loader = new PLYLoader();
            loader.load(src, geometry => {
                // 创建网格
                const color = geometry.color
                const material = new THREE.MeshStandardMaterial({color, roughness: 0.8, metalness: 0.2});
                const mesh = new THREE.Mesh(geometry, material);
                const exporter = new GLTFExporter();
                exporter.parse(mesh, (result) => {
                    const blob = new Blob([result], {type: 'application/octet-stream'});
                    const url = URL.createObjectURL(blob);
                    callback(url)
                }, {binary: true});
                 // scene.add(mesh);
            })
           // 给一些假定的点
            const datalist = [给定一些坐标]
            // 打点
            this.showpointsThree(datalist, 0xff0000, scene)
            // 添加坐标轴
            const axesHelper = new THREE.AxesHelper(300); // 300是坐标轴的长度
            scene.add(axesHelper);
             camera.position.z = 5;
             animate();
            const exporter = new GLTFExporter();
            exporter.parse(scene, (result) => {
                const blob = new Blob([result], {type: 'application/octet-stream'});
                const url = URL.createObjectURL(blob);
                callback1(url)
            }, {binary: true});
        }
    }

 第七步,将three.js加载的模型导出

将three.js加载的模型导出成cesium可以加载的格式(如.glb)

一、GLTFExporter

GLTFExporter是一个用于将3D场景导出为glTF格式的JavaScript库

// 导入GLTFExporter库
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';

// 创建GLTFExporter对象
const exporter = new GLTFExporter();

// 定义导出选项(可选)
const options = {
    binary: true, // 是否以二进制格式输出(默认为false,输出为.gltf文件)
    includeCustomExtensions: true, // 是否包含自定义扩展信息
    trs: true, // 是否将几何体的位置、旋转和缩放信息导出
    animations: [], // 要导出的动画(如果有的话)
    embedImages: false // 是否将图片嵌入到gltf文件中
};

// 使用parse方法导出场景为glTF格式
exporter.parse(scene, options, function (result) {
    // 处理导出的结果
    if (result instanceof ArrayBuffer) {
        // 以二进制格式输出
        saveArrayBuffer(result, 'scene.glb');
    } else {
        // 以JSON格式输出
        const output = JSON.stringify(result, null, 2);
        saveString(output, 'scene.gltf');
    }
}, function (error) {
    // 处理导出过程中出现的错误
    console.error('Export error:', error);
});

// 保存导出的文件
function saveArrayBuffer(buffer, filename) {
    // 实现保存二进制文件的逻辑
}

function saveString(text, filename) {
    // 实现保存JSON文件的逻辑
}
 

 一般使用exporter.parse即可,导出后会生成cesium可识别的类型的url,将此url放入cesium加载模型的uri中即可。但这样做会出现一个很奇怪的错误,以我目前的能力还解决不了,如果有大佬能解决,欢迎评论!

二、问题与解决(简陋解决) 

问题:在GLTFExporter导出的url本想以this.url = url给data定义的变量,但这种方式刚开始拿不到这个url,然而执行完cesium后又拿到了。基于这个问题,想到了其他解决方案,如下:

initthree(callback, callback1) {
    // 创建场景、相机和渲染
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    const renderer = new THREE.WebGLRenderer({
        antialiasing: true,
        alpha: true
    });
    renderer.setSize(window.innerWidth, window.innerHeight);
    const container = document.getElementById('id');
    container.appendChild(renderer.domElement);
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.addEventListener('change', () => {
        renderer.render(scene, camera) // 监听鼠标,键盘事件
    })
    // 创建灯光
    const ambientLight = new THREE.AmbientLight(0x404040);
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff);
    directionalLight.position.set(1, 1, 1).normalize();
    scene.add(directionalLight);

    function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
    }

    // 获取从父组件传来的模型文件
    const src = lodash.castArray(['Mypath'])
    // 创建加载器
    const loader = new PLYLoader();
    loader.load(src, geometry => {
        // 创建网格
        const color = geometry.color
        const material = new THREE.MeshStandardMaterial({color, roughness: 0.8, metalness: 0.2});
        const mesh = new THREE.Mesh(geometry, material);
        const exporter = new GLTFExporter();
        exporter.parse(mesh, (result) => {
            const blob = new Blob([result], {type: 'application/octet-stream'});
            const url = URL.createObjectURL(blob);
            callback(url)
        }, {binary: true});
         // scene.add(mesh);
    })
    const datalist = [给定一些坐标]
    // 打点
    this.showpointsThree(datalist, 0xff0000, scene)
    // 添加坐标轴
    const axesHelper = new THREE.AxesHelper(300); // 300是坐标轴的长度
    scene.add(axesHelper);
     camera.position.z = 5;
     animate();
    const exporter = new GLTFExporter();
    exporter.parse(scene, (result) => {
        const blob = new Blob([result], {type: 'application/octet-stream'});
        const url = URL.createObjectURL(blob);
        callback1(url)
    }, {binary: true});
}

定义两个 callback(url)回传url的值,这样就可以拿到了。但还有一个问题是exporter.parse导出场景时好像不会把mesh里的模型一起导出,所以就定义了两个exporter,如果大佬们有更好的方法欢迎指点!

 所有代码

<template>
    <div>
        <div id="my-map"></div>
        <div id="id"/>
    </div>
</template>

<script>
import lodash from 'lodash'
// import * as Cesium from 'cesium'
import {GLTFExporter} from 'three/examples/jsm/exporters/GLTFExporter';
import * as THREE from 'three';
 import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls';
import {PLYLoader} from 'three/examples/jsm/loaders/PLYLoader';
export default {
    name: 'cesium',
    components: {},
    data() {
        return {
        }
    },
    mounted() {
        // this.initthree();
        this.initCesium();
    },
    methods: {
        showpointsThree(pointslist, color, scene) {
            if (pointslist == null) {
                return
            }
            // 打点
            pointslist.forEach(point => {
                const sphereGeometry = new THREE.SphereGeometry(1, 32, 32); // 半径为5,细分度32x32
                const sphereMaterial = new THREE.MeshBasicMaterial({color: color}); // 红色
                const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
                sphere.position.set(...point); // 设置球体的位置
                scene.add(sphere); // 将             球体添加到场景中
            });
            // 计算并添加两点之间的线段
            if (pointslist.length % 2 == 0) {
                for (let i = 0; i < pointslist.length - 1; i += 2) {
                    const startPoint = pointslist[i];
                    const endPoint = pointslist[i + 1];
                    // 创建线段的几何体
                    const geometry = new THREE.BufferGeometry().setFromPoints([
                        new THREE.Vector3(...startPoint),
                        new THREE.Vector3(...endPoint)
                    ]);

                    // 创建线段的材料(这里使用LineBasicMaterial)
                    const material = new THREE.LineBasicMaterial({color: color}); // 蓝色

                    // 创建线段并添加到场景中
                    const line = new THREE.Line(geometry, material);
                    scene.add(line);
                }
            }
            //    做标记
        },
        addModel(viewer, url1, Cesium) {
            // 添加模型
            const position = Cesium.Cartesian3.fromDegrees(
                106.613922,
                29.53832,
                0.0
            );
            const heading = Cesium.Math.PI/2// Cesium.Math.toRadians(135);
            const pitch = Cesium.Math.PI/2;
            const roll = Cesium.Math.PI/2;
            const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
            const orientation = Cesium.Transforms.headingPitchRollQuaternion(
                position,
                hpr
            );
            const entity = viewer.entities.add({
                name: 'MyName',
                position: position,
                orientation: orientation,
                model: {
                    uri: url1,
                    minimumPixelSize: 0,
                    maximumScale: 20000,
                    scale: 1, // 缩放比例
                    incrementallyLoadTextures: true, // 加载模型后的纹理是否可以继续流入
                    runAnimations: true, // 指定是否应运行 glTF 动画
                    clampAnimations: true, // 指定 glTF 动画是否应在不带关键帧的持续时间内保持最后一个姿势
                    shadows: Cesium.ShadowMode.ENABLED, // 指定模型是否 投射或接收来自光源的阴影
                    // heightReference: Cesium.HeightReference.NONE, // 表示相对于地形的位置。NONE表示绝对位置
                    heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 相对位置
                }
            });
            viewer.trackedEntity = entity;
        },
        initEntityLine(Cesium, viewer) {
            const entities = viewer.entities
            // 创建两个点的位置
            let startPoint = Cesium.Cartesian3.fromDegrees(106.613922, 29.53832);
            let endPoint = Cesium.Cartesian3.fromDegrees(106.613922, 28.53822);

            // 创建线的实体
            entities.add({
                polyline: {
                    positions: [startPoint, endPoint],
                    width: 2,
                    material: Cesium.Color.RED,
                    heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 相对位置
                }
            });
        },
        addPoint(viewer, options) {
            const {name, longitude, latitude, altitude} = options;
            const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, altitude);
            viewer.entities.add({
                name: name,
                position: position,
                point: {
                    pixelSize: 10,
                    color: Cesium.Color.RED,
                    outlineColor: Cesium.Color.BLACK,
                    outlineWidth: 1,
                    heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 相对位置
                }
            });
        },
        initCesium() {
            (Cesium.Ion.defaultAccessToken = 'MyToken');
            const viewer = new Cesium.Viewer('my-map', {
                // 层高图形
                terrain: Cesium.Terrain.fromWorldTerrain({
                    requestVertexNormals: true, // 开启地形光照
                    requestWaterMask: false // 开启水面波纹
                }),
                sceneMode: window.Cesium.SceneMode.SCENE3D,
                homeButton: false,
                vrButton: true,
                sceneModePicker: false,
                baseLayerPicker: false, // 影像切换
                animation: false, // 是否显示动画控件
                infoBox: false, // 是否显示点击要素之后显示的信息
                selectionIndicator: false, // 要素选中框
                geocoder: true, // 是否显示地名查找控件
                timeline: false, // 是否显示时间线控件
                fullscreenButton: false,
                shouldAnimate: false,
                navigationHelpButton: false // 是否显示帮助信息控件
            });
            // 添加点
            this.addPoint(viewer, {
                name: '点',
                longitude: 106.613922,
                latitude: 29.53832,
                altitude: 0
            });

            // 隐藏版权信息
            viewer.cesiumWidget.creditContainer.setAttribute('style', 'display:none')


            // 优化第一步
            // 这是让你的画面以一个怎样的形式出现,相当于出场动画
            /* viewer.camera.flyTo({
                // fromDegrees()方法,将经纬度和高程转换为世界坐标,这里定位到中国
                //destination: Cesium.Cartesian3.fromDegrees(106.613922, 29.53832, 1000),
                orientation: {
                    // 指向
                    // heading:Cesium.Math.toRadians(90,0),
                    // 视角
                    // pitch:Cesium.Math.toRadians(-90),
                    roll: 0.0
                }
            });*/
            // 优化第二步
            // 显示标注
            viewer.imageryLayers.addImageryProvider(
                new Cesium.WebMapTileServiceImageryProvider({
                    url: 'http://{s}.tianditu.gov.cn/cva_c/wmts?service=wmts&request=GetTile&version=1.0.0' +
                        '&LAYER=cva&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}' +
                        '&style=default&format=tiles&tk=0a30a060a83ae06ba7a9dd5f70a3c203',
                    layer: 'tdtCva',
                    style: 'default',
                    format: 'tiles',
                    tileMatrixSetID: 'c',
                    subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
                    tilingScheme: new Cesium.GeographicTilingScheme(),
                    tileMatrixLabels: [
                        '1',
                        '2',
                        '3',
                        '4',
                        '5',
                        '6',
                        '7',
                        '8',
                        '9',
                        '10',
                        '11',
                        '12',
                        '13',
                        '14',
                        '15',
                        '16',
                        '17',
                        '18',
                        '19'
                    ],
                    maximumLevel: 18,
                    show: false
                })
            );
            this.initthree((exportedUrl) => {
                console.log('从 three_init 返回的 URL:', exportedUrl);
                // this.show_model(exportedUrl, this.viewer, Cesium)
                // 添加模型
                this.addModel(viewer, exportedUrl, Cesium)
            }, (exportedUrl1) => {
                console.log('从 three_init 返回的 URL:', exportedUrl1);
                // this.show_model(exportedUrl, this.viewer, Cesium)
                // 添加模型
                this.addModel(viewer, exportedUrl1, Cesium)
            });
        },
// 构建three场景,打包scene
        initthree(callback, callback1) {
            // 创建场景、相机和渲染
            const scene = new THREE.Scene();
            const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            const renderer = new THREE.WebGLRenderer({
                antialiasing: true,
                alpha: true
            });
            renderer.setSize(window.innerWidth, window.innerHeight);
            const container = document.getElementById('id');
            container.appendChild(renderer.domElement);
            const controls = new OrbitControls(camera, renderer.domElement);
            controls.addEventListener('change', () => {
                renderer.render(scene, camera) // 监听鼠标,键盘事件
            })
            // 创建灯光
            const ambientLight = new THREE.AmbientLight(0x404040);
            scene.add(ambientLight);

            const directionalLight = new THREE.DirectionalLight(0xffffff);
            directionalLight.position.set(1, 1, 1).normalize();
            scene.add(directionalLight);

            function animate() {
                requestAnimationFrame(animate);
                renderer.render(scene, camera);
            }

            // 获取从父组件传来的模型文件
            const src = lodash.castArray(['Mypath'])
            // 创建加载器
            const loader = new PLYLoader();
            loader.load(src, geometry => {
                // 创建网格
                const color = geometry.color
                const material = new THREE.MeshStandardMaterial({color, roughness: 0.8, metalness: 0.2});
                const mesh = new THREE.Mesh(geometry, material);
                const exporter = new GLTFExporter();
                exporter.parse(mesh, (result) => {
                    const blob = new Blob([result], {type: 'application/octet-stream'});
                    const url = URL.createObjectURL(blob);
                    callback(url)
                }, {binary: true});
                 // scene.add(mesh);
            })
            const datalist = [给定数据]
            // 打点
            this.showpointsThree(datalist, 0xff0000, scene)
            // 添加坐标轴
            const axesHelper = new THREE.AxesHelper(300); // 300是坐标轴的长度
            scene.add(axesHelper);
             camera.position.z = 5;
             animate();
            const exporter = new GLTFExporter();
            exporter.parse(scene, (result) => {
                const blob = new Blob([result], {type: 'application/octet-stream'});
                const url = URL.createObjectURL(blob);
                callback1(url)
            }, {binary: true});
        }
    }
}
</script>
  • 29
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值