说明:

注意几点:

0 行向量右乘矩阵与列向量左乘矩阵,两个矩阵互为逆矩阵

1 法线转换与mul,mul函数左乘矩阵当列矩阵计算,右乘当行矩阵计算

2 叉乘与左右手系,左手系用左手,右手系用右手,axb四指指向a,向b旋转(沿小与两个角度180的方向转),拇指的方向是叉乘方向

3 unity观察系的z方向,unity观察系是右手系,其他都是本地坐标,世界坐标,投影坐标都是左手系,所以观察系轴反向

4 投影系中w与uv伸展方向关系,w=1或-1 uv伸展正向或反向

http://blog.csdn.net/ronintao/article/details/52136673#t29

参考

1、Shadow Map 原理和改进

2、【OpenGL】02 - OpenGL中的坐标系

3、矩阵理论 (这个是京东地址)

4、维基百科(文中的数学概念出处)

5、msdn mul

6、msdn matrix

7、unity shader lab built-in

8、nvidia bump map tutorial

9、Computing
Tangent Space Basis Vectors for an Arbitrary Mesh

一、基础

坐标系的定义是:对于一个n维系统,能够使每一个点和一组(n个)标量构成一一对应的系统。

我们的出发点是三维欧几里得空间,或三维实内积空间。对于这样的三维空间,最常见的坐标系就是笛卡尔坐标系,指定了三个互相垂直的向量x、y、z,这样每个空间中的点就可以表示成

考虑原点的存在,则对点V有:

这里的x、y、z,就是三维实数空间的一组标准正交基。

原点和基,就唯一的定义了一个坐标系。

如果要展开讨论数学概念实在是太难懂,我们下面直接看unity中的各种坐标系来讨论各种情况。本文中讨论的unity坐标系有以下几个:

  • 本地坐标系。local space
  • 世界坐标系。world space
  • 相机坐标系(观察坐标系)。view space
  • 投影坐标系。projection space
  • 切线坐标系。tangent space

这几个坐标系将在下面逐个讨论。

二、本地坐标系

1、shader中的本地坐标系,与 Editor中的本地坐标系

在unity中,有一个肉眼可见的本地坐标系,当你选中一个物体时,就会显示出其本地坐标系。

图1、Editor中的本地坐标系

那么问题来了,这个坐标系,是shader中的本地坐标系吗?

产生这样的疑问是自然的,3ds max中建立模型使用的坐标系是右手坐标系,而unity editor中显示的本地坐标系是左手坐标系,显然是不一样的:

图2、3ds Max 中的本地坐标系

我们这里不对3dmax中的轴做任何修改,并在导出时选择z向上(即和在3dmax中看到的一样),则导入到unity中,并将旋转等reset,看到的是这样的:

图3、导入unity后的本地坐标系

注意此时方向已经和在3dsmax中不一样了。

那么在shader中的坐标系到底是哪个坐标系呢?我们使用下面这样的shader来观察以下:

[cpp] view
plain
 copy

  1. Shader "Custom/TestCoordShader" {
  2. SubShader{
  3. Tags{ "RenderType" = "Opaque" }
  4. LOD 200
  5. Pass{
  6. CGPROGRAM
  7. #pragma vertex   vert
  8. #pragma fragment frag
  9. #include "UnityCG.cginc"
  10. struct v2f {
  11. float4 pos : SV_POSITION;
  12. float4 col : COLOR;
  13. };
  14. v2f vert(appdata_base v) {
  15. v2f o;
  16. o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
  17. o.col = v.vertex;
  18. return o;
  19. }
  20. float4 frag(v2f i) : COLOR{
  21. return i.col.x; // i.col.y; //i.col.z;
  22. }
  23. ENDCG
  24. }
  25. }
  26. //FallBack "Diffuse"
  27. }

将 fragment 中的颜色值分别修改为 x y z,就可以得到下面的结果:

图4、shader中本地坐标系的x、y、z方向

可以看到vertex的x、y、z方向和editor中显示的坐标轴向一致,且更仔细的观察的话,会发现原点位置也一致。因此我们可以得出结论:shader中的本地坐标系,就是在editor中看到的本地坐标系

2、本地坐标系:左手坐标系

这里需要注意的是,本地坐标系是一个左手坐标系系统。

图5、左手坐标系和右手坐标系

这里不展开讨论左右手坐标系的问题,在后面会再探讨这个东西。

三、世界坐标系

1、世界坐标系的形态

