matlab z变换离散化_用C++编写一个简单的光栅化渲染器:3D篇

6700118cae83a0542b520d671a3caa95.png

3D光栅化与2D光栅化在图元绘制方面差别并不大,3D光栅化主要是多了很多坐标系(Local,world,View...),除此外遮挡算法和裁剪算法也会稍微复杂一些。

本篇文章的重点就主要集中在各种坐标系变换上。

1.基本3D变换

本文所采用的向量(vector)表示为行主序(Row Major),向量与矩阵(matrix)相乘方式为左乘(left or pre-multiplication),向量与矩阵相乘表示如下:

cc53cd7e9b860718bb72f5998df59fdf.png

a.缩放变换(Scale)

缩放变换即对一个三维向量的x,y,z分量分别进行缩放,三维向量a在x,y,z方向上进行缩放操作可以表示为:

b8e745180cd3cea7e53635d360b7e0a6.png

考虑到使用向量和矩阵相乘实现缩放变换,可知:

4a76307c04ea26dd797d41643f12d3c4.png

可以得出

,则缩放变换的矩阵表示形式为:

34da42faa7c9739101d1118b6bf06185.png

缩放变换的逆变换的矩阵表示形式为:

a7783d0da19ca25d321a4aeca05bcdc7.png

b.旋转变换(Rotation)

97843b177fac52b2f1e7f9caf33f8c48.png
向量v以单位向量n为轴旋转

如上图,向量

以单位向量
为轴旋转角度
,得到旋转后的向量
之间的夹角为
方向上的投影向量,则旋转后向量
可以表示为:

29ff3cc3a3bf55d59cde1631137ab0c7.png

,则:

43dcfbd93e6aebb71abf757fad7a24d0.png

将上式中的参数带入到矩阵中即可到旋转变换的矩阵表示:

681f9630ff0686f781a48457caeaaaf3.png

由于

为正交矩阵(各行,各列为单位向量,且两两正交),因此
,旋转变换的逆变换为:

1a516073824c28c1d1bffe87a75a2edc.png

特别地,当

为x,y,z轴时(即:
),旋转矩阵分别为:

c4f33c4671cf06640a41356988d6ad77.png

c.平移(Translation)

3D空间中的点和向量都可以用三维向量表示,前面所介绍的缩放和旋转变换对向量都适用,但平移变换对向量并无意义(平移后的向量与原向量完全相同),然而3D空间中的点却可适用平移变换。为了区分点和向量,同时一致地对它们进行表示,我们可以采用齐次坐标(homogeneous coordinates),即:

  • 当表示向量时其坐标为:
  • 当表示点时其坐标为:

使用齐次做表时对应的缩放和旋转矩阵为(齐次坐标为1x4向量,应与4x4矩阵相乘,矩阵第四列为[0,0,0,1],保证相乘后点和向量的w分量保持不变):

c8c43bf929b8877ac9ada15217716a98.png

对空间中一点

施加平移变换
可表示为:

46e2c076818fbba3c5f224dd38a807f5.png

由矩阵和向量相乘运算规则可以知:

,
,
。因此平移变换的矩阵表示为:

8f2a19530c2944f86b9afc97b2d9d31a.png

平移变换的逆变换矩阵表示形式为:

98b16386f25614fc4465bcf78635eebb.png

d.基本变换组合

可以将三种基本变换组合起来表示更复杂的变换,如:

表示对点
先后进行缩放,旋转和平移变换,但不同组合顺序的基本变换会得到完全不同的复杂变换。

已知点

,缩放变换
(x,y,z分量分别缩放7,5,3),旋转变换
(绕y轴旋转45度)和
(沿x,y,z方向分别平移6,2,4),则对点
施加
变换后得到点
,对点
施加
则得到的点
。因此在组合基本变换时需要注意运算顺序,本文采用的组合顺序为
(先缩放,然后旋转,最后平移)。

2.3D坐标系变换

本文采用的坐标系规范与DirectX相同(左手坐标系),如下图所示:

