cocos2dx 3D物理相关知识点汇总

news2024/11/19 20:27:00

(一)3D相关基础知识

网格(Mesh)

通常说的网格其实就是3D建模出来的形状。因为模型是由很多三角形组成,所以,就像网格一样。

在这里插入图片描述

纹理

纹理的作用就是给网格上色。

怎么上色的?

举个简单的例子。

  1. 想象有一张白纸,用它将模型包住,然后用画笔给模型上色。
  2. 三个顶点就能组成一个面,面的形状和位置由三角形三个顶点的位置来决定的。
  3. 准备若干的图钉,将白纸固定到模型上。 那么模型就有了形状和颜色。
  4. 导出数据,网格数据就是组成面的顶点的坐标。
  5. 颜色数据(纹理数据):图钉拆掉之后,把上色的包住的白纸展开,这张纸就是纹理贴图,也就是颜色数据。

在这里插入图片描述

  1. 图钉拔出来之后,会在白纸上留下固定的小洞,每一个洞就是模型顶点所对应的纹理位置。也就是纹理坐标,有了纹理坐标后,顶点就可以对应上纹理坐标对应的颜色。也就是,重建的时候,只需要把白纸的洞和对应的顶点坐标对上,那么就包到了模型上。纹理坐标,左上角为(0,0),右下角为(1,1)

  2. 动画的本质:把动作分解成多少帧,每一帧模型的形状都是不一样的。也就是说,动画就是改变每一帧模型的形状。导出来的是,一个fbx模型文件(网格+动画等数据)和一张纹理贴图。

(二)cocos2dx 的3D文件格式

3D文件格式

Cocos2d-x 目前支持两种 3D 文件格式:

  • Wavefront 对象文件:.obj 文件
  • Cocos2d-x 专有格式:.c3t ,.c3b 文件

支持 Wavefront 文件格式,因为它被 3D 编辑器广泛采用,并且非常容易解析。然而,它是有缺点的,不支持诸如动画的高级功能。

另一方面,c3t 和 c3b 是 Cocos2d-x 专有的文件格式,允许动画,材质和其它高级3D功能。c3t 是文本格式,c3b 是二进制格式。开发人员进行最终的游戏发布时应使用 c3b ,因为使用它性能更好。如果是想要调试文件,或是跟踪其在 Git 或任何其他版本控制系统中的更改,则应使用 c3t 。

注意:可以使用 c3b 或 c3t 文件,不能使用 obj 文件,创建 Animation3D 对象。

转换工具

fbx-conv 允许将 FBX 格式转换为 Cocos2d-x 专有格式。格式为.c3b。
fbx-conv [-a|-b|-t] FBXFile

参数含义:

  • -?:显示帮助信息
  • -a:导出文本格式和二进制格式
  • -b:导出二进制格式
  • -t:导出文本格式

工具使用注意点:

  • 模型需要一个至少包含一个纹理的材质
  • 只支持骨骼动画
  • 只支持一个骨骼对象,没有多个骨骼对象的支持
  • 您可以通过导出多个静态模型来创建一个 3D 场景
  • 网格顶点或索引的最大数量为 32767

(三)cocos2dx 3D 物理引擎

物理世界

不管是2D还是3D,要使用物理引擎,场景必须是物理世界的。

创建方法:

local pScene = cc.Scene:createWithPhysics()
if cc.Director:getInstance():getRunningScene() then
    cc.Director:getInstance():replaceScene(pScene)
else
    cc.Director:getInstance():runWithScene(pScene)
end
    
    
self._physicsScene = cc.Director:getInstance():getRunningScene()
local winSize = cc.Director:getInstance():getWinSize()
local physics3DWorld = self._physicsScene:getPhysics3DWorld()

打开调试:

physics3DWorld:setDebugDrawEnable(isDebug)

刚体

刚体是指在运动中和受力作用后,形状和大小不变,而且内部各点的相对位置不变的物体。

任何一个非角色对象,如果希望通过作用力及扭转力进行仿真运动,都需要挂在一个刚体组件。也就是说给游戏对象添加刚体组件,就能够使游戏对象受到碰撞弹开、能够受到重力下落、能够给其它刚体施加力等

所以刚体的作用就是:使游戏对象能够受力和施力

创建

3D的刚体在Physics3DRigidBody类中。其继承于Physics3DObject

创建方法为

static Physics3DRigidBody* create(Physics3DRigidBodyDes* info);

这里可以看出来传入的是一个Physics3DRigidBodyDes 对象。

