3D图形数学速成课(NOTE)

 

可以找到一组坐标(v1,v2,v3),使得

 

v = v1 a + v2 b + v3 c 1

 

而对于一个p,则可以找到一组坐标(p1,p2,p3),使得

 

p – o = p1 a + p2 b + p3 2


从上面对向量的表达,我们可以看出为了在坐标系中表示一个(如p),我们把点的位置看作是对这个基的原点o所进行的一个位移,即一个向量——p – o(有的书中把这样的向量叫做位置向量——起始于坐标原点的特殊向量),我们在表达这个向量的同时用等价的方式表达出了点p:

 

o + p1 a + p2 b + p3 c (3)

(1)(3)是坐标系下表达一个向量的不同表达方式。这里可以看出,虽然都是用代数分量的形式表达向量和点,但表达一个点比一个向量需要额外的信息。如果我写出一个代数分量表达(1, 4, 7),谁知道它是个向量还是个点!

 

我们现在把(1)(3)写成矩阵的形式:

这里(a,b,c,o)是坐标基矩阵,右边的列向量分别是向量v和点p在基下的坐标。这样,向量和点在同一个基下就有了不同的表达:3D向量的第4个代数分量是0,而3D的第4个代数分量是1。像这种这种用4个代数分量表示3D几何概念的方式是一种齐次坐标表示。


“齐次坐标表示是计算机图形学的重要手段之一,它既能够用来明确区分向量和点,同时也更易用于进行仿射(线性)几何变换。”—— F.S. Hill, JR


从普通坐标转换成齐次坐标时,

如果(x,y,z)是个点,则变为(x,y,z,1);

如果(x,y,z)是个向量,则变为(x,y,z,0)

 

从齐次坐标转换成普通坐标时,

如果是(x,y,z,1),则知道它是个点,变成(x,y,z);

如果是(x,y,z,0),则知道它是个向量,仍然变成(x,y,z)

以上是通过齐次坐标来区分向量和点的方式。从中可以思考得知,对于平移T、旋转R、缩放S3个最常见的仿射变换,平移变换只对于点才有意义,因为普通向量没有位置概念,只有大小和方向,这可以通过下面的式子清楚地看出:

而旋转和缩放对于向量和点都有意义,你可以用类似上面齐次表示来检测。从中可以看出,齐次坐标用于仿射变换非常方便。




重点



此外,对于一个普通坐标的P=(Px, Py, Pz),有对应的一族齐次坐标(wPx, wPy, wPz, w),其中w不等于零。比如,P(1, 4, 7)的齐次坐标有(1, 4, 7, 1)、(2, 8, 14, 2)、(-0.1, -0.4, -0.7, -0.1)等等。因此,如果把一个点从普通坐标变成齐次坐标,给x,y,z乘上同一个非零数w,然后增加第4个分量w;如果把一个齐次坐标转换成普通坐标,把前三个坐标同时除以第4个坐标,然后去掉第4个分量。



由于齐次坐标使用了4个分量来表达3D概念,使得平移变换可以使用矩阵进行,从而如F.S. Hill, JR所说,仿射(线性)变换的进行更加方便。由于图形硬件已经普遍地支持齐次坐标与矩阵乘法,因此更加促进了齐次坐标使用,使得它似乎成为图形学中的一个标准。



简单的线性插值

 

这是在图形学中普遍使用的基本技巧,我们在很多地方都会用到,比如2D位图的放大、缩小,Tweening变换,以及我们即将看到的透视投影变换等等。基本思想是:给一个x属于[a, b],找到y属于[c, d],使得xa的距离比上ab长度所得到的比例,等于yc的距离比上cd长度所得到的比例,用数学表达式描述很容易理解:

这样,从ab的每一个点都与cd上的唯一一个点对应。有一个x,就可以求得一个y

此外,如果x不在[a, b]内,比如x < a或者x > b,则得到的y也是符合y < c或者y > d,比例仍然不变,插值同样适用。



答疑