图6、位于原点的正方体

        和各自为政的本地坐标系不同,在unity中,每个scene都有唯一存在的一个世界坐标系。同样的,世界坐标系也是一个左手坐标系。一般常见的用法,是使得x正方向为正右方,y正方向为正上方,z正方向为正前方(常用而已),如图6中所示。

2、从本地坐标系转换到世界坐标系

        现在要将本地坐标系的点、向量等转换到世界坐标系中。

1)不移动原点的坐标系变换

        考虑我们上面对于坐标系的要素描述:原点和基。这里的本地坐标系和世界坐标系的不同就在于这两点。
        首先不考虑原点的变化,先假定本地坐标系和世界坐标系共原点O。
        而在基的方面,本地坐标系和世界坐标系是同一个三维线性空间中选取两组不同的基构成的坐标系,分为称为 local 基 和 world 基。
        容易看出,从 local 基到 world 基是一个线性变换(反之亦然),参考《矩阵理论》中对过渡矩阵和坐标系一节的讨论,可以知道,任意点 p 在世界坐标系下的位置,可以用其在本地坐标系下的位置,左乘  local 基 到 world 基的过渡矩阵的逆矩阵得到。而这个逆矩阵,实际上就是 world 
基 到 local 基的过渡矩阵。因此有:

公式1、不移动原点时,本地坐标系到世界坐标系的坐标轴变换和点变换
        注意到 world 基的正交特性,不失一般性的,令 X_world = (1, 0, 0),Y_world = (0, 1, 0),Z_world = (0, 0, 1),带入到上面的坐标轴变换公式,可以求出M_local->world,则(其中 X_local_in_world 是指该local 基在世界坐标系下的表示):

公式2、坐标系变换与坐标轴的关系
        这个结论是可以推广的,即:点P在坐标系V下的坐标,相当于其在坐标系U下的坐标,左乘矩阵T,其中T为 坐标系U的三个基(列向量)在坐标系V下的坐标构成的矩阵
        将这个矩阵记做 p 从本地坐标系变换到世界坐标系的变换矩阵 Trans:

公式3、本地坐标系变换到世界坐标系的变换矩阵 Trans

2)不移动原点的坐标系变换——举例


图7、本地坐标系到世界坐标系变换举例
        以这个cube的本地坐标系为例,其坐标轴在世界坐标系下的表示分别为:

        这样就可以得到过渡矩阵

3)仿射变换——考虑原点的移动

        前面的推导都是基于原点不移动得到的,这样假设的原因在于线性变换并不能够表示原点的移动。那么如果现在需要考虑这一变化,则需要引入仿射变换。
        所谓仿射变换,就是线性变换加平移,其实就是在刚才的线性变换的基础上再加上原点的移动
        由于已经不是线性变换,那么使用线性变换矩阵就无法表示了,也就是说,现在已经无法写成 p' = T * p 的形式。因此,引入齐次线性空间的概念,即增加第4维w,用来辅助表示移动。
        考虑这样的仿射变换,首先保持原点不变,进行线性变换,其线性变换矩阵为A,再将原点平移b,则在该仿射变换下,任意点P有:

公式4、仿射变换
        关于齐次变换的更多细节,可以参考之前的博客(这篇文章较老,冲突的概念以本文为准)。
        仔细考虑这个表示平移的b向量,会发现他是转换后的线性空间V的原点所在位置,在原线性空间U下的坐标

图8、仿射变换的原点变换
        现在回到本地坐标系向世界坐标系的变换过程中,则可以得到齐次变换下的变换矩阵:

公式4、仿射变换矩阵与坐标轴和原点
        考虑到齐次空间的特性,点的w分量为1,向量的w分量为0,则可以进一步写为:

4)在unity中获得这个转换矩阵

        Unity中已经提供了获得这个矩阵的方便形式,在script中使用
[csharp] view
plain
 copy

  1. gameObject.transform.localToWorldMatrix

在shader中使用如下的矩阵:

[cpp] view
plain
 copy

  1. _Object2World

5)转换法线

        将点或者普通的向量从本地坐标系转换到世界坐标系,只要按照上面说的,用该转换矩阵左乘原坐标值就可以了,但是对于法线,还需要一些特殊的处理
        为什么?
        回答这个问题,就需要搬出法线的定义:三维平面的法线是垂直于该平面的三维向量。曲面在某点P处的法线为垂直于该点切平面的向量。所以,在转换之后,还需要保持原有的垂直关系
        按照上面举例中的变换矩阵,假定某条法线为(1,1,0),与之垂直的一个向量(1,-1,0)。如果左乘变换矩阵,则法线变为(3.5,3.5,-0.7),向量变为(0.7,-3.5,-3.5)。变换之后的内积为 -7,即已经不再垂直。
        其实从数学上看这是显然的:

