【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 11134|回复: 20

一篇文章搞定3DXSpriet !!

[复制链接]
发表于 2006-3-25 21:00:53 | 显示全部楼层 |阅读模式

大家好!对于很多才开始学习2D游戏制作的朋友,也许3DXSpriet 是最好的选择了,最近看到越来越多的人在使用3DXSpriet ,同时出的问题也越来越多了~~每个人在才开始学习的时候都会出现无助和迷茫,我原来也是一样的。看到这么多人在询问3DXSpriet 的用法,我决定用一贴搞定3DXSpriet !!

A. 什么是ID 3DXSpriet

我们有了创建win窗口的基础下来我们谈谈2D游戏中最关键的函数 3DSprite,通过对函数的运用,你会马上发现这是一个多么简单易用的2D绘图函数。还是老办法,在你的Microsoft DirectX 9.0_b SDK 环境里运行以下下列代码(以下代码来自通过ID3DXSprite来实现DirectX 9.0C绘制2D动画),由于我们的需要我修正了其中的部分代码,使之更适合在DirectX 9.0_b SDK环境里运行。DirectX 9.0_C3DSprite参数个数与DirectX 9.0_b中是不一样的!

把SDK中例子NO.5(纹理)中的banana.bmp(或者自己找一个不要小于200*200像素的bmp文件)考到你的程序目录下。
(需要库文件d3d9.lib d3dx9.lib)

//--------------------------------程序2--------------------------------------

// 学自网络 回馈网络

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------

#include <d3dX9.h>

//-----------------------------------------------------------------------------

LPDIRECT3D9 g_pD3D = NULL;

LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;

LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;

LPDIRECT3DTEXTURE9 g_pTexture = NULL;

LPD3DXSPRITE g_pSprite = NULL;

struct CUSTOMVERTEX

{

FLOAT x, y, z, rhw;

DWORD color;

};

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)

RECT rct;

//-----------------------------------------------------------------------------

HRESULT InitD3D( HWND hWnd )

{

SetRect( &rct, 0,200, 100, 250 );

if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )

return E_FAIL;

D3DPRESENT_PARAMETERS d3dpp;

ZeroMemory( &d3dpp, sizeof(d3dpp) );

d3dpp.Windowed = TRUE;

d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,

D3DCREATE_SOFTWARE_VERTEXPROCESSING,

&d3dpp, &g_pd3dDevice ) ) )

{

return E_FAIL;

}

g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );

D3DXCreateSprite( g_pd3dDevice, &g_pSprite );

if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, "banana.bmp", &g_pTexture ) ) )

{

if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, "..\\banana.bmp", &g_pTexture ) ) )

{

MessageBox(NULL, "Could not find banana.bmp", "Textures.exe", MB_OK);

return E_FAIL;

}

}

g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );

g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);

g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);

g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);

return S_OK;

}

//-----------------------------------------------------------------------------

HRESULT InitVB()

{

CUSTOMVERTEX vertices[] =

{

{ 50.0f, 50.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color

{ 250.0f, 50.0f, 0.5f, 1.0f, 0xff00ff00, },

{ 50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },

{ 250.0f, 250.0f, 0.5f,1.0f, 0xff00ffff, },

};

if( FAILED( g_pd3dDevice->CreateVertexBuffer( 4*sizeof(CUSTOMVERTEX),

0, D3DFVF_CUSTOMVERTEX,

D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )

{

return E_FAIL;

}

VOID* pVertices;

if( FAILED( g_pVB->Lock( 0, sizeof(vertices), (void**)&pVertices, 0 ) ) )

return E_FAIL;

memcpy( pVertices, vertices, sizeof(vertices) );

g_pVB->Unlock();

return S_OK;

}

//-----------------------------------------------------------------------------

VOID Cleanup()

{

if( g_pVB != NULL )

g_pVB->Release();

if( g_pd3dDevice != NULL )

g_pd3dDevice->Release();

if( g_pD3D != NULL )

g_pD3D->Release();

}

VOID Render()

{

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );

if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )

{

g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );

g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );

g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

if ( SUCCEEDED( g_pSprite->Begin() ) )
{

rct.right +=1;//这两行不属于3DXSpriet语法
rct.left +=1; //
g_pSprite->Draw(g_pTexture, &rct, NULL,NULL,NULL, NULL, 0xffffffff);
g_pSprite->End();
}

g_pd3dDevice->EndScene();

}

