//----------------------------------------------------------------------------- // File: Meshes.cpp // // Desc: For advanced geometry, most apps will prefer to load pre-authored // meshes from a file. Fortunately, when using meshes, D3DX does most of // the work for this, parsing a geometry file and creating vertx buffers // (and index buffers) for us. This tutorial shows how to use a D3DXMESH // object, including loading it from a file and rendering it. One thing // D3DX does not handle for us is the materials and textures for a mesh, // so note that we have to handle those manually. // // Note: one advanced (but nice) feature that we don't show here is that // when cloning a mesh we can specify the FVF. So, regardless of how the // mesh was authored, we can add/remove normals, add more texture // coordinate sets (for multi-texturing), etc. // // Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- // 一応サンプルのつもり。 // 見ての通り元々チュートリアルのプログラムだったものを改造したものです。 // チュートリアルのMeshes.cppをこれで上書きしてください。 // 計画性なく試行錯誤しつつ書いたものなのでかなりごちゃごちゃしています。 // worldmap.bmp 地面用テクスチャ // shadow.bmp トゥーンシェード用テクスチャ(上が白、下が黒) // Backspace トゥーンシェード発動 // ←→ 横移動 // ↑↓ 高さ変更 // Space Return 近づく・遠ざかる // テンキー ライトの向き変更 #include #include //----------------------------------------------------------------------------- // Global variables //----------------------------------------------------------------------------- LPDIRECT3D8 g_pD3D = NULL; // Used to create the D3DDevice LPDIRECT3DDEVICE8 g_pd3dDevice = NULL; // Our rendering device // 虎 LPD3DXMESH g_pMesh = NULL; // Our mesh object in sysmem LPD3DXBUFFER g_pMeshAdjacency = NULL; // 隣接面のバッファ D3DMATERIAL8* g_pMeshMaterials = NULL; // Materials for our mesh LPDIRECT3DTEXTURE8* g_pMeshTextures = NULL; // Textures for our mesh DWORD g_dwNumMaterials = 0L; // Number of mesh materials // ティーポット LPD3DXMESH g_pTea = NULL; // Our mesh object in sysmem LPD3DXBUFFER g_pTeaAdjacency = NULL; // 隣接面のバッファ D3DMATERIAL8* g_pTeaMaterials = NULL; // Materials for our mesh LPDIRECT3DTEXTURE8* g_pTeaTextures = NULL; // Textures for our mesh DWORD g_dwNumTeaMat = 0L; // Number of mesh materials // 地面 LPDIRECT3DVERTEXBUFFER8 g_pVB = NULL; // Buffer to hold vertices LPDIRECT3DTEXTURE8 g_pTexture = NULL; // Our texture struct CUSTOMVERTEX { D3DXVECTOR3 position; // The position D3DCOLOR color; // The color FLOAT tu, tv; // The texture coordinates }; #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) // カメラ(ビュー) float g_ViewAngle = 0.0f; float g_ViewDistance = 10.0f; float g_ViewHeight = 3.0f; D3DXMATRIX g_matView; // ライト float g_LightVAngle = -1.1f; float g_LightHAngle = 0.0f; D3DXVECTOR3 g_vecDir; long g_Time = 0; long g_dTime = 0; long g_Toon = FALSE; #define WIDTH 800 #define HEIGHT 600 #define PI 3.1415926535897932f //----------------------------------------------------------------------------- // Name: InitD3D() // Desc: Initializes Direct3D //----------------------------------------------------------------------------- HRESULT InitD3D( HWND hWnd ) { // Direct3Dオブジェクトを作るのぢゃ! if( NULL == ( g_pD3D = Direct3DCreate8( D3D_SDK_VERSION ) ) ) return E_FAIL; // 現在のディスプレイモードを取得し、同じ形式のバックバッファを作成する D3DDISPLAYMODE d3ddm; if( FAILED( g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) ) return E_FAIL; // 構造体をセットする。その構造体は、D3DDeviceの作成に使われ、Since we are now // using more complex geometry, we will create a device with a zbuffer. D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof(d3dpp) ); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = d3ddm.Format; d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // Create the D3DDevice if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) ) { return E_FAIL; } // Turn on the zbuffer g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE ); g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS,TRUE); // Turn on ambient lighting //g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff ); return S_OK; } //----------------------------------------------------------------------------- // Name: InitGeometry() // Desc: Load the mesh and build the material and texture arrays //----------------------------------------------------------------------------- HRESULT InitGeometry() { LPD3DXBUFFER pD3DXMtrlBuffer; LPD3DXMESH pMesh; // 虎のメッシュを読み込む if( FAILED( D3DXLoadMeshFromX( "Tiger.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, &g_pMeshAdjacency, &pD3DXMtrlBuffer, &g_dwNumMaterials, &g_pMesh ) ) ) { return E_FAIL; } // 法線の算出 if(g_pMesh->GetFVF() != (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)){ pMesh = NULL; g_pMesh->CloneMeshFVF(g_pMesh->GetOptions(), D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,g_pd3dDevice,&pMesh); delete [] g_pMesh; g_pMesh = pMesh; D3DXComputeNormals(pMesh, NULL); } // We need to extract the material properties and texture names from the // pD3DXMtrlBuffer D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); g_pMeshMaterials = new D3DMATERIAL8[g_dwNumMaterials]; g_pMeshTextures = new LPDIRECT3DTEXTURE8[g_dwNumMaterials]; for( DWORD i=0; iRelease(); // ティーポット D3DXCreateTeapot(g_pd3dDevice,&g_pTea,&g_pTeaAdjacency); g_pTeaTextures = new LPDIRECT3DTEXTURE8[1]; D3DXCreateTextureFromFile( g_pd3dDevice, "shadow.bmp", &g_pTeaTextures[0] ); // 地面 if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, "worldmap.bmp", &g_pTexture ) ) ) return E_FAIL; if( FAILED( g_pd3dDevice->CreateVertexBuffer( 4*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB ) ) ) { return E_FAIL; } CUSTOMVERTEX* pVertices; if( FAILED( g_pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 ) ) ) return E_FAIL; pVertices[0].position = D3DXVECTOR3( -4.98f,0, -3.28f ); pVertices[0].color = 0xffffffff; pVertices[0].tu = 0.0f; pVertices[0].tv = 0.0f; pVertices[1].position = D3DXVECTOR3( -4.98f,0, 3.28f ); pVertices[1].color = 0xffffffff; pVertices[1].tu = 0.0f; pVertices[1].tv = 1.0f; pVertices[2].position = D3DXVECTOR3( 4.98f,0, -3.28f ); pVertices[2].color = 0xffffffff; pVertices[2].tu = 1.0f; pVertices[2].tv = 0.0f; pVertices[3].position = D3DXVECTOR3( 4.98f,0, 3.28f ); pVertices[3].color = 0xffffffff; pVertices[3].tu = 1.0f; pVertices[3].tv = 1.0f; g_pVB->Unlock(); return S_OK; } //----------------------------------------------------------------------------- // Name: Cleanup() // Desc: Releases all previously initialized objects //----------------------------------------------------------------------------- VOID Cleanup() { if( g_pMeshMaterials != NULL ) delete[] g_pMeshMaterials; if( g_pMeshAdjacency != NULL ) delete[] g_pMeshAdjacency; if( g_pMeshTextures ) { for( DWORD i = 0; i < g_dwNumMaterials; i++ ) { if( g_pMeshTextures[i] ) g_pMeshTextures[i]->Release(); } delete[] g_pMeshTextures; } if( g_pMesh != NULL ) g_pMesh->Release(); if( g_pTea != NULL) g_pTea->Release(); if( g_pVB != NULL ) g_pVB->Release(); if( g_pd3dDevice != NULL ) g_pd3dDevice->Release(); if( g_pD3D != NULL ) g_pD3D->Release(); } //----------------------------------------------------------------------------- // Name: SetupMatrices() // Desc: Sets up the world, view, and projection transform matrices. //----------------------------------------------------------------------------- VOID SetupMatrices() { // ビューの設定 // 左右の向きθ if (GetAsyncKeyState(VK_LEFT)) g_ViewAngle -= 0.001f * g_dTime; if (GetAsyncKeyState(VK_RIGHT)) g_ViewAngle += 0.001f * g_dTime; if (g_ViewAngle<0) g_ViewAngle += 2*PI; if (g_ViewAngle>2*PI) g_ViewAngle -= 2*PI; // Y軸からの距離r if (GetAsyncKeyState(VK_RETURN)) g_ViewDistance += 0.004f * g_dTime; if (GetAsyncKeyState(VK_SPACE)) g_ViewDistance -= 0.004f * g_dTime; if (g_ViewDistance<=0) g_ViewDistance = 0.001f; if (g_ViewDistance>20) g_ViewDistance = 20.0f; // XZ平面からの高さh if (GetAsyncKeyState(VK_UP)) g_ViewHeight += 0.002f * g_dTime; if (GetAsyncKeyState(VK_DOWN)) g_ViewHeight -= 0.002f * g_dTime; if (g_ViewHeight<=0) g_ViewHeight = 0.001f; if (g_ViewHeight>20) g_ViewHeight = 20.0f; D3DXMatrixLookAtLH( &g_matView, &D3DXVECTOR3( g_ViewDistance*cosf(g_ViewAngle), g_ViewHeight,g_ViewDistance*sinf(g_ViewAngle) ), &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ), &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) ); g_pd3dDevice->SetTransform( D3DTS_VIEW, &g_matView ); // For the projection matrix, we set up a perspective transform (which // transforms geometry from 3D view space to 2D viewport space, with // a perspective divide making objects smaller in the distance). To build // a perpsective transform, we need the field of view (1/4 pi is common), // the aspect ratio, and the near and far clipping planes (which define at // what distances geometry should be no longer be rendered). D3DXMATRIX matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, (float)WIDTH/HEIGHT, 1.0f, 100.0f ); g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); } //----------------------------------------------------------------------------- // Name: SetupLights() // Desc: Sets up the lights and materials for the scene.Lightsサンプルから持ってきた //----------------------------------------------------------------------------- VOID SetupLights() { // ライトの移動 // 左右の向きθ if (GetAsyncKeyState(VK_NUMPAD4)) g_LightHAngle += 0.001f * g_dTime; if (GetAsyncKeyState(VK_NUMPAD6)) g_LightHAngle -= 0.001f * g_dTime; if (g_LightHAngle<0) g_LightHAngle += 2*PI; if (g_LightHAngle>2*PI) g_LightHAngle -= 2*PI; // Y軸からの距離r if (GetAsyncKeyState(VK_NUMPAD2)) g_LightVAngle += 0.002f * g_dTime; if (GetAsyncKeyState(VK_NUMPAD8)) g_LightVAngle -= 0.002f * g_dTime; if (g_LightVAngle<=-PI/2) g_LightVAngle = -PI/2+0.001f; if (g_LightVAngle>=PI/2) g_LightVAngle = PI/2-0.001f; // Set up a material. The material here just has the diffuse and ambient // colors set to yellow. Note that only one material can be used at a time. D3DMATERIAL8 mtrl; ZeroMemory( &mtrl, sizeof(D3DMATERIAL8) ); mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f; mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f; mtrl.Diffuse.b = mtrl.Ambient.b = 0.4f; mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f; g_pd3dDevice->SetMaterial( &mtrl ); // Set up a white, directional light, with an oscillating direction. // Note that many lights may be active at a time (but each one slows down // the rendering of our scene). However, here we are just using one. Also, // we need to set the D3DRS_LIGHTING renderstate to enable lighting D3DLIGHT8 light; ZeroMemory( &light, sizeof(D3DLIGHT8) ); light.Type = D3DLIGHT_DIRECTIONAL; light.Diffuse.r = 1.0f; light.Diffuse.g = 1.0f; light.Diffuse.b = 1.0f; g_vecDir = D3DXVECTOR3( cosf(g_LightHAngle), tanf(g_LightVAngle), sinf(g_LightHAngle) ); D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &g_vecDir ); light.Range = 1000.0f; g_pd3dDevice->SetLight( 0, &light ); g_pd3dDevice->LightEnable( 0, TRUE ); g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE ); // Finally, turn on some ambient light. g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00505050 ); } void ToonShade(){ g_pd3dDevice->SetTexture( 0, g_pTeaTextures[0] ); g_pd3dDevice->LightEnable( 0, FALSE ); g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); D3DXMATRIX matTrans,matTrans0,matTrans1,matTrans2; D3DXVECTOR4 light1, light2; // ライト計算 D3DXMatrixInverse(&matTrans1,NULL,&g_matView); D3DXMatrixTranspose(&matTrans2,&matTrans1); D3DXVec3Transform(&light1, &g_vecDir, &matTrans2); light1.w = 0; // 4Dベクトルだと何かと都合が悪いのでW値を消去 D3DXVec4Normalize(&light2,&light1); matTrans0 = D3DXMATRIX( 1, -light2.x, 0, 0, 0, -light2.y, 0, 0, 0, -light2.z, 1, 0, 0, 0, 0, 1 ); // V値を0〜1にスケーリング D3DXMatrixScaling( &matTrans1, 1.0f,-0.5f,1.0f ); D3DXMatrixTranslation( &matTrans2, 0,0.5f,0 ); matTrans = matTrans0 * matTrans1 * matTrans2; g_pd3dDevice->SetTransform( D3DTS_TEXTURE0, &matTrans ); g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACENORMAL); g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 ); } void UnToonShade(){ // 動かないので呼んではいけない g_pd3dDevice->SetTransform( D3DTS_TEXTURE0, NULL ); g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_PASSTHRU); g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); } //----------------------------------------------------------------------------- // Name: Render() // Desc: Draws the scene //----------------------------------------------------------------------------- VOID Render() { D3DXMATRIX matWorld,matTrans,matDir,matTrans0,matTrans1,matTrans2; g_dTime = timeGetTime() - g_Time; g_Time = timeGetTime(); // Clear the backbuffer and the zbuffer g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 ); // Begin the scene g_pd3dDevice->BeginScene(); // Setup the lights and materials SetupLights(); // Setup the world, view, and projection matrices SetupMatrices(); g_pd3dDevice->LightEnable( 0, FALSE ); g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); g_pd3dDevice->SetTexture( 0, g_pTexture ); g_pd3dDevice->SetStreamSource( 0, g_pVB, sizeof(CUSTOMVERTEX) ); g_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX ); g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ); // 複数のサブセットに分かれていた場合、ループしてそれぞれの材質を指定し、描画する // 虎 D3DXMatrixTranslation( &matWorld, -2.0f,0.70f,1.5f ); g_pd3dDevice->LightEnable( 0, TRUE ); g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE ); g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); D3DXMatrixTranslation( &matWorld, -2.0f,0.70f,1.5f ); for( DWORD i=0; iSetMaterial( &g_pMeshMaterials[i] ); g_pd3dDevice->SetTexture( 0, g_pMeshTextures[i] ); if (g_Toon) ToonShade(); // Draw the mesh subset g_pMesh->DrawSubset( i ); } D3DXMatrixIdentity( &matWorld ); g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); // ティーポット g_pd3dDevice->SetTexture( 0, NULL ); D3DXMatrixTranslation( &matWorld, 0,1.0f,0 ); g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); // 描画 if (g_Toon) ToonShade(); g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); g_pTea->DrawSubset(0); D3DXMatrixIdentity( &matWorld ); g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); g_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_PASSTHRU); g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); // End the scene g_pd3dDevice->EndScene(); // Present the backbuffer contents to the display g_pd3dDevice->Present( NULL, NULL, NULL, NULL ); } //----------------------------------------------------------------------------- // Name: MsgProc() // Desc: The window's message handler //----------------------------------------------------------------------------- LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_KEYDOWN: if (wParam==VK_BACK) g_Toon = !g_Toon; return 0; case WM_DESTROY: PostQuitMessage( 0 ); return 0; } return DefWindowProc( hWnd, msg, wParam, lParam ); } //----------------------------------------------------------------------------- // Name: WinMain() // Desc: The application's entry point //----------------------------------------------------------------------------- INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT ) { // Register the window class WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), LoadIcon(NULL, IDI_ERROR), LoadCursor(NULL, IDC_ARROW), NULL, NULL, "D3D Tutorial", NULL }; RegisterClassEx( &wc ); // Create the application's window HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial 06: Meshes", WS_OVERLAPPEDWINDOW, 100, 100, WIDTH, HEIGHT, GetDesktopWindow(), NULL, wc.hInstance, NULL ); // Initialize Direct3D if( SUCCEEDED( InitD3D( hWnd ) ) ) { // Create the scene geometry if( SUCCEEDED( InitGeometry() ) ) { // Show the window ShowWindow( hWnd, SW_SHOWDEFAULT ); UpdateWindow( hWnd ); // Enter the message loop MSG msg; ZeroMemory( &msg, sizeof(msg) ); while( msg.message!=WM_QUIT ) { if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else if (GetForegroundWindow()==hWnd) Render(); } } } // Clean up everything and exit the app Cleanup(); UnregisterClass( "D3D Tutorial", wc.hInstance ); return 0; }