公式5、使用变换矩阵变换法线——不再垂直
        而从直观上,原因是这样的:

图9、使用变换矩阵变换法线——不再垂直
        因此要正确的进行法线的变换,要使得保持 V 和 N 的内积为0,因此要让 N 左乘 Trans的逆转置矩阵,这样有:

公式6、用逆转置矩阵转换法线

6)获取逆转置矩阵的捷径——mul的秘密

        上面提到要转换法线,需要使用从本地坐标系到世界坐标系的仿射变换矩阵 (即 _Object2World) 的逆转置矩阵,即应该使用 _World2Object 的转置矩阵。
        那么在shader中完成这个变换,应有:
[cpp] view
plain
 copy

  1. float4 worldPos  = mul(_Object2World, v.vertex);
  2. float4 worldNorm = mul(transpose(_World2Object), v.normal);

但在实际使用中,常常见到这样的写法:

[cpp] view
plain
 copy

  1. float4 worldPos  = mul(_Object2World, v.vertex);
  2. float4 worldNorm = mul(v.normal, _World2Object);
        这两种写法的结果是一样的吗?是的,这里就必须说明 mul 的用法了(官方文档)。
        简单来说,如果 mul 的第一个参数是矩阵 M,第二个参数是向量 V,则结果 Out 为(以vector4为例):

        如果第一个参数是向量 V,第二个参数是矩阵 M,则结果 Out 为

        则可以进行如下推导:

公式7、mul与转置矩阵
        注意到输出的vector4,在数据格式上,转置与不转置实际上并没有区别,(shader中,转置实际上只对矩阵有效果)。因此,mul(V, M) 就相当于 mul( tranpose(M), V )更进一步的,对于正交矩阵,其转置矩阵等于逆矩阵,那么通过这个方法,还可以得到他的逆矩阵,这个特性我们后面还会看到。

四、观察坐标系

1、观察坐标系的形态

        View space是观察者眼中的世界,可以认为是观察者的本地坐标系,以观察者的位置为原点。但在《Shadow
Map 原理和改进》
中可以看到,观察坐标系又与 editor 中看到的 camera 的本地坐标系有本质的区别:它是右手坐标系
        其形态如下所示:

图10、观察坐标系

2、左手坐标系和右手坐标系的互相转换——数学运算的独立性

        在考虑如何从世界坐标系转换到观察坐标系之前,我们要先思考一个问题:上一节的转换公式是在世界坐标系和本地坐标系——两个都是左手坐标系——的情况下推导的,那么现在要在左手坐标系和右手坐标系之间进行转换了,那么之前的推导是否仍然有效
        这里就要展开来谈谈矩阵运算与左右手规则的关系了。

1)线性变换定理与左右手无关

        上一节讨论的线性变换,是从一组基变换到另一组基,对基本身没有任何要求,他们甚至可以不满足互相正交的特性,到底构成的是左手坐标系还是右手坐标系,容易看到,对定理本身是完全没有影响的。

2)矩阵乘法 mul 与左右手无关

        矩阵乘法的本质实际上就是对点或向量进行变换,即更换基向量,从线性变换定理与左右手无关也容易看出 mul 也不挑剔他所在的线性空间。

3)点积与左右手无关

        点积需要在实内积空间中进行,要使得下面的点积计算方式生效,需要 a 和 b 在同一个线性空间内,且基向量两两正交

公式8、点积
        注意到unity中使用的左手坐标系和右手坐标系中的基向量都是满足正交条件的,因此点积都可以正常进行。

4)叉乘与左右手规则的关系

        叉乘是唯一需要注意的。其数学公式如下:

公式8、叉乘的数学计算方法
        可以看到,其本身也是与基向量的形态独立的,因此计算公式本身(例如,cross函数本身)并不因左右手坐标系的变化而变化
        但是,计算叉乘还有一个方法(以下这段出自wiki):