g_pd3dDevice->resent( NULL, NULL, NULL, NULL );

}

LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )

{

switch( msg )

{

case WM_DESTROY:

Cleanup();

PostQuitMessage( 0 );

return 0;

}

return DefWindowProc( hWnd, msg, wParam, lParam );

}

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )

{

WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,

GetModuleHandle(NULL), NULL, NULL, NULL, NULL,

"D3D Tutorial", NULL };

RegisterClassEx( &wc );

HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial 02: Vertices",

WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,

GetDesktopWindow(), NULL, wc.hInstance, NULL );

if( SUCCEEDED( InitD3D( hWnd ) ) )

{

if( SUCCEEDED( InitVB() ) )

{

ShowWindow( hWnd, SW_SHOWDEFAULT );

UpdateWindow( hWnd );

MSG msg;

ZeroMemory( &msg, sizeof(msg) );

while( msg.message!=WM_QUIT )

{

if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )

{

TranslateMessage( &msg );

DispatchMessage( &msg );

}

else

Render();

}

}

}

UnregisterClass( "D3D Tutorial", wc.hInstance );

return 0;

}

如过以上程序没有运行通过的话,请到 通过ID3DXSprite来实现DirectX 9.0C绘制2D动画 里查找原因或者提出疑问。

我们初步接触到3DSprite,有一个总概性的了解就可以了,下面的内容才是应该仔细的学习的部分。

[此贴子已经被作者于2006-3-25 21:33:03编辑过]
 楼主| 发表于 2006-3-25 21:05:30 | 显示全部楼层

B. 怎么运用3DXSpriet 绘制图像

开始3DSprite 的语法学习,本小节本手册的重点内内容,但并非难点,希望认真学习。

从函数的名字可以看出,这是一个D3D的函数,有很多人很迷惑,我们用D3D的方法来实现2D效果,不是大材小用,浪费资源吗?所以有很多人重操旧业,用DirectX 7.0 里面的DirectDraw来实现2D效果,认为这样绘制出来的2D效果速度快资源占用率低。在这里我也只想说3DSprite在资源上的确浪费了,当然理论上速度也要比DirectDraw慢。但是它支持硬件加速,所以在实际上它比DirectDraw快了而不是慢了。如果你有兴趣或者有自己的看法,可以到 D3D實現2D游戲在效率上會不會比用DirectDraw差? 里来讨论。

本函数在用的时候要注意,它的格式:

pSprite->Begin();
     g_pSprite->Draw();... // 具体绘制代码
    pSprite->End();

要把图像绘制到屏幕上,我们就必须用到一个函数g_pSprite->Draw(),g_pSprite->Draw()就是我们用来绘制图像的函数,我们所有的图像,都要依靠它才能显示在我们的窗口中。g_pSprite->Draw()函数必须存在于pSprite->Begin()和pSprite->End();之间,而且后面这两个函数必须成对出现 IDirect3DDevice9::BeginScene 和 IDirect3DDevice9::EndScene之间。

3DSprite要绘制图像,那么就必须加载图片,我们用莱加载的图片的方法是利用D3D中加在纹理的方法,因此,我们的还必须学习一些D3D的一些知识,如果你看过DirectX 9 进阶手册----SDK例题分析的话,那就没有多大问题了。如果没有,希望你还是看看相关书籍。那么跟着我来看看《快乐西游》中的一些代码(上一节那个完整程序中也可以查看相关内容)。


//--------------------------------程序《快乐西游》显示部分代码--------------------------------------
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++Display.cpp 游戏加载D3D图像部分++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
//////本部分完全是为了用于显示最终的图形//////////
//////至于由什么来要求显示图像,本部分并不关心////
///////////////////////////////////////////////////////////////////////
#include <d3dX9.h>
//-----------------------------------------------------------------------------
LPDIRECT3D9 g_pD3D = NULL; //设备对象
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; //设备指针
LPDIRECT3DTEXTURE9 g_pTexture = NULL; //纹理指针
LPD3DXSPRITE g_pSprite = NULL; //SPRITE对象

运行2D代码,加载一个头文件d3dX9.h就可以了,对于初学者而言,为了让自己的代码

能够编译成功,总是加载很多的头文件,这是一个很不好的习惯。

