Ogre引擎源码——Timer

四大开源3d游戏引擎探究 XreaL项目是基于Quake 3 Arena修改版引擎的非商业多人射击游戏,目标是在渲染技术上能与当今的商业游戏一较高下,开发者声称它是当前最先进的开源游戏引擎。根据Phoronix的介绍: XreaL引擎在Quake 3 Arena基础上改变了很多,它是基于Quake引擎中唯一使用OpenGL着色语言(GLSL)渲染器的,目前支持OpenGL 2.0 ES规格,但开发者已瞄准了新的OpenGL 阅读详情

一个图形绘制引擎底层有很多工具类(utility),通过读基础工具类源码可以学习到不少东西。

 

Ogre引擎中与Timer相关的文件大致不多,大致如下(只列出头文件)

WIN32/OgreTimerImp.h

GLX/OgreTimerImp.h

OSX/OgreTimerImp.h

iPhone/OgreTimerImp.h

OgreTimer.h

 

 其实这部分代码很少,真正意义上的头文件就是OgreTimer.h,以下是这个头文件的全部了

  1. #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32   
  2. # include "WIN32/OgreTimerImp.h"   
  3. #elif (OGRE_PLATFORM == OGRE_PLATFORM_LINUX) || (OGRE_PLATFORM == OGRE_PLATFORM_SYMBIAN)   
  4. # include "GLX/OgreTimerImp.h"   
  5. #elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE   
  6. # include "OSX/OgreTimerImp.h"   
  7. #elif OGRE_PLATFORM == OGRE_PLATFORM_IPHONE   
  8. # include "iPhone/OgreTimerImp.h"   
  9. #endif  

看明白了么?很简单,根据OGRE_PLATFORM宏,选择包含相应平台的Timer实现头文件。如win32下,OgreTimer.h就简单地include WIN32/OgreTimerImp.h就可以了。

 

OgreTimerImp.h中就是Timer的定义了。(下面的源码都以win32平台的Timer为例)

成员变量

  1. clock_t mZeroClock;  
  2. DWORD mStartTick;  
  3. LONGLONG mLastTime;  
  4. LARGE_INTEGER mStartTime;  
  5. LARGE_INTEGER mFrequency;  
  6. DWORD_PTR mTimerMask;  

(1)mZeroClock

程序启动后所执行的时间。

  1. mZeroClock = clock();  

clock函数返回进程启动后的执行时间,表示方法是CPU的tick数(也俗称滴答数)。

笔者的环境是vs2008,宏CLOCKS_PER_SEC的定义是1000,也就是说一个滴答数大致1/1000秒。

用mZeroClock乘以这个0.001秒就可以得到进程启动后的运行时间了,当然在计算的时候只计算tick数就足够了。

 

(2)mStartTick

系统启动后所经历的时间,时间单位是毫秒。

  1. mStartTick = GetTickCount();  
  

 

(3)mLastTime

在调用读取时间函数 unsigned long getMilliseconds() / unsigned long getMicroseconds() 后记录当前读取的最后时间,作用是当下一次时间读取错误时,进行调整。(关于时间读取错误后面会有展开。)

 

(4)mStartTime / mFrequency

用于高精度计时器时间读取 分别通过函数QueryPerformanceCounter和QueryPerformanceFrequency获得count数以及frequency。

这里需要注意的是,Timer里应用两套计时度量方法。

一套是通过使用clock()获得cpu中时钟tick,在获取时间时,使用的api如下

  1. unsigned long getMillisecondsCPU();  
  2. unsigned long getMicrosecondsCPU();  

另一种就是高精度计时器函数,api如下

  1. unsigned long getMilliseconds();  
  2. unsigned long getMicroseconds();  
  

在后面会讨论下这些api值得关注的细节。

 

(5)mTimerMask

这个变量看名字有点不明白,其实这个变量和高精度计时器读取时间有关。