该对象描述了刚体的部分属性。

Mass 质量

默认值是0.f,也就是0,是一个float类型。0.f代表的静态刚体,不会动。

在实际开发中,应该设置为0.1f到10.0,这样符合日常生活。

这个属性可以通过保持物体与物体之间的质量比来力高其物理仿真程度。

localInertia 惯性

物体保持静止状态或匀速直线运动状态的性质,称为惯性。

disableSleep

默认是false

如果为true,会调用btRigidBodysetActivationState函数设置状态为DISABLE_DEACTIVATION

其中,btRigidBody 是Bullet库的对象。

作用就是,在动画期间禁用它们的休眠状态,这样每一个模拟帧都会获得新的世界转换。

Physics3DShape对象

Physics3DShape :碰撞图形类。本质就是描述一个刚体碰撞的类型。

它包括一个ShapeType

  1. BOX 盒子
  2. SPHERE 球体
  3. CYLINDER 圆柱体
  4. CAPSULE 胶囊体
  5. CONVEX 三维凸包
  6. MESH 网格形状
  7. HEIGHT_FIELD 地形形状
  8. COMPOUND 复合碰撞

三维凸包

在这里插入图片描述

连接A和B两点的线段,有部分并没有在多边形上。那么这个便不是严格意义上的凸边形状。

凸变形的定义:在一个多边形上(包括多边形的边界及边界围封的范围)任意取两点并以一条线段连结该两点,如果线段上的每一点均在该多边形上,那么我们便说这个多边形是凸的。

接下来看凸包的定义,给定平面上的一个(有限)点集(即一组点),这个点集的凸包就是包含点集中所有点的最小面积的凸多边形。

举个例子:

在这里插入图片描述

各种包围体的示意图

在这里插入图片描述

这里就可以看得出,AABB和OBB包围盒比较松,多余的节点也比较多,而凸包包围体的更加紧凑,碰撞检测更加精确,但是算法更加复杂。

创建Physics3DShape

函数作用
static Physics3DShape* createBox(const cocos2d::Vec3& extent);创建一个盒子碰撞检测区
static Physics3DShape* createSphere(float radius);创建一个球体碰撞检测区
static Physics3DShape* createCylinder(float radius, float height);创建一个圆柱体碰撞检测区
static Physics3DShape* createCapsule(float radius, float height);创建一个胶囊体碰撞检测区
static Physics3DShape* createConvexHull(const cocos2d::Vec3 *points, int numPoints)创建一个三维凸包碰撞检测区
static Physics3DShape* createMesh(const cocos2d::Vec3 *triangles, int numTriangles);创建一个网格碰撞检测区
static Physics3DShape* createHeightfield创建一个地形碰撞检测区
static Physics3DShape* createCompoundShape创建一个复合碰撞检测区

创建一个刚体

有了上面的数据,现在就可以创建一个刚体了。