前三个变量声明是为了建立D3D设备加载图片纹理的,在我们使用g_pSprite->Draw()之前,我们必须定义一个ID3DXSprite*变量

  LPD3DXSPRITE g_pSprite = NULL; //SPRITE对象

接下来我们要在创建D3D设备(假如是g_pd3dDevice)之后, 用D3DXCreateSprite创建Sprite:

 D3DXCreateSprite( g_pd3dDevice, & g_pSprite);

释放资源的时候我们用到的是

 g_pSprite->Release ();

然后我们在正常的D3D程序Render中按照上面的要求放置好g_pSprite->Draw()的位置就可以了。

C. 详解Spriet->draw( )函数

不用说,这是我们的核心内容了。Draw()函数在DirectX 9.0c以前是有7个参数的,到了DirectX 9.0c的时候变成了5个参数,同时对pSprite->Begin(x)中的x也有了很多的设置,这个有兴趣的朋友可以参考DirectX9_c技术文档了解相关内容,在这里就不多阐述。因为我们用的是DirectX9b SDK;而且据我所知,微软新版DirectX 10 将是全新的DirectX版本,而且不对以前DirectX 兼容(不敢相信这是真的)。也就是说,以后要学习的DirectX 完全是一个全新的内容,那么说来生存在这个夹缝中的DirectX9c 真是一个高不成低不就的鸡肋了。

我们现在来看DirectX9_b环境里的Draw()函数。

 

g_pSprite-> Draw(g_pTexture, &rct, NULL, NULL,NULL,NULL,0xffffffff) ;

g_pSprite-> Draw(g_pTexture //纹理图片

&rct //纹理图片中的矩形区域

NULL //绘制图片的伸缩矩阵

NULL //绘制图片的旋转矩阵中心坐标

NULL //绘制图片的旋转角度

NULL //绘制图片的平移矩阵

0xffffffff); //绘制图片时的颜色

v 参数g_pTexture

纹理图片就是通过

 

D3DXCreateTextureFromFile( g_pd3dDevice, "bg.png", &g_pTexture );

这个函数加载的图片bg.png,你也可以根据自己的喜好加载别的格式的图片,比如bmp文件。我个人比较喜欢.png格式的图片,它是简单的支持背景透明的图片格式,简单好用。

 楼主| 发表于 2006-3-25 21:18:48 | 显示全部楼层

平移矩阵

v 参数 &rct

函数&rct指的是加载图片中的矩形区域

RECT rct_man;

SetRect( &rct_man,0,930,60,1024);

NbiGjumL.jpg

SetRect( &rct_man,x1,y1,x2,y2);

v 参数 伸缩矩阵

这个参数没有值的话就可以写NULL,如果准备付值,就可以通过&D3DXVECTOR2(x,y)来付值,在这个函数中,x,y分别表示在x轴和y轴上的放大倍数,放大中心点如图所示:

FSJkzGR9.jpg

我们游戏当中有很多的伸缩变换,实际都是从下往上方法缩小的,也就是说一般最下面的边是不变的,而放大中心并不是左下角心,这样的话可能会给我们实际制作游戏当中带来很多不便。这就要求我们在游戏设计当中合理的利用其余的参数设置来做到这一点。

v 参数 旋转矩阵坐标

旋转中心坐标如果付空值NULL的话,默认的坐标同样在图片的左做上角。同样可以通过&D3DXVECTOR2(x,y)来付值改变它的坐标位置。

3DSmJEzT.jpg

在游戏当中一般我们采用的是中心旋转。

v 参数 旋转角度

这个参数的参数类型有别于其他几个,它采用的是Float浮点型,它标示的是上面围绕旋转中心的旋转的角度。

v 参数 平移矩阵

平移矩阵是我们接触使用最多的一个矩阵,它就是表示把源图片中所选择的&rct矩阵内的图像,绘制到窗口的什么地方,付空值NULL的话,默认的坐标在窗口的左做上角(0,0)点。

如果准备付值,就依然是通过&D3DXVECTOR2(x,y)来付值,这里的x,y就是相对于窗口内部的(0,0)点的坐标,我们通过这个坐标的变化,在同一窗口绘制不同位置的元素,实现例如人物的移动等。

v 参数 绘制背景颜色