查询msdn中QueryPerformanceCounter函数的注解中可以发现,这个函数调用环境如果是多处理器(CPU)的话,由于BIOS或者HAL的原因,切换到不同CPU上的线程调用后会造成不正确的结果。所以必须保证每次调用这个函数都是在同一个CPU上进行。这个mask就是将线程调用限定在某一个CPU上。

  1. HANDLE thread = GetCurrentThread();  
  2.   
  3. // Set affinity to the first core   
  4. DWORD_PTR oldMask = SetThreadAffinityMask(thread, mTimerMask);  
  5.   
  6. // Get the constant frequency   
  7. QueryPerformanceFrequency(&mFrequency);  
  8.   
  9. // Query the timer   
  10. QueryPerformanceCounter(&mStartTime);  
  11. mStartTick = GetTickCount();  
  12.   
  13. // Reset affinity   
  14. SetThreadAffinityMask(thread, oldMask);  

通过SetThreadAffinityMask函数,设置允许执行本线程的CPU标示位,就可以达到这一目的。每次时间获取都在限定处理器上执行,执行完后恢复oldMask即可。

 

 成员函数

  1. bool setOption( const String& strKey, const void* pValue );  
  2.   
  3. /** Resets timer */  
  4. void reset();  
  5.   
  6. /** Returns milliseconds since initialisation or last reset */  
  7. unsigned long getMilliseconds();  
  8.   
  9. /** Returns microseconds since initialisation or last reset */  
  10. unsigned long getMicroseconds();  
  11.   
  12. /** Returns milliseconds since initialisation or last reset, only CPU time measured */  
  13. unsigned long getMillisecondsCPU();  
  14.   
  15. /** Returns microseconds since initialisation or last reset, only CPU time measured */  
  16. unsigned long getMicrosecondsCPU();  

注:此处省略了构造函数和析构函数,构造函数就简单调用reset函数,析构函数为空函数

 

(1) bool setOption( const String& strKey, const void* pValue )
这个函数的作用是设置mTimerMask,方法是通过GetProcessAffinityMask()获取能够执行程序的CPU标示,以mask形式给出,然后取最低标示位标示的CPU作为mTimerMask的值,作为限定CPU执行高精度计时读取。

这个函数在Ogre中并没有被调用,mTimerMask在构造函数中初始化为0,并在reset函数中有进一步的赋值。

 

(2)void reset()

顾名思义,重置一次计时状态,也用于第一次Timer的初始化。

这个函数主要做两件事情

1、设置mTimerMask

  1. // Get the current process core mask   
  2. DWORD_PTR procMask;  
  3. DWORD_PTR sysMask;  
  4. GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);  
  5. ...  
  6. // Find the lowest core that this process uses   
  7. if( mTimerMask == 0 )  
  8. {  
  9.     mTimerMask = 1;  
  10.     while( ( mTimerMask & procMask ) == 0 )  
  11.     {  
  12.     mTimerMask <<= 1;  
  13.     }  
  14. }  

设置的过程在讲解(5)mTimerMask已经提及,不再赘述。

2、在两种度量方法下,读取当前时间

  1. HANDLE thread = GetCurrentThread();  
  2.   
  3. // Set affinity to the first core   
  4. DWORD_PTR oldMask = SetThreadAffinityMask(thread, mTimerMask);  
  5.   
  6. // Get the constant frequency   
  7. QueryPerformanceFrequency(&mFrequency);  
  8.   
  9. // Query the timer   
  10. QueryPerformanceCounter(&mStartTime);  
  11.   
  12. mStartTick = GetTickCount();  
  13.   
  14. // Reset affinity   
  15. SetThreadAffinityMask(thread, oldMask);  
  16.   
  17. mLastTime = 0;  
  18. mZeroClock = clock();  

可以看到使用上面提到过的方式,将CPU限定后,读取了两种度量下的时间,并将所有成员变量进行初始化。

 

(3)时间读取函数

剩下四个函数就是两套度量方式读取时间的函数,每套方式有读取毫秒和百分之一秒两个API。

两种度量方式也已经提到过,这里讲下各自的方法。

1、CPU tick度量

基本一句代码就可以实现,就是通过clock读取当前的tick数,减去Timer初始化的mZeroClock就可以得到毫秒数,并不需要进行CPU限定。 

2、高精度计时器度量

