OpenGL学习例程及函数精析(地日模型)

前言

前段时间在工程中会用到opengl来进行一些渲染和建模的操作,未来一段时间会重点更新这个专栏,用最高信噪比的方式来讲解opengl典型函数和结构的应用。通过这种手把手的方式我相信是新手朋友学习最快的路径。这个专栏会照顾到大家,让大家能够自己上手去改一些东西并且看到效果,这样在我看来是最高效率的学习方法。

OpenGL的渲染和建模代码大结构

鉴于OpenGL一般只是一段代码中的中间处理过程,所以把整个的OpenGL操作放到一个函数当中,未来的代码构造也会与这里大致相同。

一般一个典型的OpenGL处理片段包括以下几个步骤:

  1. 初始化显示模式(RGB模式,双缓冲模式)。
  2. 初始化显示窗口的位置。
  3. 初始化显示窗口的大小。
  4. 设置OpenGL显示函数。
  5. 需要动态变化的调用相关的计数、计时
  6. 主函数循环。

在设置OpenGL显示函数的时候,又有以下几个典型步骤:

  1. 清除屏幕及缓存
  2. 定义变换类型(之前的文章有讲)
  3. 设置相机参数(视口变换)
  4. 设置观察位置
  5. 设置光源
  6. 定义物体材质
  7. 设置缓冲区交换

重点函数精析

设置相机参数(视口变换)

gluPerspective(90.0f, 1.0f, 1.0f, 20.0f);			//视口变换

设置相机参数 void gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)

aspect表示裁剪面的宽w高h比,这个影响到视野的截面有多大。
fovy是眼睛上下睁开的幅度,角度值,值越小,视野范围越狭小(眯眼),值越大,视野范围越宽阔(睁开铜铃般的大眼);
zNear表示近裁剪面到眼睛的距离,zFar表示远裁剪面到眼睛的距离,注意zNear和zFar不能设置设置为负值(你怎么看到眼睛后面的东西)。

设置观察位置

gluLookAt(0.0, 5.0, -10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);

gluLookAt用来定义观察者(相机)的状态,包括观察者在世界坐标系中所处的位置、看向世界坐标系中的方向(可以理解为眼睛所看向的方向)、观察者头部的朝向(可以在一个平面上360°旋转)

void gluLookAt (
GLdouble eyex, GLdouble eyey, GLdouble eyez,
GLdouble centerx, GLdouble centery, GLdouble centerz,
GLdouble upx, GLdouble upy, GLdouble upz);

第一二三个参数定义相机在世界坐标系中的位置坐标
第四五六个参数定义相机正对着的世界坐标系中的点的位置坐标,成像后这一点会位于画板的中心位置
第七八九参数,定义相机本身的朝向。这三个坐标是在世界坐标系中的坐标点,可以理解为人站立在相机处头的朝向。这三个坐标是世界坐标系中的坐标点,不是相机坐标系的,只是用来定义方向,注意这个不是视线(镜头)的朝向,而是摆放时相机本身的朝向,跟视线朝向方向是垂直的。

以观察者的角度去看这几个参数就很容易理解了。

第一组参数是定义人站在距离物体有多远处,
第二组参数是定义人眼看向世界坐标系中的哪个方向,有时候屏幕上黑黑的什么也看不到,可能就是这组参数设置的方向不对,有可能物体就在你身后不远处
第三组参数是人的朝向,也表示一个方向,这个朝向跟视线是垂直的。

始终需要明确的一点是openGL中世界坐标系是右手坐标系,在二维屏幕上,屏幕水平方向是x 轴方向,向右为正,屏幕竖起方向是Y轴方向,向上为正,垂直于屏幕的方向是Z轴方向,从屏幕里往外为正。

定义光源