这个非常简单,就是绘制图片的时候背景与图片的混合色,如果是白色的话,就是绘制图片原有的色彩;但是如果有特殊需求,可以采用色彩混合的方式实现不同的显示效果比如灯光色彩的变化等。通常才用0xffffffff。其中0xff的这两个ff表示透明度ff表示不透明,00表示全透明,也就是画了一块玻璃上去。

================================================================================

以上讲的是在sdk 9.0_b以前版本的,要是sdk 9.0_b以后的版本会是什么样子呢?看懂了上面的例子,看下面就简单了:

HRESULT Draw(
LPDIRECT3DTEXTURE9 pTexture, //纹理图片
CONST RECT * pSrcRect, //纹理图片中的矩形区域(就是你想画的部分)
CONST D3DXVECTOR3 * pCenter, //旋转中心
CONST D3DXVECTOR3 * pPosition,//平移矩阵
D3DCOLOR Color //渲染颜色,白色表示正常显示原图
);

到此为止,ID3DSprite就讲完了 这些内容都来自<快乐西游>模仿秀 如果你想了解更多内容的话,请在下面留言。

[此贴子已经被作者于2006-3-29 15:07:34编辑过]
发表于 2006-3-26 15:40:50 | 显示全部楼层

汗不是我多事,以下言论 如有得罪之处请多谅解,这是我们新人的想法不代表老手

我认为既然文章内容写 绘制2D动画),你就把代码也写写好

为什么代码运行后中间还出来个5彩矩形

并且下面的解释代码跟上面也有几个参数都不正确

比如你解释代码用SetRect( &rct_man,0,930,60,1024);

而源代码里是SetRect( &rct, 0,200, 100, 250 );

还有 同样可以通过&D3DXVECTOR2(x,y)来付值改变它的坐标位置。

这段代码根本在源代码里根本没有.郁闷啊,

还什么窗口大小设置拉,还有如何把代码跟SDK框架结合也仔细的讲解才是啊

就上面那这样定义窗口跟纹理的位置这样,好象都不很合理吧

我看到另个源代码是只要定义窗口大小.然后定义纹理的左坐标,就可以把原图大小

绘制到窗口里. 后面2个顶点数据都是按照定义的大小然后加上读取图片的宽跟高自动去设置

那样写才是真正可以学而马上可以拿来运用到的,并且能够彻底的理解一片代码里的结构以及运用

学起来事半功倍啊...没办法,.偶是新人...........

我还是自己一段一段的注译一下吧

如果我能把全段代码都理解了,再来贴注解

HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial 02: Vertices",

WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,

GetDesktopWindow(), NULL, wc.hInstance, NULL );

//以上是设置窗口类的名称
//窗口的标题
//WS_OVERLAPPEDWINDOW, 窗口的风格
//CW_USEDEFAULT, 窗口的坐标X
//CW_USEDEFAULT,窗口的坐标y
//CW_USEDEFAULT, 窗口的宽度
//CW_USEDEFAULT,窗口的高度
//NULL, 父窗口句柄
//NULL, 窗口的菜单句柄
//hInstance, 窗口的句柄
//NULL 参数指针

发表于 2006-3-26 15:46:06 | 显示全部楼层

还有个问题就是上面的代码编译出来的程序

点开后鼠标第一次移到窗口上面的时候,鼠标的状态是加载的形状,.然后再移动些就没有了

但是其他程序我调试没有这样的状况

不知道是不是代码那里还需要改进一下

发表于 2006-3-26 15:53:26 | 显示全部楼层

同时发现 画出来的图是一直在移动的

难道不能先写个如何把一张图片按照原大小在窗口里高清晰的显示啊

好象2D游戏里图片都是应该是按照原大小显示,没有说跟3D一样还存在什么缩放吧

并且连旋转都很少用到...

[em01][em02][em02][em02]
 楼主| 发表于 2006-3-26 19:53:21 | 显示全部楼层
对于cgj888兄的请求恕我武能为力,个人水平有限,实在没时间没精力,本来贴一份源码已经足够了,修行靠个人。只能做这么多了,觉得我说的不清楚还是看MSDN吧。
发表于 2006-3-26 20:11:02 | 显示全部楼层
cgj888学过编程没有?表示怀疑
发表于 2006-3-26 20:29:25 | 显示全部楼层
以下是引用cgj888在2006-3-26 15:53:26的发言:

同时发现 画出来的图是一直在移动的