这个度量步骤和CPU度量相似,在CPU限定的情况下,读取count数,进行相减。但是这里有个需要提及,就是在讲成员变量mLastTime时提到的错误时间调整。

通过查询Microsoft KB: Q274323(http://support.microsoft.com/kb/274323/en-us),由于芯片组的设计缺陷,QueryPerformanceCounter函数返回的结果会意外的产生跳跃的错误时间。这也就是不能单独使用高精度计时器的原因,必须有另一个计时方法来进行补偿调整。

  1. unsigned long check = GetTickCount() - mStartTick;  
  2. signed long msecOff = (signed long)(newTicks - check);  
  3. if (msecOff < -100 || msecOff > 100)  
  4. {  
  5.     LONGLONG adjust = (std::min)(msecOff * mFrequency.QuadPart / 1000, newTime - mLastTime);  
  6.     mStartTime.QuadPart += adjust;  
  7.     newTime -= adjust;  
  8.   
  9.     // Re-calculate milliseconds   
  10.     newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);  
  11. }  
  12.   
  13. // Record last time for adjust   
  14. mLastTime = newTime;  

这个是读取完高精度时间后需要进行的检验。

check变量是CPU tick度量方式得到的时间,然后将两种方式得到的时间相减,检查这个差值的绝对值,如果过大就需要进行调整。然后重新计算newTick就可以了。

 

Ogre中的Timer是很具有代表性的,笔者网上搜了下,win环境下的Timer实现基本就是这样的方式。在将来的编程过程中,如有需要,可以直接考虑拿来重用。

ROS 2 Ardent Apalone:首个稳定版的设计哲学与工程价值 ROS 2 是面向实时、跨平台、多中间件的机器人操作系统新范式,其核心依赖 DDS 通信框架、分层客户端库(rcl/rclcpp/rclpy)、节点生命周期管理及平台自适应构建系统。Ardent Apalone 作为 ROS 2 历史上第一个非 beta 稳定发行版,确立了 QoS 策略、三端(Linux/macOS/Windows)最小可行支持、DDS 中间件可插拔机制等关键设计原则。它不追求功能完备,而强调接口稳定、编译可重现、运行可验证,为后续 Foxy、Humble 等长期支持版本奠定 ABI 兼容 阅读详情

相关推荐

ROS2 Windows原生安装实战:从产线刚需到服务级集成

ROS2作为现代机器人中间件,其跨平台能力已突破Linux边界,Windows原生支持成为工业自动化、HMI系统与PLC集成的关键基础设施。其核心原理基于CMake构建系统、Fast DDS通信中间件及rclcpp/rclpy客户端库的Win32 API深度适配,技术价值在于毫秒级IPC、零拷贝共享内存传输与.NET互操作能力。典型应用场景涵盖汽车焊装力控打磨、医疗设备上位机集成、嵌入式Windows 10/11边缘节点部署等真实产线环境。本文聚焦ROS2 Humble在Windows平台的可验证安装体系,

搜索 333

OGRE渲染引擎

这篇文章简单介绍了OGRE,并介绍了OGRE中的基本类

Estelle 3579

OpenClaw部署与工业级集成实战指南

OpenClaw是一个基于ROS 2构建的开源机器人技能执行框架,核心在于通过硬件抽象层(HAL)解耦控制逻辑与底层硬件,实现跨平台机械臂技能的模块化、可测试与可审计。其技术原理依托ROS 2 Humble的实时通信机制、插件化Skill架构及标准TF/Action/Topic接口,具备强状态管理、超时控制与失败回滚能力,显著提升自动化系统的可控性与可追溯性。该框架广泛应用于学术研究与中小产线,典型场景包括UR5e等主流机械臂的视觉引导抓取、多设备灰度发布、企业IM系统(如飞书)任务协同等。本文聚焦真实工程

weixin_30321709的博客 342

【亲测免费】 探秘Ogre:一款强大的3D渲染引擎