GLfloat sun_light_ambient[]   = {0.0f, 0.0f, 0.0f, 1.0f};		//遗留强度
GLfloat sun_light_diffuse[]   = {1.0f, 1.0f, 1.0f, 1.0f};		//漫反射强度
GLfloat sun_light_specular[]  = {1.0f, 1.0f, 1.0f, 1.0f};		//镜面反射强度
GLfloat sun_light_position[]  = {0.0f, 0.0f, 0.0f, 1.0f};		//光源位置
glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position);//GL_LIGHT0:0号光源的定义,总共可以定义8个光源
glLightfv(GL_LIGHT0, GL_AMBIENT,   sun_light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE,   sun_light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, sun_light_specular);

glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);

(1)GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR属性。这三个属性表示了光源所发出的光的反射特性(以及颜色)。

每个属性由四个值表示,分别代表了颜色的R, G, B, A值。
GL_AMBIENT表示该光源所发出的光,经过非常多次的反射后,最终遗留在整个光照环境中的强度(颜色)。
GL_DIFFUSE表示该光源所发出的光,照射到粗糙表面时经过漫反射,所得到的光的强度(颜色)。
GL_SPECULAR表示该光源所发出的光,照射到光滑表面时经过镜面反射,所得到的光的强度(颜色)。

(2)GL_POSITION属性。表示光源所在的位置。由四个值(X, Y, Z, W)表示。
如果第四个值W为零,则表示该光源位于无限远处,前三个值表示了它所在的方向。

这种光源称为方向性光源,通常,太阳可以近似的被认为是方向性光源。
如果第四个值W不为零,则X/W, Y/W, Z/W表示了光源的位置。这种光源称为位置性光源。

对于位置性光源,设置其位置与设置多边形顶点的方式相似,各种矩阵变换函数例如:glTranslate*、glRotate*等在这里也同样有效。方向性光源在计算时比位置性光源快了不少,因此,在视觉效果允许的情况下,应该尽可能的使用方向性光源。

(3)GL_SPOT_DIRECTION、GL_SPOT_EXPONENT、GL_SPOT_CUTOFF属性。

表示将光源作为聚光灯使用(这些属性只对位置性光源有效)。
很多光源都是向四面八方发射光线,但有时候一些光源则是只向某个方向发射,比如手电筒,只向一个较小的角度发射光线。

GL_SPOT_DIRECTION属性有三个值,表示一个向量,即光源发射的方向。
GL_SPOT_EXPONENT属性只有一个值,表示聚光的程度,为零时表示光照范围内向各方向发射的光线强度相同,为正数时表示光照向中央集中,正对发射方向的位置受到更多光照,其它位置受到较少光照。

数值越大,聚光效果就越明显。

GL_SPOT_CUTOFF属性也只有一个值,表示一个角度,它是光源发射光线所覆盖角度的一半,其取值范围在0到90之间,也可以取180这个特殊值。取值为180时表示光源发射光线覆盖360度,即不使用聚光灯,向全周围发射。

(4)GL_CONSTANT_ATTENUATION、GL_LINEAR_ATTENUATION、GL_QUADRATIC_ATTENUATION属性。

这三个属性表示了光源所发出的光线的直线传播特性(这些属性只对位置性光源有效)。
现实生活中,光线的强度随着距离的增加而减弱,OpenGL把这个减弱的趋势抽象成函数:
衰减因子 = 1 / (k1 + k2 * d + k3 * k3 * d)
其中d表示距离,光线的初始强度乘以衰减因子,就得到对应距离的光线强度。
k1, k2, k3分别就是GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION, GL_QUADRATIC_ATTENUATION。通过设置这三个常数,就可以控制光线在传播过程中的减弱趋势。

属性还真是不少。当然了,如果是使用方向性光源,(3)(4)这两类属性就不会用到了,问题就变得简单明了。

定义材质

