DX鼠标控制摄像头源码,做了详细注解

本文介绍了一个用于将窗口坐标转换为屏幕坐标的自定义函数,并展示了如何通过键盘和鼠标操作来调整三维场景中的摄像机位置和目标点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于没有找到有关将窗口坐标转换成屏幕坐标的函数,干脆自己写了个函数.等待完善,嘿嘿

新增:按方向键左右可以移动摄像机位置  

新增:按住shift并且移动鼠标可以改变观察目标  

新增:按住鼠标左键并且移动鼠标可以改变摄像机位置  

cube.cpp文件:   

Code:
  1. //////////////////////////////////////////////////////////////////////////////////////////////////  
  2. // 2011/1/21  
  3. // cube.cpp文件:  
  4. //  
  5. // 渲染组旋转立方体在网格模式。演示了顶点和索引缓存,世界和观点变换  
  6. //       *新增功能:按方向键能上下能调整摄像机距离和目标的距离  
  7. //       *新增:按方向键左右可以移动摄像机位置  
  8. //       *新增:按住shift并且移动鼠标可以改变观察目标  
  9. //       *新增:按住鼠标左键并且移动鼠标可以改变摄像机位置    
  10. //////////////////////////////////////////////////////////////////////////////////////////////////  
  11.   
  12. #include "d3dUtility.h"  
  13.   
  14. //  
  15. // 全局设置  
  16. //  
  17.   
  18. IDirect3DDevice9* Device = 0;   //dx设备对象  
  19.   
  20. const int Width  = 640;  
  21. const int Height = 480;  
  22.   
  23. IDirect3DVertexBuffer9* VB = 0;  
  24. IDirect3DIndexBuffer9*  IB = 0;  
  25.   
  26. D3DXVECTOR3 position(0.0f, 0.0f, -5.0f);    //视角位置  
  27. D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);       //目标  
  28. D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);           //高度  
  29. D3DXMATRIX V;                               //表面,看到的东西  
  30.   
  31. //  
  32. // 顶点/类和结构  
  33. //  
  34.   
  35. struct Vertex  
  36. {  
  37.     Vertex(){}  
  38.     Vertex(float x, float y, float z)  
  39.     {  
  40.         _x = x;  _y = y;  _z = z;  
  41.     }  
  42.     float _x, _y, _z;  
  43.     static const DWORD FVF;  
  44. };  
  45. const DWORD Vertex::FVF = D3DFVF_XYZ;  
  46.   
  47. //  
  48. //框架功能  
  49. //  
  50. bool Setup()  
  51. {  
  52.     //  
  53.     // 创建顶点和索引缓冲.  
  54.     //  
  55.   
  56.     Device->CreateVertexBuffer(  
  57.         8 * sizeof(Vertex),   
  58.         D3DUSAGE_WRITEONLY,  
  59.         Vertex::FVF,  
  60.         D3DPOOL_MANAGED,  
  61.         &VB,  
  62.         0);  
  63.   
  64.     Device->CreateIndexBuffer(  
  65.         36 * sizeof(WORD),  
  66.         D3DUSAGE_WRITEONLY,  
  67.         D3DFMT_INDEX16,  
  68.         D3DPOOL_MANAGED,  
  69.         &IB,  
  70.         0);  
  71.   
  72.     //  
  73.     // 填补缓冲器与立方体数据。  
  74.     //  
  75.   
  76.     // 定义独特的顶点。  
  77.     Vertex* vertices;  
  78.     VB->Lock(0, 0, (void**)&vertices, 0);  
  79.   
  80.     // vertices of a unit cube  
  81.     vertices[0] = Vertex(-1.0f, -1.0f, -1.0f);  
  82.     vertices[1] = Vertex(-1.0f,  1.0f, -1.0f);  
  83.     vertices[2] = Vertex( 1.0f,  1.0f, -1.0f);  
  84.     vertices[3] = Vertex( 1.0f, -1.0f, -1.0f);  
  85.     vertices[4] = Vertex(-1.0f, -1.0f,  1.0f);  
  86.     vertices[5] = Vertex(-1.0f,  1.0f,  1.0f);  
  87.     vertices[6] = Vertex( 1.0f,  1.0f,  1.0f);  
  88.     vertices[7] = Vertex( 1.0f, -1.0f,  1.0f);  
  89.   
  90.     VB->Unlock();  
  91.   
  92.     // 定义三角面的立方体:  
  93.     WORD* indices = 0;  
  94.     IB->Lock(0, 0, (void**)&indices, 0);  
  95.   
  96.     //正面  
  97.     indices[0]  = 0; indices[1]  = 1; indices[2]  = 2;  
  98.     indices[3]  = 0; indices[4]  = 2; indices[5]  = 3;  
  99.   
  100.     //背面  
  101.     indices[6]  = 4; indices[7]  = 6; indices[8]  = 5;  
  102.     indices[9]  = 4; indices[10] = 7; indices[11] = 6;  
  103.   
  104.     //左面  
  105.     indices[12] = 4; indices[13] = 5; indices[14] = 1;  
  106.     indices[15] = 4; indices[16] = 1; indices[17] = 0;  
  107.   
  108.     //右面  
  109.     indices[18] = 3; indices[19] = 2; indices[20] = 6;  
  110.     indices[21] = 3; indices[22] = 6; indices[23] = 7;  
  111.   
  112.     //顶面  
  113.     indices[24] = 1; indices[25] = 5; indices[26] = 6;  
  114.     indices[27] = 1; indices[28] = 6; indices[29] = 2;  
  115.   
  116.     //底面  
  117.     indices[30] = 4; indices[31] = 0; indices[32] = 3;  
  118.     indices[33] = 4; indices[34] = 3; indices[35] = 7;  
  119.   
  120.     IB->Unlock();  
  121.   
  122.     //  
  123.     // 位置和目标照相机。  
  124.     //  
  125.   
  126.     D3DXMatrixLookAtLH(&V, &position, &target, &up);    //摄像机函数  
  127.     Device->SetTransform(D3DTS_VIEW, &V);       //转换为试图  
  128.     //  
  129.     // 投影矩阵的.  
  130.     //  
  131.   
  132.     D3DXMATRIX proj;  
  133.     D3DXMatrixPerspectiveFovLH(  
  134.             &proj,  
  135.             D3DX_PI * 0.5f, // 90 - degree  
  136.             (float)Width / (float)Height,  
  137.             1.0f,  
  138.             1000.0f);  
  139.     Device->SetTransform(D3DTS_PROJECTION, &proj);  
  140.   
  141.     //  
  142.     // 切换到网格模式。  
  143.     //  
  144.   
  145.     Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);      //设置渲染方式  
  146.   
  147.     return true;  
  148. }  
  149.   
  150. void Cleanup()  
  151. {  
  152.     d3d::Release<IDirect3DVertexBuffer9*>(VB);  
  153.     d3d::Release<IDirect3DIndexBuffer9*>(IB);  
  154. }  
  155.   
  156. //设置摄像机函数  
  157. void SetMatrixLookAt(D3DXVECTOR3 position,D3DXVECTOR3 target,D3DXVECTOR3 up,D3DXMATRIX V)  
  158. {  
  159.     D3DXMatrixLookAtLH(&V, &position, &target, &up);    //摄像机函数  
  160.     Device->SetTransform(D3DTS_VIEW, &V);       //转换为试图  
  161. }  
  162.   
  163. //主:  
  164. //将窗口坐标转换成屏幕坐标,不完整,有BUG.以后修改,为避免忘记先做注解  
  165. //函数思路:我们先计算出十字坐标的原点(0,0),也就是窗口坐标的中心点(width/2,hight/2)  
  166. //找到原点后,判断:原点右上角是第一象限;左上角是第二象限;左下角是第三象限;右下角是第四象限  
  167. //判断出象限后就可以计算出它在十字坐标上的位置(坐标)  
  168. //计算方法:ptx(鼠标所在位置) 减去 Cpt(原点),再将Y轴坐标乘-1得到相反数.  
  169. //完成  
  170. void SetCoordinate(float &ptx,float &pty)   //窗口坐标转换成屏幕坐标(十字坐标)  
  171. {  
  172.     POINT Cpt;  //原点  
  173.     Cpt.x=640/2;        //必要的话,可以用::GetClientRect()函数来获得窗口宽、高  
  174.     Cpt.y=480/2;  
  175.     if(ptx>Cpt.x && pty>Cpt.y)      //第一象限坐标转换  
  176.     {  
  177.         ptx-=Cpt.x;  
  178.         pty=(pty-Cpt.y)*-1.0f;  
  179.     }  
  180.     else if(ptx<Cpt.x && pty>Cpt.y) //第二象限坐标转换  
  181.     {  
  182.         ptx-=Cpt.x;  
  183.         pty=(pty-Cpt.y)*-1.0f;  
  184.     }  
  185.     else if(ptx<Cpt.x && pty<Cpt.y) //第三象限坐标转换  
  186.     {  
  187.         ptx-=Cpt.x;  
  188.         pty=(pty-Cpt.y)*-1.0f;  
  189.     }  
  190.     else if(ptx>Cpt.x && pty<Cpt.y) //第四象限坐标转换  
  191.     {  
  192.         ptx-=Cpt.x;  
  193.         pty=(pty-Cpt.y)*-1.0f;  
  194.     }  
  195.     else                                //原点(0,0)  
  196.     {  
  197.         ptx-=Cpt.x;  
  198.         ptx-=Cpt.y;  
  199.         //ptx=0.0f;  
  200.         //pty=0.0f;  
  201.     }  
  202.     ptx=ptx/10.0f;  
  203.     pty=pty/10.0f;  
  204. }  
  205.   
  206. bool Display(float timeDelta)  
  207. {  
  208.     if( Device )  
  209.     {  
  210.         //  
  211.         // 旋转立方体:  
  212.         //  
  213.         D3DXMATRIX Rx, Ry;  
  214.   
  215.         // 定义x轴要旋转的角度  
  216.         static  float x = 0.0f;  
  217.         D3DXMatrixRotationX(&Rx, x);  
  218.         x+=timeDelta;  
  219.         // 重置的角度对零当角度达到 2*PI也就是360°  
  220.         if(x > 2*D3DX_PI)     
  221.         { x = 0.0f; }  
  222.   
  223.         // 定义y轴要旋转的角度  
  224.         static float y = 0.0f;  
  225.         D3DXMatrixRotationY(&Ry, y);  
  226.         y += timeDelta;  
  227.   
  228.         // 重置的角度对零当角度达到 2*PI也就是360°  
  229.         if( y >= 2*D3DX_PI )  
  230.             y = 0.0f;  
  231.   
  232.         // 结合x -和y维度旋转变换.  
  233.         D3DXMATRIX p = Rx * Ry;  
  234.   
  235.         Device->SetTransform(D3DTS_WORLD, &p);  
  236.   
  237.         //  
  238.         // 画现场:  
  239.         //  
  240.         Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);  
  241.         Device->BeginScene();  
  242.   
  243.         Device->SetStreamSource(0, VB, 0, sizeof(Vertex));  
  244.         Device->SetIndices(IB);  
  245.         Device->SetFVF(Vertex::FVF);  
  246.   
  247.         // 画立方体.  
  248.         Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);  
  249.   
  250.         Device->EndScene();  
  251.         Device->Present(0, 0, 0, 0);  
  252.     }  
  253.     return true;  
  254. }  
  255.   
  256.   
  257. //  
  258. // 消息处理  
  259. //  
  260. LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
  261. {  
  262.     switch( msg )  
  263.     {  
  264.     case WM_DESTROY:  
  265.         ::PostQuitMessage(0);  
  266.         break;  
  267.           
  268.     case WM_KEYDOWN:  
  269.         switch(wParam)  
  270.         {  
  271.         case VK_ESCAPE:  
  272.             ::DestroyWindow(hwnd);break;  
  273.   
  274.         case VK_UP:             //摄像机位置靠近目标  
  275.             position.z+1<-1?position.z+=1:position.z;  
  276.             SetMatrixLookAt(position,target,up,V);  
  277.                 break;  
  278.         case VK_DOWN:           //摄像机位置远离目标  
  279.             position.z-=1;  
  280.             SetMatrixLookAt(position,target,up,V);  
  281.                 break;  
  282.         case VK_LEFT:  
  283.             position.x-=0.1f;       //摄像机向左移动,同时观察点也相应移动  
  284.             target.x-=0.1f;  
  285.             SetMatrixLookAt(position,target,up,V);  
  286.                 break;  
  287.         case VK_RIGHT:  
  288.             position.x+=0.1f;       //摄像机向右移动,同时观察点也相应移动  
  289.             target.x+=0.1f;  
  290.             SetMatrixLookAt(position,target,up,V);  
  291.                 break;  
  292.         }break;  
  293.   
  294.     case WM_MOUSEMOVE:  
  295.         if(wParam & MK_SHIFT)           //按下shift并鼠标移动:移动观察目标(坐标)  
  296.         {     
  297.             target.x=LOWORD(lParam);    //得到鼠标位置X轴坐标的点  
  298.             target.y=HIWORD(lParam);    //得到鼠标位置Y轴坐标的点  
  299.             SetCoordinate(target.x,target.y);   //坐标转换函数(自定义)  
  300.             SetMatrixLookAt(position,target,up,V);  
  301.         }  
  302.   
  303.         if(wParam & MK_LBUTTON)         //按下鼠标左键并鼠标移动:移动摄像机(坐标)  
  304.         {     
  305.             position.x=LOWORD(lParam);  //得到鼠标位置X轴坐标的点  
  306.             position.y=HIWORD(lParam);  //得到鼠标位置Y轴坐标的点  
  307.             SetCoordinate(position.x,position.y);   //坐标转换函数(自定义)  
  308.             SetMatrixLookAt(position,target,up,V);  
  309.         }break;  
  310.     }  
  311.     return ::DefWindowProc(hwnd, msg, wParam, lParam);  
  312. }  
  313.   
  314. //  
  315. // 入口函数  
  316. //  
  317. int WINAPI WinMain(HINSTANCE hinstance,  
  318.                    HINSTANCE prevInstance,   
  319.                    PSTR cmdLine,  
  320.                    int showCmd)  
  321. {  
  322.     if(!d3d::InitD3D(hinstance,  
  323.         Width, Height, true, D3DDEVTYPE_HAL, &Device))  
  324.     {  
  325.         ::MessageBox(0, "InitD3D() - FAILED", 0, 0);  
  326.         return 0;  
  327.     }  
  328.           
  329.     if(!Setup())  
  330.     {  
  331.         ::MessageBox(0, "Setup() - FAILED", 0, 0);  
  332.         return 0;  
  333.     }  
  334.   
  335.     d3d::EnterMsgLoop( Display );  
  336.   
  337.     Cleanup();  
  338.   
  339.     Device->Release();  
  340.   
  341.     return 0;  
  342. }  