是一个开源的、跨平台的实时3D图形渲染引擎,专为游戏开发和专业可视化应用设计。它的目标是简化复杂3D场景的构建与管理,让开发者可以专注于创新,而不是底层图形API。本文将带你了解Ogre的核心技术特性,应用场景,以及为何你应该考虑在你的项目中使用它。 ## 项目简介 Ogre始于2001年,由Steve Jackson创立,其名字来源于“OGRE”,这是一个早期的MUD(多用户地下城)游戏中的...

gitblog_00078的博客 1670

用Ogre引擎学习游戏编程

这只是一个简单的入门示例,Ogre引擎提供了丰富的功能和工具,可以帮助你构建复杂的游戏场景和特效。通过不断学习和实践,你可以深入了解Ogre引擎,并创建出令人惊叹的游戏作品。首先,我们加载并设置渲染系统,然后创建一个窗口和一个场景管理器。接下来,创建一个摄像机和一个视口,最后进入渲染循环,开始渲染场景。Ogre引擎是一个强大的开源3D图形引擎,广泛用于游戏开发和计算机图形学应用。安装完成后,设置你的开发环境,包括设置正确的编译器和链接器选项。在Ogre中,你可以添加各种3D对象和材质来构建你的游戏场景。

2301_79326588的博客 369

Ogre 3D引擎VC++双端RPG源码解析:渲染管线与网络同步实战

Ogre 3D引擎作为经典的跨平台开源渲染框架,其插件化架构和C++底层设计为图形编程学习提供了扎实范本。本文围绕Ogre 1.7.x版本的VC++工程实践,深入剖析RenderSystem动态加载机制、Direct3D9/OpenGL双路径切换原理,以及Winsock IOCP模型在RPG服务端的高效应用。技术价值体现在对图形API抽象层、资源生命周期管理、主线程与网络线程安全交互等核心问题的工程级解法。适用于需要理解3D引擎底层调度、验证跨平台渲染兼容性,或复用经典网络同步模式的C++图形开发者。关键词

weixin_33164198的博客 54

Ogre Timer 类 解析

Ogre Timer     一个图形绘制引擎底层有很多工具类(utility),通过读基础工具类源码可以学习到不少东西。         Ogre引擎中与Timer相关的文件大致不多,大致如下(只列出头文件) WIN32/OgreTimerImp.h GLX/OgreTimerImp.h OSX/OgreTimerImp.h iPhone/OgreTimerImp.h

终极程序 964

ros2 humble gazebo+rviz+maprviz(1)

正确导航启动命令(加载官方预设地图)没有启动gazebo,

linuxer867962392的博客 227

从零配置OGRE 3D引擎:C++图形开发入门与旋转立方体实战

3D图形渲染引擎是现代游戏开发和可视化应用的核心组件,它封装了底层图形API的复杂性,为开发者提供了高效的场景管理与渲染能力。其技术价值在于平衡性能与易用性,让开发者能够专注于内容创作与逻辑实现,广泛应用于游戏、仿真、数据可视化等领域。本文以经典的OGRE引擎为例,通过详细的编译配置和依赖管理指南,结合CMake构建工具和vcpkg包管理器,手把手带领读者完成环境搭建,并实现一个包含光照与动画的旋转立方体示例,深入讲解场景图、资源管理等核心概念。

weixin_33739541的博客 336

ogre 完整游戏 源代码 02

可运行的OGRE完整游戏,包括运行所需资源,源代码,工程文件,编译完成即可运行。共6卷

【胡学长 带你学 Global Mapper 】如何将影像地图转换为国家2000坐标系

多部门联合开展工作坐标数据不匹配怎么办?Hi,我是胡学长!今天教大家如何利用Global Mapper将谷歌影像数据转换为国家2000坐标系影像数据 。

一起来交流学习吧 1万+

ROS 2 Eloquent深度解析:平台支持、RMW选型与CLI设计哲学

ROS 2 是面向机器人系统的现代中间件框架,其核心在于分层架构、中间件抽象(RMW)与开发者体验的协同演进。Eloquent Elusor 作为关键过渡版本,首次确立了跨平台分级支持(Tier 1/2/3)的工程化范式,并将 Cyclone DDS 纳入官方支持的 RMW 实现,凸显‘接口与实现分离’的设计思想。它通过 --ros-args 显式参数语法重构命令行契约,以 YAML launch 文件推动声明式系统描述,显著降低认知负荷。这些变革不仅服务于当时嵌入式、macOS 和工业边缘场景,更成为理解

