NeHe OpenGL教程 第三十课:碰撞检测

转自【翻译】NeHe OpenGL 教程

前言

声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改。对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢。

 

NeHe OpenGL第三十课:碰撞检测

碰撞检测:

这是一课激动的教程,你也许等待它多时了。你将学会碰撞剪裁,物理模拟太多的东西,慢慢期待吧。
 
碰撞检测和物理模拟(作者:Dimitrios Christopoulos (christop@fhw.gr))

碰撞检测

这是一个我遇到的最困难的题目,因为它没有一个简单的解决办法.对于每一个程序都有一种检测碰撞的方法.当然这里有一种蛮力,它适用于各种不同的应用,当它非常的费时.
我们将讲述一种算法,它非常的快,简单并易于扩展.下面我们来看看这个算法包含的内容:

1) 碰撞检测 
移动的球-平面 
移动的球-圆柱 
移动的球-移动的球 
2) 基于物理的建模 
碰撞表示 
应用重力加速度 
3) 特殊效果 
爆炸的表示,利用互交叉的公告板形式 
声音使用Windows声音库 
4) 关于代码 
代码被分为以下5个部分 
Lesson30.cpp   : 主程序代码l 
Image.cpp, Image.h : 加载图像 
Tmatrix.cpp, Tmatrix.h : 矩阵 
Tray.cpp, Tray.h : 射线 
Tvector.cpp, Tvector.h : 向量

1) 碰撞检测

我们使用射线来完成相关的算法,它的定义为:

射线上的点 = 射线的原点+ t * 射线的方向

t 用来描述它距离原点的位置,它的范围是[0, 无限远).

现在我们可以使用射线来计算它和平面以及圆柱的交点了。

射线和平面的碰撞检测:

平面被描述为:

Xn dot X = d

Xn 是平面的法线.
X 是平面上的一个点.
d 是平面到原点的距离.

现在我们得到射线和平面的两个方程:

PointOnRay = Raystart + t * Raydirection
Xn dot X = d

如果他们相交,则上诉方程组有解,如下所示:

Xn dot PointOnRay = d

(Xn dot Raystart) + t * (Xn dot Raydirection) = d

解得 t:

t = (d - Xn dot Raystart) / (Xn dot Raydirection)

t代表原点到与平面相交点的参数,把t带回原方程我们会得到与平面的碰撞点.如果Xn*Raydirection=0。则说明它与平面平行,则将不产生碰撞。如果t为负值,则说明交点在射线的相反方向,也不会产生碰撞。
  
//判断是否和平面相交,是则返回1,否则返回0int TestIntersionPlane(const Plane& plane,const TVector& position,const TVector& direction, double& lamda, TVector&

pNormal){
double DotProduct=direction.dot(plane._Normal);
double l2;

//判断是否平行于平面
if ((DotProduct<ZERO)&&(DotProduct>-ZERO)) 
return 0;

l2=(plane._Normal.dot(plane._Position-position))/DotProduct;

if (l2<-ZERO) 
return 0;

pNormal=plane._Normal;
lamda=l2;
return 1;
}

射线-圆柱的碰撞检测

计算射线和圆柱方程组得解。  
   
int TestIntersionCylinder(const Cylinder& cylinder,const TVector& position,const TVector& direction, double& lamda, TVector& pNormal,TVector& newposition)

球-球之间的碰撞检测

球被表示为中心和它的半径,决定两个球是否相交就是求出它们之间的距离是否小于它们的直径。

在处理两个移动的球是否相交时,有一个bug就是,当它们的移动速度太快,回出现它们相交,但在相邻的两步检测不出它们是否相交的情况,如下图所示:


有一个替代的办法就是细分相邻的时间片断,如果在这之间发生了碰撞,则确定有效。我们把这个细分时间段设置为3,代码如下:   
   
//判断球和球是否相交,是则返回1,否则返回0int FindBallCol(TVector& point, double& TimePoint, double Time2, int& BallNr1, int& BallNr2){ TVector RelativeV; TRay rays; double MyTime=0.0, Add=Time2/150.0, Timedummy=10000, Timedummy2=-1; TVector posi;  //判断球和球是否相交 for (int i=0;i<NrOfBalls-1;i++) {  for (int j=i+1;j<NrOfBalls;j++)  {       RelativeV=ArrayVel[i]-ArrayVel[j];   rays=TRay(OldPos[i],TVector::unit(RelativeV));   MyTime=0.0;
if ( (rays.dist(OldPos[j])) > 40) continue;