请教文主几个问题:
1.裁剪是发生在原始投影之后,cvv之前的吗?如果是这样,那cvv的作用就没了啊;如果不是,那么cvv之后的原始z信息丢失后怎么完成裁剪啊?
2.透视投影完了之后,顶点数据是不是就是2D的了?然后根据索引缓存把一个个的三角形图元送进光栅单元?
3.经过透视投影后,顶点的z信息不是丢失了吗(透视除法)?
那么后期的z——buff测试怎么进行?
希望文主指教 TKS
Re:  Twinsen 2014-03-03 22:06发表 [回复]
回复multiapple:1.裁剪发生在透视变换之后,透视除法之前。这个时候顶点的坐标是4D的齐次形式,用透视除法可以得到CVV中的NDC坐标。而不用除法的话,第四个分量保存了一部分原始z的信息。
2.透视投影完了之后,顶点数据还是3D的,但是已经是单位话的设备坐标了,也就是NDC。三个分量的范围都在[-1,1](opengl),也就是CVV中。这个时候进行viewport(VP)变换就可以进入VP中了,变换之后在VP中进行光栅化。
3.经过透视投影后,顶点的原始z信息丢了,但得到了[-1,1]中的z,顶点之间的z顺序不会有变,不会影响通过NDC的z光栅化得到的fragment的z进行depth test。



原来Normalize Device Coordinate坐标就是所谓的CVV啊。我就是不明白Luna为什么要转化到[-1,1]这个坐标来,原来是为了以后裁剪方便啊!!!


对了,还想问下:如果要熟练的对这些矩阵变换掌握,能够到达自己编写3D引擎的程度,应该看下什么方面的数学知识???
Re:  Twinsen 2013-09-23 10:06发表 [回复]
回复i_dovelemon:如果想自己写3D引擎,以下几个应该要掌握:
1. 向量(矢量)
2. 矩阵
3. SGI经典流水线的每个细节。
我的这些文章基本上都涵盖了:)


很不错的文章,受益匪浅,谢谢作者的分享!
我有两个问题。
1. 投影面跟近裁剪面是同一个面吗?
2. 一般流程是在得到3d物体的投影坐标后,再转换到cvv坐标,最后再转成屏幕坐标。但是整个推导只是得到了将投影坐标转成cvv坐标的矩阵,最后将cvv坐标转成屏幕坐标需要做哪些工作?
Re:  Twinsen 2013-09-18 15:17发表 [回复]
回复superleg_2008:1. 投影平面可以是平行于前裁剪平面的任何平面。只要fov固定,投影得到的结果都是一样的。
2. 将cvv转换到视口坐标,就是把[-1,1]转换到[0, viewportWidth],做个简单的线性插值就可以了。

