当前位置: 首页 > article >正文

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

在这里插入图片描述

骨骼动画基础

骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。

  • 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼
  • 蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动时带动网格变形

在 OSG 中,这些功能主要由osgAnimation库提供支持。

当然可以!以下是 Day 16:骨骼动画与蒙皮(osgAnimation) 中的“核心知识点”部分,以标准 Markdown (.md) 格式呈现:


核心知识点

类名作用
osgAnimation::AnimationManagerBase动画管理器接口,定义了动画更新的基本行为
osgAnimation::BasicAnimationManager基础动画管理器实现类,用于管理和播放多个动画
osgAnimation::RigGeometry蒙皮网格数据结构,支持骨骼影响顶点的变形计算
osgAnimation::AnimationPathCallback动画路径回调,可用于控制骨骼或模型沿特定路径运动
osgDB::readNodeFile()加载模型文件(支持 OSGT 等格式),自动解析动画和骨骼信息

OSGT 格式

格式骨骼支持动画保留OSG 兼容性
.osgt✅ 完整✅ 完整⭐⭐⭐⭐⭐(原生支持,推荐使用)
.dae✅ 完整✅ 完整⭐⭐⭐⭐(需 Collada 插件)
.fbx❌ 不支持❌ 不支持不可直接读取
  • .osgt:OSG 的二进制序列化格式,支持完整的骨骼与动画数据,加载速度快,兼容性最好。
  • .dae(Collada):开放的 XML 格式,广泛用于三维模型交换,支持骨骼和动画,但需要 OSG 的 osgdb_collada 插件。
  • .fbx:Autodesk 的私有格式,功能强大,但 OpenSceneGraph 默认不支持 FBX,需要借助第三方插件(如 OpenSceneGraph-FBX)才能加载。

实战

实战1

通过代码自动生成动画效果。

animation.cpp