while (MyTime<Time2)
{
MyTime+=Add;
posi=OldPos[i]+RelativeV*MyTime;
if (posi.dist(OldPos[j])<=40) {
point=posi;
if (Timedummy>(MyTime-Add)) Timedummy=MyTime-Add;
BallNr1=i;
BallNr2=j;
break;
}

}
}

}

if (Timedummy!=10000) { TimePoint=Timedummy;
return 1;
}

return 0;
}

怎样应用我们的知识

现在我们已经可以决定射线和平面/圆柱的交点了,如下图所示:


当我们找到了碰撞位置后,下一步我们需要知道它是否发生在当前这一步中.如果距离碰撞点的位置小于这一步球体运动的间隔,则碰撞发生.我们使用如下的方程计算运动到碰撞时所需的时间:
Tc= Dsc*T / Dst 
接着我们知道碰撞点位置,如下面公式所示:
Collision point= Start + Velocity*Tc

2) 基于物理的模拟

碰撞反应

为了计算对于一个静止物体的碰撞,我们需要知道以下信息:碰撞点,碰撞法线,碰撞时间.

它是基于以下物理规律的,碰撞的入射角等于反射角.如下图所示:


R 为反射方向
I 为入射方向
N 为法线方向

反射方向有以下公式计算 :

R= 2*(-I dot N)*N + I 
  
rt2=ArrayVel[BallNr].mag();      // 返回速度向量的模
ArrayVel[BallNr].unit();      // 归一化速度向量

// 计算反射向量
ArrayVel[BallNr]=TVector::unit( (normal*(2*normal.dot(-ArrayVel[BallNr]))) + ArrayVel[BallNr] );
ArrayVel[BallNr]=ArrayVel[BallNr]*rt2;     

球体之间的碰撞

由于它很复杂,我们用下图来说明这个原理.  

U1和U2为速度向量,我们用X_Axis表示两个球中心连线的轴,U1X和U2X为U1和U2在这个轴上的分量。U1y和U2y为垂直于X_Axis轴的分量。M1和M2为两个球体的分量。V1和V2为碰撞后的速度,V1x,V1y,V2x,V2y为他们的分量。

在我们的例子里,所有球的质量都相等,解得方程为,在垂直轴上的速度不变,在X_Axis轴上互相交换速度。代码如下:
  
TVector pb1,pb2,xaxis,U1x,U1y,U2x,U2y,V1x,V1y,V2x,V2y;
double a,b;
pb1=OldPos[BallColNr1]+ArrayVel[BallColNr1]*BallTime;   // 球1的位置
pb2=OldPos[BallColNr2]+ArrayVel[BallColNr2]*BallTime;   // 球2的位置
xaxis=(pb2-pb1).unit();       // X-Axis轴
a=xaxis.dot(ArrayVel[BallColNr1]);     // X_Axis投影系数
U1x=xaxis*a;        // 计算在X_Axis轴上的速度
U1y=ArrayVel[BallColNr1]-U1x; // 计算在垂直轴上的速度
xaxis=(pb1-pb2).unit();       
b=xaxis.dot(ArrayVel[BallColNr2]);     
U2x=xaxis*b;        
U2y=ArrayVel[BallColNr2]-U2x;
V1x=(U1x+U2x-(U1x-U2x))*0.5;      // 计算新的速度
V2x=(U1x+U2x-(U2x-U1x))*0.5;
V1y=U1y;
V2y=U2y;
for (j=0;j<NrOfBalls;j++)      // 更新所有球的位置
ArrayPos[j]=OldPos[j]+ArrayVel[j]*BallTime;
ArrayVel[BallColNr1]=V1x+V1y;      // 设置新的速度
ArrayVel[BallColNr2]=V2x+V2y;      
   
万有引力的模拟

我们使用欧拉方程来模拟万有引力,如下所示: 
Velocity_New = Velovity_Old + Acceleration*TimeStep
Position_New = Position_Old + Velocity_New*TimeStep

在每次模拟中,我们用上面公式计算的速度取代旧的速度

3) 特殊效果

爆炸

最好的表示爆炸效果的就是使用两个互相垂直的平面,并使用alpha混合在窗口中显示它们。接着让alpha变为0,设定爆炸效果不可见。代码如下所示:  
   