GLfloat sun_mat_ambient[]   = {0.0f, 0.0f, 0.5f, 1.0f};		//类似于光照
GLfloat sun_mat_diffuse[]   = {0.0f, 0.0f, 0.5f, 1.0f};		//类似于光照,通常GL_AMBIENT和GL_DIFFUSE都取相同的值,可以达到比较真实的效果
GLfloat sun_mat_specular[] = {0.0f, 0.0f, 1.0f, 1.0f};		//镜面反射
GLfloat sun_mat_emission[] = {0.5f, 0.0f, 0.0f, 1.0f};		//散发淡淡的红光
GLfloat sun_mat_shininess   = 30.0f;						//0-128
glMaterialfv(GL_FRONT, GL_AMBIENT,    sun_mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE,    sun_mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR,   sun_mat_specular);
glMaterialfv(GL_FRONT, GL_EMISSION,   sun_mat_emission);
glMaterialf(GL_FRONT, GL_SHININESS, sun_mat_shininess);

glutSolidSphere(2.0, 40, 32);

控制材质:

材质与光源相似,也需要设置众多的属性。不同的是,光源是通过glLight函数来设置的,而材质则是通过glMaterial函数来设置的。glMaterial*函数有三个参数。第一个参数表示指定哪一面的属性。可以是GL_FRONT、GL_BACK或者GL_FRONT_AND_BACK。

分别表示设置“正面”“背面”的材质,或者两面同时设置。第二、第三个参数与glLight*函数的第二、三个参数作用类似。

下面分别说明glMaterial*函数可以指定的材质属性。

(1)GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR属性。
这三个属性与光源的三个对应属性类似,每一属性都由四个值组成。
GL_AMBIENT表示各种光线照射到该材质上,经过很多次反射后最终遗留在环境中的光线强度(颜色)。
GL_DIFFUSE表示光线照射到该材质上,经过漫反射后形成的光线强度(颜色)。
GL_SPECULAR表示光线照射到该材质上,经过镜面反射后形成的光线强度(颜色)。
通常,GL_AMBIENT和GL_DIFFUSE都取相同的值,可以达到比较真实的效果。
使用GL_AMBIENT_AND_DIFFUSE可以同时设置GL_AMBIENT和GL_DIFFUSE属性。

(2)GL_SHININESS属性。
该属性只有一个值,称为“镜面指数”,取值范围是0到128。
该值越小,表示材质越粗糙,点光源发射的光线照射到上面,也可以产生较大的亮点。
该值越大,表示材质越类似于镜面,光源照射到上面后,产生较小的亮点。

(3)GL_EMISSION属性。
该属性由四个值组成,表示一种颜色。
OpenGL认为该材质本身就微微的向外发射光线,以至于眼睛感觉到它有这样的颜色,但这光线又比较微弱,以至于不会影响到其它物体的颜色。

(4)GL_COLOR_INDEXES属性。
该属性仅在颜色索引模式下使用,由于颜色索引模式下的光照比RGBA模式要复杂,并且使用范围较小,这里不做讨论。

完整代码


#include <gl/glut.h>

#define WIDTH 800
#define HEIGHT 600

static GLfloat angle = 0.0f;