#include <osgViewer/Viewer>
#include <osg/Group>
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osg/MatrixTransform>
#include <osgAnimation/BasicAnimationManager>
#include <osgAnimation/UpdateMatrixTransform>
#include <osgAnimation/Animation>
#include <osgAnimation/Channel>
#include <osgGA/TrackballManipulator>
#include <osg/Material>
#include <osgDB/Registry>
#include <osg/Notify>
#include <iostream>// 创建骨骼节点
osg::MatrixTransform* createBone(const std::string& name, float length, const osg::Vec4& color) {osg::ref_ptr<osg::MatrixTransform> bone = new osg::MatrixTransform;bone->setName(name);// 创建骨骼可视化(圆柱体)osg::ref_ptr<osg::Cylinder> cylinder = new osg::Cylinder(osg::Vec3(0, 0, length/2), 0.1f, length);osg::ref_ptr<osg::ShapeDrawable> drawable = new osg::ShapeDrawable(cylinder);// 设置颜色osg::ref_ptr<osg::Material> material = new osg::Material;material->setDiffuse(osg::Material::FRONT, osg::Vec4(color));drawable->getOrCreateStateSet()->setAttributeAndModes(material.get());// 添加关节球osg::ref_ptr<osg::Sphere> jointSphere = new osg::Sphere(osg::Vec3(0, 0, 0), 0.15f);osg::ref_ptr<osg::ShapeDrawable> jointDrawable = new osg::ShapeDrawable(jointSphere);jointDrawable->setColor(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f));osg::ref_ptr<osg::Geode> geode = new osg::Geode;geode->addDrawable(drawable.get());geode->addDrawable(jointDrawable.get());bone->addChild(geode.get());return bone.release();
}// 在main函数中添加临时测试动画
class SimpleRotationCallback : public osg::NodeCallback {
public:virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {static double start = osg::Timer::instance()->time_s();double t = osg::Timer::instance()->time_s() - start;float angle = sin(t) * 1.0f; // 摆动幅度osg::MatrixTransform* mt = dynamic_cast<osg::MatrixTransform*>(node);if (mt) {mt->setMatrix(osg::Matrix::rotate(angle, osg::Vec3(0,1,0)));}traverse(node, nv);}
};// 创建动画
osgAnimation::Animation* createArmAnimation() {osg::ref_ptr<osgAnimation::Animation> animation = new osgAnimation::Animation;animation->setName("ArmAnimation");// 创建肩关节动画通道osg::ref_ptr<osgAnimation::QuatSphericalLinearChannel> shoulderChannel = new osgAnimation::QuatSphericalLinearChannel;shoulderChannel->setName("rotation");shoulderChannel->setTargetName("Shoulder");osgAnimation::QuatKeyframeContainer* shoulderKeyframes = shoulderChannel->getOrCreateSampler()->getOrCreateKeyframeContainer();shoulderKeyframes->push_back(osgAnimation::QuatKeyframe(0.0, osg::Quat(0, osg::Vec3(0,1,0))));shoulderKeyframes->push_back(osgAnimation::QuatKeyframe(2.0, osg::Quat(osg::PI/4, osg::Vec3(0,1,0))));shoulderKeyframes->push_back(osgAnimation::QuatKeyframe(4.0, osg::Quat(-osg::PI/4, osg::Vec3(0,1,0))));shoulderKeyframes->push_back(osgAnimation::QuatKeyframe(6.0, osg::Quat(0, osg::Vec3(0,1,0))));// 创建肘关节动画通道osg::ref_ptr<osgAnimation::QuatSphericalLinearChannel> elbowChannel = new osgAnimation::QuatSphericalLinearChannel;elbowChannel->setName("rotation");elbowChannel->setTargetName("Elbow");osgAnimation::QuatKeyframeContainer* elbowKeyframes = elbowChannel->getOrCreateSampler()->getOrCreateKeyframeContainer();elbowKeyframes->push_back(osgAnimation::QuatKeyframe(0.0, osg::Quat(0, osg::Vec3(0,1,0))));elbowKeyframes->push_back(osgAnimation::QuatKeyframe(1.0, osg::Quat(osg::PI/2, osg::Vec3(0,1,0))));elbowKeyframes->push_back(osgAnimation::QuatKeyframe(2.0, osg::Quat(0, osg::Vec3(0,1,0))));elbowKeyframes->push_back(osgAnimation::QuatKeyframe(3.0, osg::Quat(osg::PI/2, osg::Vec3(0,1,0))));elbowKeyframes->push_back(osgAnimation::QuatKeyframe(4.0, osg::Quat(0, osg::Vec3(0,1,0))));elbowKeyframes->push_back(osgAnimation::QuatKeyframe(6.0, osg::Quat(0, osg::Vec3(0,1,0))));// 创建腕关节动画通道osg::ref_ptr<osgAnimation::QuatSphericalLinearChannel> wristChannel = new osgAnimation::QuatSphericalLinearChannel;wristChannel->setName("rotation");wristChannel->setTargetName("Wrist");osgAnimation::QuatKeyframeContainer* wristKeyframes = wristChannel->getOrCreateSampler()->getOrCreateKeyframeContainer();wristKeyframes->push_back(osgAnimation::QuatKeyframe(0.0, osg::Quat(0, osg::Vec3(1,0,0))));wristKeyframes->push_back(osgAnimation::QuatKeyframe(1.5, osg::Quat(osg::PI/3, osg::Vec3(1,0,0))));wristKeyframes->push_back(osgAnimation::QuatKeyframe(3.0, osg::Quat(-osg::PI/3, osg::Vec3(1,0,0))));wristKeyframes->push_back(osgAnimation::QuatKeyframe(4.5, osg::Quat(osg::PI/3, osg::Vec3(1,0,0))));wristKeyframes->push_back(osgAnimation::QuatKeyframe(6.0, osg::Quat(0, osg::Vec3(1,0,0))));animation->addChannel(shoulderChannel.get());animation->addChannel(elbowChannel.get());animation->addChannel(wristChannel.get());animation->setPlayMode(osgAnimation::Animation::LOOP);animation->setDuration(6.0);return animation.release();
}// 创建手臂模型
osg::Group* createArm() {osg::ref_ptr<osg::Group> root = new osg::Group;// 创建骨骼层级结构osg::ref_ptr<osg::MatrixTransform> shoulder = createBone("Shoulder", 2.0f, osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));osg::ref_ptr<osg::MatrixTransform> elbow = createBone("Elbow", 1.5f, osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));osg::ref_ptr<osg::MatrixTransform> wrist = createBone("Wrist", 1.0f, osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));// 设置骨骼初始位置shoulder->setMatrix(osg::Matrix::translate(0, 0, 0));elbow->setMatrix(osg::Matrix::translate(0, 0, 2.0f));wrist->setMatrix(osg::Matrix::translate(0, 0, 1.5f));// 构建层级关系shoulder->addChild(elbow);elbow->addChild(wrist);// 添加动画更新回调shoulder->setUpdateCallback(new SimpleRotationCallback);elbow->setUpdateCallback(new osgAnimation::UpdateMatrixTransform("Elbow"));wrist->setUpdateCallback(new osgAnimation::UpdateMatrixTransform("Wrist"));// 创建手爪模型osg::ref_ptr<osg::Geode> handGeode = new osg::Geode;osg::ref_ptr<osg::Box> leftFinger = new osg::Box(osg::Vec3(-0.2f, 0, 0.5f), 0.1f, 0.1f, 1.0f);osg::ref_ptr<osg::Box> rightFinger = new osg::Box(osg::Vec3(0.2f, 0, 0.5f), 0.1f, 0.1f, 1.0f);osg::ref_ptr<osg::ShapeDrawable> leftDrawable = new osg::ShapeDrawable(leftFinger);osg::ref_ptr<osg::ShapeDrawable> rightDrawable = new osg::ShapeDrawable(rightFinger);leftDrawable->setColor(osg::Vec4(0.8f, 0.8f, 0.8f, 1.0f));rightDrawable->setColor(osg::Vec4(0.8f, 0.8f, 0.8f, 1.0f));handGeode->addDrawable(leftDrawable);handGeode->addDrawable(rightDrawable);wrist->addChild(handGeode);root->addChild(shoulder);// 创建底座osg::ref_ptr<osg::Geode> baseGeode = new osg::Geode;osg::ref_ptr<osg::Cylinder> baseCylinder = new osg::Cylinder(osg::Vec3(0,0,-0.5f), 1.0f, 0.5f);osg::ref_ptr<osg::ShapeDrawable> baseDrawable = new osg::ShapeDrawable(baseCylinder);baseDrawable->setColor(osg::Vec4(0.5f, 0.5f, 0.5f, 1.0f));baseGeode->addDrawable(baseDrawable);root->addChild(baseGeode);return root.release();
}int main() {// 设置调试输出级别osg::setNotifyLevel(osg::NOTICE);// 创建ViewerosgViewer::Viewer viewer;// 创建主场景组osg::ref_ptr<osg::Group> root = new osg::Group;// 添加手臂模型root->addChild(createArm());// 创建动画管理器osg::ref_ptr<osgAnimation::BasicAnimationManager> animManager = new osgAnimation::BasicAnimationManager;// 将动画管理器作为场景图的更新回调root->setUpdateCallback(animManager);// 添加动画osgAnimation::Animation* anim = createArmAnimation();animManager->registerAnimation(anim);animManager->playAnimation(anim);// 输出调试信息std::cout << "动画管理器状态: " << (animManager.valid() ? "有效" : "无效") << std::endl;std::cout << "已注册动画数量: " << animManager->getAnimationList().size() << std::endl;if (animManager->getAnimationList().size() > 0) {std::cout << "正在播放动画: " << animManager->getAnimationList()[0]->getName() << std::endl;}viewer.setSceneData(root);viewer.setCameraManipulator(new osgGA::TrackballManipulator);// 设置初始视角viewer.getCameraManipulator()->setHomePosition(osg::Vec3(0, -10, 5), // 眼睛位置osg::Vec3(0, 0, 2),   // 中心位置osg::Vec3(0, 0, 1)    // 上方向);viewer.home(); // 应用初始视角设置return viewer.run();
}
运行效果

在这里插入图片描述

加载osgt文件

animationOsgt.cpp

#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osgAnimation/BasicAnimationManager>int main() {// 1. 加载模型osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("../dumptruck.osgt");if (!model) return 1;// 2. 获取动画管理器osgAnimation::BasicAnimationManager* animManager = dynamic_cast<osgAnimation::BasicAnimationManager*>(model->getUpdateCallback());if (animManager && !animManager->getAnimationList().empty()) {// 3. 正确播放动画(两种解决方案):if (animManager) {const osgAnimation::AnimationList& animList = animManager->getAnimationList();if (!animList.empty()) {// 打印所有动画信息for (const auto& anim : animList) {std::cout << "Found animation: " << anim->getName() << " (" << anim->getDuration() << "s)\n";}// 播放第一个动画animManager->playAnimation(animList[0]);} else {std::cerr << "Warning: No animations found in the model" << std::endl;}} else {std::cerr << "Error: No AnimationManager found" << std::endl;}}// 4. 设置查看器osgViewer::Viewer viewer;viewer.setSceneData(model);viewer.setCameraManipulator(new osgGA::TrackballManipulator());return viewer.run();
}
运行效果

在这里插入图片描述

本章可能会和自己的osg版本有关系,会有一些报错。耐心解决。_

在这里插入图片描述

相关文章:

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...