// 渲染/混合爆炸效果
glEnable(GL_BLEND);       // 使用混合
glDepthMask(GL_FALSE);       // 禁用深度缓存
glBindTexture(GL_TEXTURE_2D, texture[1]);    // 设置纹理
for(i=0; i<20; i++)       // 渲染20个爆炸效果
{
 if(ExplosionArray[i]._Alpha>=0)
 {
  glPushMatrix();
  ExplosionArray[i]._Alpha-=0.01f;   // 设置alpha
  ExplosionArray[i]._Scale+=0.03f;   // 设置缩放
  // 设置颜色
  glColor4f(1,1,0,ExplosionArray[i]._Alpha);  
  glScalef(ExplosionArray[i]._Scale,ExplosionArray[i]._Scale,ExplosionArray[i]._Scale);
  // 设置位置
  glTranslatef((float)ExplosionArray[i]._Position.X()/ExplosionArray[i]._Scale,
   (float)ExplosionArray[i]._Position.Y()/ExplosionArray[i]._Scale,
   (float)ExplosionArray[i]._Position.Z()/ExplosionArray[i]._Scale);
  glCallList(dlist);     // 调用显示列表绘制爆炸效果
  glPopMatrix();
 }
}

声音

在Windows下我们简单的调用PlaySound()函数播放声音。

4) 代码的流程

如果你成功的读完了理论部分,在你开始运行程序并播放声音以前。我们将用伪代码向你介绍一些整个流程,以便你能成功的看懂代码。  
   
While (Timestep!=0)
{
 对每一个球
 {
  计算最近的与平面碰撞的位置;
  计算最近的与圆柱碰撞的位置;
  如果碰撞发生,则保存并替换最近的碰撞点;
 }
 检测各个球之间的碰撞;
 如果碰撞发生,则保存并替换最近的碰撞点;

 If (碰撞发生)
 {
  移动所有的球道碰撞点的时间;
  (We already have computed the point, normal and collision time.)
  计算碰撞后的效果;
  Timestep-=CollisonTime;
 }
 else
  移动所有的球体一步
}

下面是对上面伪代码的实现:
  
//模拟函数,计算碰撞检测和物理模拟void idle(){  double rt,rt2,rt4,lamda=10000;  TVector norm,uveloc;  TVector normal,point,time;  double RestTime,BallTime;  TVector Pos2;  int BallNr=0,dummy=0,BallColNr1,BallColNr2;  TVector Nc;
//如果没有锁定到球上,旋转摄像机
if (!hook_toball1)
{
camera_rotation+=0.1f;
if (camera_rotation>360)
camera_rotation=0;
}

RestTime=Time;
lamda=1000;

//计算重力加速度
for (int j=0;j<NrOfBalls;j++)
ArrayVel[j]+=accel*RestTime;

//如果在一步的模拟时间内(如果来不及计算,则跳过几步)
while (RestTime>ZERO)
{
lamda=10000;

//对于每个球,找到它们最近的碰撞点
for (int i=0;i<NrOfBalls;i++)
{
//计算新的位置和移动的距离
OldPos[i]=ArrayPos[i];
TVector::unit(ArrayVel[i],uveloc);
ArrayPos[i]=ArrayPos[i]+ArrayVel[i]*RestTime;
rt2=OldPos[i].dist(ArrayPos[i]);

//测试是否和墙面碰撞
if (TestIntersionPlane(pl1,OldPos[i],uveloc,rt,norm))

//计算碰撞的时间
rt4=rt*RestTime/rt2;

//如果小于当前保存的碰撞时间,则更新它
if (rt4<=lamda)

if (rt4<=RestTime+ZERO)
if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
{
normal=norm;
point=OldPos[i]+uveloc*rt;
lamda=rt4;
BallNr=i;
}
}
}

if (TestIntersionPlane(pl2,OldPos[i],uveloc,rt,norm))
{
rt4=rt*RestTime/rt2;

if (rt4<=lamda)

if (rt4<=RestTime+ZERO)
if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
{
normal=norm;
point=OldPos[i]+uveloc*rt;
lamda=rt4;
BallNr=i;
dummy=1;
}
}

}