b260d4c59610da4a27fb0c43677b092e.png

已知坐标系A和坐标系B,坐标系B的x,y,z轴在坐标系A下可表示为

,坐标系B的原点在坐标系A下表示为

88f5c167610d746c29e7569e544610d0.png
坐标系A与B

则将坐标系B中一点

从坐标系B变换到坐标系A的变换矩阵为:

031820ed202460205826251439d7fd88.png

变换过程中点

在空间中的位置并没有发生改变,只是参考坐标系发生了改变,从B坐标系变到A坐标系。(缩放,旋转,平移变换只有在同一坐标系下才有意义。)

a. 本地空间(Local Space,Local Coordinate System)

3D渲染中用到的每个模型都有自己的本地坐标系,因为每个模型都在独立的坐标系中进行建模,所以本地坐标系也被称为模型坐标系(model space)。使用本地坐标系有如下好处:

  • 建模更加方便,每个模型在自己的本地空间的中央进行建模,不同模型之间互不干扰。
  • 建好的模型可以被应用到多个场景(多个不同坐标系中),而不用对模型做任何改动。
  • 有利于大规模的重复的实例绘制(instance)。

b. 世界空间(World Space,World Coordinate System)

在本地坐标系中建好的模型都会经过缩放,旋转,平移等操作后变换到世界坐标系中的不同位置构成渲染场景。

模型一开始放置在世界坐标系中时,其本地坐标系与世界坐标系重合,经过一系列缩放,旋转,平移变换后被放置在世界坐标系中的适当位置构成渲染场景,经过变换后的Local Space的x,y,z轴及原点在World Space下表示为

。则从本地坐标系到世界坐标系的世界变换
可以表示为:

3902cf18d7b383ec4c15f14405048c0e.png

可以通过世界变换将本地坐标系中的点转换到世界坐标系中,即

c. 观察空间(View Space,View Coordinate System)

eac95eb748a6aed58059ac7ec62f073e.png
view space与view volume

有了场景之后,还需要在场景中放置一个虚拟的摄像机才能在场景中实现漫游,以摄像机的角度来观察游戏场景。此时可以为摄像机附加一个坐标系,相机所看的方向为坐标系z轴,x轴指向相机的右侧,y轴指向相机的上方,这个附加在相机上的坐标系即为观察坐标系(相机坐标系)。

相机能够将可视范围内的3D场景转化为2D图像(不在view volume内的物体可以直接剔除)。

若观察坐标系的x,y,z轴以及原点在世界坐标系下可以表示为:

,则可以得到从观察坐标系到世界坐标系的变换
:

007b11705e43857e74536ddfd187bef4.png

但我们需要的是观察坐标系到世界坐标系的逆变换,即世界坐标系到观察坐标系的变换

。而从世界坐标系到观察坐标系的变换只涉及到旋转和平移变换,则
又可以表示为
。因此从世界坐标系到观察坐标系的变换
可以表示为:

21fdba52d085a3893041fe37373dc67c.png

d. 齐次裁剪空间与归一化设备坐标系(Homogeneous Clip Space and Normalized Device Coordinates)

现在需要将相机可视范围内的物体投影到2D平面上,相机的可视范围可以用一个处于近平面(near plane)与远平面(far plane)之间的平截棱锥(view frustum)表示:

e42c9e05fbf0e320acb02a7da699a1b3.png
View frustum

这里采用view frustum的near plane作为投影平面,由于从3D场景投影转换为2D图像后会损失一个维度,因此在投影过程中还需要保留物体在view space中的z值来判断物体之间的遮挡关系。如下图:

0a14eebcc21e20c6c4a80dbbf4a7c18c.png
需要深度值z来判断空间中点的遮挡关系

空间中的两点p0,p1经过投影后都位于near plane上的q点,需要根据p0,p1在view space中的深度值(z值)来判断应该绘制p0还是p1点。因为需要保存深度值到缓存中,并根据深度值来判断空间物体遮挡关系,这种遮挡算法就被称为z-buffer。