公式9、叉乘
        这里方向向量 n 的确定,通常会介绍右手规则。但实际上,右手规则仅适用于右手坐标系下的情况,在左手坐标系中,需要使用左手规则。总结来说,就是叉乘的数学表达式是独立于左右手坐标系的。但如果使用X手判定准则来进行方向的判断,则在左手坐标系中应使用左手准则,在右手坐标系中使用右手准则。

3、从世界坐标系变换到观察坐标系

        经过了上面的讨论,我们可以放心大胆的说,可以按照本地坐标系变换到世界坐标系的思路,再从世界坐标系变换到观察坐标系。
        在 Script 中获得这个变换矩阵的方法是:
[cpp] view
plain
 copy

  1. Camera.worldToCameraMatrix

在shader中,这一步的单独的矩阵是:

[cpp] view
plain
 copy

  1. UNITY_MATRIX_V
        综合从本地坐标系到观察坐标系的变换矩阵:
[cpp] view
plain
 copy

  1. UNITY_MATRIX_MV

4、值得注意的 z 分量和 w 分量

        到目前为止,无论是本地坐标系到世界坐标系的变换,还是世界坐标系到观察坐标系的变换,都不影响点(或向量)的 w 分量,仍然保持为 1 (或0,对于向量)。
另外,可以注意下 z 分量,可以看到,由于 z 的正方向的缘故,所以观察者可见的所有点的 z 分量都小于0,且距离越远,负的值越大。

五、投影坐标系

1、投影坐标系的形态

        投影坐标系是将观察者眼中的世界进行截取和归一得到的(比较详细的讨论可以参考《【OpenGL】02
- OpenGL中的坐标系》
),首先截取世界中,camera的平截体包含的部分,然后又再次变为一个左手坐标系(对透视投影来说,坐标系的概念可能已经拓展)
图11、投影坐标系:正投影和透视投影
        这就产生了问题,为什么前面也是左手坐标系(本地坐标系,世界坐标系),后面也是左手坐标系(投影坐标系),中间为什么要费力的插一个右手坐标系呢(观察坐标系)?实际上,在Opengl中,本地坐标系和世界坐标系都是右手坐标系,也就是说,直到投影空间中才变换为左手。而unity中的本地坐标系和世界坐标系是左手系统,所以显得观察坐标系比较的特别。

2、正投影

        正投影见第一张图,在从观察坐标系变换到投影坐标系之后,点 (x,y,z)的取值范围有:

        其变换矩阵可以参考我的坐标系那篇博客:

公式10、正投影的投影变换矩阵

3、透视投影

        透视投影的情况要复杂的多,在这一步,w 值开始正式发挥作用。
        先直接来看变换矩阵(关于求法仍建议阅读坐标系一文)

公式11、透视投影的投影变换矩阵
        对原观察坐标系下点P,变换到投影坐标系下坐标P’为:

公式12、透视投影变换下点的变换情况
        如果只考虑(x,y,z),那么和正投影是相同的,但是多了第四维w,使得 z 坐标轴的指向产生了弯曲

图12、透视坐标系

4、从观察坐标系到投影坐标系——获取变换矩阵

        自己想要计算的话,可以用上面提供的公式计算,unity本身也为我们提供了获取这个变换矩阵的方式。
        在shader中,这一步单独的变换矩阵:
[cpp] view
plain
 copy

  1. UNITY_MATRIX_P
        在script中,如果使用 camera.projectionMatrix ,可能会发现与 shader 中的这个矩阵有些差异,这是由于,在我的电脑上(目前不清楚是否和显卡有关),实际使用的变换矩阵,最终会使得 z 的取值范围为 [0, 1],和上面公式略有不同。
        因此在script中,需要使用下面的代码来获取投影变换矩阵:
[cpp] view
plain
 copy

  1. GL.GetGPUProjectionMatrix(c.projectionMatrix, false)

5、值得注意的w分量

        之前的 w 分量一直为1,现在终于有了作用。在正投影变换后,w的值仍然是1;但是在透视投影变换之后,w的值等于观察坐标系下的 -z。另外,在透视坐标系中,在 shader 中实际应该使用的 x、y、z分量应当是 P 在变换后的坐标值的 Px、Py、Pz分量除以 w 来获取。
        一说到除以就必须当心0除问题,w有可能是0吗?答案是不可能,这是由于透视投影的camera的视锥体中的点,其z的取值范围是 [-ZFar, -ZNear],不会取值到0。

六、切线空间