if (TestIntersionPlane(pl3,OldPos[i],uveloc,rt,norm))
{
rt4=rt*RestTime/rt2;

if (rt4<=lamda)

if (rt4<=RestTime+ZERO)
if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
{
normal=norm;
point=OldPos[i]+uveloc*rt;
lamda=rt4;
BallNr=i;
}
}
}

if (TestIntersionPlane(pl4,OldPos[i],uveloc,rt,norm))
{
rt4=rt*RestTime/rt2;

if (rt4<=lamda)

if (rt4<=RestTime+ZERO)
if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
{
normal=norm;
point=OldPos[i]+uveloc*rt;
lamda=rt4;
BallNr=i;
}
}
}

if (TestIntersionPlane(pl5,OldPos[i],uveloc,rt,norm))
{
rt4=rt*RestTime/rt2;

if (rt4<=lamda)

if (rt4<=RestTime+ZERO)
if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
{
normal=norm;
point=OldPos[i]+uveloc*rt;
lamda=rt4;
BallNr=i;
}
}
}

//测试是否与三个圆柱相碰
if (TestIntersionCylinder(cyl1,OldPos[i],uveloc,rt,norm,Nc))
{
rt4=rt*RestTime/rt2;

if (rt4<=lamda)

if (rt4<=RestTime+ZERO)
if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
{
normal=norm;
point=Nc;
lamda=rt4;
BallNr=i;
}
}

}
if (TestIntersionCylinder(cyl2,OldPos[i],uveloc,rt,norm,Nc))
{
rt4=rt*RestTime/rt2;

if (rt4<=lamda)

if (rt4<=RestTime+ZERO)
if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
{
normal=norm;
point=Nc;
lamda=rt4;
BallNr=i;
}
}

}
if (TestIntersionCylinder(cyl3,OldPos[i],uveloc,rt,norm,Nc))
{
rt4=rt*RestTime/rt2;

if (rt4<=lamda)

if (rt4<=RestTime+ZERO)
if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
{
normal=norm;
point=Nc;
lamda=rt4;
BallNr=i;
}
}

}
}

//计算每个球之间的碰撞,如果碰撞时间小于与上面的碰撞,则替换它们
if (FindBallCol(Pos2,BallTime,RestTime,BallColNr1,BallColNr2))
{
if (sounds)
PlaySound("Data/Explode.wav",NULL,SND_FILENAME|SND_ASYNC);

if ( (lamda==10000) || (lamda>BallTime) )
{
RestTime=RestTime-BallTime;

TVector pb1,pb2,xaxis,U1x,U1y,U2x,U2y,V1x,V1y,V2x,V2y;
double a,b;

pb1=OldPos[BallColNr1]+ArrayVel[BallColNr1]*BallTime;
pb2=OldPos[BallColNr2]+ArrayVel[BallColNr2]*BallTime;
xaxis=(pb2-pb1).unit();

a=xaxis.dot(ArrayVel[BallColNr1]);
U1x=xaxis*a;
U1y=ArrayVel[BallColNr1]-U1x;

xaxis=(pb1-pb2).unit();
b=xaxis.dot(ArrayVel[BallColNr2]);
U2x=xaxis*b;
U2y=ArrayVel[BallColNr2]-U2x;

V1x=(U1x+U2x-(U1x-U2x))*0.5;
V2x=(U1x+U2x-(U2x-U1x))*0.5;
V1y=U1y;
V2y=U2y;

for (j=0;j<NrOfBalls;j++)
ArrayPos[j]=OldPos[j]+ArrayVel[j]*BallTime;

ArrayVel[BallColNr1]=V1x+V1y;
ArrayVel[BallColNr2]=V2x+V2y;

//Update explosion array
for(j=0;j<20;j++)
{
if (ExplosionArray[j]._Alpha<=0)
{
ExplosionArray[j]._Alpha=1;
ExplosionArray[j]._Position=ArrayPos[BallColNr1];
ExplosionArray[j]._Scale=1;
break;
}
}

continue;
}
}

