尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
SensorsCalibration 实战:Ceres 通用无约束最小化框架 GradientProblem 与 GradientProblemSolver 完全指南
自动驾驶计算机视觉【免费下载链接】SensorsCalibrationOpenCalib: A Multi-sensor Calibration Toolbox for Autonomous Driving项目地址https://gitcode.com/gh_mirrors/se/SensorsCalibration点击查看免费下载导读本文聚焦 Ceres Solver 中被多数使用者忽略的一条重要技术路线不依赖最小二乘结构、仅凭目标函数值与梯度即可求解的一般无约束优化问题。Ceres 通过GradientProblem与GradientProblemSolver两个核心类向用户开放这一能力它是传感器标定场景中处理非最小二乘形式目标函数例如需要直接最小化的能量项、损失函数非平方和形式的重要工具。读完本文你将掌握FirstOrderFunction建模接口、GradientProblem组装方式、GradientProblemSolver::Options全部参数的含义与调优要点并能在你自己的标定工程中独立复现 Rosenbrock 函数的求解流程。本文以仓库内 gradient_solver.rst 为骨架结合joint_calib模块实际打包的 Ceres 头文件源码进行纵深印证。一、定位一阶求解器与最小二乘求解器的区别Ceres Solver 的大部分文档与示例都在讲解非线性最小二乘Non-linear Least Squares目标函数形如残差平方和通过ceres::Problem建模、ceres::Solver求解采用信赖域Trust Region策略。而在 gradient_tutorial.rst 中明确指出Ceres 内部还内置了一个通用的无约束优化求解器它只需要目标函数值与梯度即可求解任意形式的无约束优化问题这就是本文的主角GradientProblem与GradientProblemSolver。两者最本质的差异在于目标函数的形式约束Problem最小二乘要求目标函数可表达为若干残差项的平方和求解器利用该结构构造线性子问题GradientProblem一般无约束不限制目标函数的具体形式只需要能计算f(x)与∇f(x)求解器基于线搜索Line Search与拟牛顿方向迭代下降。在 gradient_problem.h 的头文件注释中这一区别被原样陈述Instances of GradientProblem represent general non-linear optimization problems that must be solved using just the value of the objective function and its gradient. Unlike the Problem class, which can only be used to model non-linear least squares problems, instances of GradientProblem not restricted in the form of the objective function.二、建模FirstOrderFunction 与 GradientProblem2.1 FirstOrderFunction函数值与梯度的评价接口FirstOrderFunction是一阶优化的最小建模单元负责计算目标函数值及其梯度。接口定义见 first_order_function.h如下class FirstOrderFunction { public: virtual ~FirstOrderFunction() {} virtual bool Evaluate(const double* const parameters, double* cost, double* gradient) const 0; virtual int NumParameters() const 0; };接口契约要点Evaluate同时计算目标函数值cost与梯度gradientcost保证永不为NULL而gradient可以为NULL——当调用方只需要函数值例如线搜索过程中的纯函数值评估时实现应跳过梯度计算以节省开销求值成功返回true失败返回falseNumParameters()返回参数向量的维度即定义域的大小。从源码角度看Evaluate中gradient为空时的短路处理在AutoDiffFirstOrderFunction::Evaluate中也有对应实现autodiff_first_order_function.h保证只计算函数值时不引入微分开销。2.2 GradientProblem问题组装与参数化GradientProblem是将目标函数组织成可求解问题的容器结构上是FirstOrderFunction 可选LocalParameterization的组合见 gradient_problem.hclass GradientProblem { public: explicit GradientProblem(FirstOrderFunction* function); GradientProblem(FirstOrderFunction* function, LocalParameterization* parameterization); int NumParameters() const; int NumLocalParameters() const; bool Evaluate(const double* parameters, double* cost, double* gradient) const; bool Plus(const double* x, const double* delta, double* x_plus_delta) const; };关键语义构造函数接管所有权GradientProblem会拥有传入的FirstOrderFunction与LocalParameterization对象源码中通过std::unique_ptr管理见 gradient_problem.h调用方无需再手动释放LocalParameterization的作用是处理环境空间ambient space与局部切空间local tangent space之间的来回映射。传感器标定中最典型的例子是旋转参数的局部参数化——四元数/旋转矩阵的流形约束无法在欧氏切空间直接表示未提供参数化时切空间默认与梯度所在的环境欧氏空间重合即使用普通向量运算NumParameters()与环境空间维度一致NumLocalParameters()返回切空间维度两者仅在设置了LocalParameterization时不同注意头文件注释明确Evaluate调用非线程安全This call is not thread safe多线程场景下需要外部同步。三、求解Solve 调用与完整示例Rosenbrock 函数3.1 Solve 入口求解通过全局函数ceres::Solve完成声明见 gradient_problem_solver.hvoid Solve(const GradientProblemSolver::Options options, const GradientProblem problem, double* parameters, GradientProblemSolver::Summary* summary);语义以parameters中的当前值作为初始猜测求解给定的GradientProblem求解结束后结果直接写回parameters运行状态写入summary。3.2 完整可运行示例Rosenbrock 函数官方教程gradient_tutorial.rst以著名的 Rosenbrock 函数为例f(x,y) (1-x)^2 100*(y - x^2)^2第一步定义FirstOrderFunction子类。注意gradient为 NULL 时跳过梯度计算的分支class Rosenbrock : public ceres::FirstOrderFunction { public: virtual bool Evaluate(const double* parameters, double* cost, double* gradient) const { const double x parameters[0]; const double y parameters[1]; cost[0] (1.0 - x) * (1.0 - x) 100.0 * (y - x * x) * (y - x * x); if (gradient ! NULL) { gradient[0] -2.0 * (1.0 - x) - 200.0 * (y - x * x) * 2.0 * x; gradient[1] 200.0 * (y - x * x); } return true; } virtual int NumParameters() const { return 2; } };该示例同样以注释形式完整出现在 gradient_problem.h 的类头注释中可作为源码级参考。第二步构造问题、配置选项并求解double parameters[2] {-1.2, 1.0}; ceres::GradientProblem problem(new Rosenbrock()); ceres::GradientProblemSolver::Options options; options.minimizer_progress_to_stdout true; ceres::GradientProblemSolver::Summary summary; ceres::Solve(options, problem, parameters, summary); std::cout summary.FullReport() \n;第三步运行结果。在默认配置LBFGS方向 WOLFE线搜索下从初始点(-1.2, 1.0)出发经过 35 次迭代收敛目标函数值从2.420000e01降至1.885250e-22梯度最大范数降到9.032775e-13判定依据为Gradient tolerance reachedCONVERGENCE。四、GradientProblemSolver::Options全部参数详解GradientProblemSolver::Options控制求解器的整体行为全部字段的声明与默认值见 gradient_problem_solver.h。使用前可用IsValid(string* error)校验配置合法性。4.1 参数总表含默认值参数默认值可选值 / 说明line_search_direction_typeLBFGSSTEEPEST_DESCENT、NONLINEAR_CONJUGATE_GRADIENT、BFGS、LBFGSline_search_typeWOLFEARMIJO、WOLFE强 Wolfe 条件nonlinear_conjugate_gradient_typeFLETCHER_RIBEERE即FLETCHER_REEVESFLETCHER_REEVES、POLAK_RIBIERE、HESTENES_STIEFELmax_lbfgs_rank20L-BFGS 对 Hessian 逆的近似秩use_approximate_eigenvalue_bfgs_scalingfalse是否启用 Oren 特征值近似缩放line_search_interpolation_typeCUBICBISECTION、QUADRATIC、CUBICmin_line_search_step_size1e-9步长下限低于此值截断为 0line_search_sufficient_function_decrease1e-4Armijo 充分下降系数max_line_search_step_contraction1e-3线搜索步长收缩上限比例min_line_search_step_contraction0.6线搜索步长收缩下限比例max_num_line_search_step_size_iterations20单次线搜索最大试探步数max_num_line_search_direction_restarts5搜索方向算法最大重启次数line_search_sufficient_curvature_decrease0.9强 Wolfe 曲率条件系数max_line_search_step_expansion10.0Wolfe 线搜索括区间阶段的扩张上限max_num_iterations50求解器最大迭代次数max_solver_time_in_seconds1e6求解器最大运行时间秒function_tolerance1e-6函数值相对变化收敛阈值gradient_tolerance1e-10梯度范数收敛阈值parameter_tolerance1e-8参数步长收敛阈值logging_typePER_MINIMIZER_ITERATIONSILENT、PER_MINIMIZER_ITERATIONminimizer_progress_to_stdoutfalse进度输出到 STDOUTupdate_state_every_iterationfalse每轮迭代后更新外部参数块callbacks空每轮迭代结束回调求解器不接管所有权注max_solver_time_in_seconds在 gradient_solver.rst 中记录默认值为1e6而同仓库头文件 gradient_problem_solver.h 中实现值为1e9min_line_search_step_size在文档中未标注默认值头文件中为1e-9。实际以头文件声明为准。4.2 搜索方向四种策略的本质line_search_direction_type决定每一步的下降方向枚举定义见 types.hSTEEPEST_DESCENT最速下降取负梯度方向实现简单但收敛通常较慢NONLINEAR_CONJUGATE_GRADIENT非线性共轭梯度将线性共轭梯度推广到非线性函数方向递推规则由nonlinear_conjugate_gradient_type进一步细分为FLETCHER_REEVES、POLAK_RIBIERE、HESTENES_STIEFEL三种变体对应 types.hBFGS拟牛顿维护一个稠密的 Hessian 逆近似矩阵通过秩一更新逐步逼近真实 Hessian满足割线方程并保持正定LBFGS有限内存 BFGS只保留最近 M 次参数与梯度的观测历史无需构造完整的 N×N 稠密矩阵即可计算搜索方向。types.h注释特别强调当参数规模较大、完整存储 Hessian 近似不可行时L-BFGS 尤为重要——这正是高维传感器标定参数空间的典型场景。4.3 线搜索ARMIJO 与 WOLFEline_search_type选择步长策略types.hARMIJO回溯线搜索配合多项式插值或二分WOLFE满足强 Wolfe 条件即 Armijo 充分下降条件 曲率条件。文档特别警告为保证BFGS与LBFGS方向算法赖以成立的假设正定、充分下降成立应使用WOLFE线搜索。若二者组合不当收敛保证将被破坏。Armijo 条件的数学形式为f(step_size) f(0) sufficient_function_decrease * [f(0) * step_size]其中line_search_sufficient_function_decrease默认 1e-4控制充分下降的严格程度。强 Wolfe 的曲率条件要求沿搜索方向的梯度模长充分衰减|f(step_size)| sufficient_curvature_decrease * |f(0)|line_search_sufficient_curvature_decrease默认 0.9。4.4 线搜索的工程细节参数线搜索本质上是一系列试步、收缩、扩张的迭代过程以下参数控制其行为边界收缩contraction每轮迭代中new_step_size max_line_search_step_contraction * step_size默认1e-3下限与new_step_size min_line_search_step_contraction * step_size默认0.6上限且要求0 max min 1扩张expansionWolfe 线搜索的括区间bracketing阶段步长按max_line_search_step_expansion默认10.0需 1逐轮放大直到找到满足条件的点或确定包含满足条件点的区间上界步长截断若步长低于min_line_search_step_size默认 1e-9截断为零试探次数上限max_num_line_search_step_size_iterations默认 20。一个值得注意的保护行为若使用WOLFE搜索且当前搜索中已经找到满足 Armijo 条件的点即使该点不满足强 Wolfe 条件也会返回其中函数值最低者作为新步长防止优化器过早终止在次优点方向重启max_num_line_search_direction_restarts默认 5限制搜索方向算法的重启次数。重启发生在当前算法无法产生新的下降方向时通常意味着数值失败或所用近似失效。4.5 收敛判据三类容差求解器在以下任一条件满足时终止function_tolerance默认 1e-6当|Δcost| / cost function_tolerance时终止其中 Δcost 为当前线搜索迭代中目标函数值的变化允许上升或下降gradient_tolerance默认 1e-10当||x - Π ⊞(x, -g(x))||∞ gradient_tolerance时终止其中Π是到边界约束的投影⊞是参数向量整体局部参数化的Plus运算。文档建议该值通常取function_tolerance的 1e-4 倍量级parameter_tolerance默认 1e-8当||Δx|| (||x|| parameter_tolerance) * parameter_tolerance时终止Δx 为当前线搜索迭代线性求解器计算出的步长。此外max_num_iterations默认 50与max_solver_time_in_seconds提供硬性上限保护。4.6 特征值缩放BFGS 的进阶开关use_approximate_eigenvalue_bfgs_scaling默认false对应 Oren 提出的自缩放方法将初始 Hessian 逆近似从单位阵I改为I * γ其中γ (y_k s_k) / (y_k y_k) y_k ∇f(k1) - ∇f(k) s_k x(k1) - x(k)文档给出两条重要经验启用后并不总是提升收敛对某些问题类别甚至可能显著恶化因此默认关闭当问题对不同参数的灵敏度差异很大时尤其危险单一标量无法刻画这种差异会把低灵敏度参数对应的 Jacobian 近似部分错误地缩小还可能降低对 Jacobian 误差的鲁棒性。因此该开关应在问题规模大、各参数灵敏度接近时才值得尝试。4.7 日志与回调logging_type默认PER_MINIMIZER_ITERATION控制日志粒度SILENT关闭minimizer_progress_to_stdout默认false默认进度按 vlog 级别写到STDERR置true且logging_type非SILENT时输出到STDOUTcallbacks每轮迭代结束时按向量顺序执行。求解器不接管这些指针的所有权The solver does NOT take ownership of these pointersupdate_state_every_iteration默认false默认只在求解终止时更新外部参数块置true后每轮迭代都更新便于配合IterationCallback做可视化等交互式应用。五、GradientProblemSolver::Summary结果解读Summary记录求解终止后的完整状态定义见 gradient_problem_solver.h成员 / 方法含义BriefReport()一行简洁的终止状态描述FullReport()多行完整求解报告IsSolutionUsable()解是否数值可信termination_type为CONVERGENCE、USER_SUCCESS或NO_CONVERGENCE时为truetermination_type求解器终止原因TerminationType默认FAILUREmessage终止原因文本默认 ceres::GradientProblemSolve was not called.initial_cost/final_cost优化前后的目标函数值iterations按顺序记录每一轮迭代的IterationSummarynum_cost_evaluations仅计算函数值不含梯度的次数num_gradient_evaluations同时计算梯度与函数值的次数total_time_in_seconds求解器内总耗时cost_evaluation_time_in_seconds函数值评估总耗时gradient_evaluation_time_in_seconds梯度评估总耗时num_parameters/num_local_parameters参数总数 / 切空间维度二者仅在设置LocalParameterization时不同line_search_direction_type/line_search_type/line_search_interpolation_type实际使用的方向、线搜索与插值类型nonlinear_conjugate_gradient_type当方向为NONLINEAR_CONJUGATE_GRADIENT时的具体变体max_lbfgs_rank当方向为LBFGS时的 Hessian 近似秩推荐实践求解结束后先调用summary.IsSolutionUsable()判断结果是否可信再输出FullReport()用于排障与归档。六、进度输出的字段解读设置minimizer_progress_to_stdout true后每轮迭代输出形如0: f: 2.317806e05 d: 0.00e00 g: 3.19e-01 h: 0.00e00 s: 0.00e00 e: 0 it: 2.98e-02 tt: 8.50e-02 1: f: 2.312019e05 d: 5.79e02 g: 3.18e-01 h: 2.41e01 s: 1.00e00 e: 1 it: 4.54e-02 tt: 1.31e-01 2: f: 2.300462e05 d: 1.16e03 g: 3.17e-01 h: 4.90e01 s: 2.54e-03 e: 1 it: 4.96e-02 tt: 1.81e-01各字段含义f当前目标函数值d若本轮步长被接受目标函数值的变化量g梯度的最大范数∞-范数h本轮参数向量的变化量s线搜索计算出的最优步长e线搜索内部的函数/梯度评估次数it本轮迭代耗时tt求解器累计总耗时。Rosenbrock 示例的完整输出见 gradient_tutorial.rst可以看到f从2.42e01单调下降到1.88e-22g逐步逼近1e-10量级最终以CONVERGENCE (Gradient tolerance reached. Gradient max norm: 9.032775e-13 1.000000e-10)结束FullReport中还包含Parameters 2、Line search direction LBFGS (20)、Line search type CUBIC WOLFE、Minimizer iterations 35等摘要字段。七、自动微分AutoDiffFirstOrderFunction手写梯度容易出错且难以维护。Ceres 提供了AutoDiffFirstOrderFunction模板把**自动微分Automatic Differentiation**机制接入一阶框架见 autodiff_first_order_function.hFirstOrderFunction* function new AutoDiffFirstOrderFunctionQuadraticCostFunctor, 4( new QuadraticCostFunctor(1.0));使用要点需要自定义一个模板化operator()的函子functor参数用模板类型T表示按普通标量方式书写目标函数函子把计算结果写入最后一个参数唯一的非常量参数并返回true表示成功kNumParameters为参数维度且必须为正源码中有static_assert(kNumParameters 0)框架会以Jetdouble, kNumParameters替换T借助 Jet 求导见 autodiff_first_order_function.h 的实现每个参数分量单独注入单位基向量梯度由 Jet 的v部分一次性收集警告函子会以不同类型实例化任何与其它T类型变量混合的数值必须显式转换为T如T(a_)。这样GradientProblem场景也能享受与最小二乘AutoDiffCostFunction同等的免手写导数体验。八、与 SensorsCalibration 仓库的实际关联SensorsCalibration 的joint_calib模块联合相机内参与激光雷达-相机外参标定见 README.md正是围绕 Ceres 构建的非线性优化应用本文讲解的一阶求解器与其同处于同一个3rdparty/ceres三方库内。二者的关系值得说明joint_calib中的标定精化走的是最小二乘路径以 nonlinear_optimizer.cpp 中的refine_H为例它构建ceres::Problem、添加AutoDiffCostFunction残差块再调用ceres::Solve(solver_options, problem, summary)这是标准的Problem/Solver用法而GradientProblem框架解决的是无法写成最小二乘形式的一类问题例如目标函数直接包含非平方项能量、惩罚项或自定义损失函数的一般无约束优化。两者共享FirstOrderFunction/CostFunction接口思想一阶函数的角色相当于最小二乘中的CostFunction见 gradient_tutorial.rst 的类比说明joint_calib的标定工程依赖Cmake、OpenCV 2.4.13/1.9、PCL 1.7/1.9编译与运行方式参见 joint_calib/README.mdmkdir -p build cd build cmake .. make然后执行./bin/lidar2camera data/intrinsic/ data/circle.csv。如果你正在编写一个非最小二乘形式的目标函数例如基于信息熵、基于距离场或自定义正则项的标定能量函数那么本仓库内置的 Ceres 一阶求解器是直接可用的现成方案——FirstOrderFunctionGradientProblemGradientProblemSolver::Optionsceres::Solve四步即可完成一次完整求解无需引入额外的最小二乘结构约束。九、调参实战建议结合文档说明与源码实现给出以下可操作的调参清单默认配置优先LBFGSWOLFECUBIC是经过验证的稳健组合先跑通再优化维度很大时优先 L-BFGS当参数数超过数百个、无法承受稠密 Hessian 近似矩阵时保持LBFGS并视内存/收敛质量调整max_lbfgs_rank默认 20。文档明确提示秩增大带来线性增长的时空复杂度而解质量的提升存在上限只使用割线信息、近似被约束为正定最优秩需要针对具体问题实验确定需要精确梯度时关闭特征值缩放use_approximate_eigenvalue_bfgs_scaling默认关闭除非你的问题各参数灵敏度接近且已在多个初始点上验证过收益否则不建议开启收敛判据联动调整gradient_tolerance与function_tolerance建议保持文档推荐的 1e-10 / 1e-6 量级搭配若标定精度要求低可适度放宽以换取迭代次数减少善用 Summary 与进度输出开发期设置minimizer_progress_to_stdout true观察f/g/s走势用FullReport()核对num_cost_evaluations与num_gradient_evaluations判断梯度计算是否被频繁调用、是否存在性能瓶颈回调与交互式可视化构建交互式标定工具时将update_state_every_iteration置true并在callbacks中注册IterationCallback即可每轮拿到最新参数块用于界面刷新注意回调指针所有权仍在调用方。十、总结GradientProblem与GradientProblemSolver是 Ceres 中一条独立于最小二乘Problem/Solver的完整求解链前者通过FirstOrderFunction建模函数值 梯度目标配合可选的LocalParameterization处理流形参数后者以线搜索为核心提供最速下降、非线性共轭梯度、BFGS、L-BFGS 四种方向策略与 Armijo、Wolfe 两种线搜索准则配以三类收敛容差、日志与回调机制。结合 SensorsCalibration 仓库内joint_calib对 Ceres 的实际依赖这套框架可直接服务于标定工程中无法用最小二乘形式表达的优化目标是自动驾驶多传感器标定工具箱中值得掌握的一等公民能力。赞分享自动驾驶计算机视觉【免费下载链接】SensorsCalibrationOpenCalib: A Multi-sensor Calibration Toolbox for Autonomous Driving项目地址https://gitcode.com/gh_mirrors/se/SensorsCalibration点击查看免费下载相关推荐SensorsCalibration 内置 Ceres 通用无约束最小化求解器GradientProblem 与 GradientProblemSolver 深度指南SensorsCalibration 内置 Ceres 通用无约束最小化求解器GradientProblem 与 GradientProblemSolver自动驾驶计算机视觉Ceres Solver 一般无约束最优化实战GradientProblem 与 GradientProblemSolver 使用指南基于 SensorsCalibration 仓库Ceres Solver 一般无约束最优化实战GradientProblem 与 GradientProblemSolver 使用指南基于 SensorsC自动驾驶计算机视觉Ceres Solver 一般无约束最小化指南GradientProblem 与 GradientProblemSolver 深度实战解析Ceres Solver 一般无约束最小化指南GradientProblem 与 GradientProblemSolver 深度实战解析 导读 本文围绕 C自动驾驶计算机视觉上一篇Darling终极指南如何在Linux上完美运行macOS应用下一篇两次选择生成第一套 OpenCore EFIOpCore-Simplify 快速上手创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