PS:虽然原理上是使用View Space的z值进行遮挡判断,但其实DirectX的z-buffer里存储的是NDC Space的z值。z-buffer是单通道的图片,可以用一个Image<float>对象表示。

1dec75a334f3ba361151b8ee9b8389c6.png
View volume变换到CVV

投影的同时还需要对穿过view frustum的图元进行裁剪,为了方便裁剪,可以将view frustum变换成为一个长方体,这样就可以更快捷的判断图元与view frustum的关系。经过变换后的view frustum被称为canonical view volume(CVV)。处在CVV内的点

满足一下关系:

经过变换后CVV所处的坐标系就被称为归一化坐标系(Normalized Device Coordinates,NDC)(裁剪,投影都是在这一变换过程中进行的)。

8cbba1b52e58ec1e45336c23c79a8e28.png
将View space内的点p投影到near plane上

已知View space中的一点

,要将其投影到near plane(
)上,投影到2D平面后的点为
,且near plane的宽度和高度分别为
,由几何关系可知:

投影后的点

位于near plane内,因此满足:

经过以下变换后可满足CVV内点坐标的要求:

由于以上变换为非线性变换的,因此无法用矩阵表示,可以将上诉变换拆分为两个部分:线性部分和非线性部分,非线性部分表示为除以

(透视除法)。这时将点
变换到CVV内点
的变换
可以表示为:

494950332a93e398e93bd01f57d630a5.png

CVV内点

可以表示为 :

现在还需要将点

坐标变换到CVV坐标范围内,位于view volume点
坐标满足 :

经过变换

变换到NDC空间后的点
的坐标满足:

由矩阵与向量运算规则可知:

则:

可以解出

因此变换矩阵

可以表示为:

752ada19c789fdcc85dfb05fe49b668a.png

PS:投影矩阵还有其他推导和表示形式,使用参数不同但效果相同。

整个投影变换包含两个部分:

  • (透视除法)

若投影变换前的点

的深度值(z)为0,则进行透视除法时会出现除0的情况,为了避免除0,必须在透视除法之前对穿过w=0平面的图元进行裁剪,而在透视除法之前的空间就被称为
齐次裁剪空间

在齐次裁剪空间中位于view frustum内的点

满足:

由于每个顶点的z值不同,所以图元中每个顶点在齐次裁剪空间中的clip volume大小也完全不同。

e. 屏幕空间(Screen Space)

最后位于view frustum内的图元经过了前面一系列变换后,将会被变换到屏幕空间(2D坐标系)中进行光栅化。此坐标系与上一篇2D光栅化所使用的屏幕空间坐标系相同:

aa398ccb1ddd73a484c7f5d5bcaea17d.png

此2D坐标系以Viewport左上角为原点,处于Viewport中的点

的坐标范围为:

可以通过如下变换将NDC空间内的点

变换到屏幕空间中(由于screen space的y轴与NDC space 的y轴相反,所以需要反转y轴):

f. 坐标系变换总览

cdd67ce4b7256db3299679614b83dbbd.png

3. 3D光栅化

3D光栅化发生在图元被变换到Screen space之后,因为这里的Screen space与2D的Screen Space完全一致,所以2D的光栅化算法在这里也依然适用。

然而由于图元经过了投影变换,且投影变换为非线性变换,所以不能用简单的线性插值来获取fragment的属性。

39176a7d0e7e2efc5dc977f1850abc4d.png
投影变换不会保持相对距离不变性

如上图所示,view space中的线段v0v1上两点

在near plane上的投影为点
中间一点
在near plane上的投影为点
。从图中可以看出点v到p0,p1的距离比值与点q到s0,s1的距离比值完全不同,投影变换不保持距离不变。

为了执行z-buffer算法,需要通过点

获取到点
的深度值(z)。

的深度值可以通过如下方法插值得到:

证明如下:

由于点