1、切线空间的形态

        在做 bump map的时候,会提到切线空间 tangent space。切线空间的具体意义这里不展开讨论(关于这个问题,解释的最清楚的是《OpenGL的法线贴图教程》),这里主要讨论坐标系变换问题。
        切线空间的坐标轴分别为:
  • X轴——切线 tangent
  • Y轴——副切线 biTangent
  • Z轴——法线 normal
        其中,法线即我们平时所说的法线:


        切线选取的是,与法线垂直的,沿着贴图uv的u变量增长方向的向量:


        副切线则选取与这两个向量都垂直的,一般通过叉乘得到。从而构成坐标系:


        需要注意的是,unity中,实际获得的 B 向量,可能与这张图中的 B 向量反向

2、在unity中获得和使用切空间变换矩阵

        在unity中,有这样一个宏 TANGENT_SPACE_ROTATION,可以获得变换到切线空间
[cpp] view
plain
 copy

  1. #define TANGENT_SPACE_ROTATION \
  2. float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; \
  3. float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal )
        使用的时候,可以这样用:
[cpp] view
plain
 copy

  1. TANGENT_SPACE_ROTATION;
  2. o.viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex));
        这个变换矩阵有很多细节值得说明,我们下面一个一个来看。

3、这是个什么样的矩阵?

        这个问题换个问法就是,float3x3如何构造?
        实际上,float3x3是行优先填充元素的,可以看这里。所以,这个矩阵是:

        注意,这个矩阵作为变换矩阵是非常奇怪的。回忆我们在 第三节世界坐标系 中,第2小节的结论:
  • 点P在坐标系V下的坐标,相当于其在坐标系U下的坐标,左乘矩阵T,其中T为 坐标系U的三个基(列向量)在坐标系V下的坐标构成的矩阵。
        因此变换矩阵应当是一个由三个列向量构成的矩阵,而现在却是三个行向量,这是为什么?

4、转置与逆矩阵

        现在回答前面的问题:原因在于,实际上这是一个逆矩阵。
        首先,可以注意到,三个基向量(T,B,N)都是单位向量,且两两正交。则其构成的矩阵是一个正交矩阵。对于正交矩阵,其转置矩阵就是他的逆矩阵,因此有:

        注意看后面的这个矩阵,他显然满足前面的结论,T、B、N都是在本地坐标系下的值,因此这个列向量构成的 [T B N] 矩阵,是将点从切线坐标系变换到本地坐标系的变换矩阵。 那么这个矩阵的逆矩阵,就是将点从本地坐标系变换到切线坐标系的变换矩阵。而由于正交,其逆矩阵就是其转置矩阵,所以从本地坐标系变换到切线坐标系的变换矩阵,就是我们在第2小节里面看到的情况

5、左手坐标系?右手坐标系?

        由于 B 向量是叉乘得到的,那么一个值得关注的问题就是,这个坐标系到底是左手规则还是右手规则?这就牵涉到之前的另外一个结论:对于叉乘,在左手坐标系中使用左手规则,在右手坐标系中使用右手规则,但是无论使用哪个规则,其数学计算表达式并不会有任何不同。
        而现在,N、T都是在本地坐标系中的向量,而本地坐标系是一个左手坐标系,所以 N 和 T 的叉乘使用左手规则,那么在没有其他变数的情况下,T、B、N应该如下,构成一个左手坐标系


        但是现在还有一个变量 tangent.w,他的取值为 1 或 -1。如果为1,则上面的结论不变,如果为-1,则B则会反向,从而构成一个右手坐标系。
