CameraClass
CameraClass.h

1 //============================================================================= 2 // Name: CameraClass.h 3 // Des: 一个封装了实现虚拟摄像机的类的头文件 4 //============================================================================= 5 #pragma once 6 #include <d3d9.h> 7 #include <d3dx9.h> 8 9 class CameraClass 10 { 11 private: 12 //成员变量的申明 13 D3DXVECTOR3 m_vRightVector;// 右分量向量 14 D3DXVECTOR3 m_vUpVector; // 上分量向量 15 D3DXVECTOR3 m_vLookVector; // 观察方向向量 16 D3DXVECTOR3 m_vCameraPosition;// 摄像机位置的向量 17 D3DXVECTOR3 m_vTargetPosition; //目标观察位置的向量 18 D3DXMATRIX m_matView; // 取景变换矩阵 19 D3DXMATRIX m_matProj; // 投影变换矩阵 20 LPDIRECT3DDEVICE9 m_pd3dDevice; //Direct3D设备对象 21 public: 22 //一个计算取景变换的函数 23 VOID CalculateViewMatrix(D3DXMATRIX *pMatrix); //计算取景变换矩阵 24 //三个Get系列函数 25 VOID GetProjMatrix(D3DXMATRIX *pMatrix) { *pMatrix = m_matProj; } //返回当前投影矩阵 26 VOID GetCameraPosition(D3DXVECTOR3 *pVector) { *pVector = m_vCameraPosition; } //返回当前摄像机位置矩阵 27 VOID GetLookVector(D3DXVECTOR3 *pVector) { *pVector = m_vLookVector; } //返回当前的观察矩阵 28 29 //四个Set系列函数,注意他们都参数都有默认值NULL的,调用时不写参数也可以 30 VOID SetTargetPosition(D3DXVECTOR3 *pLookat = NULL); //设置摄像机的目标观察位置向量 31 VOID SetCameraPosition(D3DXVECTOR3 *pVector = NULL); //设置摄像机所在的位置向量 32 VOID SetViewMatrix(D3DXMATRIX *pMatrix = NULL); //设置取景变换矩阵 33 VOID SetProjMatrix(D3DXMATRIX *pMatrix = NULL); //设置投影变换矩阵 34 35 36 37 public: 38 // 沿各分量平移的三个函数 39 VOID MoveAlongRightVec(FLOAT fUnits); // 沿right向量移动 40 VOID MoveAlongUpVec(FLOAT fUnits); // 沿up向量移动 41 VOID MoveAlongLookVec(FLOAT fUnits); // 沿look向量移动 42 43 // 绕各分量旋转的三个函数 44 VOID RotationRightVec(FLOAT fAngle); // 绕right向量选择 45 VOID RotationUpVec(FLOAT fAngle); // 绕up向量旋转 46 VOID RotationLookVec(FLOAT fAngle); // 绕look向量旋转 47 public: 48 CameraClass(IDirect3DDevice9 *pd3dDevice); 49 virtual ~CameraClass(void); 50 };
CameraClass.cpp