weixin_33851177的博客 430

医疗信创国产化替代目前面临哪些难题?如何利用国产虚拟化技术促进医院信创建设

业务系统众多,存在大量信创改造模糊地带,既有老系统,也有新系统,故障点多,管理难度高,IT人力资源不足,其对硬件的支撑能力也提出了越来越高的要求,由此造成硬件成本、管理成本以及能耗成本都非常高。

云宏winhong的博客 2655

PX4+Gazebo+ROS2无人机轨迹跟踪仿真环境搭建指南

无人机仿真技术是飞控算法验证的重要环节,其中PX4、Gazebo与ROS2的协同构成了一套典型的软件在环仿真方案。PX4作为开源飞控栈负责底层姿态与位置控制,Gazebo提供物理环境模拟,而ROS2则承担上层任务调度与通信。通过Micro XRCE-DDS中间件实现ROS2与PX4的数据桥接,开发者可以灵活编写轨迹生成器,将期望位置指令发送给飞控,从而验证轨迹跟踪算法。该环境广泛应用于无人机自主导航、编队飞行及视觉伺服研究,在Ubuntu 22.04 + ROS2 Humble + PX4 v1.14的组合

weixin_34198881的博客 524

VXLAN技术详解

VXLAN(虚拟可扩展局域网)是一种Overlay二层虚拟化技术,通过MAC-in-UDP封装在IP网络上构建大规模虚拟二层网络。核心组件包括VTEP(隧道端点)、24位VNI(支持1600万个虚拟网络)和VXLAN网关。相比VLAN,VXLAN具有超大规模扩展、跨三层互联、支持虚拟机无缝迁移等优势,适用于云数据中心多租户隔离、跨数据中心互联等场景。其基于IP路由的封装方式无需改造物理网络,为现代云网络提供了弹性、安全的虚拟化解决方案。

kjkdd的博客 594

使用python排八字 计算八字的相合相冲五行分值等 ...

简介 八字术是一种古老的算命术。它运用阴阳、五行、干支、八卦等理论,把人的出生年月日时转化为八个字,进而推算人的富贵贫贱、祸福吉凶、穷通寿天、名利地位、家庭六亲等方面的情况 八字源自古代的中国,是一种利用天干和地支来准确记录年、月、日、时的方式,由“年干,年支”、“月干,月支”、“日干,日支”、“时干,时支”,共八个干支所组成(共八个字),年、月、日、时...

weixin_33717298的博客 5309

ROS2与PX4无人机自主控制:Offboard模式画圆轨迹实现与Gazebo仿真指南

自主飞行控制是无人机应用开发的核心能力,而ROS2与PX4的协同工作为这一领域提供了强大的技术框架。理解无人机的控制链路,关键在于区分上层轨迹生成与底层姿态控制:ROS2节点负责计算目标位置,PX4飞控则执行位置与姿态的闭环稳定。在Gazebo仿真环境中,通过MAVROS桥接实现MAVLink与ROS2话题的转换,使得开发者可以专注算法逻辑,而无需直接操作底层电机。该方案广泛应用于航迹规划、视觉跟随、编队飞行等场景,其价值在于将复杂的自主控制任务模块化,为快速原型验证与算法迭代提供了高效的工程实践路径。本文

weixin_34327223的博客 347

openclaw update时出现Skipped:this OpenClaw install isn‘t a git checkout,and the package manager解决方案

本文主要介绍了openclaw update时出现openclaw update时出现Skipped:this OpenClaw install isn’t a git checkout,and the package manager解决方案,希望能对使用openclaw的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 12万+

高校ROS2遥操机器人教学系统选型与部署实战