为点
在near plane上的投影,因此点
与点
的关系为:

位于
之间,则:
  • 式(1)

由点

之间, 点
之间则有:

带入式(1)可得:

式(2)

又s0和s1分别为p0和p1在near plane上的投影,则:

带入式(2)可得:

化简得:

则:

带入式(1)可得:

则若View space中三角形

,变换到Screen Space后为三角形
内一点
在Screen Space的投影为
内的点
,对三角形
内的点(fragment)
,可以通过如下方法取得fragment
在View Space中对应的深度值:

为点
在三角形
内的重心坐标。

执行z-buffer算法时,若当前光栅化的点

(fragment or pixel)的深度值小于z-buffe中点
处对应位置的深度值,则当前光栅化的点未被遮挡,可以将点
的深度值写入到z-buffer,并对
进行着色 (shading)操作。

在对点进行shading时还需要点的其他属性值(纹理坐标,点的颜色,法线等...)

9028d9d711bc028802f3e4ac21768ee4.png

如上图已知view space中,三角形两边上两点

对应深度值和属性值分别为
,则线段
内一点
的深度值和属性值为
,由线性插值可知深度值与属性值存在的关系为:

式(3)

且点

的深度值与
的深度值存在的关系为:

带入式(3)可得:

则 :

可得对Screen space三角形

内一点
的任意属性插值的公式为:

为点
的重心坐标,
分别为
在view space中对应点的深度值。

PS:可以用这个方法插值得到

在NDC Space内对应点的深度值。

整个3D光栅化算法可以由如下伪代码表示:

// Local space
Triangle tri;// *W ,变换到World Space
TransformToWorldSpace(tri, W);// *V ,变换到View Space
TransformToViewSpace(tri, V);// *P ,变换到Homogeneous Clip Space
TransformToHomogeneousClipSpace(tri, P);// 在Homogeneous Clip Space进行裁剪和剔除
Clip(tri);// 除以w分量 ,经过透视除法后变换到NDC Space
PerspectiveDivide(tri);// 获取三角形顶点在Screen Space中的坐标
screen_space_triangle = GetScreenSpacePositon(tri);// 进入Screen Space后就可以同2D一样可以采用Half-Space光栅化算法
{//获取Screen Space三角形的包围盒GetBoundingBox(screen_space_triangle, box_min, box_max);//遍历包围盒中的fragmentfor (fragment(or pixel) in BoundingBox){//用PrepDotP判断fragment是否在三角形中,if (fragment in screen_space_triangle){//若fragment在三角形中,则计算fragment的重心坐标用于插值GetBarycentricCoordinates(λ0, λ1, λ2);//插值获得fragment在View Space中的深度值view_z = GetViewSpaceZ();//再次插值获得fragment在NDC Space中的深度值ndc_z = GetNDCSpaceZ(view_z);//若当前光栅化的fragment的深度值小于Z-Buffer中对应位置的fragment的深度值,则当前fragment未被遮挡if (ndc_z < ZBuffer(fragment.pos)){//插值当前fragment的属性(normal,uv...)InterpolatedAttributes(fragment);//着色Shading(fragment);}}}
}

光栅化部分的代码可以参考2D光栅化篇。


4. 3D裁剪

3D裁剪发生在齐次裁剪空间。齐次裁剪空间中CVV内的点需要满足一下要求:

可以在裁剪之前对不在CVV内的三角形直接剔除(三个顶点均不在CVV内),只需要对穿过CVV的三角形进行裁剪(裁剪方法与2D裁剪相似)。

CVV由6个面组成(left,right,top,bottom,near,far),每个面将空间分为两个区域,因此可以用6bit二进制编码对这些区域进行编码。对齐次裁剪空间内一点

,若:
  • ,则点在left裁剪平面外侧,第一位编码为1;
  • ,则点在right裁剪平面外侧,第二位编码为1;
  • ,则点在bottom裁剪平面外侧,第三位编码为1;
  • ,则点在top裁剪平面外侧,第四位编码为1;
  • ,则点在near裁剪平面外侧,第五位编码为1;
  • ,则点在far裁剪平面外侧,第六位编码为1;