1 //============================================================================= 2 // Name: CameraClass.cpp 3 // Des: 一个封装了实现虚拟摄像机的类的源文件 4 //============================================================================= 5 #include "CameraClass.h" 6 7 #ifndef WINDOW_WIDTH 8 #define WINDOW_WIDTH 800 //为窗口宽度定义的宏,以方便在此处修改窗口宽度 9 #define WINDOW_HEIGHT 600 //为窗口高度定义的宏,以方便在此处修改窗口高度 10 #endif 11 12 //----------------------------------------------------------------------------- 13 // Desc: 构造函数 14 //----------------------------------------------------------------------------- 15 CameraClass::CameraClass(IDirect3DDevice9 *pd3dDevice) 16 { 17 m_pd3dDevice = pd3dDevice; 18 m_vRightVector = D3DXVECTOR3(1.0f, 0.0f, 0.0f); // 默认右向量与X正半轴重合 19 m_vUpVector = D3DXVECTOR3(0.0f, 1.0f, 0.0f); // 默认上向量与Y正半轴重合 20 m_vLookVector = D3DXVECTOR3(0.0f, 0.0f, 1.0f); // 默认观察向量与Z正半轴重合 21 m_vCameraPosition = D3DXVECTOR3(0.0f, 0.0f, -250.0f); // 默认摄像机坐标为(0.0f, 0.0f, -250.0f) 22 m_vTargetPosition = D3DXVECTOR3(0.0f, 0.0f, 0.0f);//默认观察目标位置为(0.0f, 0.0f, 0.0f); 23 24 } 25 26 27 //----------------------------------------------------------------------------- 28 // Name:CameraClass::CalculateViewMatrix( ) 29 // Desc: 根据给定的矩阵计算出取景变换矩阵 30 //----------------------------------------------------------------------------- 31 VOID CameraClass::CalculateViewMatrix(D3DXMATRIX *pMatrix) 32 { 33 //1.先把3个向量都规范化并使其相互垂直,成为一组正交矩阵 34 D3DXVec3Normalize(&m_vLookVector, &m_vLookVector); //规范化观察分量 35 D3DXVec3Cross(&m_vUpVector, &m_vLookVector, &m_vRightVector); // 上向量与观察向量垂直 36 D3DXVec3Normalize(&m_vUpVector, &m_vUpVector); // 规范化上向量 37 D3DXVec3Cross(&m_vRightVector, &m_vUpVector, &m_vLookVector); // 右向量与上向量垂直 38 D3DXVec3Normalize(&m_vRightVector, &m_vRightVector); // 规范化右向量 39 40 41 // 2.创建出取景变换矩阵 42 //依次写出取景变换矩阵的第一行 43 pMatrix->_11 = m_vRightVector.x; // Rx 44 pMatrix->_12 = m_vUpVector.x; // Ux 45 pMatrix->_13 = m_vLookVector.x; // Lx 46 pMatrix->_14 = 0.0f; 47 //依次写出取景变换矩阵的第二行 48 pMatrix->_21 = m_vRightVector.y; // Ry 49 pMatrix->_22 = m_vUpVector.y; // Uy 50 pMatrix->_23 = m_vLookVector.y; // Ly 51 pMatrix->_24 = 0.0f; 52 //依次写出取景变换矩阵的第三行 53 pMatrix->_31 = m_vRightVector.z; // Rz 54 pMatrix->_32 = m_vUpVector.z; // Uz 55 pMatrix->_33 = m_vLookVector.z; // Lz 56 pMatrix->_34 = 0.0f; 57 //依次写出取景变换矩阵的第四行 58 pMatrix->_41 = -D3DXVec3Dot(&m_vRightVector, &m_vCameraPosition); // -P*R 59 pMatrix->_42 = -D3DXVec3Dot(&m_vUpVector, &m_vCameraPosition); // -P*U 60 pMatrix->_43 = -D3DXVec3Dot(&m_vLookVector, &m_vCameraPosition); // -P*L 61 pMatrix->_44 = 1.0f; 62 } 63 64 65 //----------------------------------------------------------------------------- 66 // Name:CameraClass::SetTargetPosition( ) 67 // Desc: 设置摄像机的观察位置 68 //----------------------------------------------------------------------------- 69 VOID CameraClass::SetTargetPosition(D3DXVECTOR3 *pLookat) 70 { 71 //先看看pLookat是否为默认值NULL 72 if (pLookat != NULL) m_vTargetPosition = (*pLookat); 73 else m_vTargetPosition = D3DXVECTOR3(0.0f, 0.0f, 1.0f); 74 75 m_vLookVector = m_vTargetPosition - m_vCameraPosition;//观察点位置减摄像机位置,得到观察方向向量 76 D3DXVec3Normalize(&m_vLookVector, &m_vLookVector);//规范化m_vLookVector向量 77 78 //正交并规范化m_vUpVector和m_vRightVector 79 D3DXVec3Cross(&m_vUpVector, &m_vLookVector, &m_vRightVector); 80 D3DXVec3Normalize(&m_vUpVector, &m_vUpVector); 81 D3DXVec3Cross(&m_vRightVector, &m_vUpVector, &m_vLookVector); 82 D3DXVec3Normalize(&m_vRightVector, &m_vRightVector); 83 } 84 85 //----------------------------------------------------------------------------- 86 // Name:CameraClass::SetCameraPosition( ) 87 // Desc: 设置摄像机所在的位置 88 //----------------------------------------------------------------------------- 89 VOID CameraClass::SetCameraPosition(D3DXVECTOR3 *pVector) 90 { 91 D3DXVECTOR3 V = D3DXVECTOR3(0.0f, 0.0f, -250.0f); 92 m_vCameraPosition = pVector ? (*pVector) : V;//三目运算符,如果pVector为真的话, 93 //返回*pVector的值(即m_vCameraPosition=*pVector), 94 //否则返回V的值(即m_vCameraPosition=V) 95 } 96 97 //----------------------------------------------------------------------------- 98 // Name:CameraClass::SetViewMatrix( ) 99 // Desc: 设置取景变换矩阵 100 //----------------------------------------------------------------------------- 101 VOID CameraClass::SetViewMatrix(D3DXMATRIX *pMatrix) 102 { 103 //根据pMatrix的值先做一下判断 104 if (pMatrix) m_matView = *pMatrix; 105 else CalculateViewMatrix(&m_matView); 106 m_pd3dDevice->SetTransform(D3DTS_VIEW, &m_matView); 107 //把取景变换矩阵的值分下来分别给右分量,上分量,和观察分量 108 m_vRightVector = D3DXVECTOR3(m_matView._11, m_matView._12, m_matView._13); 109 m_vUpVector = D3DXVECTOR3(m_matView._21, m_matView._22, m_matView._23); 110 m_vLookVector = D3DXVECTOR3(m_matView._31, m_matView._32, m_matView._33); 111 } 112 113 //----------------------------------------------------------------------------- 114 // Name:CameraClass::SetProjMatrix( ) 115 // Desc: 设置投影变换矩阵 116 //----------------------------------------------------------------------------- 117 VOID CameraClass::SetProjMatrix(D3DXMATRIX *pMatrix) 118 { 119 //判断值有没有,没有的话就计算一下 120 if (pMatrix != NULL) m_matProj = *pMatrix; 121 else D3DXMatrixPerspectiveFovLH(&m_matProj, D3DX_PI / 4.0f, (float)((double)WINDOW_WIDTH/WINDOW_HEIGHT), 1.0f, 30000.0f);//视截体远景设为30000.0f,这样就不怕看不到远处的物体了 122 m_pd3dDevice->SetTransform(D3DTS_PROJECTION, &m_matProj);//设置投影变换矩阵 123 } 124 125 //----------------------------------------------------------------------------- 126 // Name:CameraClass::MoveAlongRightVec( ) 127 // Desc: 沿右向量平移fUnits个单位 128 //----------------------------------------------------------------------------- 129 VOID CameraClass::MoveAlongRightVec(FLOAT fUnits) 130 { 131 //直接乘以fUnits的量来累加就行了 132 m_vCameraPosition += m_vRightVector * fUnits; 133 m_vTargetPosition += m_vRightVector * fUnits; 134 } 135 136 //----------------------------------------------------------------------------- 137 // Name:CameraClass::MoveAlongUpVec( ) 138 // Desc: 沿上向量平移fUnits个单位 139 //----------------------------------------------------------------------------- 140 VOID CameraClass::MoveAlongUpVec(FLOAT fUnits) 141 { 142 //直接乘以fUnits的量来累加就行了 143 m_vCameraPosition += m_vUpVector * fUnits; 144 m_vTargetPosition += m_vUpVector * fUnits; 145 } 146 147 //----------------------------------------------------------------------------- 148 // Name:CameraClass::MoveAlongLookVec( ) 149 // Desc: 沿观察向量平移fUnits个单位 150 //----------------------------------------------------------------------------- 151 VOID CameraClass::MoveAlongLookVec(FLOAT fUnits) 152 { 153 //直接乘以fUnits的量来累加就行了 154 m_vCameraPosition += m_vLookVector * fUnits; 155 m_vTargetPosition += m_vLookVector * fUnits; 156 } 157 158 //----------------------------------------------------------------------------- 159 // Name:CameraClass::RotationRightVec( ) 160 // Desc: 沿右向量旋转fAngle个弧度单位的角度 161 //----------------------------------------------------------------------------- 162 VOID CameraClass::RotationRightVec(FLOAT fAngle) 163 { 164 D3DXMATRIX R; 165 D3DXMatrixRotationAxis(&R, &m_vRightVector, fAngle);//创建出绕m_vRightVector旋转fAngle个角度的R矩阵 166 D3DXVec3TransformCoord(&m_vUpVector, &m_vUpVector, &R);//让m_vUpVector向量绕m_vRightVector旋转fAngle个角度 167 D3DXVec3TransformCoord(&m_vLookVector, &m_vLookVector, &R);//让m_vLookVector向量绕m_vRightVector旋转fAngle个角度 168 169 m_vTargetPosition = m_vLookVector * D3DXVec3Length(&m_vCameraPosition);//更新一下观察点的新位置(方向乘以模=向量) 170 } 171 172 //----------------------------------------------------------------------------- 173 // Name:CameraClass::RotationUpVec( ) 174 // Desc: 沿上向量旋转fAngle个弧度单位的角度 175 //----------------------------------------------------------------------------- 176 VOID CameraClass::RotationUpVec(FLOAT fAngle) 177 { 178 D3DXMATRIX R; 179 D3DXMatrixRotationAxis(&R, &m_vUpVector, fAngle);//创建出绕m_vUpVector旋转fAngle个角度的R矩阵 180 D3DXVec3TransformCoord(&m_vRightVector, &m_vRightVector, &R);//让m_vRightVector向量绕m_vUpVector旋转fAngle个角度 181 D3DXVec3TransformCoord(&m_vLookVector, &m_vLookVector, &R);//让m_vLookVector向量绕m_vUpVector旋转fAngle个角度 182 183 m_vTargetPosition = m_vLookVector * D3DXVec3Length(&m_vCameraPosition);//更新一下观察点的新位置(方向乘以模=向量) 184 } 185 186 //----------------------------------------------------------------------------- 187 // Name:CameraClass::RotationLookVec( ) 188 // Desc: 沿观察向量旋转fAngle个弧度单位的角度 189 //----------------------------------------------------------------------------- 190 VOID CameraClass::RotationLookVec(FLOAT fAngle) 191 { 192 D3DXMATRIX R; 193 D3DXMatrixRotationAxis(&R, &m_vLookVector, fAngle);//创建出绕m_vLookVector旋转fAngle个角度的R矩阵 194 D3DXVec3TransformCoord(&m_vRightVector, &m_vRightVector, &R);//让m_vRightVector向量绕m_vLookVector旋转fAngle个角度 195 D3DXVec3TransformCoord(&m_vUpVector, &m_vUpVector, &R);//让m_vUpVector向量绕m_vLookVector旋转fAngle个角度 196 197 m_vTargetPosition = m_vLookVector * D3DXVec3Length(&m_vCameraPosition);//更新一下观察点的新位置(方向乘以模=向量) 198 } 199 200 201 //----------------------------------------------------------------------------- 202 // Desc: 析构函数 203 //----------------------------------------------------------------------------- 204 CameraClass::~CameraClass(void) 205 { 206 }
main.cpp