d3dUtility.cpp文件:  

Code:
  1. //////////////////////////////////////////////////////////////////////////////////////////////////  
  2. //   
  3. // d3dUtility.cpp文件:  
  4. //   
  5. // 作者:弗兰克露娜(C)保留所有权利  
  6. //  
  7. // 系统:的AMD Athlon 1800 + XP,512 DDR的Geforce 3日,Windows XP,MSVC + + 7.0  
  8. //  
  9. // 组:提供效用函数简化大体任务。  
  10. //            
  11. //////////////////////////////////////////////////////////////////////////////////////////////////  
  12.   
  13. #include "d3dUtility.h"  
  14.   
  15. bool d3d::InitD3D(  
  16.     HINSTANCE hInstance,  
  17.     int width, int height,  
  18.     bool windowed,  
  19.     D3DDEVTYPE deviceType,  
  20.     IDirect3DDevice9** device)  
  21. {  
  22.     //  
  23.     //创造应用的主窗口.  
  24.     //  
  25.   
  26.     WNDCLASS wc;  
  27.   
  28.     wc.style         = CS_HREDRAW | CS_VREDRAW;  
  29.     wc.lpfnWndProc   = (WNDPROC)d3d::WndProc;   
  30.     wc.cbClsExtra    = 0;  
  31.     wc.cbWndExtra    = 0;  
  32.     wc.hInstance     = hInstance;  
  33.     wc.hIcon         = LoadIcon(0, IDI_APPLICATION);  
  34.     wc.hCursor       = LoadCursor(0, IDC_ARROW);  
  35.     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  
  36.     wc.lpszMenuName  = 0;  
  37.     wc.lpszClassName = "Direct3D9App";  
  38.   
  39.     if( !RegisterClass(&wc) )   
  40.     {  
  41.         ::MessageBox(0, "RegisterClass() - FAILED", 0, 0);  
  42.         return false;  
  43.     }  
  44.           
  45.     HWND hwnd = 0;  
  46.     hwnd = ::CreateWindow("Direct3D9App""Direct3D9App",   
  47.         WS_EX_TOPMOST,  
  48.         0, 0, width, height,  
  49.         0 /*父窗口句柄*/, 0 /* 菜单 */, hInstance, 0 /*扩展*/);   
  50.   
  51.     if( !hwnd )  
  52.     {  
  53.         ::MessageBox(0, "CreateWindow() - FAILED", 0, 0);  
  54.         return false;  
  55.     }  
  56.   
  57.     ::ShowWindow(hwnd, SW_SHOW);  
  58.     ::UpdateWindow(hwnd);  
  59.   
  60.     //  
  61.     // 初始 D3D:   
  62.     //  
  63.   
  64.     HRESULT hr = 0;  
  65.   
  66.     // Step 1: 创建 IDirect3D9 对象.  
  67.   
  68.     IDirect3D9* d3d9 = 0;  
  69.     d3d9 = Direct3DCreate9(D3D_SDK_VERSION);  
  70.   
  71.     if( !d3d9 )  
  72.     {  
  73.         ::MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);  
  74.         return false;  
  75.     }  
  76.   
  77.     // Step 2: 检查硬件能否支持硬件顶点处理.  
  78.   
  79.     D3DCAPS9 caps;  
  80.     d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);  
  81.   
  82.     int vp = 0;  
  83.     if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )  
  84.         vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;  
  85.     else  
  86.         vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;  
  87.   
  88.     // Step 3: 填满 the D3DPRESENT_PARAMETERS 结构体.  
  89.    
  90.     D3DPRESENT_PARAMETERS d3dpp;  
  91.     d3dpp.BackBufferWidth            = width;  
  92.     d3dpp.BackBufferHeight           = height;  
  93.     d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;  
  94.     d3dpp.BackBufferCount            = 1;  
  95.     d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;  
  96.     d3dpp.MultiSampleQuality         = 0;  
  97.     d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD;   
  98.     d3dpp.hDeviceWindow              = hwnd;  
  99.     d3dpp.Windowed                   = windowed;  
  100.     d3dpp.EnableAutoDepthStencil     = true;   
  101.     d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;  
  102.     d3dpp.Flags                      = 0;  
  103.     d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;  
  104.     d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;  
  105.   
  106.     // Step 4:创建设备.  
  107.   
  108.     hr = d3d9->CreateDevice(  
  109.         D3DADAPTER_DEFAULT, // 主要适配器显卡(省缺值)  
  110.         deviceType,         // 设备类型  
  111.         hwnd,               // 和设备相关的窗口句柄  
  112.         vp,                 // 顶点处理类型  
  113.         &d3dpp,             // D3DPRESENT_PARAMETERS参数结构体  
  114.         device);            // 返回已经创建的设备对象  
  115.   
  116.     if( FAILED(hr) )  
  117.     {  
  118.         // 再试一次使用16位深度缓冲  
  119.         d3dpp.AutoDepthStencilFormat = D3DFMT_D16;  
  120.           
  121.         hr = d3d9->CreateDevice(  
  122.             D3DADAPTER_DEFAULT,  
  123.             deviceType,  
  124.             hwnd,  
  125.             vp,  
  126.             &d3dpp,  
  127.             device);  
  128.   
  129.         if( FAILED(hr) )  
  130.         {  
  131.             d3d9->Release(); // 释放D3D对象  
  132.             ::MessageBox(0, "CreateDevice() - FAILED", 0, 0);  
  133.             return false;  
  134.         }  
  135.     }  
  136.   
  137.     d3d9->Release(); // done with d3d9 object  
  138.       
  139.     return true;  
  140. }  
  141.   
  142. int d3d::EnterMsgLoop( bool (*ptr_display)(float timeDelta))  
  143. {  
  144.     MSG msg;  
  145.     ::ZeroMemory(&msg, sizeof(MSG));  
  146.   
  147.     static float lastTime = (float)timeGetTime();           //得到最近(相对过去)时间  
  148.   
  149.     while(msg.message != WM_QUIT)  
  150.     {  
  151.         if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))  
  152.         {  
  153.             ::TranslateMessage(&msg);  
  154.             ::DispatchMessage(&msg);  
  155.         }  
  156.         else  
  157.         {     
  158.             float currTime  = (float)timeGetTime();             //得到当前时间  
  159.             float timeDelta = (currTime - lastTime)*0.0018;     //相当于控制物体的旋转速度0.001~0.002之间为好  
  160.   
  161.             ptr_display(timeDelta);     //不解释  
  162.   
  163.             lastTime = currTime;        //将当前时间传给最近(过去)时间  
  164.         }  
  165.     }  
  166.     return msg.wParam;  
  167. }  