//最后的测试,替换下次碰撞的时间,并更新爆炸效果的数组
if (lamda!=10000)

 RestTime-=lamda;

 for (j=0;j<NrOfBalls;j++)
  ArrayPos[j]=OldPos[j]+ArrayVel[j]*lamda;

 rt2=ArrayVel[BallNr].mag();
 ArrayVel[BallNr].unit();
 ArrayVel[BallNr]=TVector::unit( (normal*(2*normal.dot(-ArrayVel[BallNr]))) + ArrayVel[BallNr] );
 ArrayVel[BallNr]=ArrayVel[BallNr]*rt2;

 for(j=0;j<20;j++)
 {
  if (ExplosionArray[j]._Alpha<=0)
  {
   ExplosionArray[j]._Alpha=1;
   ExplosionArray[j]._Position=point;
   ExplosionArray[j]._Scale=1;
   break;
  }
 }
}
else
 RestTime=0;
}
}
原文及其个版本源代码下载:

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=30

没有整理与归纳的知识,一文不值!高度概括与梳理的知识,才是自己真正的知识与技能。 永远不要让自己的自由、好奇、充满创造力的想法被现实的框架所束缚,让创造力自由成长吧! 多花时间,关心他(她)人,正如别人所关心你的。理想的腾飞与实现,没有别人的支持与帮助,是万万不能的。







本文转自wenglabs博客园博客,原文链接:http://www.cnblogs.com/arxive/p/6239517.html,如需转载请自行联系原作者



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

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

相关文章

andorid手机电脑操作

之前一直使用androidscreencast在pc上对手机进行操作,好久都没用了,前些天再次用的时候,提演示样例如以下: 决定还是自己写一个吧,由于7月份要做一个小分享,打算讲一些android的东西,须要在电脑上显示手机这边的画面,提供一定的操作. 花了一点时间做好了,给大家截一个图,代码放…

在组策略中使用脚本为域用户添加网络打印机

使用脚本为用户添加网络打印机 如果你想让培训部门的用户登录后就能添加网络打印机&#xff0c;就可以使用登录脚本来实现。其中DCServer是域控制&#xff0c;MarketPC1是市场部门的计算机&#xff0c;韩立辉用户是培训部门的用户。下面就验证使用组策略为培训部门的用户添加网…

为什么我从 Git Flow 开发模式切换到了 Trunk Based 开发模式?

我已经使用 Git Flow 构建我的 Git 分支有几年了。但是&#xff0c;我遇到了 Git Flow 的一些问题&#xff0c;其中大部分来自长期存在的分支。解决这些问题的方案就是 Trunk Based Development。这是一个非常简单的技术&#xff0c;也是有效的持续交付的基础。在这篇文章中&am…

DedeCMS 提示信息! ----------dede_addonarticle

把数据保存到数据库附加表 dede_addonarticle 时出错&#xff0c;请把相关信息提交给DedeCms官方。Duplicate entry ’2532′ for key ‘PRIMARY’出现这种情况其实是你的主键是不可重复的&#xff0c;现在重复插入值为2532的主键了。可以去掉主键唯一&#xff0c;或是设成自增…

搭建基于.NetFrameWork的私有nuget服务端及打包项目发布上传

一、私有Nuget服务端搭建 1.创建一个.NetFramework web项目 2.在nuget管理中 安装 nuget.server包 3.安装完成后修改web.config里面的 apikey 和 packagesPath apikey&#xff1a;推送包到nuget服务端 packpage: 上传上来的包存放的服务器位置 4.发布web项目到IIS中&#xff0c…

linux 网络配置 阮一峰,Vim 配置入门

Vim 是最重要的编辑器之一&#xff0c;主要有下面几个优点。可以不使用鼠标&#xff0c;完全用键盘操作。系统资源占用小&#xff0c;打开大文件毫无压力。键盘命令变成肌肉记忆以后&#xff0c;操作速度极快。服务器默认都安装 Vi 或 Vim。Vim 的配置不太容易&#xff0c;它有…

Linux 文件区块连续吗,关于Linux文件系统的的简单理解和认识

关于Linux文件系统的的简单理解和认识关于文件系统的运作&#xff0c;这与操作系统带的档案数据有关。例如Linux操作系统的档案权限(rwx)与文件属性(拥有者&#xff0c;群组&#xff0c;时间参数等)。文件系统通常会将这两部分的数据分别存放在不同的区块&#xff0c;权限与属性…

Microsoft Desktop Virtualization

基本上有两套啦&#xff0c;一是大家较为熟悉的MED-V。另外就是VDI(虚拟桌面基础架构)&#xff0c;也就是以下的组合&#xff1a;1、Windows Server 2008 with Hyper-V 2、System Center Virtual Machine Manager (VMM) 2008 VMM 20083、Windows Vista Enterprise Centralized …