这个变量的存在是由于B 向量通常还代表着 uv 中 v 增长的方向,所以需要调整 B 轴使得他和 v 增长的方向一致。(这里可参考这篇文章

        至此,对于坐标系的讨论基本就告一段落了。

Unity 中的坐标系的更多相关文章

  1. maya和Unity中的坐标系旋转

    maya软件是用的右手坐标系,默认旋转顺序是ZYX,即先绕Z轴旋转,再绕Y轴旋转,最后绕X轴旋转. 比如在maya软件中,右侧的旋转顺序是可选的,默认的选择是“XYZ”,其实物体旋转顺序是倒着念,即上 ...

  2. 解读Unity中的CG编写Shader系列八(镜面反射)

    转自http://www.itnose.net/detail/6117378.html 讨论完漫反射之后,接下来肯定就是镜面反射了 在开始镜面反射shader的coding之前,要扩充一下前面提到的知 ...

  3. 解读Unity中的CG编写Shader系列三

    转自http://www.itnose.net/detail/6096068.html 在上一个例子中,我们得到了由mesh组件传递的信息经过数学转换至合适的颜色区间以颜色的形式着色到物体上.这篇文章 ...

  4. unity中的欧拉角

    unity中欧拉角用的是heading - pitch -bank系统(zxy惯性空间旋转系统):当认为旋转顺序是zxy时,是相对于惯性坐标系旋转.当认为旋转顺序是yxz时,是相对于物体坐标系旋转. ...

  5. 【Unity编程】Unity中的欧拉旋转

    欧拉角的定义 在写这篇博客之前,我搜索了网上很多关于欧拉角的定义,发现大部分引用自维基百科的定义,我这里也引述一下: 维基百科定义 莱昂哈德·欧拉用欧拉角来描述刚体在三维欧几里得空间的取向.对于任何参 ...

  6. 骨骼动画的原理及在Unity中的使用

    制作骨骼动画 我们看看这几步操作后,我们得到了那些数据: 1.每个皮肤顶点的初始世界坐标. 2.每个骨骼关节顶点的初始世界坐标. 3.每个顶点被骨骼顶点的影响信息. 4.骨骼如何移动. 骨骼动画原理 ...

  7. unity中camera摄像头控制详解

    目录 1. 缘起 2. 开发 2.1. 建立项目 2.2. 旋转 2.2.1. 四元数 2.3. 移动 2.3.1. 向量操作 2.4. 镜头拉伸 2.5. 复位 2.6. 优化 1 缘起 我们的产品 ...

  8. 介绍Unity中相机的投影矩阵与剪切图像、投影概念

    这篇作为上一篇的补充介绍,主要讲Unity里面的投影矩阵的问题: 上篇的链接写给VR手游开发小白的教程:(三)UnityVR插件CardboardSDKForUnity解析(二) 关于Unity中的C ...

  9. 游戏的物理和数学:Unity中的弹道和移动目标提前量计算

    下载地址:https://www.jianguoyun.com/p/DZPN6ocQ2siRBhihnx8 弹道计算是游戏里常见的问题,其中关于击中移动目标的自动计算提前量的话题,看似简单,其实还是挺 ...

随机推荐

  1. Numpy数组的保存与读取方法

    1. 数组以二进制格式保存 np.save和np.load是读写磁盘数组数据的两个主要函数.默认情况下,数组以未压缩的原始二进制格式保存在扩展名为npy的文件中,以数组a为例 np.save(&quo ...

  2. 设置ubuntu默认输入python进入python3

    执行下面两条命令 sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 100 sudo update- ...

  3. iOS MVVM+RAC 从基础到demo

    一.关于经典模式MVC的简介 MVC是构建iOS App的标准模式,是苹果推荐的一个用来组织代码的权威范式,市面上大部分App都是这样构建的,具体组建模式不细说,iOS入门者都比较了解(虽然不一定能完 ...

  4. Java一致性的实现

    一致性     内存模型 每一个线程有一个工作内存和主存独立 工作内存存放主存中变量的值的拷贝     Happen Before 1.程序次序规则:在一个单独的线程中,按照程序代码的执行流顺序,(时 ...

  5. 在win7下使用git和gitlab进行code review

    1.安装 Git-2.6.3-64-bit.exe  下载地址:http://pan.baidu.com/s/1hqGvwnq 2.根据收到的邮件进入gitlab网站,并修改密码登陆 3.新建一个文件 ...

  6. iOS 开发实践之 Auto Layout

    原:http://xuexuefeng.com/autolayout/?utm_source=tuicool 本文是博主 iOS 开发实践系列中的一篇,主要讲述 iOS 中 Auto Layout(自 ...

  7. POJ 1330 Nearest Common Ancestors 【最近公共祖先LCA算法+Tarjan离线算法】

    Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20715   Accept ...

  8. .net 常用的插件列表

    1,.net 分布式Session 解决方案RedisSessionStateProvider 2,c# 表达式树查看工具 Expression Tree Visualizer 3,sqlbuilde ...

  9. python操作cad

    from pyautocad import Autocad # 自動連接上cad,只要cad是開着的,就創建了一個<pyautocad.api.Autocad> 對象.這個對象連接最近打開 ...

  10. BZOJ 1202 [HNOI2005]狡猾的商人:并查集(维护距离)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1202 题意: 有一个账本,记录了n个月的盈亏. 每个月的数值:正为盈,负为亏. 你知道m个 ...