Hi Twinsen 有个问题想问一下你,我目前正在看Andre LaMothe的3D游戏编程大师,在书中讲到的投影矩阵和你最后推导出来的矩阵相差很大
(P311页,其矩阵为
(d,0,0,0),
(0,d,0,0),
(0,0,1,1),
(0,0,0,0)),
我个人认为存在差别的原因有几个:
1`书中的矩阵乘法和你推导的是相反的(你推导的是矩阵x坐标点,书中的是坐标点x矩阵)。
2`关于x,y的投影,书中采用的是特殊形式(两个角度均为90度,d值为1,也就是你用到的-N值[那块也不太理解,为何为-N?]),而你推导的是一般形式
3`书中没有涉及到z值的投影,这块就我后续的一些了解,需要将z转换为1/z,因为1/z才是成线性的,用于后续的剪裁,z缓冲,纹理映射(目前不太懂这块)
我想问的是
1·关于前两点我说的是否正确?
2·第三点如果为了转换为1/z,为何为(az+b)/z=a+(1/z)b的形式?,我看你后来给silent2088的解释为如果为(z+b)/z=1+(1/z)*b将没有唯一的解,这块不是很理解,另外我还是不太理解为何不能直接存储1/z?
我需要先看看哪方面的知识才能理解么?
谢谢
Re:  Twinsen 2012-12-18 14:00发表 [回复]
回复Eran:恩,那本书的推导我很久之前也研究过。在这本书中,作者去掉了cvv裁剪的部分,因此得到了更简单一些的投影矩阵。1 你的前两点说的没错。还有一点就是他好像把视口变幻也揉进了这个矩阵。另外,作者去掉了cvv裁剪这个步骤,使用了更简单的提出方式。2 其实用1/z已经可以了,但这也是去掉了cvv裁剪的情况。至于我为什么说是(az+b)/z=a+(1/z)b这样的形式,是因为: z和z'也非线性关系 ,和透视纹理映射一样,是z'=a(1/z)+b的关系, 也就是说z'和1/z是线性关系 ,也就是z'=(az+b)/z的关系(线性关系的一般形式是y=ax+b,其中x和y是变量,a和b是系数)。这是我在研究透视纹理映射的时候学到的。 具体的推论可以参考我的透视纹理映射的文章;)


44楼  Twinsen 2010-03-09 11:25发表 [回复] [引用] [举报]
在shader下的几何阶段,来自用户的矩阵基本上包括:模型变换矩阵,观察矩阵,透视矩阵这三个(前两个可以合并)。其中只有最后一个矩阵和裁剪有关。裁剪程序会使用CVV对透视变换之后的图元进行裁剪,用户只能够通过设置透视矩阵来改变变成CVV之前的视锥体,对CVV本身没有插手的余地,CVV是固定的。最后程序会用CVV来对顶点组成的图元进行裁剪操作。裁剪信息只有两类:裁剪体CVV(固定的东西)以及图元顶点们。

如果在shader下没有指定透视矩阵的相关参数(fov, aspect, near, far),则d3d或者ogl会使用默认的透视矩阵进行操作。具体的默认值可以参考d3d或者ogl的相关手册。
41楼  CxxlMan 2010-03-09 03:02发表 [回复]
現在的情況是在 shader 下用戶自定的矩陣並未告知 D3D 和 OpenGL,而裁剪須要有足夠的訊息,這些訊息要從哪取得呢
40楼  Twinsen 2010-03-06 16:01发表 [回复]
CxxlMan, -(za+b)/z=-1的时候,z是等于-N的(OpenGL环境) 。非shader时,D3D会通过用户提供的参数生成透视投影矩阵。shader下需要用户自己定制这个矩阵,具体的矩阵形式可以参考《深入探索透视投影变换(续)》中关于d3d相应矩阵的推导,如果对推导过程不感兴趣,可以直接使用结论。



39楼  CxxlMan 2010-03-06 08:25发表 [回复] [引用] [举报]
要由 -(za+b)/z 得到近裁剪面的 z 值,須設 -(za+b)/z = -1,經轉化後 z = -(b / (a-1)),但這是已知矩陣的情況下,
若是使用 Shader 的方式來編寫 D3D 的程式,D3D 應不知矩陣的內容吧?只知一系列轉換前的頂點(x,x,z,1)和一系列轉換後的頂點(x',x',z',w),
所以須由 兩個 轉換後的頂點中的 z' 值(za+b)求 a 和 b 的解,
D3D 是不是這樣做的呢?
38楼  Twinsen 2010-03-02 21:45发表 [回复]
对,-(za+b)/z就是原始z在CVV空间中的对应物,范围是[-1, 1]。


兩個 轉換後的頂點中的 z' 值(za+b)求 a 和 b 的解,
我对这句话的理解,之所以需要两个 ,因为解方程需要两个

37楼  silent2088 2010-03-02 18:55发表 [回复] [引用] [举报]
-(za+b)/z,不是投影之后的z,投影之后的z已经在-N平面上了,这个z是原始z在CVV空间中的对应物。
上面是引用你的话,我想说:“这个z是原始z在CVV空间中的对应物。”在这一句中的z是指-(za+b)/z这个嘛?
36楼  Twinsen 2010-03-02 15:19发表 [回复]
这样得到的z会存在精度问题。越靠近-N的原始z在CVV中的z的精度范围越高 。提高整体精度的方法就增大N。这一点可以通过考察方程组进行分析,CVV的z范围曲线在很多图形学文献中都有展现。
35楼  Twinsen 2010-03-02 15:14发表 [回复]
silent2088,你说的没错!-(za+b)/z,不是投影之后的z,投影之后的z已经在-N平面上了, 这个z是原始z在CVV空间中的对应物,它的范围会在[-1, 1] ,用来在光栅化阶段进行片元的z缓冲测试。请注意, 虽然原始z在范围[-N, -F]对应新z在范围[-1, 1], 这个变化却不是线性的
因为新z的计算并不是对原始z进行简单线性插值得到的, 而是通过透视矩阵ver1上面的非线性方程组得到的
34楼  Twinsen 2010-03-02 09:35发表 [回复] [引用] [举报]
silent2088, za+b是一种一元一次的线性形式 ,可以用矩阵非常容易的处理,你可以看透视矩阵版本一的a和b。如果写成 二次或者以上的形式就无法用矩阵简单表示,方程组解起来也很困难 。如果写成 za,会和下面的z抵销掉 。如果写成 z+b,关于z的方程组无唯一解 。因此使用上述形式。
Re:  silent2088 2010-03-02 14:16发表 [回复] [引用] [举报]
回复Twinsen:你刚开始说投影的结果z’始终等于-N,在投影面上。实际上,z’对于投影后的P’已经没有意义了,这个信息点已经没用了,利用这个没用的信息点存储z,那你为什么突然变到(za+b)/z?我想是不是如下这样的(你帮忙看下对不对)最后得到的z'你说是在归一化的坐标系中的cvv的值,然后通过比较最后变化后的z'值来进行z深度测试的吗?
Re:  Twinsen 2010-05-04 14:26发表 [回复] [引用] [举报]
回复silent2088: D3DXMatrixPerspectiveLH()调用的时候并没有进行实际的透视投影,只是设置了当前的透视投影矩阵
透视投影是在用API渲染多边形的时候在流水线内部自动进行的,也包括透视除法。就算用shader, 有几个地方也是无法插手的:裁剪、透视除法、视口变换以及光栅化

33楼  silent2088 2010-03-01 17:35发表 [回复] [引用] [举报]
我弄不懂你那个为什么要把z写成(za+b)/z,你说了两个原因,第一个我了解了,第二个,你说为了方便进行多边形剪裁,怎么方便啦! 为什么是za+b呢?你为什么不写成其它的形式呢?
Re:  zjghs2007 2011-12-07 16:57发表 [回复] [引用] [举报]
回复silent2088:回复silent2088:
已知: z (点p在z轴上的值)
目标: z‘ (深度信息 -1~+1)
原始问题就转化为,怎么在已知点p的z坐标的情况下,求得用在深度测试中的z’
透视投影中z‘与z之间为非线性关系 —— z‘z = az +b
(PS:正交投影中z’与z为线性关系—— z’ = az + b)
那你肯定要问: (1) 为什么正交投影中z‘和z为线性关系 (2)为什么透视投影不能和正交投影一样都采用线性关系
如果理解了这两个问题,那么就解决你的疑问了~~~ 
关于(1): 正交投影的实质就是 将Frustum的中心先平移到eye坐标系原点,然后再缩放至CVV。x,y,z三轴均是如此,而对z平移和缩放不就是 z’ = az + b吗?为线性关系 ^_^解决
关于(2): 透视投影没有这么简单粗暴,x‘和y’不是简单的平移和缩放就能搞定,x‘ = -Nx/z; y'= -Ny/z,即 x’和x,y'和y不是线性关系,均与z有关。但是注意,此时z‘和z仍可以写成线性关系z’ = az+b,因为透视投影跟正交投影不同的地方只是影响x‘,y’的计算,那为什么z‘也要采取z’z = az+b的非线性关系呢?因为,要少数服从多数啊~~~ ^_^

如果现在你还没有清楚,那是正常的,因为还有一个关键的东西需要理解!
重要: 矩阵*向量 只能模拟线性关系的处理 @###@
所以对于 x‘ = -Nx/z; y'= -Ny/z 必须要先用 矩阵*向量 得到线性关系 x‘ = -Nx; y'= -Ny,然后同时除以z才能得到最终结果 x‘ = -Nx/z; y'= -Ny/z。
记住x,y,z三个轴地位等价,所以处理过程肯定是相同的,对z而言,也需要先用 矩阵*向量 得到线性关系 z’ = az+b (公式1),然后再除以z得到最终结果 z‘ = a + b/z, 即得到z‘和z的非线性关系式 z’z = az + b
现在又有问题了,凭什么 公式1 要这样写,线性关系 z‘= az 或者z' = b为什么不行? 当然啦。要保证方程组 z=N时,z'=-1;z=F时,z'=1有解就必须要 z’ = a + b/z。 z‘= az 和z' = b均是无解! ^_^ 解决

不用谢我哈~~~
Re:  multiapple 2014-03-06 09:17发表 [回复]
回复zjghs2007:不好意思 打扰下 你说的
【矩阵*向量 只能模拟线性关系的处理】
那透视矩阵为什么能把平头椎(视见体)转换成立方体(齐次裁剪空间)呢?这应该不是线性关系吧》?。。。求解释
Re:  Twinsen 2011-12-08 09:53发表 [回复]
回复zjghs2007:恩。 zjghs2007解释的非常详细,很好!其实除了这些方面,还有一个重要的点,也是我后来研究透视纹理映射才得到的结论。
那就是,z和z'也非线性关系,和透视纹理映射一样,是z'=a(1/z)+b的关系,也就是说z'和1/z是线性关系。
因此就是z'=(az+b)/z的关系 。具体的推论可以参考我的透视纹理映射的文章;)


32楼  Twinsen 2010-02-28 10:12发表 [回复]
这个也是目前图形API标准流水线发展的结果。dos年代图形程序员使用的透视投影矩阵大都没有这么复杂,都是很原始、直接的投影目的,就像上面的透视矩阵版本一,甚至都没有将z分量进行规范化。大多数的流水线还是自己定制的,因为没有硬件加速,所以使用软件渲染。
31楼  CxxlMan 2010-02-27 23:55发表 [回复] [引用] [举报]
因為一般討論轉換矩陣和裁剪的關係著墨實在太少了,直覺上認為轉換矩陣的功能就只在空間變換和投影上,我也不是沒想過在透視除法前做裁剪,但以為要另外做處理,須另外提供裁剪邊界相關訊息,沒想到裁剪平面的訊息就隱藏在矩陣中
Re:  tjwhs 2012-08-20 14:29发表 [回复] [引用] [举报]
回复CxxlMan: 个人认为为什么在透视除法前做裁剪:
1:透视除法前能做裁剪:做法:
1.1:判定阶段:如果-w<x<w,-w<y<w,-w<z<w。那么这一点就在CVV中。
1.2:计算阶段:如果线段AB需呀裁剪,计算新点:
t=-(Xa+Wa)/((Xb+Wb)-(Xa+Wa))(对于-w裁剪)
Xnew=Xa+t(Xb-Xa).
所以在除法前完全能做。
2:为什么在除法前做:因为除法是很费时的,在除法前剔除一些顶点,对于除法来说能减少不少时间。
综上所述:既然裁剪在除法之前能做,又能节约时间,那为什么不在除法之前做呢???对吧。。


30楼  Twinsen 2010-02-26 16:52发表 [回复] [引用] [举报]
但是,实际上的裁剪使用的形式是透视除法之前的形式,也就是(x, y, z, w)的形式,使用这样一个形式的好处是,我 们可以在裁剪的时候使用w分量进行某些工作 ,而且也可以在裁剪过程中 进行临时的透视除法得到CVV中的坐标,一举两得。 最后 经过了裁剪,就进行真正的透视除法 ,得到了CVV中的物体坐标。这样讲是不是清楚一些了?
Re:  silent2088 2010-05-04 13:54发表 [回复] [引用] [举报]
回复Twinsen:你好! 我实现了阴影之后,对这个东西还有一定的理解了, 我还想问下楼主,你上面所说到“其中z/w得到的就是NDC中的深度值,用来做z缓冲深度测试&quot; 我用的是DX,我想问的是它不是有函数吗? 进行透视投影的DX中是D3DXMatrixPerspectiveLH ,它是在这个函数执行的时候就进行透视除法吧! 我看到的有些关于阴影的例子,它们怎么要自己去执行z/w啊?
Re:  silent2088 2010-05-04 14:24发表 [回复] [引用] [举报]
回复silent2088: 噢! 我差不多想明白了![e04]
Re:  Twinsen 2010-05-04 14:27发表 [回复]
回复silent2088: 自己作透视除法 的情况基本上都是希望 自己控制这几个shader不能编程的阶段 。或者是要把一个顶点不通过流水线而是自己变换到屏幕上。比如一 些特殊UI,或者做2D的拾取 等等。
Re:  Twinsen 2010-05-04 14:27发表 [回复] [引用] [举报]
回复silent2088: D3DXMatrixPerspectiveLH()调用的时候并没有进行实际的透视投影,只是设置了当前的透视投影矩阵。 透视投影是在用API渲染 多边形的时候在流水线内部自动进行的,也包括透视除法。就算用shader, 有几个地方也是无法插手的 :裁剪、透视除法、视口变换以及光栅化。
Re:  silent2088 2010-05-04 15:06发表 [回复] [引用] [举报]
回复Twinsen:嗯!明白了!将相机坐标系中的(x,y,z)实际上是转换到cvv中的坐标吧! 像z值应该是离相机的距离值, 乘完透视矩阵后-(za+b)/z实际就是在cvv中的值,如果近平面和远平面的值分别是1和1000,那么乘完后的值就是在这1~1000之间的值, 就是这样进行z缓冲消隐的吧!
Re:  Twinsen 2010-05-04 15:39发表 [回复] [引用] [举报]
回复silent2088: 在相机空间中的近远裁剪平面不管是多少,变换到CVV中之后都是[-1, 1](OpenGL)
Re:  silent2088 2010-05-04 15:57发表 [回复] [引用] [举报]
回复Twinsen: 噢! 乘出来以后它都是在-1~1之间的啊!
Re:  Twinsen 2010-05-04 16:03发表 [回复]
回复silent2088:对,没错!



8楼  Twinsen 2009-09-27 12:40发表 [回复]
diyer2002

opengl在进行裁剪的时候使用的是未经透视除法的 齐次坐标形式 ,在这个 形式的基础上进行裁剪比较方便 (主要是可以 留住原始的z值 ,并且在CVV裁剪的时候 随时可以用x,y,z除以w得到CVV中的值 )。而 裁剪完毕之后呢,才会真正的使用透视除法把齐次形式变成普通形式 。在外部看来,实际上可以理解为裁剪和透视除法是一步完成的,但具体来看就是我上面所说那样的。
7楼  diyer2002 2009-09-20 19:41发表 [回复]
&quot;是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume)中,待裁剪完毕后进行透视除法的行为&quot;

请问如果没有进行透视除法,如何能得到CVV,既然裁剪是在CVV中进行的,为啥在裁剪完毕,才进行透视除法(没有进行透视除法,如何得到CVV?)?

9楼  Twinsen 2009-09-27 12:45发表 [回复] [引用] [举报]
lovewhatilove

恩,你说的没错,这样简化计算不错。实际上
投影平面可以是任意的,但大多数的情况则简化为前裁剪平面。 这里的推导肯定是以通用的前裁剪平面来看待,为什么呢? 就是因为现在的图形API基本上都用这个平面

因此就是z'=(az+b)/z的关系  为什么不是 z'=-(az+b)/z,负号哪去了????


11楼  Twinsen 2010-02-10 09:46发表 [回复] [引用] [举报]
CxxlMan,我们推导矩阵的时候需要除以z,但 实际上矩阵推导完成之后,会在透视除法之前进行裁剪。所以z=0的部分都会被剔除掉 ,不会出现除零的情况。这也 看出裁剪的必要性
10楼  CxxlMan 2010-02-09 20:16发表 [回复]
我有一個疑問
那個 z 的值若正好為 0 不會有問題嗎?





CVV的z范围曲线在很多图形学文献中都有展现。??????/
因为新z的计算并不是对原始z进行简单线性插值得到的, 而是通过透视矩阵ver1上面的非线性方程组得到的 ?????????

这个式子在z = -N的时候值为-1,而在z = -F的时候值为1  ,为什么?????????为什么不是 1 到 -1 呢??????



平行于近裁面 都可以投影,那各个平行关系的投影面有区别吗??????

实际上 投影平面可以是任意的,但大多数的情况则简化为前裁剪平面。 这里的推导肯定是以通用的前裁剪平面来看待,为什么呢? 就是因为现在的图形API基本上都用这个平面



opengl在进行裁剪的时候使用的是未经透视除法的齐次坐标形式,在这个形式的基础上进行裁剪比较方便(主要是可以留住原始的z值,并且在CVV裁剪的时候随时可以用x,y,z除以w得到CVV中的值)。而裁剪完毕之后呢,才会真正的使用透视除法把齐次形式变成普通形式。在外部看来,实际上可以理解为裁剪和透视除法是一步完成的,但具体来看就是我上面所说那样的。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值