//-----------------------------------【宏定义部分】-------------------------------------------- #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 #define WINDOW_TITLE L"安康学院数字媒体技术" //-----------------------------------【头文件包含部分】--------------------------------------- #include<d3d9.h> #include <d3dx9.h> #include <tchar.h> #include <time.h> #include "DirectInputClass.h" //第1步,添加cameraclass.h头文件 #include "CameraClass.h" //-----------------------------------【库文件包含部分】--------------------------------------- #pragma comment(lib,"winmm.lib") #pragma comment(lib,"d3d9.lib") #pragma comment(lib,"d3dx9.lib") #pragma comment(lib, "dinput8.lib") #pragma comment(lib,"dxguid.lib") //第2步:定义顶点结构体 struct CUSTOMVERTEX { FLOAT _x, _y, _z; FLOAT _nx, _ny, _nz; FLOAT _u, _v; CUSTOMVERTEX(FLOAT x, FLOAT y, FLOAT z, FLOAT nx, FLOAT ny, FLOAT nz, FLOAT u, FLOAT v) { _x = x, _y = y, _z = z; _nx = nx, _ny = ny, _nz = nz; _u = u, _v = v; } }; #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1) //-----------------------------------【全局变量声明部分】------------------------------------- LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; LPD3DXFONT g_pTextFPS =NULL; LPD3DXFONT g_pTextAdaperName = NULL; LPD3DXFONT g_pTextHelper = NULL; LPD3DXFONT g_pTextInfor = NULL; float g_FPS=0.0f; wchar_t g_strFPS[50]={0}; wchar_t g_strAdapterName[60]={0}; D3DXMATRIX g_matWorld; DInputClass* g_pDInput = NULL; //一个DInputClass类的指针 //第3步:定义CameraClass类的指针 CameraClass* g_pCamera = NULL; LPD3DXMESH g_pMesh = NULL; D3DMATERIAL9* g_pMaterials = NULL; LPDIRECT3DTEXTURE9* g_pTextures = NULL; DWORD g_dwNumMtrls = 0; //第4步:定义柱子网格对象,草地对象 LPD3DXMESH g_cylinder = NULL; //柱子网格对象 D3DMATERIAL9 g_MaterialCylinder; //材质 LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL; //绘制草地的顶点缓存对象 LPDIRECT3DTEXTURE9 g_pTexture = NULL; //绘制草地的纹理对象 //-----------------------------------【全局函数声明部分】------------------------------------- LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ); HRESULT Direct3D_Init(HWND hwnd,HINSTANCE hInstance); HRESULT Objects_Init(); void Direct3D_Render(HWND hwnd); void Direct3D_Update(HWND hwnd); void Direct3D_CleanUp( ); float Get_FPS(); //第5步:注销 Matrix_Set(),定义HelpText_Render //void Matrix_Set(); void HelpText_Render(HWND hwnd); //-----------------------------------【WinMain( )函数】-------------------------------------- // 描述:Windows应用程序的入口函数,我们的程序从这里开始 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd) { //【1】开始设计一个完整的窗口类 WNDCLASSEX wndClass = { 0 }; wndClass.cbSize = sizeof( WNDCLASSEX ) ; wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = WndProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = hInstance; wndClass.hIcon=(HICON)::LoadImage(NULL,L"icon.ico",IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE); wndClass.hCursor = LoadCursor( NULL, IDC_ARROW ); wndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = L"ForTheDreamOfGameDevelop"; //【2】注册窗口类 if( !RegisterClassEx( &wndClass ) ) return -1; //【3】正式创建窗口 HWND hwnd = CreateWindow( L"ForTheDreamOfGameDevelop",WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL ); if (!(S_OK==Direct3D_Init (hwnd,hInstance))) { MessageBox(hwnd, _T("Direct3D初始化失败~!"), _T("消息窗口"), 0); //使用MessageBox函数,创建一个消息窗口 } //【4】窗口的移动、显示与更新 MoveWindow(hwnd,250,80,WINDOW_WIDTH,WINDOW_HEIGHT,true); ShowWindow(hwnd, nShowCmd ); UpdateWindow(hwnd); g_pDInput = new DInputClass(); g_pDInput->Init(hwnd,hInstance,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); //第6步:换歌曲 PlaySound(L"雅尼 - 兰花.wav", NULL, SND_FILENAME | SND_ASYNC|SND_LOOP); //循环播放背景音乐 //【5】消息循环过程 MSG msg = { 0 }; while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) ) //查看应用程序消息队列,有消息时将队列中的消息派发出去。 { TranslateMessage( &msg ); //将虚拟键消息转换为字符消息 DispatchMessage( &msg ); //该函数分发一个消息给窗口程序。 } else { //第6步 添加调用更新函数,进行画面的更新 Direct3D_Update(hwnd); //调用更新函数,进行画面的更新 Direct3D_Render(hwnd); //进行渲染 } } //【6】窗口类的注销 UnregisterClass(L"ForTheDreamOfGameDevelop", wndClass.hInstance); return 0; } //-----------------------------------【WndProc( )函数】-------------------------------------- LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { switch( message ) { case WM_PAINT: Direct3D_Render(hwnd); ValidateRect(hwnd, NULL); break; case WM_KEYDOWN: if (wParam == VK_ESCAPE) DestroyWindow(hwnd); break; case WM_DESTROY: Direct3D_CleanUp(); PostQuitMessage( 0 ); break; default: return DefWindowProc( hwnd, message, wParam, lParam ); } return 0; } //-----------------------------------【Direct3D_Init( )函数】-------------------------------------- //第4步:对应修改Direct3D_Init参数 HRESULT Direct3D_Init(HWND hwnd,HINSTANCE hInstance) { //Direct3D初始化,第一步 LPDIRECT3D9 pD3D=NULL; if(NULL==(pD3D=Direct3DCreate9(D3D_SDK_VERSION))) return E_FAIL; //Direct3D初始化,第二步 D3DCAPS9 caps; int vp = 0; if( FAILED( pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps ) ) ) { return E_FAIL; } if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //Direct3D初始化,第三步,D3DPRESENT_PARAMETERS结构体 D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.BackBufferWidth = WINDOW_WIDTH; d3dpp.BackBufferHeight = WINDOW_HEIGHT; d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; d3dpp.BackBufferCount = 2; d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; d3dpp.MultiSampleQuality = 0; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = hwnd; d3dpp.Windowed = true; d3dpp.EnableAutoDepthStencil = true; d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; d3dpp.Flags = 0; d3dpp.FullScreen_RefreshRateInHz = 0; d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; //Direct3D初始化,第四步 if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, vp, &d3dpp, &g_pd3dDevice))) return E_FAIL; wchar_t TempName[60]=L"当前显卡型号:"; D3DADAPTER_IDENTIFIER9 Adapter; pD3D->GetAdapterIdentifier(0,0,&Adapter); int len = MultiByteToWideChar(CP_ACP,0, Adapter.Description, -1, NULL, 0); MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, g_strAdapterName, len); wcscat_s(TempName,g_strAdapterName); wcscpy_s(g_strAdapterName,TempName); if(!(S_OK==Objects_Init())) return E_FAIL; SAFE_RELEASE(pD3D); return S_OK; } //-----------------------------------【Object_Init( )函数】-------------------------------------- HRESULT Objects_Init() { D3DXCreateFont(g_pd3dDevice, 36, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, _T("Calibri"), &g_pTextFPS); D3DXCreateFont(g_pd3dDevice, 20, 0, 1000, 0, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"华文中宋", &g_pTextAdaperName); D3DXCreateFont(g_pd3dDevice, 23, 0, 1000, 0, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"微软雅黑", &g_pTextHelper); D3DXCreateFont(g_pd3dDevice, 26, 0, 1000, 0, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"黑体", &g_pTextInfor); // 从X文件中加载网格数据 LPD3DXBUFFER pAdjBuffer = NULL; LPD3DXBUFFER pMtrlBuffer = NULL; //第7步:换模型 //D3DXLoadMeshFromX(L"Optimus.x", D3DXMESH_MANAGED, g_pd3dDevice, D3DXLoadMeshFromX(L"WYJ.X", D3DXMESH_MANAGED, g_pd3dDevice, &pAdjBuffer, &pMtrlBuffer, NULL, &g_dwNumMtrls, &g_pMesh); // 读取材质和纹理数据 D3DXMATERIAL *pMtrls = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer();//创建一个D3DXMATERIAL结构体用于读取材质和纹理信息 g_pMaterials = new D3DMATERIAL9[g_dwNumMtrls]; g_pTextures = new LPDIRECT3DTEXTURE9[g_dwNumMtrls]; for (DWORD i=0; i<g_dwNumMtrls; i++) { //获取材质,并设置一下环境光的颜色值 g_pMaterials[i] = pMtrls[i].MatD3D; g_pMaterials[i].Ambient = g_pMaterials[i].Diffuse; //创建一下纹理对象 g_pTextures[i] = NULL; D3DXCreateTextureFromFileA(g_pd3dDevice, pMtrls[i].pTextureFilename, &g_pTextures[i]); } pAdjBuffer->Release(); pMtrlBuffer->Release(); //第8步:初始化草地,柱子,灯光,摄像机 // 设置渲染状态 //g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); //开启背面消隐 //g_pd3dDevice->SetRenderState(D3DRS_AMBIENT, D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f)); //设置环境光 //Matrix_Set();//调用封装了四大变换的函数,对Direct3D世界变换,取景变换,投影变换,视口变换进行设置 // 创建一片草坪,50X50=250张纹理 g_pd3dDevice->CreateVertexBuffer(4 * sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_MANAGED, &g_pVertexBuffer, 0); CUSTOMVERTEX *pVertices = NULL; g_pVertexBuffer->Lock(0, 0, (void**)&pVertices, 0); pVertices[0] = CUSTOMVERTEX(-500.0f, 0.0f, -500.0f, 0.0f, 1.0f, 0.0f, 0.0f, 50.0f); pVertices[1] = CUSTOMVERTEX(-500.0f, 0.0f, 500.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); pVertices[2] = CUSTOMVERTEX( 500.0f, 0.0f, -500.0f, 0.0f, 1.0f, 0.0f, 50.0f, 50.0f); pVertices[3] = CUSTOMVERTEX( 500.0f, 0.0f, 500.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f); g_pVertexBuffer->Unlock(); // 创建地板纹理 D3DXCreateTextureFromFile(g_pd3dDevice, L"grass.jpg", &g_pTexture); //创建柱子 D3DXCreateCylinder(g_pd3dDevice, 10.0f, 10.0f, 500.0f, 60, 60, &g_cylinder, 0); g_MaterialCylinder.Ambient = D3DXCOLOR(0.9f, 0.0f, 0.8f, 1.0f); g_MaterialCylinder.Diffuse = D3DXCOLOR(0.9f, 0.0f, 0.8f, 1.0f); g_MaterialCylinder.Specular = D3DXCOLOR(0.9f, 0.2f, 0.9f, 0.9f); g_MaterialCylinder.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.9f, 1.0f); // 设置光照 D3DLIGHT9 light; ::ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_DIRECTIONAL; light.Ambient = D3DXCOLOR(0.7f, 0.7f, 0.7f, 1.0f); light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); light.Specular = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f); light.Direction = D3DXVECTOR3(1.0f, 0.0f, 0.0f); g_pd3dDevice->SetLight(0, &light); g_pd3dDevice->LightEnable(0, true); g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true); g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true); // 创建并初始化虚拟摄像机 g_pCamera = new CameraClass(g_pd3dDevice); g_pCamera->SetCameraPosition(&D3DXVECTOR3(0.0f, 200.0f, -300.0f)); //设置摄像机所在的位置 g_pCamera->SetTargetPosition(&D3DXVECTOR3(0.0f, 300.0f, 0.0f)); //设置目标观察点所在的位置 g_pCamera->SetViewMatrix(); //设置取景变换矩阵 g_pCamera->SetProjMatrix(); //设置投影变换矩阵 // 设置纹理过滤和纹理寻址方式 g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); g_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); return S_OK; } //第9步:注销掉Matrix_Set( )函数 //-----------------------------------【Matrix_Set( )函数】-------------------------------------- //void Matrix_Set() //{ ////第11步 世界变换矩阵的设置,改动到鼠标键盘操作后对世界变换矩阵修改 // // //-------------------------------------------------------------------------------------- // //【四大变换之一】:世界变换矩阵的设置 // //-------------------------------------------------------------------------------------- // // //-------------------------------------------------------------------------------------- // //【四大变换之二】:取景变换矩阵的设置 // //-------------------------------------------------------------------------------------- // D3DXMATRIX matView; //定义一个矩阵 // // D3DXVECTOR3 vEye(0.0f, 0.0f, -1300.0f); //摄像机的位置 // D3DXVECTOR3 vAt(0.0f, 0.0f, 0.0f); //观察点的位置 // D3DXVECTOR3 vUp(0.0f, 1.0f, 0.0f);//向上的向量 // D3DXMatrixLookAtLH(&matView, &vEye, &vAt, &vUp); //计算出取景变换矩阵 // g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView); //应用取景变换矩阵 // // //-------------------------------------------------------------------------------------- // //【四大变换之三】:投影变换矩阵的设置 // //-------------------------------------------------------------------------------------- // D3DXMATRIX matProj; //定义一个矩阵 // D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4.0f,(float)((double)WINDOW_WIDTH/WINDOW_HEIGHT),1.0f, 10000.0f); //计算投影变换矩阵 // g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj); //设置投影变换矩阵 // // //-------------------------------------------------------------------------------------- // //【四大变换之四】:视口变换的设置 // //-------------------------------------------------------------------------------------- // D3DVIEWPORT9 vp; //实例化一个D3DVIEWPORT9结构体,然后做填空题给各个参数赋值就可以了 // vp.X = 0; //表示视口相对于窗口的X坐标 // vp.Y = 0; //视口相对对窗口的Y坐标 // vp.Width = WINDOW_WIDTH; //视口的宽度 // vp.Height = WINDOW_HEIGHT; //视口的高度 // vp.MinZ = 0.0f; //视口在深度缓存中的最小深度值 // vp.MaxZ = 1.0f; //视口在深度缓存中的最大深度值 // g_pd3dDevice->SetViewport(&vp); //视口的设置 //} //-----------------------------------【Direct3D_Update( )函数】-------------------------------- // 描述:不是即时渲染代码但是需要即时调用的,如按键后的坐标的更改,都放在这里 //-------------------------------------------------------------------------------------------------- void Direct3D_Update( HWND hwnd) { g_pDInput->GetInput(); //第10步:注销掉以前的键鼠控制代码 //// 按住鼠标左键并拖动,为平移操作 // //static FLOAT fPosX = 0.0f, fPosY = 0.0f, fPosZ = 0.0f; //if (g_pDInput->IsMouseButtonDown(0)) //{ // fPosX += (g_pDInput->MouseDX())* 0.08f; // fPosY += (g_pDInput->MouseDY()) * -0.08f; //} ////鼠标滚轮,为观察点收缩操作 //fPosZ +=(g_pDInput->MouseDZ())* 0.02f;// g_diMouseState.lZ * 0.02f; //// 平移物体 //if (g_pDInput->IsKeyDown(DIK_A)) fPosX -= 0.005f; //if (g_pDInput->IsKeyDown(DIK_D)) fPosX += 0.005f; //if (g_pDInput->IsKeyDown(DIK_W)) fPosY += 0.005f; //if (g_pDInput->IsKeyDown(DIK_S)) fPosY -= 0.005f; //D3DXMatrixTranslation(&g_matWorld, fPosX, fPosY, fPosZ); //// 按住鼠标右键并拖动,为旋转操作 //static float fAngleX = 0.0f, fAngleY =0.0f; //if (g_pDInput->IsMouseButtonDown(1)) //{ // fAngleX += (g_pDInput->MouseDY())* -0.01f; // fAngleY += (g_pDInput->MouseDX()) * -0.01f; //} //// 旋转物体 //if (g_pDInput->IsKeyDown(DIK_UP)) fAngleX += 0.005f; //if (g_pDInput->IsKeyDown(DIK_DOWN)) fAngleX -= 0.005f; //if (g_pDInput->IsKeyDown(DIK_LEFT)) fAngleY -= 0.005f; //if (g_pDInput->IsKeyDown(DIK_RIGHT)) fAngleY += 0.005f; //D3DXMATRIX Rx, Ry; //D3DXMatrixRotationX(&Rx, fAngleX); //D3DXMatrixRotationY(&Ry, fAngleY); ////得到最终的矩阵并设置 //g_matWorld = Rx * Ry * g_matWorld;//得到最终的矩阵 //g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_matWorld);//设置世界矩阵 //第11步:重新编写键鼠控制代码 // 沿摄像机各分量移动视角 if (g_pDInput->IsKeyDown(DIK_A)) g_pCamera->MoveAlongRightVec(-0.3f); if (g_pDInput->IsKeyDown(DIK_D)) g_pCamera->MoveAlongRightVec( 0.3f); if (g_pDInput->IsKeyDown(DIK_W)) g_pCamera->MoveAlongLookVec( 0.3f); if (g_pDInput->IsKeyDown(DIK_S)) g_pCamera->MoveAlongLookVec(-0.3f); if (g_pDInput->IsKeyDown(DIK_R)) g_pCamera->MoveAlongUpVec( 0.3f); if (g_pDInput->IsKeyDown(DIK_F)) g_pCamera->MoveAlongUpVec(-0.3f); //沿摄像机各分量旋转视角 if (g_pDInput->IsKeyDown(DIK_LEFT)) g_pCamera->RotationUpVec(-0.003f); if (g_pDInput->IsKeyDown(DIK_RIGHT)) g_pCamera->RotationUpVec( 0.003f); if (g_pDInput->IsKeyDown(DIK_UP)) g_pCamera->RotationRightVec(-0.003f); if (g_pDInput->IsKeyDown(DIK_DOWN)) g_pCamera->RotationRightVec( 0.003f); if (g_pDInput->IsKeyDown(DIK_Q)) g_pCamera->RotationLookVec( 0.001f); if (g_pDInput->IsKeyDown(DIK_E)) g_pCamera->RotationLookVec(-0.001f); //鼠标控制右向量和上向量的旋转 g_pCamera->RotationUpVec(g_pDInput->MouseDX()* 0.001f); g_pCamera->RotationRightVec(g_pDInput->MouseDY() * 0.001f); //鼠标滚轮控制观察点收缩操作 static FLOAT fPosZ=0.0f; fPosZ += g_pDInput->MouseDZ()*0.03f; //计算并设置取景变换矩阵 D3DXMATRIX matView; g_pCamera->CalculateViewMatrix(&matView); g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView); //把正确的世界变换矩阵存到g_matWorld中 D3DXMatrixTranslation(&g_matWorld, 0.0f, 0.0f, fPosZ); //以下这段代码用于限制鼠标光标移动区域 POINT lt,rb; RECT rect; GetClientRect(hwnd,&rect); //取得窗口内部矩形 //将矩形左上点坐标存入lt中 lt.x = rect.left; lt.y = rect.top; //将矩形右下坐标存入rb中 rb.x = rect.right; rb.y = rect.bottom; //将lt和rb的窗口坐标转换为屏幕坐标 ClientToScreen(hwnd,<); ClientToScreen(hwnd,&rb); //以屏幕坐标重新设定矩形区域 rect.left = lt.x; rect.top = lt.y; rect.right = rb.x; rect.bottom = rb.y; //限制鼠标光标移动区域 ClipCursor(&rect); ShowCursor(false); //隐藏鼠标光标 } //-----------------------------------【Direct3D_Render( )函数】-------------------------------------- void Direct3D_Render(HWND hwnd) {//1 //第12步:修改清屏操作 //g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(100, 100, 100), 1.0f, 0); //RECT formatRect; //GetClientRect(hwnd, &formatRect); g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, D3DCOLOR_XRGB(50, 100, 250), 1.0f, 0); //2 g_pd3dDevice->BeginScene(); //3 //第13步:绘制人物 g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_matWorld);//设置模型的世界矩阵,为绘制做准备 // 用一个for循环,进行模型的网格各个部分的绘制 for (DWORD i = 0; i < g_dwNumMtrls; i++) { g_pd3dDevice->SetMaterial(&g_pMaterials[i]);//设置此部分的材质 g_pd3dDevice->SetTexture(0, g_pTextures[i]);//设置此部分的纹理 g_pMesh->DrawSubset(i);//绘制此部分 } //第14步:注销屏幕信息 //int charCount = swprintf_s(g_strFPS, 20, _T("FPS:%0.3f"), Get_FPS() ); //g_pTextFPS->DrawText(NULL, g_strFPS, charCount , &formatRect, DT_TOP | DT_RIGHT, D3DCOLOR_RGBA(0,239,136,255)); // g_pTextAdaperName->DrawText(NULL,g_strAdapterName, -1, &formatRect, // DT_TOP | DT_LEFT, D3DXCOLOR(1.0f, 0.5f, 0.0f, 1.0f)); // formatRect.top = 30; //static wchar_t strInfo[256] = {0}; //swprintf_s(strInfo,-1, L"模型坐标: (%.2f, %.2f, %.2f)", g_matWorld._41, g_matWorld._42, g_matWorld._43); //g_pTextHelper->DrawText(NULL, strInfo, -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(135,239,136,255)); // formatRect.left = 0,formatRect.top = 380; //g_pTextInfor->DrawText(NULL, L"控制说明:", -1, &formatRect, // DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235,123,230,255)); //formatRect.top += 35; //g_pTextHelper->DrawText(NULL, L" 按住鼠标左键并拖动:平移模型", -1, &formatRect, // DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); //formatRect.top += 25; //g_pTextHelper->DrawText(NULL, L" 按住鼠标右键并拖动:旋转模型", -1, &formatRect, // DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); //formatRect.top += 25; //g_pTextHelper->DrawText(NULL, L" 滑动鼠标滚轮:拉伸模型", -1, &formatRect, // DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); //formatRect.top += 25; //g_pTextHelper->DrawText(NULL, L" W、S、A、D键:平移模型 ", -1, &formatRect, // DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); //formatRect.top += 25; //g_pTextHelper->DrawText(NULL, L" 上、下、左、右方向键:旋转模型 ", -1, &formatRect, // DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); //formatRect.top += 25; //g_pTextHelper->DrawText(NULL, L" ESC键 : 退出程序", -1, &formatRect, // DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); //第15步:绘制草坪,柱子,调用屏幕信息函数 // 绘制草坪 D3DXMATRIX matWorld; D3DXMatrixTranslation(&matWorld, 0.0f, 0.0f, 0.0f); g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld); g_pd3dDevice->SetTexture(0, g_pTexture); g_pd3dDevice->SetStreamSource(0, g_pVertexBuffer, 0, sizeof(CUSTOMVERTEX)); g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); //绘制柱子 D3DXMATRIX TransMatrix, RotMatrix, FinalMatrix; D3DXMatrixRotationX(&RotMatrix, -D3DX_PI * 0.5f); g_pd3dDevice->SetMaterial(&g_MaterialCylinder); for(int i = 0; i < 6; i++) { D3DXMatrixTranslation(&TransMatrix, -100.0f, 0.0f, -150.0f + (i * 75.0f)); FinalMatrix = RotMatrix * TransMatrix ; g_pd3dDevice->SetTransform(D3DTS_WORLD, &FinalMatrix); g_cylinder->DrawSubset(0); D3DXMatrixTranslation(&TransMatrix, 100.0f, 0.0f, -150.0f + (i * 75.0f)); FinalMatrix = RotMatrix * TransMatrix ; g_pd3dDevice->SetTransform(D3DTS_WORLD, &FinalMatrix); g_cylinder->DrawSubset(0); } HelpText_Render(hwnd); //4 g_pd3dDevice->EndScene(); //5 g_pd3dDevice->Present(NULL, NULL, NULL, NULL); } //第16步:添加帮助信息的函数 //-----------------------------------【HelpText_Render( )函数】------------------------------- // 描述:封装了帮助信息的函数 //-------------------------------------------------------------------------------------------------- void HelpText_Render(HWND hwnd) { //定义一个矩形,用于获取主窗口矩形 RECT formatRect; GetClientRect(hwnd, &formatRect); //在窗口右上角处,显示每秒帧数 formatRect.top = 5; int charCount = swprintf_s(g_strFPS, 20, _T("FPS:%0.3f"), Get_FPS() ); g_pTextFPS->DrawText(NULL, g_strFPS, charCount , &formatRect, DT_TOP | DT_RIGHT, D3DCOLOR_RGBA(0,239,136,255)); //显示显卡类型名 g_pTextAdaperName->DrawText(NULL,g_strAdapterName, -1, &formatRect, DT_TOP | DT_LEFT, D3DXCOLOR(1.0f, 0.5f, 0.0f, 1.0f)); // 输出帮助信息 formatRect.left = 0,formatRect.top = 380; g_pTextInfor->DrawText(NULL, L"控制说明:", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235,123,230,255)); formatRect.top += 35; g_pTextHelper->DrawText(NULL, L" W:向前飞翔 S:向后飞翔 ", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelper->DrawText(NULL, L" A:向左飞翔 D:向右飞翔", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelper->DrawText(NULL, L" R:垂直向上飞翔 F:垂直向下飞翔", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelper->DrawText(NULL, L" Q:向左倾斜 E:向右倾斜", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelper->DrawText(NULL, L" 上、下、左、右方向键、鼠标移动:视角变化 ", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelper->DrawText(NULL, L" 鼠标滚轮:人物模型Y轴方向移动", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelper->DrawText(NULL, L" ESC键 : 退出程序", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); } //-----------------------------------【Get_FPS( )函数】------------------------------------------ float Get_FPS() { static float fps = 0;//fps值 static int frameCount = 0;//帧数 static float currentTime =0.0f;//当前时间 static float lastTime = 0.0f;//持续时间 frameCount++; currentTime=timeGetTime()*0.001f;//获取系统时间 if(currentTime-lastTime>1.0f) { fps = (float)frameCount /(currentTime - lastTime); lastTime=currentTime; frameCount=0; } return fps; } //-----------------------------------【Direct3D_CleanUp( )函数】-------------------------------- void Direct3D_CleanUp() { //第17步:释放COM接口对象 for (DWORD i = 0; i<g_dwNumMtrls; i++) SAFE_RELEASE(g_pTextures[i]); SAFE_DELETE(g_pTextures); SAFE_DELETE(g_pMaterials); SAFE_DELETE(g_pDInput); SAFE_RELEASE(g_cylinder); SAFE_RELEASE(g_pMesh); SAFE_RELEASE(g_pd3dDevice); SAFE_RELEASE(g_pTextAdaperName) SAFE_RELEASE(g_pTextHelper) SAFE_RELEASE(g_pTextInfor) SAFE_RELEASE(g_pTextFPS) SAFE_RELEASE(g_pd3dDevice) }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理