void myDisplay(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  //清除屏幕及深度缓存

	// 创建透视效果视图
	glMatrixMode(GL_PROJECTION);						//声明当前进行的是投影变换,GL_MODELVIEW:模型变换,GL_PROJECTION:投影变换
	glLoadIdentity();									//重置当前的模型观察矩阵
	gluPerspective(90.0f, 1.0f, 1.0f, 20.0f);			//视口变换
	/*  
		设置相机参数
		void gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
		aspect表示裁剪面的宽w高h比,这个影响到视野的截面有多大。
		fovy是眼睛上下睁开的幅度,角度值,值越小,视野范围越狭小(眯眼),值越大,视野范围越宽阔(睁开铜铃般的大眼);
		zNear表示近裁剪面到眼睛的距离,zFar表示远裁剪面到眼睛的距离,注意zNear和zFar不能设置设置为负值(你怎么看到眼睛后面的东西)。
   */
	glMatrixMode(GL_MODELVIEW);							//声明当前进行的是模型变换
	glLoadIdentity();
	gluLookAt(0.0, 5.0, -10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
	/*
		设置观察位置
		gluLookAt用来定义观察者(相机)的状态,包括观察者在世界坐标系中所处的位置、看向世界坐标系中的方向(可以理解为眼睛所看向的方向)、观察者头部的朝向(可以在一个平面上360°旋转)
		void gluLookAt (
		GLdouble eyex,    GLdouble eyey,     GLdouble eyez, 
		GLdouble centerx,     GLdouble centery,     GLdouble centerz, 
		GLdouble upx,     GLdouble upy,     GLdouble upz);
		第一二三个参数定义相机在世界坐标系中的位置坐标
		第四五六个参数定义相机正对着的世界坐标系中的点的位置坐标,成像后这一点会位于画板的中心位置
		第七八九参数,定义相机本身的朝向。这三个坐标是在世界坐标系中的坐标点,可以理解为人站立在相机处头的朝向。这三个坐标是世界坐标系中的坐标点,不是相机坐标系的,只是用来定义方向,注意这个不是视线(镜头)的朝向,而是摆放时相机本身的朝向,跟视线朝向方向是垂直的。
		以观察者的角度去看这几个参数就很容易理解了。
		第一组参数是定义人站在距离物体有多远处,
		第二组参数是定义人眼看向世界坐标系中的哪个方向,有时候屏幕上黑黑的什么也看不到,可能就是这组参数设置的方向不对,有可能物体就在你身后不远处
		第三组参数是人的朝向,也表示一个方向,这个朝向跟视线是垂直的。
		
		始终需要明确的一点是openGL中世界坐标系是右手坐标系,在二维屏幕上,屏幕水平方向是x 轴方向,向右为正,屏幕竖起方向是Y轴方向,向上为正,垂直于屏幕的方向是Z轴方向,从屏幕里往外为正。
	*/
	{
		GLfloat other_light_ambient[]   = {0.0f, 0.0f, 0.0f, 1.0f};		//遗留强度
		GLfloat other_light_diffuse[]   = {1.0f, 1.0f, 1.0f, 1.0f};		//漫反射强度
		GLfloat other_light_specular[]  = {1.0f, 1.0f, 1.0f, 1.0f};		//镜面反射强度
		GLfloat other_light_position[]  = {0.0f, 0.0f, 10.0f, 1.0f};		//光源位置

		glLightfv(GL_LIGHT1, GL_POSITION,	other_light_position);//GL_LIGHT1:1号光源的定义,总共可以定义8个光源
		glLightfv(GL_LIGHT1, GL_AMBIENT,	other_light_ambient);
		glLightfv(GL_LIGHT1, GL_DIFFUSE,	other_light_diffuse);
		glLightfv(GL_LIGHT1, GL_SPECULAR,	other_light_specular);

		glEnable(GL_LIGHT1);
		glEnable(GL_LIGHTING);
		glEnable(GL_DEPTH_TEST);
	}
	// 定义太阳光源,它是一种白色的光源
	{
		GLfloat sun_light_ambient[]   = {0.0f, 0.0f, 0.0f, 1.0f};		//遗留强度
		GLfloat sun_light_diffuse[]   = {1.0f, 1.0f, 1.0f, 1.0f};		//漫反射强度
		GLfloat sun_light_specular[]  = {1.0f, 1.0f, 1.0f, 1.0f};		//镜面反射强度
		GLfloat sun_light_position[]  = {0.0f, 0.0f, 0.0f, 1.0f};		//光源位置
	/*
	(1)GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR属性。这三个属性表示了光源所发出的光的反射特性(以及颜色)。
		每个属性由四个值表示,分别代表了颜色的R, G, B, A值。
		GL_AMBIENT表示该光源所发出的光,经过非常多次的反射后,最终遗留在整个光照环境中的强度(颜色)。
		GL_DIFFUSE表示该光源所发出的光,照射到粗糙表面时经过漫反射,所得到的光的强度(颜色)。
		GL_SPECULAR表示该光源所发出的光,照射到光滑表面时经过镜面反射,所得到的光的强度(颜色)。
	
	(2)GL_POSITION属性。表示光源所在的位置。由四个值(X, Y, Z, W)表示。
		如果第四个值W为零,则表示该光源位于无限远处,前三个值表示了它所在的方向。
		这种光源称为方向性光源,通常,太阳可以近似的被认为是方向性光源。
		如果第四个值W不为零,则X/W, Y/W, Z/W表示了光源的位置。这种光源称为位置性光源。
		对于位置性光源,设置其位置与设置多边形顶点的方式相似,各种矩阵变换函数例如:glTranslate*、glRotate*等在这里也同样有效。方向性光源在计算时比位置性光源快了不少,因此,在视觉效果允许的情况下,应该尽可能的使用方向性光源。
	
	(3)GL_SPOT_DIRECTION、GL_SPOT_EXPONENT、GL_SPOT_CUTOFF属性。
		表示将光源作为聚光灯使用(这些属性只对位置性光源有效)。
		很多光源都是向四面八方发射光线,但有时候一些光源则是只向某个方向发射,比如手电筒,只向一个较小的角度发射光线。
		GL_SPOT_DIRECTION属性有三个值,表示一个向量,即光源发射的方向。
		GL_SPOT_EXPONENT属性只有一个值,表示聚光的程度,为零时表示光照范围内向各方向发射的光线强度相同,为正数时表示光照向中央集中,正对发射方向的位置受到更多光照,其它位置受到较少光照。
		数值越大,聚光效果就越明显。
		GL_SPOT_CUTOFF属性也只有一个值,表示一个角度,它是光源发射光线所覆盖角度的一半,其取值范围在0到90之间,也可以取180这个特殊值。取值为180时表示光源发射光线覆盖360度,即不使用聚光灯,向全周围发射。
	(4)GL_CONSTANT_ATTENUATION、GL_LINEAR_ATTENUATION、GL_QUADRATIC_ATTENUATION属性。
		这三个属性表示了光源所发出的光线的直线传播特性(这些属性只对位置性光源有效)。
		现实生活中,光线的强度随着距离的增加而减弱,OpenGL把这个减弱的趋势抽象成函数:衰减因子 = 1 / (k1 + k2 * d + k3 * k3 * d)
		其中d表示距离,光线的初始强度乘以衰减因子,就得到对应距离的光线强度。
		k1, k2, k3分别就是GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION, GL_QUADRATIC_ATTENUATION。通过设置这三个常数,就可以控制光线在传播过程中的减弱趋势。

		属性还真是不少。当然了,如果是使用方向性光源,(3)(4)这两类属性就不会用到了,问题就变得简单明了。
	
	*/
		glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position);//GL_LIGHT0:0号光源的定义,总共可以定义8个光源
		glLightfv(GL_LIGHT0, GL_AMBIENT,   sun_light_ambient);
		glLightfv(GL_LIGHT0, GL_DIFFUSE,   sun_light_diffuse);
		glLightfv(GL_LIGHT0, GL_SPECULAR, sun_light_specular);

		glEnable(GL_LIGHT0);
		glEnable(GL_LIGHTING);
		glEnable(GL_DEPTH_TEST);
	}


	// 定义太阳的材质并绘制太阳
	{
		GLfloat sun_mat_ambient[]   = {0.0f, 0.0f, 0.5f, 1.0f};		//类似于光照
		GLfloat sun_mat_diffuse[]   = {0.0f, 0.0f, 0.5f, 1.0f};		//类似于光照,通常GL_AMBIENT和GL_DIFFUSE都取相同的值,可以达到比较真实的效果
		GLfloat sun_mat_specular[] = {0.0f, 0.0f, 1.0f, 1.0f};		//镜面反射
		GLfloat sun_mat_emission[] = {0.5f, 0.0f, 0.0f, 1.0f};		//散发淡淡的红光
		GLfloat sun_mat_shininess   = 30.0f;							//0-128
	/*
		控制材质:
		材质与光源相似,也需要设置众多的属性。不同的是,光源是通过glLight*函数来设置的,而材质则是通过glMaterial*函数来设置的。
		glMaterial*函数有三个参数。第一个参数表示指定哪一面的属性。可以是GL_FRONT、GL_BACK或者GL_FRONT_AND_BACK。
		分别表示设置“正面”“背面”的材质,或者两面同时设置。第二、第三个参数与glLight*函数的第二、三个参数作用类似。
		下面分别说明glMaterial*函数可以指定的材质属性。
		(1)GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR属性。
			这三个属性与光源的三个对应属性类似,每一属性都由四个值组成。
			GL_AMBIENT表示各种光线照射到该材质上,经过很多次反射后最终遗留在环境中的光线强度(颜色)。
			GL_DIFFUSE表示光线照射到该材质上,经过漫反射后形成的光线强度(颜色)。
			GL_SPECULAR表示光线照射到该材质上,经过镜面反射后形成的光线强度(颜色)。
			通常,GL_AMBIENT和GL_DIFFUSE都取相同的值,可以达到比较真实的效果。
			使用GL_AMBIENT_AND_DIFFUSE可以同时设置GL_AMBIENT和GL_DIFFUSE属性。
		(2)GL_SHININESS属性。
			该属性只有一个值,称为“镜面指数”,取值范围是0到128。
			该值越小,表示材质越粗糙,点光源发射的光线照射到上面,也可以产生较大的亮点。
			该值越大,表示材质越类似于镜面,光源照射到上面后,产生较小的亮点。
		(3)GL_EMISSION属性。
			该属性由四个值组成,表示一种颜色。
			OpenGL认为该材质本身就微微的向外发射光线,以至于眼睛感觉到它有这样的颜色,但这光线又比较微弱,以至于不会影响到其它物体的颜色。
		(4)GL_COLOR_INDEXES属性。
			该属性仅在颜色索引模式下使用,由于颜色索引模式下的光照比RGBA模式要复杂,并且使用范围较小,这里不做讨论。

		*/

		glMaterialfv(GL_FRONT, GL_AMBIENT,    sun_mat_ambient);
		glMaterialfv(GL_FRONT, GL_DIFFUSE,    sun_mat_diffuse);
		glMaterialfv(GL_FRONT, GL_SPECULAR,   sun_mat_specular);
		glMaterialfv(GL_FRONT, GL_EMISSION,   sun_mat_emission);
		glMaterialf (GL_FRONT, GL_SHININESS, sun_mat_shininess);

		glutSolidSphere(2.0, 40, 32);
	}

	// 定义地球的材质并绘制地球
	{
		GLfloat earth_mat_ambient[]   = {0.0f, 0.0f, 0.5f, 1.0f};
		GLfloat earth_mat_diffuse[]   = {0.0f, 0.0f, 0.5f, 1.0f};
		GLfloat earth_mat_specular[] = {0.0f, 0.0f, 1.0f, 1.0f};
		GLfloat earth_mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};
		GLfloat earth_mat_shininess   = 30.0f;

		glMaterialfv(GL_FRONT, GL_AMBIENT,    earth_mat_ambient);
		glMaterialfv(GL_FRONT, GL_DIFFUSE,    earth_mat_diffuse);
		glMaterialfv(GL_FRONT, GL_SPECULAR,   earth_mat_specular);
		glMaterialfv(GL_FRONT, GL_EMISSION,   earth_mat_emission);
		glMaterialf (GL_FRONT, GL_SHININESS, earth_mat_shininess);

		glRotatef(angle, 0.0f, -1.0f, 0.0f);
		glTranslatef(5.0f, 0.0f, 0.0f);
		glutSolidSphere(2.0, 40, 32);
	}


	glutSwapBuffers();
}
void myIdle(void)
{
	angle += 1.0f;
	if( angle >= 360.0f )
		angle = 0.0f;
	myDisplay();
}

int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutInitWindowPosition(200, 200);
	glutInitWindowSize(WIDTH, HEIGHT);
	glutCreateWindow("OpenGL光照演示");
	glutDisplayFunc(&myDisplay);
	glutIdleFunc(&myIdle);
	glutMainLoop();
	return 0;
}

效果

在这里插入图片描述
各位读者也可以修改上面的属性等参数,尝试获取不同的效果。

(上面的内容如有不正确的地方请及时与我联系修正,谢谢!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KingsMan666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值