d3dUtility.h文件:  

Code:
  1. //////////////////////////////////////////////////////////////////////////////////////////////////  
  2. //   
  3. // d3dUtility.h文件:  
  4. //   
  5. // 作者:弗兰克露娜(C)保留所有权利  
  6. //  
  7. // 系统:的AMD Athlon 1800 + XP,512 DDR的Geforce 3日,Windows XP,MSVC + + 7.0  
  8. //  
  9. // 组:提供效用函数简化大体任务。  
  10. //            
  11. //////////////////////////////////////////////////////////////////////////////////////////////////  
  12.   
  13. #ifndef __d3dUtilityH__  
  14. #define __d3dUtilityH__  
  15.   
  16. #include <d3dx9.h>  
  17. #include <string>  
  18.   
  19. namespace d3d  
  20. {  
  21.     bool InitD3D(  
  22.         HINSTANCE hInstance,       // [in]应用实例的.  
  23.         int width, int height,     // [in]后台缓存尺寸.  
  24.         bool windowed,             // [in]窗口或全屏.  
  25.         D3DDEVTYPE deviceType,     // [in] HAL or REF  
  26.         IDirect3DDevice9** device);// [out]指定创建的设备.  
  27.   
  28.     int EnterMsgLoop(   
  29.         bool (*ptr_display)(float timeDelta));  
  30.   
  31.     LRESULT CALLBACK WndProc(  
  32.         HWND hwnd,  
  33.         UINT msg,   
  34.         WPARAM wParam,  
  35.         LPARAM lParam);  
  36.   
  37.     template<class T> void Release(T t)  
  38.     {  
  39.         if( t )  
  40.         {  
  41.             t->Release();  
  42.             t = 0;  
  43.         }  
  44.     }  
  45.           
  46.     template<class T> void Delete(T t)  
  47.     {  
  48.         if( t )  
  49.         {  
  50.             delete t;  
  51.             t = 0;  
  52.         }  
  53.     }  
  54. }  
  55.   
  56. #endif // __d3dUtilityH__  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值