不止替换SQL关键词:KFS如何拆解并重构异构数据库DDL

不止替换SQL关键词:KFS如何拆解并重构异构数据库DDL

在某大型医院的数据同步项目中,260条同步链路同时运行,源端涉及Oracle、MySQL、SQL Server、KES V8R6、Vastbase等10多种数据库,并持续向目标库汇聚数据。 在这样的环境里,把数据同步过去并不难。真正让链路“卡住”的&#xff0c…

📅 2026/10/15 2:17:46
Rust 全局声明体系重构:RFC 0246 对 `const` 与 `static` 的划分及其在现代 Rust 中的演进

Rust 全局声明体系重构:RFC 0246 对 `const` 与 `static` 的划分及其在现代 Rust 中的演进

文档 【免费下载链接】rfcs RFCs for changes to Rust 项目地址: https://gitcode.com/gh_mirrors/rf/rfcs 点击查看 免费下载 本文以 Rust RFC 仓库中的 text/0246-const-vs-static.md 为绝对主线,系统梳理 2014 年该 RFC 提出"将全局声明拆分为 …

📅 2026/10/15 2:17:46
嵌入式GUI是库还是系统?FlyThings OS三层架构解析

嵌入式GUI是库还是系统?FlyThings OS三层架构解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/15 2:12:46
MORE NEWS