对三角形进行裁剪时,先根据三角形三个顶点的Clip Code判断三角形与裁剪平面的关系,然后再采用Sutherland–Hodgman算法对三角形进行裁剪。

若采用Half-Space光栅化算法则只需要对near裁剪平面进行裁剪即可(防止透视除法时除0,在near plane上的点w=camera space z=near。由于Half-Space算法只处理三角形包围盒与Viewport交集内的fragment,所以left,right,top,bottom裁剪平面可以不做处理)。

对齐次裁剪空间内的线段

若其穿过near裁剪平面,则其与near裁剪平面的交点
满足:

即:

由于

位于near裁剪平面上,有
,可以求出
,进而求出交点
的坐标。

下面给出使用Sutherland–Hodgman算法对穿过near plane的三角形进行裁剪的代码(Sutherland–Hodgman的介绍可以参考2D篇):

void 

其他裁剪平面的处理与near plane相似(更完整的裁剪代码可以参考我的光栅化项目)


63ba6d1f587ff8a0a8d243992d3b4496.gif

到这里为止整个3D光栅化的流程也就结束了,有了fragment插值后的属性即可进行光照着色,渲染相关的内容这里就不再提及了。

Tips1:背面剔除(Backface Culling)

根据使用的光栅化算法的不同可以选择在不用的坐标系中进行背面剔除。

如果使用Scan-Line算法,则可以在齐次裁剪空间或者NDC Space进行背面剔除,在这两个空间中是以相机观察方向为z轴。可以用叉乘求出三角形的面法线,然后用面法线和z轴做点乘,判断三角形面是否为背面。

若使用Half-Space算法,则可以在转换到Screen Space之后,光栅化之前做背面剔除。可以使用PrepDotP(Edge Function)求三角形的面积,当顶点为顺时针时则PrepDotP大于

0,逆时针则小于0。可以借此判断三角形是否为背面。

1d0e6755ecff0086b4f52d335fe5b62c.png
三角形顶点顺时针和逆时针排列时PrepDotP的结果不同。

Tips2:Top-Left rule

对于有共享边的相邻三角形,会对共享边进行重复光栅化。

eb7295d65e3e832b62d59f3aa46b0c56.png
共享边会重复光栅化

为了解决共享边的重复绘制,可以采用Top-Left rule,对三角形的top边和Left边不进行光栅化。

0f0deab7ba05fa5ed66bdb9cf88fe646.png
Screen Space y轴向下

对三角形的任意一条边V[i]V[(i+1)%3],若:

  • V[(i+1)%3].x-V[i].x >0 且 V[(i+1)%3].y-V[i].y = 0则为top edge(如第二个三角形的v2v0边)。
  • V[(i+1)%3].y-V[i].y < 0则为left edge。

Top-Left rule可以和PrepDotP结合起来判断是否应该对当前的fragment进行光栅化(fragment 在三角形内,且不为top or left edge)。

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

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

相关文章

Catalan数列

引入 今天听学长讲了卡特兰数列后对其有了更深的认识&#xff0c;在此完善了一下之前的博客加以总结。 首先用一个经典的例子来描述一下Catalan数列&#xff0c;我们有一个1~n的数列和一个大小为n的栈&#xff0c;我们有如下两种操作&#xff1a; 当未入栈序列不为空时&#xf…

计算机和外部通信方式,计算机和外部的通信方式

计算机和外部交换信息又称为通信(Communication)。按数据传送方式分为并行通信和串行通信两种基本方式。1、并行通信并行通信就是把传送数据的n位数用n条传输线同时传送。其优点是传送速度快、信息率高。并且&#xff0c;通常只要提供二条控制和状态线&#xff0c;就能完成CPU和…

stm32入门之keil5的安装以及第一个工程的建立