local rbDes = {}
rbDes.mass = 0.0
rbDes.shape = cc.Physics3DShape:createMesh(trianglesList, math.floor(#trianglesList / 3))
local rigidBody = cc.Physics3DRigidBody:create(rbDes)

Physics3DComponent 物理组件

作用是将Node的数据和刚体的数据相互关联,同时可以指定其相对于其父节点的一些偏移设置

用法

先看它的创建函数:

static Physics3DComponent* create(Physics3DObject* physicsObj, const cocos2d::Vec3& translateInPhysics = cocos2d::Vec3::ZERO, const cocos2d::Quaternion& rotInPhsyics = cocos2d::Quaternion::ZERO);

参数一是一个Physics3DObject 对象,那么也就是上面创建出来的刚体对象就可以传入,即

local component = cc.Physics3DComponent:create(rigidBody)

碰撞检测

包围盒

上面也说到了,Physics3DShape类就是定义包围盒类型的。

要想碰撞,就需要给刚体定义包围盒。

所谓的包围盒,就是就是给物体装进一个盒子里,该盒子可以装下物体。

包围盒算法

cocos2dx 提供了两种包围盒算法,一个是AABB,一个OBB。

AABB

AABB(axis-aligned bounding box)包围盒被称为轴对其包围盒。

在2D中的AABB包围盒:

在这里插入图片描述

在这里插入图片描述

很明显可以得知其特点:

  1. 四边形,用四边形包围物体
  2. 四边形的每一个边都和坐标系的轴垂直

在3D中的AABB包围盒:
在这里插入图片描述

特点如下:

  1. 为六面体
  2. 六面体的每一条边都平行于一个坐标平面
2D中AABB碰撞规则和条件

规则 :物体A与物体B分别沿两个坐标轴做投影,只有在两个坐标轴都发生重叠的情况下,两个物体才意味着发生了碰撞

在这里插入图片描述

未重合的判断条件:

  1. 物体A的Y轴方向最大值小于物体B的Y轴方向最小值
  2. 物体A的X轴方向最大值小于物体B的X轴方向最小值
  3. 物体B的Y轴方向最大值小于物体A的Y轴方向最小值
  4. 物体B的X轴方向最大值小于物体A的X轴方向最小值

只要满足上面的条件,那么就表示两个物体没有重合,也就是没有发生碰撞,反之,则认为物体A和物体B发生了碰撞。

3D中AABB碰撞规则和条件

从2D的AABB碰撞判断来看,是否发生重合需要两个信息:

  1. 物体A最小点(左下角),和物体A最大点(右上角)的信息
  2. 物体B最小点,和物体B最大点的信息

在3D中AABB是一个六面体。

相比2D坐标系,多了一个Z轴。其AABB实际上依然可以采用上面4个顶点的信息来进行判断。

在这里插入图片描述

图中圈出来的两个点,便可以确定八个顶点的全部信息。

在cocos3dx中提供了AABB类,用来保存包围盒的最大顶点和最小顶点的信息。

每一个Sprite3D对象都提供了获取AABB包围盒的接口,在AABB类中也提供了相应判断碰撞检测的方法。

bool AABB::intersects(const AABB& aabb) const
{
    return ((_min.x >= aabb._min.x && _min.x <= aabb._max.x) || (aabb._min.x >= _min.x && aabb._min.x <= _max.x)) &&
           ((_min.y >= aabb._min.y && _min.y <= aabb._max.y) || (aabb._min.y >= _min.y && aabb._min.y <= _max.y)) &&
           ((_min.z >= aabb._min.z && _min.z <= aabb._max.z) || (aabb._min.z >= _min.z && aabb._min.z <= _max.z));
}

bool AABB::containPoint(const Vec3& point) const
{
    if (point.x < _min.x) return false;
    if (point.y < _min.y) return false;
    if (point.z < _min.z) return false;
    if (point.x > _max.x) return false;
    if (point.y > _max.y) return false;
    if (point.z > _max.z) return false;
    return true;
}

这里需要注意的是,AABB类一开始保存的最大顶点和最小顶点的信息是基于物体的坐标系,那么在实际的碰撞检测中,需要将其转换到世界坐标系的点上

void AABB::transform(const Mat4& mat)
{
    Vec3 corners[8];
     // Near face, specified counter-clockwise
    // Left-top-front.
    corners[0].set(_min.x, _max.y, _max.z);
    // Left-bottom-front.
    corners[1].set(_min.x, _min.y, _max.z);
    // Right-bottom-front.
    corners[2].set(_max.x, _min.y, _max.z);
    // Right-top-front.
    corners[3].set(_max.x, _max.y, _max.z);

    // Far face, specified clockwise
    // Right-top-back.
    corners[4].set(_max.x, _max.y, _min.z);
    // Right-bottom-back.
    corners[5].set(_max.x, _min.y, _min.z);
    // Left-bottom-back.
    corners[6].set(_min.x, _min.y, _min.z);
    // Left-top-back.
    corners[7].set(_min.x, _max.y, _min.z);

    // Transform the corners, recalculate the min and max points along the way.
    for (int i = 0; i < 8; i++)
        mat.transformPoint(&corners[i]);
    
    reset();
    
    updateMinMax(corners, 8);
}
OBB

OBB(Oriented Bounding Box)包围盒也被称作有向包围盒或定向包围盒,它会随着物体的移动、缩放、旋转。

首先要明确一点,AABB是不能随着物体进行旋转的。

OBB包围盒比AABB更小。
在这里插入图片描述

可以发现,它的每一条边,并不是和AABB一样,同坐标系的轴平行。

所以,这就决定了它一般用来做精准碰撞判断的。

但是精准的代价就是计算更加复杂,所需要消耗的资源就更多。

如何最小消耗的表示一个OBB包围盒就是对计算和性能优化的对好方式。

对于AABB的最大点和最小点来确定整个包围盒的方式,对于OBB肯定是不适用的。

在cocos2dx中使用了如下的数据去存储一个OBB包围盒:

Vec3 _center;   // obb center
Vec3 _xAxis;    // x axis of obb, unit vector
Vec3 _yAxis;    // y axis of obb, unit vector
Vec3 _zAxis;    // z axis of obb, unit vector
Vec3 _extentX;  // _xAxis * _extents.x
Vec3 _extentY;  // _yAxis * _extents.y
Vec3 _extentZ;  // _zAxis * _extents.z
Vec3 _extents;  // obb length along each axis

每一个Vec3 都是三个浮点数,这样算下来的确开销比较大。

减少开销的办法:只存储旋转矩阵的两个轴,只是在测试的时候,利用叉积计算第三个轴。

OBB包围盒的创建

cocos2dx 提供了2种创建方式,一个是直接用AABB去创建一个OBB。

OBB::OBB(const AABB& aabb)
{
    reset();
    
    _center = (aabb._min + aabb._max);
    _center.scale(0.5f);
    _xAxis.set(1.0f, 0.0f, 0.0f);
    _yAxis.set(0.0f, 1.0f, 0.0f);
    _zAxis.set(0.0f, 0.0f, 1.0f);
    
    _extents = aabb._max - aabb._min;
    _extents.scale(0.5f);
    
    computeExtAxis();
}

使用的办法也很简单:

local aabb = self._sprite:getAABB()
self._obbt = cc.OBB:new(aabb)

第二个方法就是利用协方差矩阵来确定一个方向包围盒,说通俗点就是将原基下的坐标转换到新基上,然后依照新基算出AABB包围盒,然后再转换到原基,这个时候就是原基的OBB包围盒了。

即:新基下的AABB包围盒 = 原基下的OBB包围盒

具体怎么计算的,那就是另外的话题了。

cocos2dx 提供的方法

OBB::OBB(const Vec3* verts, int num)
{
    if (!verts) return;
    
    reset();
    
    Mat4 matTransform = _getOBBOrientation(verts, num);
    
    //    For matTransform is orthogonal, so the inverse matrix is just rotate it;
    matTransform.transpose();
    
    Vec3 vecMax = matTransform * Vec3(verts[0].x, verts[0].y, verts[0].z);
    
    Vec3 vecMin = vecMax;
    
    for (int i = 1; i < num; i++)
    {
        Vec3 vect = matTransform * Vec3(verts[i].x, verts[i].y, verts[i].z);
        
        vecMax.x = vecMax.x > vect.x ? vecMax.x : vect.x;
        vecMax.y = vecMax.y > vect.y ? vecMax.y : vect.y;
        vecMax.z = vecMax.z > vect.z ? vecMax.z : vect.z;
        
        vecMin.x = vecMin.x < vect.x ? vecMin.x : vect.x;
        vecMin.y = vecMin.y < vect.y ? vecMin.y : vect.y;
        vecMin.z = vecMin.z < vect.z ? vecMin.z : vect.z;
    }
    
    matTransform.transpose();
    
    _xAxis.set(matTransform.m[0], matTransform.m[1], matTransform.m[2]);
    _yAxis.set(matTransform.m[4], matTransform.m[5], matTransform.m[6]);
    _zAxis.set(matTransform.m[8], matTransform.m[9], matTransform.m[10]);
    
    _center    = 0.5f * (vecMax + vecMin);
    _center *= matTransform;
    
    _xAxis.normalize();
    _yAxis.normalize();
    _zAxis.normalize();
    
    _extents = 0.5f * (vecMax - vecMin);
    
    computeExtAxis();
}
OBB包围盒的碰撞检测方法

通常采用的是分离轴定理(separating axis theorem)

先用2D来理解:两个凸包多边形,当且仅当存在一条线,这两个多边形在这条线上的投影不相交,则这两个多边形也不相交

简单的来说,就是可以找到一条直线,让物体A和物体B,一个在左边,一个在右边,然后该直线垂直的线为分离轴,可以发现,物体A和物体B在该轴的投影是没有相交的。

在这里插入图片描述

3D中一样的道理。由于分离轴可能有无数种存在,所以一般选取几个可以测试的即可。

在cocos2dx中,OBB包围盒的凸面体基本都是长方体。两个长方体的碰撞可以归结为:

  1. 面与面的碰撞
  2. 面与边的碰撞
  3. 边与边的碰撞

那么在选取分离轴的时候,只需要取第一个包围盒的3个坐标轴、第二个包围盒的3个坐标轴,以及垂直于某一个轴的9个轴。(一共是15个轴)

垂直于某一轴的9个轴 : 取包围盒A的X轴方向的某一边矢量(不是X坐标轴,是x轴方向边的矢量),再取包围盒B的X轴方向的某一边矢量,对两个矢量做叉乘,叉乘结果就是垂直于A和B的矢量的方向矢量,这就是一个分离轴。如此重复,用包围盒A的X轴方向的某一边矢量依次叉乘包围盒B的X,Y,Z,然后再用包围盒A的Y和Z轴方向的某一边矢量再进行这一遍流程,总共得到9个轴。

cocos2dx 相应的代码在:

bool OBB::intersects(const OBB& box) const
{
    float min1, max1, min2, max2;
    for (int i = 0; i < 3; i++)
    {
        getInterval(*this, getFaceDirection(i), min1, max1);
        getInterval(box, getFaceDirection(i), min2, max2);
        if (max1 < min2 || max2 < min1) return false;
    }
    
    for (int i = 0; i < 3; i++)
    {
        getInterval(*this, box.getFaceDirection(i), min1, max1);
        getInterval(box, box.getFaceDirection(i), min2, max2);
        if (max1 < min2 || max2 < min1) return false;
    }
    
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            Vec3 axis;
            Vec3::cross(getEdgeDirection(i), box.getEdgeDirection(j), &axis);
            getInterval(*this, axis, min1, max1);
            getInterval(box, axis, min2, max2);
            if (max1 < min2 || max2 < min1) return false;
        }
    }
    
    return true;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/10996.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

m基于GA遗传优化的生产工艺设备布置优化matlab仿真

目录 1.算法概述 2.仿真效果预览 3.核心MATLAB程序 4.完整MATLAB程序 1.算法概述 在设备布置的问题上&#xff0c;本文将作业车间设备布置这个多目标优化问题看成是包含布局面积&#xff0c;物流成本和生产工艺的连续优化的多行设备布置问题&#xff0c;使之更具有实际意义…

如何在 Rocky Linux 上安装 Apache Kafka?

Apache Kafka 是一种分布式数据存储&#xff0c;用于实时处理流数据&#xff0c;它由 Apache Software Foundation 开发&#xff0c;使用 Java 和 Scala 编写&#xff0c;Apache Kafka 用于构建实时流式数据管道和适应数据流的应用程序&#xff0c;特别适用于企业级应用程序和关…

robots.txt漏洞

robots.txt漏洞描述: 搜索引擎可以通过robots文件可以获知哪些页面可以爬取,哪些页面不可以爬取。Robots协议是网站国际互联网界通行的道德规范,其目的是保护网站数据和敏感信息、确保用户个人信息和隐私不被侵犯,如果robots.txt文件编辑的太过详细,反而会泄露网站的敏感…

[附源码]java毕业设计基于学生信息管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Delphi中关于PChar、Char数组、string[](ShortString)及结构体长度及占用空间的一些特性说明和测试

关于特性 1&#xff0c;string和Char数组都是一块内存, 其中存放连续的字符. string保存具体字符的内存对用户 是透明的, 由Delphi管理它的分配, 复制和释放, 用户不能干预2&#xff0c;关于ShortString&#xff0c;内存中用第一个字节来表示字符串的长度。FF255,所以这个特性…

【MySQL】MySQL复制与高可用水平扩展架构实战(MySQL专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

天王刘德华走红毯,到哪他都是最耀眼的明星

第三十五届金鸡奖&#xff0c;已经在福建厦门落下帷幕&#xff0c;如果要说本届金鸡奖谁收获最大&#xff0c;无疑是天王刘德华。在金鸡奖颁奖典礼现场&#xff0c;功夫巨星吴京登上热搜&#xff0c;然而热搜的主角却不是他&#xff0c;而是天王刘德华。 在本届金鸡奖颁奖典礼现…

cubeIDE开发, stm32调试信息串口通信输出显示

关于cubeIDE开发基本技巧及流程&#xff0c;本文不详细叙述&#xff0c;请参考&#xff1a;cubeIDE快速开发流程_py_free的博客-CSDN博客_cubeide汉化 一、stm32串口配置 本文采用的开发板是stm32L496VGT3,其有两个 USB 接口&#xff0c;一个为 USB ST-link 复用接口&#xff…

代码随想录——最长递增子序列的个数

题目 给定一个未排序的整数数组&#xff0c;找到最长递增子序列的个数。 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列&#xff0c;分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。 示例 2: 输入: [2,2,2,2,2] 输出: 5 解释: 最长递增子序列的长度是1&#xff0c;并且…

Oracle 表创建和表管理

1.表的命名 必须以字母开头字符长度在1-30之间只能包含A-Z&#xff0c;a-z,0-9,_,$和#被同一个用户拥有的对象不能有重复的名字 2.表的创建 SQL> create table t01(id number(4),name varchar2(15));Table created.SQL> desc t01Name …

现场直击!维视智造携多款明星产品亮相VisionChina 2022深圳机器视觉展

11月15日&#xff0c;2022年中国&#xff08;深圳&#xff09;机器视觉展在深圳国际会展中心&#xff08;宝安新馆&#xff09;盛大开幕&#xff0c;维视智造携MV-CR读码相机、3D线激光相机、VisionBank AI多相机智能视觉系统等多款行业领先产品及解决方案亮相。 1 ►现场速击 …

C基础--内存对齐问题(结构体对齐)

问题现象 在调试一个软件功能时&#xff0c;发现一个结构体对齐的问题&#xff0c;以前没有太关注&#xff0c;现在把它总结出来。先看示例&#xff1a; 结构体1&#xff1a; typedef struct {char magic[4];uint32_t crc32;uint32_t lenght;uint16_t ver;uint16_t IFrameCnt…

多线程DPDK应用的内存优化

作者 Conor Walsh is a software engineering intern with the Architecture Team of Intel’s Network Platform Group (NPG), based in Intel Shannon (Ireland). 引言 高速包处理是一种资源密集型应用。一种解决方案是将包处理流水线(pipeline)分离到多线程以提高程序性能…

大一新生HTML期末作业,网页制作作业——海鲜餐饮网站登录页面(单页面)HTML+CSS+JavaScript

&#x1f468;‍&#x1f393;静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计&#x1f469;‍&#x1f393;,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等&#xff0c;用的最多的还是DW&#xff0c;当然不同软件写出的…

STM32G0开发笔记-Platformio+libopencm3-FreeRTOS和FreeModbus库使用

title: STM32G0开发笔记-Platformiolibopencm3-FreeRTOS和FreeModbus库使用 tags: STM32MCUSTM32G070libopencm3MonkeyPiFreeRTOSModbus categories: STM32 date: 2022-9-11 19:52:05 [原文&#xff1a;makerinchina.cn] 使用Platformio平台的libopencm3开发框架来开发STM32…

docker -- 入门篇 (数据卷、自定义镜像、安装mysql redis)

1 数据卷 采用上一章节创建的centos镜像启动容器 doc01 docker run -it --name doc01 lhy/centos:1.00 2 数据卷容器 启动子容器doc02 实现继承doc01的关系 docker run -it --name doc02 --volumes-from doc01 lhy/centos:1.00 启动子容器doc03 实现继承doc01的关系 docker…

【计算机毕业设计】病人跟踪治疗信息管理系统源码

一、系统截图&#xff08;需要演示视频可以私聊&#xff09; 摘 要 病人跟踪治疗信息管理系统采用B/S模式&#xff0c;促进了病人跟踪治疗信息管理系统的安全、快捷、高效的发展。传统的管理模式还处于手工处理阶段&#xff0c;管理效率极低&#xff0c;随着病人的不断增多&a…

mac pro M1(ARM)安装:安装zookeeper可视化工具PrettyZoo、ZooKeeperAssistant

0. 引言 今天安装zookeeper的可视化工具遇到一些问题&#xff0c;将其记录下来&#xff0c;以供后续的同学参考&#xff0c;在mac软件安装上少走弯路。同时也让大家体会下这两款不同的zk可视化工具的差别 1. 安装PrettyZoo 1、下载 直接在github上选择版本下载&#xff1a; …

8 - 复习总结java中的继承与多态

1. 继承 1.1 为什么需要继承 先看一个例子: 比如猫和狗都是动物&#xff0c;都可以用一个类来描述。 使用java语言来描述&#xff1a; class Cat{String name;int age;float wight;public void bark(){System.out.println(name"汪汪汪叫");}public void eat(){S…

PyTorch使用快速梯度符号攻击(FGSM)实现对抗性样本生成(附源码和数据集MNIST手写数字)

需要源码和数据集请点赞关注收藏后评论区留言或者私信~~~ 一、威胁模型 对抗性机器学习&#xff0c;意思是在训练的模型中添加细微的扰动最后会导致模型性能的巨大差异&#xff0c;接下来我们通过一个图像分类器上的示例来进行讲解&#xff0c;具体的说&#xff0c;会使用第一…