[Rotation Transform] 旋转变换
[Rotation Transform] 旋转变换
- 旋转矩阵
- 绕当前坐标系指定轴的变换矩阵
- 给定欧拉角的变换
- 欧拉角表示旋转的缺点
- 四元数与旋转
- 旋转顺序的验证
- Shader中的方向变换
- 法线变换
这篇文章纪录一些关于旋转变换的知识,和Unity引擎中的旋转相关API。
游戏中对Transform的变换通常包含平移旋转与缩放,常用的旋转变换有旋转矩阵和四元数两种。
旋转矩阵
绕当前坐标系指定轴的变换矩阵
一个对向量进行位移旋转缩放的复合变换的矩阵可以表示成以下形式:
P n e w = M t r a n s l a t i o n M r o t a t i o n M s c a l e P o l d {P_{new}} = {M_{translation}}{M_{rotation}}{M_{scale}}{P_{old}} Pnew=MtranslationMrotationMscalePold
旋转变换与缩放变换是线性变换,在三维空间中变换矩阵可以表示成3X3的形式,而位移变换是仿射变换,需要4X4的矩阵表示,因为本文只讨论旋转变换,定义后面的部分会直接使用3X3矩阵。且对于线性变换,我们使用列向量代表点,则3X3过渡矩阵的行向量代表坐标变换中的基( x 、 y 、 z x、y、z x、y、z轴)。
绕 x 、 y 、 z x、y、z x、y、z轴旋转 θ \theta θ度的矩阵:
R x ( θ ) = [ 1 0 0 0 0 cos θ − sin θ 0 0 sin θ cos θ 0 0 0 0 1 ] {{R}_{x}}(\theta )=\left[ \begin{matrix} 1 & 0 & 0 & 0 \\ 0 & \cos \theta & -\sin \theta & 0 \\ 0 & \sin \theta & \cos \theta & 0 \\ 0 & 0 & 0 & 1 \\ \end{matrix} \right] Rx(θ)=⎣⎢⎢⎡10000cosθsinθ00−sinθcosθ00001⎦⎥⎥⎤
R y ( θ ) = [ cos θ 0 − sin θ 0 0 1 0 0 sin θ 0 cos θ 0 0 0 0 1 ] {{R}_{y}}(\theta )=\left[ \begin{matrix} \cos \theta & 0 & -\sin \theta & 0 \\ 0 & \text{1} & \text{0} & 0 \\ \sin \theta & \text{0} & \cos \theta & 0 \\ 0 & 0 & 0 & 1 \\ \end{matrix} \right] Ry(θ)=⎣⎢⎢⎡cosθ0sinθ00100−sinθ0cosθ00001⎦⎥⎥⎤
R z ( θ ) = [ cos θ − sin θ 0 0 sin θ cos θ 0 0 0 0 1 0 0 0 0 1 ] {{R}_{z}}(\theta )=\left[ \begin{matrix} \cos \theta & -\sin \theta & 0 & 0 \\ \sin \theta & \cos \theta & \text{0} & 0 \\ 0 & \text{0} & \text{1} & 0 \\ 0 & 0 & 0 & 1 \\ \end{matrix} \right] Rz(θ)=⎣⎢⎢⎡cosθsinθ00−sinθcosθ0000100001⎦⎥⎥⎤
给定欧拉角的变换
如果旋转的需求是一个欧拉角,那么我们要怎么处理呢?事实上对于一个给定欧拉角的旋转,我们需要确定一个旋转顺序,可以想象以不同的顺序绕 x 、 y 、 z x、y、z x、y、z轴旋转得到的结果是不同的(对于四元数也是一样的)。Unity中的约定为 z 、 x 、 y z、x、y z、x、y: “Applies a rotation of eulerAngles.z degrees around the z-axis, eulerAngles.x degrees around the x-axis, and eulerAngles.y degrees around the y-axis (in that order)”。
还需要注意的是这个 z 、 x 、 y z、x、y z、x、y顺序所在的坐标系指的是旋转前的坐标系,不随旋转而改变,我们观察一个组合旋转矩阵:
M r o t a t i o n = M r o t a t i o n Z M r o t a t i o n X M r o t a t i o n Y {{M}_{rotation}}={{M}_{rotationZ}}{{M}_{rotationX}}{{M}_{rotationY}} Mrotation=MrotationZMrotationXMrotationY
坐标系Transform可以用一个矩阵来表示,而旋转矩阵实际作用就是旋转坐标系,从上面的3个旋转矩阵中可以知道,每一个旋转都是对当前坐标系的旋转。该矩阵去变换一个坐标系的的过程为,绕当前坐标系Y轴旋转 θ \theta θ度,得到一个新的旋转后坐标系,继续绕当前旋转后坐标系X轴旋转 θ \theta θ度,得到一个新的两次旋转后坐标系,继续绕当前旋转后坐标系Z轴旋转 θ \theta θ度。这代表的是一个在当前坐标系,按 y 、 x 、 z y、x、z y、x、z顺序的旋转。
上面的过程与按照旋转前坐标系的旋转顺序 z 、 x 、 y z、x、y z、x、y是等价的,就是说他们所代表的顺序是相反的。
证明:
按照旋转前坐标系的旋转顺序z、x、y可以用以下矩阵表示
M r o t a t i o n = M Y M X M Z {{M}_{rotation}}={{M}_{Y}}{{M}_{X}}{{M}_{Z}} Mrotation=MYMXMZ
第一步旋转变换 M Z {{M}_{Z}} MZ,因为还没有发生坐标系变换 M Z = M r o t a t i o n Z {{M}_{Z}}={{M}_{rotationZ}} MZ=MrotationZ,初始坐标系的基为 I I I,经过 M Z {{M}_{Z}} MZ变换,新坐标的基为 M Z T {{M}_{Z}}^{T} MZT(转置是因为使用列向量表示点,所以 M r o t a t i o n Z {{M}_{rotationZ}} MrotationZ变换矩阵的行向量表示基,求解过渡矩阵需要的是列向量形式的基),基 I I I到基 M Z T {{M}_{Z}}^{T} MZT的过渡矩阵P有 I × P = M Z T I\times P={{M}_{Z}}^{T} I×P=MZT, P = M r o t a t i o n Z T P={{M}_{rotationZ}}^{T} P=MrotationZT,旋转矩阵正交 P = M r o t a t i o n Z − 1 P={{M}_{rotationZ}}^{-1} P=MrotationZ−1。
第二步旋转变换 M X {{M}_{X}} MX,是 M r o t a t i o n X {{M}_{rotationX}} MrotationX在基 I I I中的表达,而矩阵连续变化则已经更换了基,线性变换 M r o t a t i o n X {{M}_{rotationX}} MrotationX在新基 M Z T {{M}_{Z}}^{T} MZT中表示为 M X = P − 1 M r o t a t i o n X P = M r o t a t i o n Z M r o t a t i o n X M r o t a t i o n Z − 1 {{M}_{X}}={{P}^{-1}}{{M}_{rotationX}}{P}={{M}_{rotationZ}}{{M}_{rotationX}}{{M}_{rotationZ}}^{-1} MX=P−1MrotationXP=MrotationZMrotationXMrotationZ−1,由 I I I到第二步变换后基 ( M X M Z ) T ({{M}_{X}}{{M}_{Z}})^{T} (MXMZ)T的的过度矩阵为 P = M r o t a t i o n Z M r o t a t i o n X {P}={{M}_{rotationZ}}{{M}_{rotationX}} P=MrotationZMrotationX。
第三步旋转变换 M Y {{M}_{Y}} MY,同理是 M r o t a t i o n Y {{M}_{rotationY}} MrotationY在基 I I I中的表达,线性变换 M r o t a t i o n Y {{M}_{rotationY}} MrotationY在新基 ( M X M Z ) T ({{M}_{X}}{{M}_{Z}})^{T} (MXMZ)T中表示为 M Y = P − 1 M r o t a t i o n Y P = M r o t a t i o n Z M r o t a t i o n X M r o t a t i o n Y ( M r o t a t i o n Z M r o t a t i o n X ) − 1 {{M}_{Y}}={{P}^{-1}}{{M}_{rotationY}}{P}={{M}_{rotationZ}}{{M}_{rotationX}}{{M}_{rotationY}}({{M}_{rotationZ}}{{M}_{rotationX}})^{-1} MY=P−1MrotationYP=MrotationZMrotationXMrotationY(MrotationZMrotationX)−1。M r o t a t i o n = M Y M X M Z = ( M r o t a t i o n Z M r o t a t i o n X M r o t a t i o n Y ( M r o t a t i o n Z M r o t a t i o n X ) − 1 ) ( M r o t a t i o n Z M r o t a t i o n X M r o t a t i o n Z ) ( M r o t a t i o n Z − 1 ) = M r o t a t i o n Z M r o t a t i o n X M r o t a t i o n Y {{M}_{rotation}}={{M}_{Y}}{{M}_{X}}{{M}_{Z}} \\ =({{M}_{rotationZ}}{{M}_{rotationX}}{{M}_{rotationY}}{{({{M}_{rotationZ}}{{M}_{rotationX}})}^{-1}})({{M}_{rotationZ}}{{M}_{rotationX}}{{M}_{rotationZ}})({{M}_{rotationZ}}^{-1}) \\ ={{M}_{rotationZ}}{{M}_{rotationX}}{{M}_{rotationY}} Mrotation=MYMXMZ=(MrotationZMrotationXMrotationY(MrotationZMrotationX)−1)(MrotationZMrotationXMrotationZ)(MrotationZ−1)=MrotationZMrotationXMrotationY
实际上Unity中的旋转按照欧拉角的表达就是: M r o t a t i o n = M r o t a t i o n Z M r o t a t i o n X M r o t a t i o n Y {{M}_{rotation}}={{M}_{rotationZ}}{{M}_{rotationX}}{{M}_{rotationY}} Mrotation=MrotationZMrotationXMrotationY
欧拉角表示旋转的缺点
我们可以看出,用欧拉角表示旋转是顺序相关的,会导致结果不够直观,所谓的万向节死锁就是这种不直观造成的现象。具体现象是第二个旋转轴(X轴)的旋转角度为±90°时,第三次旋转与第一次旋转对应相同或相反的旋转轴,也可以理解为第二次旋转将第三次旋转的旋转轴旋转到与第一次旋转的旋转轴共线的位置,把transform面板上的Rotation的x设置为±90时改变 z 、 y z、y z、y即可尝试。
我们看看万向节死锁的数学表达是什么, z 、 x 、 y z、x、y z、x、y轴转动度数分别 r 、 p 、 h r、p、h r、p、h时为进一步展开旋转矩阵:
M r o t a t i o n = M r o t a t i o n Z M r o t a t i o n X M r o t a t i o n Y = [ cos r cosh − sin r sin p sinh − sin r cos p cos r sinh + sin r sin p cosh sin r cosh + cos r sin p sinh cos r cos p sin r sinh − cos r sin p cosh − cos p sinh sin p cos p cosh ] {{M}_{rotation}}={{M}_{rotationZ}}{{M}_{rotationX}}{{M}_{rotationY}}\\=\left[ \begin{matrix} \cos r\cosh -\sin r\sin p\sinh & -\sin r\cos p & \cos r\sinh +\sin r\sin p\cosh \\ \sin r\cosh +\cos r\sin p\sinh & \cos r\cos p & \sin r\sinh -\cos r\sin p\cosh \\ -\cos p\sinh & \sin p & \cos p\cosh \\ \end{matrix} \right] Mrotation=MrotationZMrotationXMrotationY=⎣⎡cosrcosh−sinrsinpsinhsinrcosh+cosrsinpsinh−cospsinh−sinrcospcosrcospsinpcosrsinh+sinrsinpcoshsinrsinh−cosrsinpcoshcospcosh⎦⎤
p = ± 90 ° p=±90° p=±90°时
M r o t a t i o n = [ cos r cosh ∓ sin r sinh 0 cos r sinh ± sin r cosh sin r cosh ± cos r sinh 0 sin r sinh ∓ cos r cosh 0 ± 1 0 ] = + 90 ∘ [ cos ( r + h ) 0 sin ( r + h ) sin ( r + h ) 0 − cos ( r + h ) 0 1 0 ] = − 90 ∘ [ cos ( r − h ) 0 − sin ( r − h ) sin ( r − h ) 0 cos ( r − h ) 0 − 1 0 ] {{M}_{rotation}}=\left[ \begin{matrix} \cos r\cosh \mp \sin r\sinh & 0 & \cos r\sinh \pm \sin r\cosh \\ \sin r\cosh \pm \cos r\sinh & 0 & \sin r\sinh \mp \cos r\cosh \\ 0 & \pm 1 & 0 \\ \end{matrix} \right] \\ \overset{+{{90}^{\circ }}}{\mathop{=}}\,\left[ \begin{matrix} \cos (r+h) & 0 & \sin (r+h) \\ \sin (r+h) & 0 & -\cos (r+h) \\ 0 & 1 & 0 \\ \end{matrix} \right] \\ \overset{-{{90}^{\circ }}}{\mathop{=}}\,\left[ \begin{matrix} \cos (r-h) & 0 & -\sin (r-h) \\ \sin (r-h) & 0 & \cos (r-h) \\ 0 & -1 & 0 \\ \end{matrix} \right] \\ Mrotation=⎣⎡cosrcosh∓sinrsinhsinrcosh±cosrsinh000±1cosrsinh±sinrcoshsinrsinh∓cosrcosh0⎦⎤=+90∘⎣⎡cos(r+h)sin(r+h)0001sin(r+h)−cos(r+h)0⎦⎤=−90∘⎣⎡cos(r−h)sin(r−h)000−1−sin(r−h)cos(r−h)0⎦⎤
可以看出 r 、 h r、h r、h出现共线的转动的原因。
四元数与旋转
对旋转而言,四元数要比欧拉角和矩阵更好用,对于给定轴与角度的旋转非常直观,易于进行球面插值,很多运算过程不需要计算三角函数。关于四元数的数学意义这里不赘述了,四元数 q ^ p ^ q ^ − 1 \hat{q}\hat{p}{{\hat{q}}^{-1}} q^p^q^−1表示四元数 q ^ \hat{q} q^对向量 p ^ \hat{p} p^的变换,Unity中被封装为乘法。虽然Transform使用四元数存储计算旋转信息,但对于需要显示的图形,还是会将其转换为矩阵传入Shader。
四元数是区别于矩阵的一种旋转的表达方式,但旋转结果是相同的,所以通过欧拉角来构造四元数也需要遵行约定好顺序 z 、 x 、 y z、x、y z、x、y。
旋转顺序的验证
在Unity中对旋转顺序进行验证。
using UnityEngine;public class Rotation : MonoBehaviour
{public Vector3 angle;public Transform[] transforms;public void Rotate(){transforms[0].Rotate(angle, Space.Self);ZXY_OriginalCoordinate(transforms[1], angle);YXZ_FollowCoordinate(transforms[2], angle);transforms[3].rotation *= Quaternion.Euler(angle);QuaternionZXY_OriginalCoordinate(transforms[4], angle);QuaternionYXZ_FollowCoordinate(transforms[5], angle);}public void ResetRotation(){for (int i = 0; i < transforms.Length; i++){transforms[i].rotation = Quaternion.identity;}}private void ZXY_OriginalCoordinate(Transform transform, Vector3 angle){Vector3 x = transform.right;Vector3 y = transform.up;Vector3 z = transform.forward;transform.Rotate(z, angle.z, Space.World);transform.Rotate(x, angle.x, Space.World);transform.Rotate(y, angle.y, Space.World);}private void YXZ_FollowCoordinate(Transform transform, Vector3 angle){transform.Rotate(Vector3.up, angle.y, Space.Self);transform.Rotate(Vector3.right, angle.x, Space.Self);transform.Rotate(Vector3.forward, angle.z, Space.Self);}private void QuaternionZXY_OriginalCoordinate(Transform transform, Vector3 angle){Quaternion x = Quaternion.AngleAxis(angle.x, transform.right);Quaternion y = Quaternion.AngleAxis(angle.y, transform.up);Quaternion z = Quaternion.AngleAxis(angle.z, transform.forward);transform.rotation = (y * (x * (z * transform.rotation)));}private void QuaternionYXZ_FollowCoordinate(Transform transform, Vector3 angle){transform.rotation *= Quaternion.AngleAxis(angle.y, Vector3.up);transform.rotation *= Quaternion.AngleAxis(angle.x, Vector3.right);transform.rotation *= Quaternion.AngleAxis(angle.z, Vector3.forward);}#if UNITY_EDITORprivate void OnDrawGizmos(){for (int i = 0; i < transforms.Length; i++){UnityEditor.Handles.PositionHandle(transforms[i].position, transforms[i].rotation);}}
#endif
}
对于不同欧拉角,六种旋转方式的结果是相同的。
Shader中的方向变换
Shader中常用到的方向变换包括直线光方向、视线方向、统一缩放下的法线等。变换表示线性3X3变换矩阵M与三维向量p相乘,但Mp与pM的形式都有使用,前者把向量作为行向量,后者是列向量。我们具体选行向量还是列向量呢?下面是变换矩阵的总结, x a x_a xa表示空间A的基 x x x在空间B中的值:
P B = M A → B P A {{P}_{B}}={{M}_{A\to B}}{{P}_{A}} PB=MA→BPA P A = M B → A P B {{P}_{A}}={{M}_{B\to A}}{{P}_{B}} PA=MB→APB P B T = P A T M B → A {{P}_{B}}^T={{P}_{A}}^T{{M}_{B\to A}} PBT=PATMB→A P A T = P B T M A → B {{P}_{A}}^T={{P}_{B}}^T{{M}_{A\to B}} PAT=PBTMA→B M A → B = [ ∣ ∣ ∣ x a y a z a ∣ ∣ ∣ ] = [ − x b − − y b − − z b − ] = M B → A T {{M}_{A\to B}}=\left[ \begin{matrix} | & | & | \\ {{x}_{a}} & {{y}_{a}} & {{z}_{a}} \\ | & | & | \\ \end{matrix} \right]=\left[ \begin{matrix} -& {{x}_{b}} & - \\ -& {{y}_{b}} & - \\ -& {{z}_{b}} & - \\ \end{matrix} \right]={{M}_{B\to A}}^T MA→B=⎣⎡∣xa∣∣ya∣∣za∣⎦⎤=⎣⎡−−−xbybzb−−−⎦⎤=MB→AT M B → A = [ ∣ ∣ ∣ x b y b z b ∣ ∣ ∣ ] = [ − x a − − y a − − z a − ] = M A → B T {{M}_{B\to A}}=\left[ \begin{matrix} | & | & | \\ {{x}_{b}} & {{y}_{b}} & {{z}_{b}} \\ | & | & | \\ \end{matrix} \right]=\left[ \begin{matrix} -& {{x}_{a}} & - \\ -& {{y}_{a}} & - \\ -& {{z}_{a}} & - \\ \end{matrix} \right]={{M}_{A\to B}}^T MB→A=⎣⎡∣xb∣∣yb∣∣zb∣⎦⎤=⎣⎡−−−xayaza−−−⎦⎤=MA→BT
例如把法线贴图( N T a n g e n t N_{Tangent} NTangent)从切线空间变换到世界空间( N W o r l d N_{World} NWorld),已知由法线、切线、副法线,构成的矩阵:
M W o r l d → T a n g e n t = [ − n − − t − − b − ] {{M}_{World\to Tangent}}=\left[ \begin{matrix} -& {n} & - \\ -& {t} & - \\ -& {b} & - \\ \end{matrix} \right] MWorld→Tangent=⎣⎡−−−ntb−−−⎦⎤ N W o r l d T = N T a n g e n t T M W o r l d → T a n g e n t {N_{World}}^T = {N_{Tangent}}^T {{M}_{World\to Tangent}} NWorldT=NTangentTMWorld→Tangent
使用行向量在左,矩阵在右的乘法。
法线变换
如上图所示,在存在缩放时,法线的变换矩阵与模型顶点的变换矩阵不同。切线可以用模型上两个点的差值表示,所以模型顶点的变换公式适用于切线。当使用3X3性变换矩阵 M A → B {M}_{A\to B} MA→B表示坐标空间A到坐标空间B的顶点变换时,切线变换可以表示为
T B = M A → B T A {T_{B}} = {{M}_{A\to B}}{T_{A}} TB=MA→BTA
此时法线变换可以表示为
N B = ( M A → B T ) − 1 N A {N_{B}} = ({{M}_{A\to B}}^T)^{-1}{N_{A}} NB=(MA→BT)−1NA
注意,这个变换不保证法线的长度是归一化的,需要再归一化操作一次。
证明:
T A ⋅ N A = T A T N A = T A T ( M A → B − 1 M A → B ) T N A = T A T M A → B T ( M A → B − 1 ) T N A = ( M A → B T A ) T ( M A → B − 1 ) T N A = T B T N B = 0 {T_{A}}\cdot {N_{A}} ={T_{A}}^{T}{N_{A}} \\= {T_{A}}^{T}({{{M}_{A\to B}}}^{-1}{{{M}_{A\to B}}})^{T}{N_{A}} \\={T_{A}}^{T}{{{M}_{A\to B}}}^{T}({{{M}_{A\to B}}}^{-1})^{T}{N_{A}} \\=({{M}_{A\to B}}{T_{A}})^{T}({{{M}_{A\to B}}}^{-1})^{T}{N_{A}} \\={T_{B}}^{T}{N_B} =0 TA⋅NA=TATNA=TAT(MA→B−1MA→B)TNA=TATMA→BT(MA→B−1)TNA=(MA→BTA)T(MA→B−1)TNA=TBTNB=0 M N = ( M A → B − 1 ) T = ( M A → B T ) − 1 {M_N} =({{{M}_{A\to B}}}^{-1})^{T}=({{{M}_{A\to B}}}^{T})^{-1} MN=(MA→B−1)T=(MA→BT)−1
在不存在缩放时 M A → B {{{M}_{A\to B}}} MA→B是正交矩阵 M N = ( M A → B − 1 ) T = M A → B {M_N} =({{{M}_{A\to B}}}^{-1})^{T}={{{M}_{A\to B}}} MN=(MA→B−1)T=MA→B;系数为 k k k的统一缩放变换时, M N = 1 k M A → B {M_N} =\frac{1}{k}{{{M}_{A\to B}}} MN=k1MA→B。实际操作过程中,会把不存在缩放与统一缩放合并处理,最后都进行归一化操作。
[Rotation Transform] 旋转变换相关推荐
- blender oc 渲染器中英文对照
advanced tools 高级工具,高级工具 render setting 渲染设定值 values =数值 displacement 移位,移位 projection 投影投影投影 transf ...
- 原生Transform编辑器,这个两个脚本能直接更改检视窗口的Tranform的显示
//********************************************************************** // 文件名(File Name): Transfor ...
- Unity基础知识、Transform类
Transform类 1)本类中的属性 -parent: 获取当前游戏对象的父对象的Transform Transform fourTrans = transform.parent; transfor ...
- java衍生作用_java-如何从AffineTransform衍生的形状对象中“...
您可以使用AffineTransform.transform(Point2D, Point2D)变换多边形上的单个点. 如果您不使用旋转变换来移动船,而是将船的位置保持在一个(x,y)位置,那么事情就 ...
- Real-time Rendering (3rd edition)学习笔记第4章
目录 第4章 变换(Transforms) 4.1 基本变换(Basic Transforms) 4.1.1 平移(Translation) 4.1.2 旋转(Rotation) 4.1.3 缩放(S ...
- Unity-动画系统-动画片段
动画片段简介 动画片段预览 动画片段设置 导入动画片段 创建和编辑动画片段 剪切动画片段 动画片段简介 动画片段是Unity动画系统的基础,无论是新版动画系统还是旧版动画系统都需要使用动画片段. 动画 ...
- css3图片旋转轮播_使用CSS和JavaScript构建3D旋转轮播
css3图片旋转轮播 A lot has been said on the use of traditional 2D carousels, for example this piece on Sma ...
- Literature reviews of top KiTS19
1st:An attempt at beating the 3D U-Net 德国癌症研究中心(DKFZ)医学图像计算部 Things new:Here we apply a 3D U-Net to ...
- Unity3D心得分享
本篇文章的内容以各种tips为主,不间断更新 2019/05/10 最近更新: 使用Instantiate初始化参数去实例对象 Unity DEMO学习 ======================= ...
最新文章
- Hello World
- 写给程序员的美术创作指南
- 四则运算题目生成程序
- 看完后,别再说自己不懂用户画像了
- SpringCloud Alibaba Sentinel断路器介绍与控制台搭建
- TreeMap源码解析
- python零基础入门五小时教学_五小时轻松入门Python
- Excel VBA 打开对话框,获取文件夹路径
- VS2012全屏背景修改教程
- Geodetector软件下载、地理探测器的应用实践与结果解读
- 2020-8-15 无线充电原理和注意事项 WCP/铁氧体
- 计算机安全模式都进不了系统,win10电脑安全模式都进不去怎么办
- 100本《架构师》迷你书——限时免费领取
- 蓝桥 百亿富翁 stack<Type> 栈
- java 模拟登录58同城,Java项目实战之同城信息网站(类似58同城)开发
- keystone中Vertify operation出现:No handlers could be found for logger keystoneclient.httpclient的问题
- 【心电信号】基于matlab小波阙值心电信号去噪【含Matlab源码 2188期】
- 邓应海:美联储缩表预期升温黄金下挫!最新黄金走势分析
- 4D产品生产流程(详细)
- read_exposure_data()
热门文章
- 历史经验之解决vMix22闪退的办法(亲测管用)
- JS中如何让某个动作延迟几秒执行(☆)
- 键盘修改器,绝对管用
- [转] 关于“时间”的一次探索
- 微视点:网传社交游戏公司“五分钟”面临倒闭,引发各方热议
- 合同管理系统应该具备那些功能?
- 【数据结构与算法】迪杰斯特拉算法的介绍和最短路径问题程序实现
- 【MMD动作+镜头下载】Chocolate Train
- 华为鸿蒙系统老手机能用吗_华为使用自家“鸿蒙”系统,旧手机的安卓系统可以更新成那个系统吗?...
- 零基础学习资料(建议收藏)