摘自&#xff1a;stm32入门之keil5的安装以及第一个工程的建立 作者&#xff1a;SKY丶丿平才 发布时间&#xff1a; 2020-12-06 17:08:30 网址&#xff1a;https://blog.csdn.net/weixin_48264057/article/details/110734596 文章目录 前言一、keil5的下载与安装1.下载相关链接…

微信电脑客户端_无聊的话,用微信玩玩电脑

被禁足的2020注定是让人印象深刻的一年如果现在你很无聊来试试用微信玩玩电脑看能否给这不出门就是做贡献的日子带来一点乐趣开启步骤1、在能使用(接触的)的电脑上安装上Hipc在电脑访问 hipc.cn下载PC客户端(仅2M左右大小)2、安装PC客户端3、微信扫一扫绑定现在看看如何用微信玩…

epic堡垒之夜显示服务器离线,堡垒之夜epic服务器进不去 | 手游网游页游攻略大全...

发布时间&#xff1a;2017-12-19堡垒之夜开国服了,那么有的小伙伴就发现自己的国服为什么进不去,下面牛游戏小编就为你们带来了堡垒之夜国服进不去的解决办法,想了解的小伙伴就一起来看看吧,希望能对你们有帮助. 解决办法如下: 1.重新下载并安装游戏,下载前关 ...标签&#xff…

动态加载 回显_ElementUI cascader级联动态加载及回显

先看图&#xff0c;你是否也遇到这个需求&#xff1f;如果你正在焦头烂额&#xff0c;无脑抓瞎&#xff0c;那么你来对地方了&#xff0c;因为我将给你一个简单易懂的实现方案。我也在网上翻了无数页答案&#xff0c;也照着别人的代码和思路尝试了&#xff0c;事实上并不能解决…

单片机的四种烧写方式

参考&#xff1a;单片机的四种烧写方式 作者&#xff1a;爱学习的小王呀 发布时间&#xff1a;2020-11-27 20:05:12 网址&#xff1a;https://blog.csdn.net/hongliwong/article/details/110245095?spm1001.2014.3001.5501 参考&#xff1a;单片机3种烧录方式解析 作者&#x…

关于驰骋表单引擎中字段扩展设置对文本框Pop窗体返回值的升级说明 2012/11/13...

为什么80%的码农都做不了架构师&#xff1f;>>> 关于驰骋表单引擎中字段扩展设置对文本框Pop窗体返回值的升级说明 2012/11/13 现有功能: 以前版本仅支持自己定义url&#xff0c;返回值到文本框上. 升级功能: 1, 增加了可以自己定义数据源模式&#xff0c;数据源可…

中兴f650 2.0.3 固件降级_手机资讯:如何升级iOS12.1.4正式版iOS12.1.4正式版升降级教程...

如今使用IT数码设备的小伙伴们是越来越多了&#xff0c;那么IT数码设备当中是有很多知识的&#xff0c;这些知识很多小伙伴一般都是不知道的&#xff0c;就好比最近就有很多小伙伴们想要知道如何升级正式版正式版升降级教程&#xff0c;那么既然现在大家对于如何升级正式版正式…

C# 加密解密类

一. MD5 1 防止看到明文 数据库密码&#xff0c;加盐(原密码固定字符串&#xff0c;然后再MD5/双MD5) 2 防篡改 3 急速秒传(第一次上传文件&#xff0c;保存md5摘要&#xff0c;第二次上传检查md5摘要) 4文件下载(防篡改&#xff0c;官方发布的时候给一个md5摘要&#xf…

请求solr服务器未响应,solr与tomcat整合

一、准备工作&#xff1a;我使用的是tomcat7.0,solr-4.8.1solr-4.8.1解压后是这样的。二、开始配置了1、首先要创建两个文件夹。home和server。我是创建在与solr-4.8.1同一根目录上的。D:\work-tool\server\solr\home和D:\work-tool\server\solr\server2、从solr-4.8.1\dist复制…

WeMos下实现小车避障与手机控制