机器人遥操作是机器人操作系统(ROS)教学中的高阶实践环节,其核心在于ROS2通信机制、跨平台硬件协同与实时空间交互的有机统一。理解ROS2的DDS底层架构、QoS策略配置及坐标系转换原理,是保障遥操低延迟与确定性的技术基础;而VR/AR设备与工业机械臂(如UR5e)的选型,需兼顾教学可修改性、接口开放性与长期课程兼容性。本文聚焦高校实验室真实场景,围绕ROS2 Humble版本适配、PC VR与ROS2原生驱动集成、力反馈闭环开发等关键链路,提供从Ubuntu环境搭建、OpenVR数据桥接到MoveIt2

weixin_33827590的博客 384

深度强化Q学习-基于微软AirSim仿真环境的自动驾驶案例(原理代码详解简易可行)

最近在学习《强化学习原理与Python实现》,肖智清著。参考第十二章的自动驾驶案例,写一篇总结,尽量做到简单可行,让有志于自动驾驶的小伙伴可以通过此篇博客可以管中窥豹,初步了解自动驾驶的强化学习训练过程。 本篇将自动驾驶问题转化为回合制的强化学习任务,设计以车辆观察图像和运行状态为输入的自动驾驶算法,并在AirSim仿真环境中进行训练和测试。本篇使用带经验回放和目标网络的基于深度Q网络算法设计并实现智能体,对经验回放、目标网络和深度Q学习算法进行简单介绍,并用代码实现。

shao918516的博客 8599

ANSYS2022R1——安装源文件下载和安装教程——软件管家

14.当提示输入安装目录:#3时,①点击【浏览】,②选安装包解压后的【ANSYS2022R1_WINX64_Disk2】文件夹中【ANSYS2022R1_WINX64_Disk3】文件夹,③点击【选择文件夹】,④点击【OK】。12.当提示输入安装目录:#2时:①点击【浏览】,②选安装包解压后的【ANSYS2022.R1(64bit)】文件夹中的【ANSYS2022R1_WINX64_Disk2】文件夹,③点击【选择文件夹】,④点击【OK】。】②点击【OK】③点击【OK】。

qq_15963745的博客 2325

OGRE引擎详解:技术特点、优势、局限性与应用场景

OGRE(Object-Oriented Graphics Rendering Engine,面向对象的图形渲染引擎)是一款开源的3D图形引擎,广泛应用于游戏开发、模拟、虚拟现实等多个领域。OGRE引擎的设计目标是提供一个高效、灵活且易于使用的渲染引擎,以支持开发人员在不同平台上创建复杂的3D图形应用程序。

小宝哥Code的专栏 2926

学习STM32的CAN总线通信

在配置时,确保您启用了CAN总线功能。CAN节点是CAN总线上的一个设备,每个节点都有唯一的标识符。在CAN总线中,有两种类型的节点:CAN控制器和CAN外设。步骤2:配置CAN总线 在STM32CubeMX中,选择CAN总线模块并进行必要的配置。在CAN总线中,有两个重要的概念:CAN节点和CAN帧。步骤5:测试CAN总线通信 在成功编译和烧录代码后,您可以使用串口调试助手或其他CAN总线工具来测试CAN总线通信。步骤3:编写CAN总线通信代码 在项目的主代码文件中,我们将编写CAN总线通信的示例代码。

2401_85258012的博客 496

OGRE 三维图形渲染引擎

OGRE 是一个三维 (3D) 图形渲染引擎。它是面向对象的,并且高效,抽象化了不同的 API 和平台,这样可以以场景为对象来使用物体,支持多种场景。它已经成功地被应用于诸多三维仿真领域,包括网络游戏和三维仿真项目。功能和特点◆ 简单易用的面向对象接口◆ 最小化渲染 3D 场景◆ 自动完成功能◆ 类设计简洁◆ 完全的面向对象◆ 支持 Direct3D 和 OpenGL◆ 支持 Windows,Linux 和 Mac OSX◆ 强大的材质声明语言◆ 支持顶点和片断程序。

格物致知的专栏 [音视频编解码 网络协议 计算机视觉 计算机图形学 图像理解 语音识别 机器学习 模拟电路 传感器] 788

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

上一篇: XNA Shader编程教程2-漫反射光照
下一篇: normalMapping --- 切线空间 tangent space
凭谁问
博客等级 码龄15年 178粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值