更多资讯

📰

PoB离线Build规划:天赋树与伤害计算一次算清

PoB离线Build规划:天赋树与伤害计算一次算清 【免费下载链接】PathOfBuilding Offline build planner for Path of Exile. 项目地址: https://gitcode.com/GitHub_Trending/pa/PathOfBuilding 凌晨两点,你又一次在天赋树上手动数格子:…

📰

微信API发送失败别盲目重试:个人微信二次开发判断法

客服反馈:「发货通知怎么发了两条?」 打开日志,往往是这样:第一次请求超时了,程序自动又发了一次;其实第一条早就到了。 个人微信 API 二次开发里,失败就重试听着负责,却是双发和失…

📰

CKEditor 4 聚焦状态下销毁内联编辑器的空引用崩溃:`isInline of null` 问题与 Bender 手动测试解析

前端UI组件 【免费下载链接】ckeditor4 The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins. 项目地址: https://gitcode.com/gh_mirrors/ck/ckeditor4 点击查看 免费下载 导读 本文围绕 CKEditor 4 官方仓库中的…

📰

如何在电脑上运行《索尼克:释放》:Unleashed Recompiled 静态重编译版完整上手指南

如何在电脑上运行《索尼克:释放》:Unleashed Recompiled 静态重编译版完整上手指南 【免费下载链接】UnleashedRecomp An unofficial PC port of the Xbox 360 version of Sonic Unleashed created through the process of static recompilation. 项目…

📰

叉积判向:从三角形朝向到背面剔除的工程实战

做图形学的人,早晚都会撞上"叉积"这堵墙。第一次在代码里写cross(a, b) ax*by - ay*bx的时候,我压根没意识到,这个只有一行乘减运算的小东西,居然能决定三角形到底是顺时针还是逆时针,进而影响到背面剔除、…

📰

Wing 语言 inflight Handler 单例语义剖析:以 `inflight_handler_singleton.test.w` 快照测试为例

编程语言编译器云原生语言运行时 【免费下载链接】wing A programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡ 项目地址: https://gitcode.com/gh_mirrors/wi/wing 点击查看 免…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