Tiege

Members
  • Content count

    77
  • Joined

  • Last visited

Community Reputation

102 Neutral

About Tiege

  • Rank
    Member
  1. Ground Collision methods?

    Well i don't intend to use others' libraries :\. I don't need things like friction, impulse, etc. Just want my guy to not fall through the floor But thanks for the advice!
  2. Ground Collision methods?

    Sorry about the confusing terminology. Obviously I have little to no idea what I'm doing haha. Thanks for being patient with me. I like the idea of that convex hull method. How would I go about implementing that in my code? Also once I eventually do have my collision area mapped out then give a bounding box to the character or something how would I detect the intersection between the two? I have a map made and also kind of the collision mask to go with it. Would it just be simpler to make the collision meshes solid for my collision with the terrain and platforms?
  3. Ground Collision methods?

    [quote name='Krohm' timestamp='1318239809' post='4871020'] [quote name='Tiege' timestamp='1318204643' post='4870910']The most practical I can think of is [i]hard coding[/i] all the points on the map I want to make line segments for the boundaries.[/quote]You must be joking. Consider a data-driven approach instead, you might find [url="http://www.json.org/"]JSON[/url] useful. Separating collision geometry from visible geometry is heavily recommended. It is standard in many AAA games for performance reasons, but it buys a lot of flexibility even in small projects (the infamous "secret room wall"). [quote name='Tiege' timestamp='1318204643' post='4870910'](1) Is there a way to make meshes physical with other meshes or (2) is that all manually coded with collision boxes and spheres, etc?[/quote](1) Yes, there is, but it's not automatic. In general, meshes are approximated in some way. In general you'll have to figure out yourself whatever a mesh is solid or not. An artist will have to flag the mesh as "nonsolid". In certain systems, this "nonsolid" flag was embedded in material properties. (2) It is [i]automatically [/i][s]coded[/s] input (by using data-driven systems). Very little things are hardcoded nowadays. If your level is data, your collisions should be data as well (and preferably go together). Do not mix data and hard-coded stuff (hard-coded ~= assumption). It will sink way too much effort in the making. Historically, cubes/boxes/spheres have been used. Now k-DOPs, convex hulls, cones... if everything fails, the whole tri-mesh will be used. Trimeshes are typically quite slow, but sometimes they are necessary. [/quote] Thanks for the info. I was wondering about visible vs collision geometry because in tutorials where they create bounding boxes/spheres, I just wondered why bother loading an additional model if you have to program that anyway? The only thing that model gives is its max and min vertices to create a box. But for example think of a map in super smash bros melee. The background is the invisible geometry (im assuming) which has no interaction but gives the game visual. The collision geometry is the ground, the platforms, etc. The stuff the characters can actually stand on. This is basically what i'm trying to create. I would make a bounding box for the platforms but what about the ground when it's slanted and distorted so that it cant possibly be covered correctly by boxes? Something like this: [img]http://img36.imageshack.us/img36/5766/maptg.jpg[/img]
  4. For those of you out there who use Blender. How do you export a model with multiple animations in a single file? Is it through the action editor? Like if you add say a walk, idle, and run action then when you export those are all included? And how are they arranged to access using directx animation tracks?
  5. I'm making a side scroller and just curious about possible collision methods for the map itself. The most practical I can think of is hard coding all the points on the map I want to make line segments for the boundaries. I also thought about making a second layer for the map which will be the actual physical part while the rest is passthrough. But if I have to hardcode the physical parts anyway then is it just a waste loading it if I don't really need it? Is there a way to make meshes physical with other meshes or is that all manually coded with collision boxes and spheres, etc?
  6. I'm making a side scroller and just curious about possible collision methods for the map itself. The most practical I can think of is hard coding all the points on the map I want to make line segments for the boundaries. I also thought about making a second layer for the map which will be the actual physical part while the rest is passthrough. But if I have to hardcode the physical parts anyway then is it just a waste loading it if I don't really need it? Is there a way to make meshes physical with other meshes or is that all manually coded with collision boxes and spheres, etc?
  7. Sorry I actually have a question. How did you fit more than one animation in a single file? And what program did you use? My friend is making models for me using Blender but were not sure exactly how to get multiple animations in the same .x file.
  8. [quote name='EVE' timestamp='1317581877' post='4868335'] Hello! My code: [code] // -------- INCLUDE ---------------- #include <Windows.h> #include <windowsx.h> #include <d3dx9.h> #include <stdio.h> IDirect3DDevice9* device = *(IDirect3DDevice9**)0xC97C28; // DirectX Device IDirect3DTexture9* pTexture; // bool DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) { if(fdwReason == DLL_PROCESS_ATTACH) { if(D3DXCreateTextureFromFile(device, L"tex.png", &pTexture) != D3D_OK) { printf("Fail!"); return 0; } printf("Abc!"); } return TRUE; } [/code] Log: [code] Abc![/code] I don't know why the crash occurs. Earlier this code to run! And today I see crash. I greet and please for help. [/quote] In your If statement get rid of the != D3D_OK and just put ! infront of the function
  9. Can anyone see something in this code that I can't as to why my materials and textures wont load on my animated models? I'm sure the pathing is correct because I can get it to work for a static model but when I load mesh from hierarchy the model loads, renders, and animates but it's just black (no material or texture). Any thoughts? I am using code from tutorials I've read [code] HRESULT CMeshHierarchy::CreateMeshContainer( LPCSTR Name, CONST D3DXMESHDATA *meshData, CONST D3DXMATERIAL *materials, CONST D3DXEFFECTINSTANCE *effectInstances, DWORD numMaterials, CONST DWORD *adjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER* retNewMeshContainer) { // Create a mesh container structure to fill and initilaise to zero values // Note: I use my extended version of the structure (D3DXMESHCONTAINER_EXTENDED) defined in MeshStructures.h D3DXMESHCONTAINER_EXTENDED *newMeshContainer=new D3DXMESHCONTAINER_EXTENDED; ZeroMemory(newMeshContainer, sizeof(D3DXMESHCONTAINER_EXTENDED)); // Always a good idea to initialise return pointer before proceeding *retNewMeshContainer = 0; // The mesh name (may be 0) needs copying over if (Name != NULL) { newMeshContainer->Name = new char[strlen(Name) + 1]; strcpy(newMeshContainer->Name, Name); } // The mesh type (D3DXMESHTYPE_MESH, D3DXMESHTYPE_PMESH or D3DXMESHTYPE_PATCHMESH) if (meshData->Type!=D3DXMESHTYPE_MESH) { // This demo does not handle mesh types other than the standard // Other types are D3DXMESHTYPE_PMESH (progressive mesh) and D3DXMESHTYPE_PATCHMESH (patch mesh) DestroyMeshContainer(newMeshContainer); return E_FAIL; } newMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; // Adjacency data - holds information about triangle adjacency, required by the ID3DMESH object DWORD dwFaces = meshData->pMesh->GetNumFaces(); newMeshContainer->pAdjacency = new DWORD[dwFaces*3]; if (adjacency) { memcpy(newMeshContainer->pAdjacency, adjacency, sizeof(DWORD) * dwFaces*3); } else { // Added 24/08/10: previously did not detect null adjacency if(FAILED( newMeshContainer->MeshData.pMesh->GenerateAdjacency( 1e-6f, (DWORD*)(void*)newMeshContainer->pAdjacency ) ) ) FillMemory((void*)newMeshContainer->pAdjacency, dwFaces*3, 0xFF ); } // Get the Direct3D device, luckily this is held in the mesh itself (Note: must release it when done with it) LPDIRECT3DDEVICE9 pd3dDevice = 0; meshData->pMesh->GetDevice(&pd3dDevice); // Changed 24/09/07 - can just assign pointer and add a ref rather than need to clone newMeshContainer->MeshData.pMesh=meshData->pMesh; newMeshContainer->MeshData.pMesh->AddRef(); // Create material and texture arrays. Note that I always want to have at least one newMeshContainer->NumMaterials = max(numMaterials,1); newMeshContainer->exMaterials = new D3DMATERIAL9[newMeshContainer->NumMaterials]; newMeshContainer->exTextures = new LPDIRECT3DTEXTURE9[newMeshContainer->NumMaterials]; ZeroMemory(newMeshContainer->exTextures, sizeof(LPDIRECT3DTEXTURE9) * newMeshContainer->NumMaterials); if (numMaterials>0) { // Load all the textures and copy the materials over for(DWORD i = 0; i < numMaterials; ++i) { newMeshContainer->exTextures[i] = 0; newMeshContainer->exMaterials[i]=materials[i].MatD3D; if(materials[i].pTextureFilename) { D3DXCreateTextureFromFile(pd3dDevice, materials[i].pTextureFilename, &newMeshContainer->exTextures[i]); } } } else // make a default material in the case where the mesh did not provide one { ZeroMemory(&newMeshContainer->exMaterials[0], sizeof( D3DMATERIAL9 ) ); newMeshContainer->exMaterials[0].Diffuse.r = 0.5f; newMeshContainer->exMaterials[0].Diffuse.g = 0.5f; newMeshContainer->exMaterials[0].Diffuse.b = 0.5f; newMeshContainer->exMaterials[0].Specular = newMeshContainer->exMaterials[0].Diffuse; newMeshContainer->exTextures[0]=0; } // If there is skin data associated with the mesh copy it over if (pSkinInfo) { // save off the SkinInfo newMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); // Need an array of offset matrices to move the vertices from the figure space to the bone's space UINT numBones = pSkinInfo->GetNumBones(); newMeshContainer->exBoneOffsets = new D3DXMATRIX[numBones]; // Create the arrays for the bones and the frame matrices newMeshContainer->exFrameCombinedMatrixPointer = new D3DXMATRIX*[numBones]; // get each of the bone offset matrices so that we don't need to get them later for (UINT i = 0; i < numBones; i++) newMeshContainer->exBoneOffsets[i] = *(newMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i)); // Note: in the Microsoft samples a GenerateSkinnedMesh function is called here in order to prepare // the skinned mesh data for optimial hardware acceleration. As mentioned in the notes this sample // does not do hardware skinning but instead uses software skinning. } else { // No skin info so 0 all the pointers newMeshContainer->pSkinInfo = 0; newMeshContainer->exBoneOffsets = 0; newMeshContainer->exSkinMesh = 0; newMeshContainer->exFrameCombinedMatrixPointer = 0; } // When we got the device we caused an internal reference count to be incremented // So we now need to release it pd3dDevice->Release(); // The mesh may contain a reference to an effect file if (effectInstances) { if (effectInstances->pEffectFilename) MessageBox(NULL, "Effect Instance", "Model Load Error", MB_OK); } // Set the output mesh container pointer to our newly created one *retNewMeshContainer = newMeshContainer; return S_OK; } [/code] [code] void Model::DrawMeshContainer(LPD3DXMESHCONTAINER meshContainerBase, LPD3DXFRAME frameBase) { // Cast to our extended frame type D3DXFRAME_EXTENDED *frame = (D3DXFRAME_EXTENDED*)frameBase; // Cast to our extended mesh container D3DXMESHCONTAINER_EXTENDED *meshContainer = (D3DXMESHCONTAINER_EXTENDED*)meshContainerBase; // Loop through all the materials in the mesh rendering each subset for (unsigned int iMaterial = 0; iMaterial < meshContainer->NumMaterials; iMaterial++) { // use the material in our extended data rather than the one in meshContainer->pMaterials[iMaterial].MatD3D pd3dDevice->SetMaterial( &meshContainer->exMaterials[iMaterial] ); pd3dDevice->SetTexture( 0, meshContainer->exTextures[iMaterial] ); // Select the mesh to draw, if there is skin then use the skinned mesh else the normal one LPD3DXMESH pDrawMesh = (meshContainer->pSkinInfo) ? meshContainer->exSkinMesh: meshContainer->MeshData.pMesh; // Finally Call the mesh draw function pDrawMesh->DrawSubset(iMaterial); } } [/code]
  10. I'm trying to load an x file with multiple animations. So far the only way I know how is putting them at different frames. Example walking: 1 - 100, running 101 - 200. But how do I specify specific frames to loop through for animations? The X file animation tutorial on this site talks about tracks and setanimation. But I'm using Blender and I don't know how to set it up like that in blender.
  11. Rotation + Translation

    [quote name='yckx' timestamp='1316402771' post='4863219'] Yay! I'd been wondering if you'd ever gotten it working. But, you should probably track down where your actually setting your updated world matrix [/quote] Ya I pinpointed it. It only works if the x file is animated too haha. I have to add an independent setTransform function if its not animated. Thinking about putting my matrix functions in my model class so each model can keep track of its own position etc. I have to toy more with matrices to make sure if I have 50 models up at once each keeping track of their own position I can link them all together
  12. When load an animated x file is there a function or method to select specific frames to shuffle through animations? For example if I have 0-100 walking and 101-200 running how do I select the ranges when I want. I know with x files you can use animation sets. But How do you assign animations to sets in the model editor? Im using Blender. I also heard its easier to do it the first way I mentioned but is that done in Blender or in my program with directx?
  13. Rotation + Translation

    I took about a week break since I got a new full time job and was never in the mood to think about this. But today I finally got it figured out and I want to thank all of you who put up with me and my non sensible help. Especially Yogurt and Whitewizard. Anyway I figured out my matrices were automatically being updated somewhere else in the animation code so I was basically doing it twice with my SetTransform functions. So the line of code that made what I wanted to work was : [code] D3DXMatrixMultiply(&matWorld, &(matRotX * matRotY), &matTrans); [/code] since it just multiplies the matrices without updating them so they get updated later ( i have no idea where haha). This is exactly what I needed and thanks for all your helpful info and guidance!
  14. Rotation + Translation

    UPDATE: So after some tinkering I think I REALLY found the source of my problem. I noticed that my translation still applied without having any setTransform functions... My character is animated and I used the guide of this website to get it to work. I have an UpdateFrameMatrices() function my my model class which already uses matrices so I'm guessing this is where it is conflicting with what I want to apply to my object. Thank you guys for all your help so far I know I'm super annoying because I have no idea what's going on. Now I need to figure out how to apply transformations to the .x file animation tutorial code that is given on this website. If you can find where or even if they give me room to make me move and edit my object how I want let me know, I can't seem to find it. Source.cpp: [code] #include "model.h" char* filename = "BarbA2.x"; //globals LPDIRECT3D9 d3dObject=NULL; LPDIRECT3DDEVICE9 d3dDevice; LPDIRECTINPUT8 din; // the pointer to our DirectInput interface LPDIRECTINPUTDEVICE8 dinkeyboard; // the pointer to the keyboard device BYTE keystate[256]; // the storage for the key-information D3DXMATRIX matWorld; D3DXMATRIX resRotX; D3DXMATRIX resRotY; Model* pModel = NULL; Model* pModel2 = NULL; static float vector = 0; static bool jump = false; static float indexx = 0.0f; static float indexy = 0.0f; bool right = true; void initDInput(HINSTANCE hInstance, HWND hWnd); // sets up and initializes DirectInput void detect_input(void); // gets the current input state void cleanDInput(void); // closes DirectInput and releases memory void Render(); HRESULT InitD3D( HWND hWnd ) { //create D3D Object if( NULL == ( d3dObject=Direct3DCreate9(D3D_SDK_VERSION) ) ) return E_FAIL; //setup structure for parameters for D3D Device D3DPRESENT_PARAMETERS presParams; ZeroMemory(&presParams,sizeof(presParams)); presParams.Windowed=TRUE; presParams.SwapEffect=D3DSWAPEFFECT_DISCARD; presParams.BackBufferFormat=D3DFMT_UNKNOWN; presParams.PresentationInterval=D3DPRESENT_INTERVAL_ONE; //create D3D Device if( FAILED (d3dObject->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &presParams, &d3dDevice) ) ) { return E_FAIL; } // Turn on ambient lighting d3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff ); return S_OK; } VOID SetupMatrices() { // Set up world matrix //Set Model Orientation // Set view matrix D3DXVECTOR3 vEyePt( 0.0f, 0.0f, 50.0f ); D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f ); D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f ); D3DXMATRIXA16 matView; D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec ); d3dDevice->SetTransform( D3DTS_VIEW, &matView ); // Set Projection Matrix D3DXMATRIXA16 matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 500.0f ); d3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); } void checkInput() { if(keystate[DIK_LEFT] & 0x80) { indexx -= 0.5f; right = false; } if(keystate[DIK_RIGHT] & 0x80) { indexx += 0.5f; right = true; } if(keystate[DIK_UP] & 0x80) { if ( jump == false) { jump = true; vector = 2; } } return; } void Advance() { static float orientation = 0; static DWORD lastTime=timeGetTime(); float timeElapsed=0.001f*(timeGetTime()-lastTime); lastTime=timeGetTime(); //gravity indexy-=vector; if (indexy < 0) vector-=0.25; if (indexy > 0) { jump = false; vector=0; } if(keystate[DIK_R] & 0x80) orientation = 3.14159; if(keystate[DIK_L] & 0x80) orientation = 0; //pModel->SetOrientation(&matRot, right, indexx, indexy); //pModel->SetPosition(&matWorld,0,indexx,indexy); pModel->FrameMove(timeElapsed,&matWorld); return; } void Render() { D3DXMATRIX matTrans; D3DXMATRIX matRotX; D3DXMATRIX matRotY; //clear buffer d3dDevice->Clear(0,NULL,D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,50,100),1.0f,0); //begin scene d3dDevice->BeginScene(); Advance(); checkInput(); //Fix orientation of character (only needed once) D3DXMatrixRotationX( &matRotX, D3DXToRadian(90.0f) ); D3DXMatrixRotationY( &matWorld, D3DXToRadian(90.0f) ); // Move character left or right D3DXMatrixTranslation(&matWorld, indexx, indexy, 0); //Transform character world //d3dDevice->SetTransform( D3DTS_WORLD, &(matRotX * matRotY) ); //d3dDevice->SetTransform( D3DTS_WORLD, &(matTrans) ); //Render Model pModel->DrawFrame(pModel->GetFrameRoot()); //end scene d3dDevice->EndScene(); //present screen d3dDevice->Present( NULL, NULL, NULL, NULL ); } void initDInput(HINSTANCE hInstance, HWND hWnd) { // create the DirectInput interface DirectInput8Create(hInstance, // the handle to the application DIRECTINPUT_VERSION, // the compatible version IID_IDirectInput8, // the DirectInput interface version (void**)&din, // the pointer to the interface NULL); // COM stuff, so we'll set it to NULL // create the keyboard device din->CreateDevice(GUID_SysKeyboard, // the default keyboard ID being used &dinkeyboard, // the pointer to the device interface NULL); // COM stuff, so we'll set it to NULL // set the data format to keyboard format dinkeyboard->SetDataFormat(&c_dfDIKeyboard); // set the control we will have over the keyboard dinkeyboard->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); } // this is the function that gets the latest input data void detect_input(void) { // get access if we don't have it already dinkeyboard->Acquire(); // get the input data dinkeyboard->GetDeviceState(256, (LPVOID)keystate); } // this is the function that closes DirectInput void cleanDInput(void) { dinkeyboard->Unacquire(); // make sure the keyboard is unacquired din->Release(); // close DirectInput before exiting } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { //case WM_COMMAND: // handle menu selections etc. //break; //case WM_PAINT: // draw our window - note: you must paint something here or not trap it! //break; case WM_DESTROY: PostQuitMessage(0); break; default: // We do not want to handle this message so pass back to Windows // to handle it in a default way return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style= CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc= (WNDPROC)WndProc; wcex.cbClsExtra= 0; wcex.cbWndExtra= 0; wcex.hInstance= hInstance; wcex.hIcon= 0; wcex.hCursor= LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName= 0; wcex.lpszClassName= "MyWindowClass"; wcex.hIconSm= 0; // Now we can go ahead and register our new window class RegisterClassEx(&wcex); HWND hWnd = CreateWindow("MyWindowClass", "Poop", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); //call initD3D InitD3D(hWnd); initDInput(hInstance, hWnd); // initialize DirectInput //Make model pModel = new Model(d3dDevice); //Load the new pModel->Load(filename); SetupMatrices(); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); //enter main loop MSG msg; while (PeekMessage(&msg, NULL, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); detect_input(); Render(); } cleanDInput(); return (int)msg.wParam; }[/code] model.cpp (my model class) [code] #include "model.h" Model::Model(LPDIRECT3DDEVICE9 pD3DDevice) { pd3dDevice = pD3DDevice; pFrameRoot = NULL; boneMatrices = NULL; currentAnimationSet = -1; numAnimationSets = 0; maxBones = 0; pAnimController = NULL; } Model::~Model() { //Delete Animation Controller if (pAnimController) pAnimController->Release(); //if there is a frame hierarchyo if(pFrameRoot) { //Allocation class CMeshHierarchy Alloc; D3DXFrameDestroy(pFrameRoot, &Alloc); pFrameRoot = NULL; } //Delete the bones if (boneMatrices) delete [] boneMatrices; //Make the Device not point to the other device pd3dDevice = NULL; } void Model::Load(char* filename) { CMeshHierarchy Alloc; if(FAILED(D3DXLoadMeshHierarchyFromX( filename, D3DXMESH_MANAGED, pd3dDevice, &Alloc, NULL, &pFrameRoot, &pAnimController ))) { MessageBox(NULL, filename, "Model Load Error", MB_OK); } //Set Breakpoint to check value of pFrameRoot if (pFrameRoot) { SetupBoneMatrices((D3DXFRAME_EXTENDED*)pFrameRoot); if(pAnimController) numAnimationSets = pAnimController->GetMaxNumAnimationSets(); // Create the bone matrices array for use during FrameMove to hold the final transform boneMatrices = new D3DXMATRIX[maxBones]; ZeroMemory(boneMatrices, sizeof(D3DXMATRIX)*maxBones); } } void Model::FrameMove(float elapsedTime,const D3DXMATRIX *matWorld) { float speed = 30; elapsedTime/=speed; // Advance the time and set in the controller if (pAnimController != NULL) pAnimController->AdvanceTime(elapsedTime, NULL); currentTime+=elapsedTime; // Now update the model matrices in the hierarchy UpdateFrameMatrices(pFrameRoot, matWorld); // If the model contains a skinned mesh update the vertices UpdateSkinnedMesh(pFrameRoot); } void Model::UpdateSkinnedMesh(const D3DXFRAME *frameBase) { D3DXFRAME_EXTENDED *currentFrame = (D3DXFRAME_EXTENDED*)frameBase; D3DXMESHCONTAINER_EXTENDED* pMesh = (D3DXMESHCONTAINER_EXTENDED*)currentFrame->pMeshContainer; while(pMesh && pMesh->pSkinInfo) // handle chained skinned mesh added 24/08/10 { unsigned int Bones = pMesh->pSkinInfo->GetNumBones(); // Create the bone matrices that transform each bone from bone space into character space // (via exFrameCombinedMatrixPointer) and also wraps the mesh around the bones using the bone offsets // in exBoneOffsetsArray for (unsigned int i = 0; i < Bones; ++i) { // Note: during set up exFrameCombinedMatrixPointer is made to point to the correct frame matrix (exCombinedTransformationMatrix) // So it does not directly get updated but uses the existing frame calculated value from the correct 'controller' frame D3DXMatrixMultiply(&boneMatrices[i],&pMesh->exBoneOffsets[i], pMesh->exFrameCombinedMatrixPointer[i]); } // We need to modify the vertex positions based on the new bone matrices. This is achieved // by locking the vertex buffers and then calling UpdateSkinnedMesh. UpdateSkinnedMesh takes the // original vertex data (in pMesh->MeshData.pMesh), applies the matrices and writes the new vertices // out to skin mesh (pMesh->exSkinMesh). // UpdateSkinnedMesh uses software skinning which is the slowest way of carrying out skinning // but is easiest to describe and works on the majority of graphic devices. // Other methods exist that use hardware to do this skinning - see the notes and the // DirectX SDK skinned mesh sample for more details void *srcPtr=0; pMesh->MeshData.pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&srcPtr); void *destPtr=0; pMesh->exSkinMesh->LockVertexBuffer(0, (void**)&destPtr); // Update the skinned mesh pMesh->pSkinInfo->UpdateSkinnedMesh(boneMatrices, NULL, srcPtr, destPtr); // Note: bounds may have changed due to skinning! Need to recalc D3DXVECTOR3 min,max; D3DXComputeBoundingBox((D3DXVECTOR3*)destPtr,pMesh->exSkinMesh->GetNumVertices(), D3DXGetFVFVertexSize(pMesh->exSkinMesh->GetFVF()),&min,&max); // Unlock the meshes vertex buffers pMesh->exSkinMesh->UnlockVertexBuffer(); pMesh->MeshData.pMesh->UnlockVertexBuffer(); // If we have more than one mesh pMesh=(D3DXMESHCONTAINER_EXTENDED*)pMesh->pNextMeshContainer; } // If we have a sibling recurse if (currentFrame->pFrameSibling != NULL) UpdateSkinnedMesh(currentFrame->pFrameSibling); // If we have a child recurse if (currentFrame->pFrameFirstChild != NULL) UpdateSkinnedMesh(currentFrame->pFrameFirstChild); } void Model::UpdateFrameMatrices(const D3DXFRAME *frameBase, const D3DXMATRIX *parentMatrix) { D3DXFRAME_EXTENDED *currentFrame = (D3DXFRAME_EXTENDED*)frameBase; // If parent matrix exists multiply our frame matrix by it if (parentMatrix != NULL) D3DXMatrixMultiply(&currentFrame->exCombinedTransformationMatrix, &currentFrame->TransformationMatrix, parentMatrix); else currentFrame->exCombinedTransformationMatrix = currentFrame->TransformationMatrix; // If we have a sibling recurse if (currentFrame->pFrameSibling != NULL) UpdateFrameMatrices(currentFrame->pFrameSibling, parentMatrix); // If we have a child recurse if (currentFrame->pFrameFirstChild != NULL) UpdateFrameMatrices(currentFrame->pFrameFirstChild, &currentFrame->exCombinedTransformationMatrix); } void Model::SetupBoneMatrices(D3DXFRAME_EXTENDED *pFrame) { // Cast to our extended structure first D3DXMESHCONTAINER_EXTENDED* pMesh = (D3DXMESHCONTAINER_EXTENDED*)pFrame->pMeshContainer; // If this frame has a mesh and there is skin info, then setup the bone matrices // Note: handles multiple mesh (// Added 24/08/10 while(pMesh && pMesh->pSkinInfo) { // Create a copy of the mesh to skin into later D3DVERTEXELEMENT9 Declaration[MAX_FVF_DECL_SIZE]; if (FAILED(pMesh->MeshData.pMesh->GetDeclaration(Declaration))) return; pMesh->MeshData.pMesh->CloneMesh(D3DXMESH_MANAGED, Declaration, pd3dDevice, &pMesh->exSkinMesh); // Max bones is calculated for later use (to know how big to make the temp bone matrices array) maxBones=max(maxBones,(UINT)pMesh->pSkinInfo->GetNumBones()); // For each bone work out its matrix for (unsigned int i = 0; i < pMesh->pSkinInfo->GetNumBones(); i++) { // Find the frame containing the bone // Must do this from root as skinned mesh and bone frame are not together D3DXFRAME_EXTENDED* pTempFrame = (D3DXFRAME_EXTENDED*)D3DXFrameFind(pFrameRoot, pMesh->pSkinInfo->GetBoneName(i)); // set the bone part - Note just point it at the transformation matrix of the relevant frame (aliase) pMesh->exFrameCombinedMatrixPointer[i] = &pTempFrame->exCombinedTransformationMatrix; } pMesh=(D3DXMESHCONTAINER_EXTENDED*)pMesh->pNextMeshContainer; } // Pass on to sibblings if(pFrame->pFrameSibling) SetupBoneMatrices((D3DXFRAME_EXTENDED*)pFrame->pFrameSibling); // Pass on to children if(pFrame->pFrameFirstChild) SetupBoneMatrices((D3DXFRAME_EXTENDED*)pFrame->pFrameFirstChild); } void Model::DrawFrame(LPD3DXFRAME frame) { // Draw all mesh containers in this frame LPD3DXMESHCONTAINER meshContainer = frame->pMeshContainer; while (meshContainer) { DrawMeshContainer(meshContainer, frame); meshContainer = meshContainer->pNextMeshContainer; } // Recurse for sibblings if (frame->pFrameSibling != NULL) DrawFrame(frame->pFrameSibling); // Recurse for children if (frame->pFrameFirstChild != NULL) DrawFrame(frame->pFrameFirstChild); } void Model::DrawMeshContainer(LPD3DXMESHCONTAINER meshContainerBase, LPD3DXFRAME frameBase) { // Cast to our extended frame type D3DXFRAME_EXTENDED *frame = (D3DXFRAME_EXTENDED*)frameBase; // Cast to our extended mesh container D3DXMESHCONTAINER_EXTENDED *meshContainer = (D3DXMESHCONTAINER_EXTENDED*)meshContainerBase; // Loop through all the materials in the mesh rendering each subset for (unsigned int iMaterial = 0; iMaterial < meshContainer->NumMaterials; iMaterial++) { // use the material in our extended data rather than the one in meshContainer->pMaterials[iMaterial].MatD3D pd3dDevice->SetMaterial( &meshContainer->exMaterials[iMaterial] ); pd3dDevice->SetTexture( 0, meshContainer->exTextures[iMaterial] ); // Select the mesh to draw, if there is skin then use the skinned mesh else the normal one LPD3DXMESH pDrawMesh = (meshContainer->pSkinInfo) ? meshContainer->exSkinMesh: meshContainer->MeshData.pMesh; // Finally Call the mesh draw function pDrawMesh->DrawSubset(iMaterial); } } [/code] allocatehierarchy.cpp: [code] #include "allocatehierarchy.h" HRESULT CMeshHierarchy::CreateFrame(LPCSTR Name, LPD3DXFRAME *retNewFrame) { // Always a good idea to initialise a return pointer before proceeding *retNewFrame = 0; // Create a new frame using the derived version of the structure D3DXFRAME_EXTENDED *newFrame = new D3DXFRAME_EXTENDED; ZeroMemory(newFrame,sizeof(D3DXFRAME_EXTENDED)); // Now fill in the data members in the frame structure // Now initialize other data members of the frame to defaults D3DXMatrixIdentity(&newFrame->TransformationMatrix); D3DXMatrixIdentity(&newFrame->exCombinedTransformationMatrix); newFrame->pMeshContainer = 0; newFrame->pFrameSibling = 0; newFrame->pFrameFirstChild = 0; // Assign the return pointer to our newly created frame *retNewFrame = newFrame; // The frame name (note: may be 0 or zero length) if (Name != NULL) { newFrame->Name = new char[strlen(Name) + 1]; strcpy(newFrame->Name, Name); } return S_OK; } /** * \brief callback called when a mesh data is encountered during the .x file load * \param Name - name of the Mesh (const char*) * \param meshData - the mesh data * \param materials - material array * \param effectInstances - effect files / settings for the mesh * \param numMaterials - number of materials in the mesh * \param adjacency - adjacency array * \param pSkinInfo - skin info. * \param retNewMeshContainer - output pointer to assign our newly created mesh container * \return success code * \author Keith Ditchburn \date 17 July 2005 */ HRESULT CMeshHierarchy::CreateMeshContainer( LPCSTR Name, CONST D3DXMESHDATA *meshData, CONST D3DXMATERIAL *materials, CONST D3DXEFFECTINSTANCE *effectInstances, DWORD numMaterials, CONST DWORD *adjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER* retNewMeshContainer) { // Create a mesh container structure to fill and initilaise to zero values // Note: I use my extended version of the structure (D3DXMESHCONTAINER_EXTENDED) defined in MeshStructures.h D3DXMESHCONTAINER_EXTENDED *newMeshContainer=new D3DXMESHCONTAINER_EXTENDED; ZeroMemory(newMeshContainer, sizeof(D3DXMESHCONTAINER_EXTENDED)); // Always a good idea to initialise return pointer before proceeding *retNewMeshContainer = 0; // The mesh name (may be 0) needs copying over if (Name != NULL) { newMeshContainer->Name = new char[strlen(Name) + 1]; strcpy(newMeshContainer->Name, Name); } // The mesh type (D3DXMESHTYPE_MESH, D3DXMESHTYPE_PMESH or D3DXMESHTYPE_PATCHMESH) if (meshData->Type!=D3DXMESHTYPE_MESH) { // This demo does not handle mesh types other than the standard // Other types are D3DXMESHTYPE_PMESH (progressive mesh) and D3DXMESHTYPE_PATCHMESH (patch mesh) DestroyMeshContainer(newMeshContainer); return E_FAIL; } newMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; // Adjacency data - holds information about triangle adjacency, required by the ID3DMESH object DWORD dwFaces = meshData->pMesh->GetNumFaces(); newMeshContainer->pAdjacency = new DWORD[dwFaces*3]; if (adjacency) { memcpy(newMeshContainer->pAdjacency, adjacency, sizeof(DWORD) * dwFaces*3); } else { // Added 24/08/10: previously did not detect null adjacency if(FAILED( newMeshContainer->MeshData.pMesh->GenerateAdjacency( 1e-6f, (DWORD*)(void*)newMeshContainer->pAdjacency ) ) ) FillMemory((void*)newMeshContainer->pAdjacency, dwFaces*3, 0xFF ); } // Get the Direct3D device, luckily this is held in the mesh itself (Note: must release it when done with it) LPDIRECT3DDEVICE9 pd3dDevice = 0; meshData->pMesh->GetDevice(&pd3dDevice); // Changed 24/09/07 - can just assign pointer and add a ref rather than need to clone newMeshContainer->MeshData.pMesh=meshData->pMesh; newMeshContainer->MeshData.pMesh->AddRef(); // Create material and texture arrays. Note that I always want to have at least one newMeshContainer->NumMaterials = max(numMaterials,1); newMeshContainer->exMaterials = new D3DMATERIAL9[newMeshContainer->NumMaterials]; newMeshContainer->exTextures = new LPDIRECT3DTEXTURE9[newMeshContainer->NumMaterials]; ZeroMemory(newMeshContainer->exTextures, sizeof(LPDIRECT3DTEXTURE9) * newMeshContainer->NumMaterials); if (numMaterials>0) { // Load all the textures and copy the materials over for(DWORD i = 0; i < numMaterials; ++i) { newMeshContainer->exTextures[i] = 0; newMeshContainer->exMaterials[i]=materials[i].MatD3D; if(materials[i].pTextureFilename) { D3DXCreateTextureFromFile(pd3dDevice, materials[i].pTextureFilename, &newMeshContainer->exTextures[i]); } } } else // make a default material in the case where the mesh did not provide one { ZeroMemory(&newMeshContainer->exMaterials[0], sizeof( D3DMATERIAL9 ) ); newMeshContainer->exMaterials[0].Diffuse.r = 0.5f; newMeshContainer->exMaterials[0].Diffuse.g = 0.5f; newMeshContainer->exMaterials[0].Diffuse.b = 0.5f; newMeshContainer->exMaterials[0].Specular = newMeshContainer->exMaterials[0].Diffuse; newMeshContainer->exTextures[0]=0; } // If there is skin data associated with the mesh copy it over if (pSkinInfo) { // save off the SkinInfo newMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); // Need an array of offset matrices to move the vertices from the figure space to the bone's space UINT numBones = pSkinInfo->GetNumBones(); newMeshContainer->exBoneOffsets = new D3DXMATRIX[numBones]; // Create the arrays for the bones and the frame matrices newMeshContainer->exFrameCombinedMatrixPointer = new D3DXMATRIX*[numBones]; // get each of the bone offset matrices so that we don't need to get them later for (UINT i = 0; i < numBones; i++) newMeshContainer->exBoneOffsets[i] = *(newMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i)); // Note: in the Microsoft samples a GenerateSkinnedMesh function is called here in order to prepare // the skinned mesh data for optimial hardware acceleration. As mentioned in the notes this sample // does not do hardware skinning but instead uses software skinning. } else { // No skin info so 0 all the pointers newMeshContainer->pSkinInfo = 0; newMeshContainer->exBoneOffsets = 0; newMeshContainer->exSkinMesh = 0; newMeshContainer->exFrameCombinedMatrixPointer = 0; } // When we got the device we caused an internal reference count to be incremented // So we now need to release it pd3dDevice->Release(); // The mesh may contain a reference to an effect file if (effectInstances) { if (effectInstances->pEffectFilename) MessageBox(NULL, "Effect Instance", "Model Load Error", MB_OK); } // Set the output mesh container pointer to our newly created one *retNewMeshContainer = newMeshContainer; return S_OK; } /** * \brief callback called to deallocate the frame data * \param the frame to free * \return success result * \author Keith Ditchburn \date 17 July 2005 */ HRESULT CMeshHierarchy::DestroyFrame(LPD3DXFRAME frameToFree) { // Convert to our extended type. OK to do this as we know for sure it is: D3DXFRAME_EXTENDED *frame = (D3DXFRAME_EXTENDED*)frameToFree; delete []frame->Name; delete frame; return S_OK; } /** * \brief callback called to deallocate the mesh container data * \param the mesh data to free * \return success result * \author Keith Ditchburn \date 17 July 2005 */ HRESULT CMeshHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER meshContainerBase) { // Convert to our extended type. OK as we know for sure it is: D3DXMESHCONTAINER_EXTENDED* meshContainer = (D3DXMESHCONTAINER_EXTENDED*)meshContainerBase; if (!meshContainer) return S_OK; // name delete []meshContainer->Name; meshContainer->Name=0; // material array delete []meshContainer->exMaterials; meshContainer->exMaterials=0; // release the textures before deleting the array if(meshContainer->exTextures) { for(UINT i = 0; i < meshContainer->NumMaterials; ++i) { if (meshContainer->exTextures[i]) meshContainer->exTextures[i]->Release(); } } // texture array delete []meshContainer->exTextures; // adjacency data delete []meshContainer->pAdjacency; // bone parts delete []meshContainer->exBoneOffsets; // frame matrices delete []meshContainer->exFrameCombinedMatrixPointer; // release skin mesh if (meshContainer->exSkinMesh) meshContainer->exSkinMesh->Release(); // release the main mesh if (meshContainer->MeshData.pMesh) meshContainer->MeshData.pMesh->Release(); // release skin information if (meshContainer->pSkinInfo) meshContainer->pSkinInfo->Release(); // finally delete the mesh container itself delete meshContainer; meshContainer=0; return S_OK; } [/code]