难道不能先写个如何把一张图片按照原大小在窗口里高清晰的显示啊

好象2D游戏里图片都是应该是按照原大小显示,没有说跟3D一样还存在什么缩放吧

并且连旋转都很少用到...

[em01][em02][em02][em02]

强汗...........

谁说2D游戏里图片没有缩放的!!超级玛丽吃了蘑菇变大的时候,一大一小的不是缩放啊!乌龟鸭子死的时候不是翻转啊!!实在佩服的不行啊~~

再说了,这篇文章好像是在讲那个函数的参数,你不用就不等于微软不提供吧。我怀疑你这种人等有一天想用旋转缩放的时候又会跑来嚷嚷怎么一次没讲清楚~~你还是多看看代码自己分析吧!不要怪别人,没有人有义务教你的。

发表于 2006-3-26 21:26:21 | 显示全部楼层

谁说2D游戏里图片没有缩放的!!超级玛丽吃了蘑菇变大的时候,一大一小的不是缩放啊!乌龟鸭子死的时候不是翻转啊!!实在佩服的不行啊~~

楼上的,如果我分析的没错的话

超级玛丽吃了蘑菇变大的时候,那是一段动画,实际就是存在几张由小变大的图

否则的话那人物就不好看了.并且乌龟鸭子死的时候不是翻转啊也一样道理

我看了传奇里的人物死亡啊动物死亡啊那都是很多图片组成动画的,好象没你说这样把图片缩放的吧

如果用缩放的做的游戏,我看那画面就漂亮不到那去了

在3D游戏里倒是很多缩放的

还有本人的确是新人.但是我总有权利提问题吧....至于你回答不回答那是你的权利

否则来论坛做什么.........

还有楼主啊我看到你在http://www.gameres.com/bbs也发布了一篇文章

大概意思就是说你鼯鼠自己请教别人问题的时候.别人都说很简单,并且他们都叫你去看书去

现在你到了他们那水平了,还不一样叫我们看啊...那时候你还发了 一大篇豪言说那些叫你看书的人呢

 楼主| 发表于 2006-3-26 21:46:36 | 显示全部楼层

cgj888 你好~

2D中用到反转和放大是很多的,如果都是用另外的图片的话,那样资源就非常多,在那个8位机时代,都是按照字节来节省空间的,不会用到那么多的图片。翻转最常见,比如超级玛丽向前和向后两套动作只要翻转一下就可以了。

这里说得参数是微软提供的,觉得没必要可以不用。

关于你说的我原来求3DXSpriet讲解那是不错,那个时候,没有人告诉我怎么用。我在CSDN上最直白,写的是“跪求源代码”。但那时候都没有人贴。所以自从我写完3DXSpriet我就把源代码贴出来了,有了可以运行的源代码还有什么好说的了?程序最终的就是源码,那比任何教材都好!

发表于 2006-3-26 23:41:28 | 显示全部楼层

研究代码中///////////////////////////

[em01][em01][em01]
发表于 2006-12-13 16:31:13 | 显示全部楼层

偶有不明白的地方,请教指

3D中CUSTOMVERTEX顶点结构,是怎样变换到2D视图空间中的?

偶没有见代码中有D3DXMatrixLookAtHL调用...


[此贴子已经被作者于2006-12-13 18:23:25编辑过]
 楼主| 发表于 2007-1-23 22:26:13 | 显示全部楼层
QUOTE:
以下是引用gaoyinxin在2007-1-23 16:21:29的发言:

我在DXUT框架中用

g_pSprite->OnResetDevice();

重新获得图片资源后,每次窗口改变后g_pSprite的大小是不变的(按照图片大小的吧)

那,如果我想要获得sprite随窗口大小一起调整变化的效果,什么解决方案最好呢?

虽然应该可以用缩放和平移的说,但是有没有更好的办法。

g_pSprite绘制出来的图片大小是改变,但是绘制图片的位置是和窗体的左上角相对不变得。
发表于 2007-1-23 16:21:29 | 显示全部楼层

我在DXUT框架中用

g_pSprite->OnResetDevice();

重新获得图片资源后,每次窗口改变后g_pSprite的大小是不变的(按照图片大小的吧)

那,如果我想要获得sprite随窗口大小一起调整变化的效果,什么解决方案最好呢?

虽然应该可以用缩放和平移的说,但是有没有更好的办法。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 13:12

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表