参考&#xff1a;WeMos下实现小车避障与手机控制 作者&#xff1a;爱学习的小王呀 发布时间&#xff1a;2020-10-02 10:17:45 网址&#xff1a;https://blog.csdn.net/hongliwong/article/details/108900048?spm1001.2014.3001.5501 目录前言一、项目软硬件平台及开发环境1.硬…

苹果手机耗电快_iPhone12用5G耗电快,苹果回应

原标题&#xff1a;iPhone12用5G耗电快&#xff0c;苹果回应北京头条客户端10月24日消息&#xff0c;针对有媒体测试苹果iPhone12开启5G模式下&#xff0c;用电量提升的问题&#xff0c;苹果iPhone营销副总裁Kaiann Drance回应称&#xff0c;iPhone12 增加的智能数据模式可以平…

Ubuntu12 10下安装JDK7

为什么80%的码农都做不了架构师&#xff1f;>>> Ubuntu12 10版本下&#xff0c;不再预装JDK&#xff0c;包括OpenJdk&#xff0c;所以我们要从Oracle官网上下载java7的压缩包&#xff0c;选择适合自己电脑的安装包&#xff0c;我选的是jdk-7u9-linux-i586.tar.gz。…

neo4j python 算法_python操作neo4j简单实例

一&#xff1a;neo4j是什么neo4j:Neo4j是一个高性能的,NOSQL图形数据库,有关于更多neo4j的资料出门右拐二:python操作neo4j的实现python中neo4j的操作可以利用驱动包或者py2neo包&#xff0c;我采用py2neo第三方包实现以下简单功能&#xff0c;先建立一个neo4j的链接对于neo4j的…

尚硅谷的 ediary 笔记_干货分享 | 硅谷创新加速营第五讲教您合理规划融资需求 降低投资风险...

5月26日上午&#xff0c;康佳之星携手青岛蓝谷管理局、斯坦福青岛研究院、海尔海创汇联合举办的第二届硅谷创新加速营第五讲顺利完成。斯坦福青岛研究院董事长的Claude Leglise先生做客直播间&#xff0c;为现场创业者、企业家讲授创业之路必修课&#xff1a;企业财务规划。本讲…

虚拟机的服务器黑屏,VMware Workstation 14运行虚拟机黑屏解决办法

VMware Workstation 14运行虚拟机黑屏解决办法升级到VMware workstation 14 pro后所有虚拟系统全部黑屏&#xff0c;VMware 14 黑屏&#xff0c;VMware Workstation 14运行虚拟机黑屏是什么原因步骤如下&#xff0c;步骤如下&#xff0c;1、以管理员身份运行命令提示符(cmd.exe…

c++ 冒泡排序_干货|python笔记1-冒泡排序

面试的时候经常有面试官喜欢问如何进行冒泡排序&#xff1f;这个问题相信可以难倒一批的同学&#xff0c;本篇就详细讲解如何用python进行冒泡排序。基本原理01概念&#xff1a;冒泡排序是一种交换排序&#xff0c;它的基本思想是&#xff1a;两两比较相邻记录的关键字&#xf…

双链表嵌套的简单学生信息管理系统

参考&#xff1a;实现双链表嵌套的简单学生信息管理 作者&#xff1a;三速何时sub20 发布时间&#xff1a; 2020-07-20 10:44:40 网址&#xff1a;https://blog.csdn.net/weixin_44234294/article/details/107458155?spm1001.2014.3001.5501 参考&#xff1a;双链表嵌套实现简…

scrapy如何指定生成python3的项目_如何把阿里图标库的图标生成代码并应用于自己的项目...

有时候需要用很多图标去完成一定的页面效果和工作展现&#xff0c;框架内置的图标可能满足不了我们的需求&#xff0c;有个很好的图标库想必大家都知道-----就是阿里图标库。那么我们如何才能够把阿狸图标库的图标引用到自己的项目中呢&#xff1f;耐着性子往下看吧&#xff01…