签入在服务器上之后,别人获取了,在解决方案资源管理器中找不到。

签入在服务器上之后&#xff0c;别人获取了&#xff0c;在解决方案资源管理器中找不到。 这个问题具体原因我也不太清楚&#xff0c;但是我找到了一个解决方案。直接在解决方案上右键&#xff0c;添加&#xff0c;添加现有项。把在解决方案资源管理器上看不见的选中&#xff0c…

03JavaScript程序设计修炼之道-2019-06-20_20-31-49

## DomDocument object model 文档对象模型Dom树html|head body| |meta title div|ul|li li li在js世界中&#xff0c;把dom树的每个元素都看成一个对象&#xff0c;对象就有属性和方法dom学什么 dom节点操作 查找元素 元素增删改查 样式操作 事件绑定等## 事件三要素 1 事件源…

linux 独占 cpu,宋宝华:谈一谈Linux让实时 高性能任务独占CPU的事

本文主要讨论在高实时要求、高效能计算、DPDK等领域&#xff0c;Linux如何让某一个线程排他性独占CPU&#xff1b;独占CPU涉及的线程、中断隔离原理&#xff1b;以及如何在排他性独占的状况下&#xff0c;甚至让系统的timer tick也不打断独占任务&#xff0c;从而实现最低的延迟…

linux update语句,MySQL 多表 update sql语句总结

MySQL 多表 update 有几种不同的写法。假定我们有两张表&#xff0c;一张表为Product表存放产品信息&#xff0c;其中有产品价格列Price&#xff1b;另外一张表是ProductPrice表&#xff0c;我们要将ProductPrice表中的价格字段Price更新为Price表中价格字段的80%。在Mysql中我…

linux延时与定时操作

1、at ---系统延迟任务发起命令 at time >command ---任务指令 >ctrld ---发起任务 at -l ---列出延时任务Id at -r id ---删除改id任务 at -m ---让无输出的命令产生邮件 at -M ---让有输…

Windows Server 2008 部署权限管理RMS

1.1 实战&#xff1a;部署权限管理 试验目的&#xff1a; 在单域环境中部署活动目录权限管理服务&#xff0c;实现文档的保护。 试验环境&#xff1a; ? DCServer安装Windows Server 2008企业版&#xff0c;是ess.com的域控制器&#xff0c;安装企业CA。 ? RMSServer安装Wind…

编写一个字节数的rtu C语言校验程序,Modbus通信协议中CRC校验的快速C语言算法

Modbus通信协议中CRC校验的快速C语言算法2004年第11期            福 建 电 脑  63Modbus通信协议中CRC校验的快速C语言算法孟开元(西安石油大学计算机学院陕西西安710065)【摘 要】 本文主要讨论了Modbus通信协议的RTU帧格式中常用的错误校验方法,即循环冗…

如何让CloudStack使用KVM创建Windows实例成功识别并挂载数据盘

问题产生背景&#xff1a; 使用CloudStack KVM组合进行资源池纳管工作&#xff0c;通过ISO镜像文件创建了两个模板&#xff1a; RHEL6U3 64位系统以及WindowsServer2008 R2 SP1 64位系统。然后通过模板创建实例&#xff0c;挂载外接存储&#xff0c;实例启动后&#xff0c;通过…

云计算openstack介绍

转载于:https://www.cnblogs.com/WIU1905/p/11107593.html

**加密解密基础、PKI及SSL、创建私有CA**

进程间通信 socket通信 客户端-->请求--> 路由转发 --> 服务端&#xff0c;取出资源 --> 封装为可响应给客户端的请求报文从接收请求端口发出 SSL/TLS协议的实现 OpenSSL OpenSSL程序组件 1234[rootlocalhost CA]# rpm -ql openssl /usr/lib/libcrypto.so.10 //加…

5.3 上午

观看英语课程——《恋练有词》 学习Linux 转载于:https://www.cnblogs.com/bgd140206110/p/6801164.html

mysql索引随记

为什么80%的码农都做不了架构师&#xff1f;>>> 先了解下Btree&#xff1a;https://my.oschina.net/u/3646190/blog/1593094 为什么每个数据项&#xff0c;即索引字段要尽量的小&#xff0c;比如int占4字节&#xff0c;要比bigint8字节少一半&#xff1f; 通过上面…