• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天行健 君子當自強而不息

            Working with Morphing Animation(2)

            Building a Morphed Mesh through Manipulation

            Directly manipulating a mesh's vertex buffers is probably the easiest way to work with morphing. For this method you'll need a third mesh that contains the final coordinates of each vertex after morphing; it's this third mesh that you'll render.

            To create the third mesh, which I call the resulting morphed mesh, you can clone the source mesh and be on your way.

            // Declare third mesh to use for resulting morphed mesh
            ID3DXMesh *pResultMesh = NULL;

            // Clone the mesh using the source mesh pSourceMesh
            pSourceMesh−>CloneMeshFVF(0, pSourceMesh−>GetFVF(), pDevice,&pResultMesh);

            After you've created the resulting morphed mesh (pResultMesh), you can begin processing the morphing animation by locking the source, target, and resulting morphed mesh's vertex buffers. Before you do that however, you need to declare a generic vertex structure that contains only the vertex coordinates, which you'll use to lock and access each vertex buffer.

            typedef struct {
              D3DXVECTOR3 vecPos;
            } sGenericVertex;

            Also, because each vertex buffer contains vertices of varying sizes (for example, the source might use normals whereas the target doesn't), you need to calculate the size of the vertex structure used for each mesh's vertices. You can do so using the D3DXGetFVFVertexSize function.

            // pSourceMesh = source mesh object
            // pTargetMesh = target mesh object
            // pResultMesh = resulting morphed mesh object
            DWORD SourceSize = D3DXGetFVFVertexSize(pSourceMesh−>GetFVF());
            DWORD TargetSize = D3DXGetFVFVertexSize(pTargetMesh−>GetFVF());
            DWORD ResultSize = D3DXGetFVFVertexSize(pResultMesh−>GetFVF());

            Now you can lock the vertex buffers and assign the pointers to them.

            // Declare vertex pointers
            char *pSourcePtr, *pTargetPtr, *pResultPtr;
            pSourceMesh−>LockVertexBuffer (D3DLOCK_READONLY, (void**)&pSourcePtr);
            pTargetMesh−>LockVertexBuffer (D3DLOCK_READONLY, (void**)&pTargetPtr);
            pResultMesh−>LockVertexBuffer (0, (void**)&pResultPtr);

            Notice how I assigned a few char * pointers to the vertex buffers instead of using the generic vertex structure? You need to do that because the vertices in the buffers could be of any size, remember? Whenever you need to access a vertex, you cast the pointer to the generic vertex structure and access the data. To go to the next vertex in the list, add the size of the vertex structure to the pointer. Get it? If not, don't worry−the upcoming code will help you make sense of it all.

            After you've locked the buffers you can begin iterating through all vertices, grabbing the coordinates and using the calculations from the previous section to calculate the morphed vertex positions. Assuming that the length of the animation is stored in Length and the current time you are using is stored in Time, the following code will illustrate how to perform the calculations:

            // Length = FLOAT with length of animation in milliseconds
            // Time = FLOAT with time in animation to use
            // Calculate a scalar value to use for calculations
            float Scalar = Time / Length;
            // Loop through all vertices
            for(DWORD i=0;i<pSourceMesh−>GetNumVertices();i++)
            {
            // Cast vertex buffer pointers to a generic vertex structure
            sGenericVertex *pSourceVertex = (sGenericVertex*)pSourcePtr;
            sGenericVertex *pTargetVertex = (sGenericVertex*)pTargetPtr;
            sGenericVertex *pResultVertex = (sGenericVertex*)pResultPtr;
            	// Get source coordinates and scale them
            D3DXVECTOR3 vecSource = pSourceVertex−>vecPos;
            vecSource *= (1.0f − Scalar);
            	// Get target coordinates and scale them
            D3DXVECTOR3 vecTarget = pTargetVertex−>vecPos;
            vecTarget *= Scalar;
            	// Store summed coordinates in resulting morphed mesh
            pResultVertex−>vecPos = vecSource + vecTarget;
            	// Go to next vertices in each buffer and continue loop
            pSourcePtr += SourceSize;
            pTargetPtr += TargetSize;
            pResultPtr += ResultSize;
            }

            Up to this point I've skipped over the topic of vertex normals because normals are identical to vertex coordinates in that you use scalar and inversed scalar values on the normals to perform the same calculations as you do for the vertex coordinates.

            In the preceding code, you can calculate the morphing normal values by first seeing whether the mesh uses normals. If so, during the loop of all vertices you grab the normals from both the source and target vertices, multiply by the scalar and inversed scalar, and store the results. Take another look at the code to see how to do that:

            // Length = FLOAT with length of animation in milliseconds
            // Time = FLOAT with time in animation to use
            // Calculate a scalar value to use for calculations
            float Scalar = Time / Length;
            // Set a flag if using normals
            BOOL UseNormals = FALSE;
            if(pSourceMesh−>GetFVF() & D3DFVF_NORMAL && pTargetMesh−>GetFVF() & D3DFVF_NORMAL)
            UseNormals = TRUE;
            // Loop through all vertices
            for(DWORD i=0;i<pSourceMesh−>GetNumVertices();i++)
            {
            // Cast vertex buffer pointers to a generic vertex structure
            sGenericVertex *pSourceVertex = (sGenericVertex*)pSourcePtr;
            sGenericVertex *pTargetVertex = (sGenericVertex*)pTargetPtr;
            sGenericVertex *pResultVertex = (sGenericVertex*)pResultPtr;
            	// Get source coordinates and scale them
            D3DXVECTOR3 vecSource = pSourceVertex−>vecPos;
            vecSource *= (1.0f − Scalar);
            	// Get target coordinates and scale them
            D3DXVECTOR3 vecTarget = pTargetVertex−>vecPos;
            vecTarget *= Scalar;
            	// Store summed coordinates in resulting morphed mesh
            pResultVertex−>vecPos = vecSource + vecTarget;
            	// Process normals if flagged
            if(UseNormals == TRUE)
            {
            // Adjust generic vertex structure pointers to access
            // normals, which are next vector after coordinates.
            pSourceVertex++; pTargetVertex++; pResultVertex++;
            		// Get normals and apply scalar and inversed scalar values
            D3DXVECTOR3 vecSource = pSourceVertex−>vecPos;
            vecSource *= (1.0f − Scalar);
            		D3DXVECTOR3 vecTarget = pTargetVertex−>vecPos;
            vecTarget *= Scalar;
            		pResultVertex−>vecPos = vecSource + vecTarget;
            }
            	// Go to next vertices in each buffer and continue loop
            pSourcePtr += SourceSize;
            pTargetPtr += TargetSize;
            pResultPtr += ResultSize;
            }

            Everything looks great! All you need to do now is unlock the vertex buffers and render the resulting mesh! I'll skip the code to unlock the buffers and get right to the good part−rendering the meshes.

             

            Drawing Morphed Meshes

            If you're building the morphing meshes by directly manipulating the resulting mesh's vertex buffer, as shown in the previous section, then rendering the morphing mesh is the same as for any other ID3DXMesh object you've been using. For example, you can loop through each material in the mesh, set the material and texture, and then draw the currently iterated subset. No need to show any code here−it's just simple mesh rendering.

            On the other hand, if you want to move past the basics and start playing with real power, you can create your own vertex shader to render the morphing meshes for you. Take my word for it−this is something you'll definitely want to do. Using a vertex shader means you have one less mesh to deal with because the resulting mesh object is no longer needed; the speed increase is well worth a little extra effort.

            Before you can move on to using a vertex shader, however, you need to figure out how to render the mesh's subsets yourself.

             

            Dissecting the Subsets

            To draw the morphing mesh, you need to set the source mesh's vertex stream as well as the target mesh's stream. Also, you need to set only the source mesh's indices. At that point, it's only a matter of scanning through every subset and rendering the polygons related to each subset.

            Wait a second! How do you render the subsets yourself? By duplicating what the ID3DXMesh::DrawSubset function does, that's how! The DrawSubset function works in one of two ways. The first method, which you use if your mesh has not been optimized to use an attribute table, is to scan the entire list of attributes and render those batches of polygons belonging to the same subset. This method
            can be a little slow because it renders multimaterial meshes in small batches of polygons.

            The second method, which is used after you optimize the mesh to use an attribute table, works by scanning the built attribute table to determine which grouped faces are drawn all in one shot. That is, all faces that belong to the same subset are grouped together beforehand and rendered in one call to DrawPrimitive or DrawIndexedPrimitive. That seems like the way to go!

            To use the second method of rendering, you need to first optimize your source mesh. You can (and should) do this when you load the mesh. It's a safe habit to optimize all meshes you load using the ID3DXMesh::OptimizeInPlace function, as shown in the following bit of code:

            // pMesh = just−loaded mesh
            pMesh−>OptimizeInPlace(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL);

            Once the mesh is optimized, you can query the ID3DXMesh object for the attribute table it is using. The attribute table is of the data type D3DXATTRIBUTERANGE, which is defined as follows:

            typedef struct_D3DXATTRIBUTERANGE {
              DWORD AttribId;
              DWORD FaceStart;
              DWORD FaceCount;
              DWORD VertexStart;
              DWORD VertexCount;
            } D3DXATTRIBUTERANGE;

            The first variable, AttribId is the subset number that the structure represents. For each material in your mesh, you have one D3DXATTRIBUTERANGE structure with the AttribId set to match the subset number.

            Next come FaceStart and FaceCount. You use these two variables to determine which polygon faces belong to the subset. Here's where the optimization comes in handy−all faces belonging to the same subset are grouped together in the index buffer. FaceStart represents the first face in the index buffer belonging to the subset, whereas FaceCount represents the number of polygon faces to render using that subset.

            Last, you see VertexStart and VertexCount, which, much like FaceStart and FaceCount, determine which vertices are used during the call to render the polygons. VertexStart represents the first vertex in the vertex buffer to use for a subset, and VertexCount represents the number of vertices you can render in one call. When you optimize a mesh based on vertices, you'll notice that all vertices are packed in
            the buffer to reduce the number of vertices used in a call to render a subset.

            For each subset in your mesh you must have a matching D3DXATTRIBUTERANGE structure. Therefore, a mesh using three materials will have three attribute structures. After you've optimized a mesh (using ID3DXMesh::OptimizeInPlace ), you can get the attribute table by first querying the mesh object for the number of attribute structures using the ID3DXMesh::GetAttributeTable function, as shown
            here:

            // Get the number of attributes in the table
            DWORD NumAttributes;
            pMesh−>GetAttributeTable(NULL, &NumAttributes);

            At this point, you only need to allocate a number of D3DXATTRIBUTERANGE objects and call the GetAttributeTable function again, this time supplying a pointer to your array of attribute objects.

            // Allocate memory for the attribute table and query for the table data
            D3DXATTRIBUTERANGE *pAttributes;
            pAttributes = new D3DXATTRIBUTERANGE[NumAttributes];
            pMesh−>GetAttributeTable(pAttributes, NumAttributes);

            Cool! After you've got the attribute data, you can pretty much render the subsets by scanning through each attribute table object and using the specified data in each in a call to DrawIndexedPrimitive. In fact, do that now by first grabbing the mesh's vertex buffer and index buffer pointers.

            // Get the vertex buffer interface
            IDirect3DVertexBuffer9 *pVB;
            pMesh−>GetVertexBuffer(&pVB);

            // Get the index buffer interface
            IDirect3DIndexBuffer9 *pIB;
            pMesh−>GetIndexBuffer(&pIB);

            Now that you have both buffer pointers, go ahead and set up your streams, vertex shader, and vertex element declaration, and loop through each subset, setting the texture and then rendering the polygons.

            // Set the vertex shader and declaration
            pDevice−>SetFVF(NULL); // Clear FVF usage
            pDevice−>SetVertexShader(pShader);
            pDevice−>SetVertexDeclaration(pDecl);
            // Set the streams
            pDevice−>SetStreamSource(0, pVB, 0, pMesh−>GetNumBytesPerVertex());
            pDevice−>SetIndices(pIB);
            // Go through each subset
            for(DWORD i=0;i<NumAttributes;i++)
            {
            // Get the material id#
            DWORD MatID = pAttributes[i];
            	// Set the texture of the subset
            pDevice−>SetTexture(0, pTexture[AttribID]);
            	// Render the polygons using the table
            pDevice−>DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0,
            pAttributes[i].VertexStart,
            pAttributes[i].VertexCount,
            pAttributes[i].FaceStart * 3,
            pAttributes[i].FaceCount);
            }

            After you've rendered the subsets you can free the vertex buffer and index buffer interfaces you obtained.

            pVB−>Release(); pVB = NULL;
            pIB−>Release(); pIB = NULL;

            When you're done with the attribute table, make sure to free that memory as well.

            delete [] pAttributes; pAttributes = NULL;

            All right, now you're getting somewhere! Now that you know how to render the subsets yourself, it's time to move on to using a vertex shader.

             

            Check Out the Demos

            This project demonstrates building morphing meshes by directly manipulating a mesh's vertex buffer.

            Figure 8.4: The animated dolphin jumps over morphing sea waves!


            WinMain.cpp:

            #include <windows.h>
            #include 
            <d3d9.h>
            #include 
            <d3dx9.h>
            #include 
            "Direct3D.h"

            // A generic coordinate vertex structure
            struct sVertex
            {
                D3DXVECTOR3 pos;
            };

            // Background vertex structure, fvf, and texture.
            struct sBackdropVertex
            {
                
            float x, y, z, rhw;
                
            float u, v;
            };

            #define BACKDROP_FVF (D3DFVF_XYZRHW | D3DFVF_TEX1)

            // Structure to contain a morphing mesh
            struct sMorphMesh
            {
                D3DXMESHCONTAINER_EX
            * source_mesh;
                D3DXMESHCONTAINER_EX
            * target_mesh;
                D3DXMESHCONTAINER_EX
            * result_mesh;

                
            long    normal_offset;
                DWORD    vertex_pitch;

                sMorphMesh()
                {
                    ZeroMemory(
            thissizeof(*this));
                }

                
            ~sMorphMesh()
                {
                    delete source_mesh; source_mesh 
            = NULL;
                    delete target_mesh; target_mesh 
            = NULL;
                    delete result_mesh; result_mesh 
            = NULL;
                }
            };

            //////////////////////////////////////////////////////////////////////////////////////////////

            IDirect3D9
            *                g_d3d;
            IDirect3DDevice9
            *        g_device;
            IDirect3DVertexBuffer9
            *    g_backdrop_vb;
            IDirect3DTexture9
            *        g_backdrop_texture;
            sMorphMesh
            *                g_water_morph_mesh;
            sMorphMesh
            *                g_dolphin_morph_mesh;

            const char CLASS_NAME[] = "MorphClass";
            const char CAPTION[]    = "Morphing Demo";

            ////////////////////////////////////////////////////////////////////////////////////////////////

            LRESULT FAR PASCAL window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

            bool do_init(HWND hwnd);
            void do_shutdown();
            void do_frame();

            // Function to load a group of meshes for morphing
            bool load_morphing_mesh(sMorphMesh* morph_mesh,
                                    
            const char* source_mesh_file,
                                    
            const char* target_mesh_file,
                                    
            const char* texture_path);

            // Function to build a resulting morphes mesh
            void build_morph_mesh(sMorphMesh* morph_mesh, float scalar);

            //////////////////////////////////////////////////////////////////////////////////////////////

            int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR, int cmd_show)
            {      
                CoInitialize(NULL);    
            // Initialize the COM system

                
            // Create the window class here and register it

                WNDCLASSEX win_class;  

                win_class.cbSize        
            = sizeof(win_class);
                win_class.style         
            = CS_CLASSDC;
                win_class.lpfnWndProc   
            = window_proc;
                win_class.cbClsExtra    
            = 0;
                win_class.cbWndExtra    
            = 0;
                win_class.hInstance     
            = inst;
                win_class.hIcon         
            = LoadIcon(NULL, IDI_APPLICATION);
                win_class.hCursor       
            = LoadCursor(NULL, IDC_ARROW);
                win_class.hbrBackground 
            = NULL;
                win_class.lpszMenuName  
            = NULL;
                win_class.lpszClassName 
            = CLASS_NAME;
                win_class.hIconSm       
            = LoadIcon(NULL, IDI_APPLICATION);

                
            if(!RegisterClassEx(&win_class))
                    
            return -1;

                
            // Create the main window
                HWND hwnd = CreateWindow(CLASS_NAME, CAPTION, WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
                                         
            00640480, NULL, NULL, inst, NULL);

                
            if(hwnd == NULL)
                    
            return -1;

                ShowWindow(hwnd, cmd_show);
                UpdateWindow(hwnd);

                
            // Call init function and enter message pump
                if(do_init(hwnd)) 
                {
                    MSG msg;    
                    ZeroMemory(
            &msg, sizeof(MSG));

                    
            // Start message pump, waiting for user to exit
                    while(msg.message != WM_QUIT) 
                    {
                        
            if(PeekMessage(&msg, NULL, 00, PM_REMOVE)) 
                        {
                            TranslateMessage(
            &msg);
                            DispatchMessage(
            &msg);
                        }
                        
                        do_frame();    
            // Render a single frame
                    }
                }
              
                do_shutdown();
                UnregisterClass(CLASS_NAME, inst);
                CoUninitialize();

                
            return 0;
            }

            LRESULT FAR PASCAL window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
            {
                
            // Only handle window destruction messages
                switch(msg) 
                {
                
            case WM_DESTROY:
                    PostQuitMessage(
            0);
                    
            break;

                
            case WM_KEYDOWN:
                    
            if(wParam == VK_ESCAPE)
                        DestroyWindow(hwnd);

                    
            break;
                }

                
            return DefWindowProc(hwnd, msg, wParam, lParam);
            }

            bool do_init(HWND hwnd)
            {
                init_d3d(
            &g_d3d, &g_device, hwnd, falsefalse);

                g_water_morph_mesh 
            = new sMorphMesh;

                
            if(! load_morphing_mesh(g_water_morph_mesh, "..\\Data\\Water1.x""..\\Data\\Water2.x""..\\Data\\"))
                    
            return false;

                g_dolphin_morph_mesh 
            = new sMorphMesh;

                
            if(! load_morphing_mesh(g_dolphin_morph_mesh, "..\\Data\\Dolphin1.x""..\\Data\\Dolphin3.x""..\\Data\\"))
                    
            return false;

                
            // create the backdrop

                sBackdropVertex backdrop_verts[
            4= {
                    {   
            0.0f,   0.01.01.0f0.0f0.0f },
                    { 
            640.0f,   0.01.01.0f1.0f0.0f },
                    {   
            0.0f480.01.01.0f0.0f1.0f },
                    { 
            640.0f480.01.01.0f1.0f1.0f }
                };

                g_device
            ->CreateVertexBuffer(sizeof(backdrop_verts), D3DUSAGE_WRITEONLY, BACKDROP_FVF, D3DPOOL_DEFAULT,
                                             
            &g_backdrop_vb, NULL);

                
            char* ptr;
                g_backdrop_vb
            ->Lock(00, (void**)&ptr, 0);
                memcpy(ptr, backdrop_verts, 
            sizeof(backdrop_verts));
                g_backdrop_vb
            ->Unlock();

                D3DXCreateTextureFromFile(g_device, 
            "..\\Data\\Sky.bmp"&g_backdrop_texture);

                
            // Create and enable a directional light

                D3DLIGHT9 light;
                ZeroMemory(
            &light, sizeof(light));

                light.Type 
            = D3DLIGHT_DIRECTIONAL;
                light.Diffuse.r 
            = light.Diffuse.g = light.Diffuse.b = light.Diffuse.a = 1.0f;
                light.Direction 
            = D3DXVECTOR3(0.0f-1.0f0.0f);

                g_device
            ->SetLight(0&light);
                g_device
            ->LightEnable(0, TRUE);

                
            // start playing an ocean sound
                PlaySound("..\\Data\\Ocean.wav", NULL, SND_ASYNC | SND_LOOP);

                
            return true;
            }

            void do_shutdown()
            {
                
            // Stop playing an ocean sound
                PlaySound(NULL, NULL, 0);

                
            // release backdrop data
                release_com(g_backdrop_vb);
                release_com(g_backdrop_texture);

                
            // free mesh data
                delete g_water_morph_mesh;        g_water_morph_mesh   = NULL;
                delete g_dolphin_morph_mesh;    g_dolphin_morph_mesh 
            = NULL;
                
                
            // release D3D objects
                release_com(g_device);
                release_com(g_d3d);
            }

            void do_frame()
            {
                
            static float dolphin_x_pos = 0.0f, dolphin_z_pos = 256.0f;

                
            // build the water morphing mesh using a time-based sine-wave scalar value
                float water_scalar = (sin(timeGetTime() * 0.001f+ 1.0f* 0.5f;
                build_morph_mesh(g_water_morph_mesh, water_scalar);

                
            // build the dolphin morphing mesh using a time-based scalar value
                float dolphin_time_factor = (timeGetTime() % 501/ 250.0f;
                
            float dolphin_scalar = (dolphin_time_factor <= 1.0f? dolphin_time_factor : (2.0f - dolphin_time_factor);
                build_morph_mesh(g_dolphin_morph_mesh, dolphin_scalar);

                
            // calculate the angle of the dolphin's movement and reposition the dolphin if it's far enough underwater.

                
            float dolphin_angle = (timeGetTime() % 6280/ 1000.0f * 3.0f;

                
            if(sin(dolphin_angle) < -0.7f)
                {
                    dolphin_x_pos 
            = (float)(rand() % 1400- 700.0f;
                    dolphin_z_pos 
            = (float)(rand() % 1500);
                }

                
            // create and set the view transformation        

                D3DXMATRIX  mat_view;
                D3DXVECTOR3 eye(
            0.0f170.0f-1000.0f);
                D3DXVECTOR3 at(
            0.0f150.0f0.0f);  
                D3DXVECTOR3 up(
            0.0f1.0f0.0f);

                D3DXMatrixLookAtLH(
            &mat_view, &eye, &at, &up);
                g_device
            ->SetTransform(D3DTS_VIEW, &mat_view);    

                
            // clear the device and start drawing the scene

                g_device
            ->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(000255), 1.0f0);

                g_device
            ->BeginScene();    

                
            // draw the backdrop
                g_device->SetFVF(BACKDROP_FVF);
                g_device
            ->SetStreamSource(0, g_backdrop_vb, 0sizeof(sBackdropVertex));
                g_device
            ->SetTexture(0, g_backdrop_texture);
                g_device
            ->DrawPrimitive(D3DPT_TRIANGLESTRIP, 02);

                
            // set identity matrix for world transformation
                D3DXMATRIX mat_world;
                D3DXMatrixIdentity(
            &mat_world);
                g_device
            ->SetTransform(D3DTS_WORLD, &mat_world);

                g_device
            ->SetRenderState(D3DRS_LIGHTING, TRUE);

                draw_mesh(g_water_morph_mesh
            ->result_mesh);

                
            // draw the jumping dolphin

                D3DXMatrixRotationZ(
            &mat_world, dolphin_angle - 1.57f);

                mat_world._41 
            = dolphin_x_pos + cos(dolphin_angle) * 256.0f;
                mat_world._42 
            = sin(dolphin_angle) * 512.0f;
                mat_world._43 
            = dolphin_z_pos;

                g_device
            ->SetTransform(D3DTS_WORLD, &mat_world);
                draw_mesh(g_dolphin_morph_mesh
            ->result_mesh);

                g_device
            ->SetRenderState(D3DRS_LIGHTING, FALSE);

                g_device
            ->EndScene();

                g_device
            ->Present(NULL, NULL, NULL, NULL);
            }

            bool load_morphing_mesh(sMorphMesh* morph_mesh,
                                    
            const char* source_mesh_file,
                                    
            const char* target_mesh_file,
                                    
            const char* texture_path)
            {
                
            if(FAILED(load_mesh(&morph_mesh->source_mesh, g_device, source_mesh_file, texture_path, 0, D3DXMESH_SYSTEMMEM)))
                    
            return false;

                
            if(FAILED(load_mesh(&morph_mesh->target_mesh, g_device, target_mesh_file, texture_path, 0, D3DXMESH_SYSTEMMEM)))
                    
            return false;

                
            // reload the source mesh as a resulting morphed mesh container
                if(FAILED(load_mesh(&morph_mesh->result_mesh, g_device, source_mesh_file, texture_path, 0, D3DXMESH_SYSTEMMEM)))
                    
            return false;

                DWORD mesh_fvf 
            = morph_mesh->source_mesh->MeshData.pMesh->GetFVF();

                
            // determin if source mesh uses normals and calculate offset
                if(mesh_fvf & D3DFVF_NORMAL)
                    morph_mesh
            ->normal_offset = 3 * sizeof(float);
                
            else
                    morph_mesh
            ->normal_offset = 0;

                morph_mesh
            ->vertex_pitch = D3DXGetFVFVertexSize(mesh_fvf);

                
            return true;
            }

            void build_morph_mesh(sMorphMesh* morph_mesh, float scalar)
            {
                
            char* source_ptr;
                
            char* target_ptr;
                
            char* result_ptr;

                morph_mesh
            ->source_mesh->MeshData.pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&source_ptr);
                morph_mesh
            ->target_mesh->MeshData.pMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&target_ptr);
                morph_mesh
            ->result_mesh->MeshData.pMesh->LockVertexBuffer(0, (void**)&result_ptr);

                DWORD num_verts 
            = morph_mesh->source_mesh->MeshData.pMesh->GetNumVertices();

                
            // go through each vertex and interpolate coordinates
                for(DWORD i = 0; i < num_verts; i++)
                {
                    sVertex
            * source_vert = (sVertex*) source_ptr;
                    sVertex
            * target_vert = (sVertex*) target_ptr;
                    sVertex
            * result_vert = (sVertex*) result_ptr;

                    D3DXVECTOR3 source_pos 
            = source_vert->pos;
                    source_pos 
            *= (1.0f - scalar);

                    D3DXVECTOR3 target_pos 
            = target_vert->pos;
                    target_pos 
            *= scalar;

                    result_vert
            ->pos = source_pos + target_pos;

                    
            // handle interpolation of normals
                    if(morph_mesh->normal_offset)
                    {
                        sVertex
            * source_normal = (sVertex*&source_ptr[morph_mesh->normal_offset];
                        sVertex
            * target_normal = (sVertex*&target_ptr[morph_mesh->normal_offset];
                        sVertex
            * result_normal = (sVertex*&result_ptr[morph_mesh->normal_offset];

                        D3DXVECTOR3 source_pos 
            = source_normal->pos;
                        source_pos 
            *= (1.0f - scalar);

                        D3DXVECTOR3 target_pos 
            = target_normal->pos;
                        target_pos 
            *= scalar;

                        result_normal
            ->pos = source_pos + target_pos;
                    }

                    
            // goto next vertex
                    source_ptr += morph_mesh->vertex_pitch;
                    target_ptr 
            += morph_mesh->vertex_pitch;
                    result_ptr 
            += morph_mesh->vertex_pitch;
                }

                morph_mesh
            ->source_mesh->MeshData.pMesh->UnlockVertexBuffer();
                morph_mesh
            ->target_mesh->MeshData.pMesh->UnlockVertexBuffer();
                morph_mesh
            ->result_mesh->MeshData.pMesh->UnlockVertexBuffer();
            }

             

            download source file


            posted on 2008-04-28 18:09 lovedday 閱讀(1286) 評論(0)  編輯 收藏 引用

            公告

            導航

            統計

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關鏈接

            搜索

            最新評論

            国内精品久久国产大陆| 无码人妻久久一区二区三区免费丨 | 久久青青草原精品国产| 久久99精品久久久久久久不卡| 久久精品无码午夜福利理论片| 久久精品国产91久久综合麻豆自制| 久久久久香蕉视频| 久久婷婷五月综合色奶水99啪| 嫩草影院久久国产精品| 精品久久久久久国产| 91精品国产色综久久 | 中文字幕无码久久人妻| 久久国产高潮流白浆免费观看| 久久久久18| 秋霞久久国产精品电影院| 亚洲色欲久久久综合网东京热 | 精品久久久久久无码人妻蜜桃| 亚洲AV日韩AV天堂久久| 午夜福利91久久福利| 国产成人香蕉久久久久| 日韩AV无码久久一区二区| 色播久久人人爽人人爽人人片aV| 97久久综合精品久久久综合| 久久久久久国产a免费观看黄色大片 | 久久精品国产清自在天天线| 久久国产精品77777| 亚洲精品国精品久久99热一| 久久婷婷色香五月综合激情| 久久se精品一区二区影院| 国产一久久香蕉国产线看观看| 日韩AV无码久久一区二区| 色婷婷综合久久久中文字幕| 久久精品人人做人人爽电影| 久久午夜福利无码1000合集| 中文字幕精品久久| 久久笫一福利免费导航 | 国产亚州精品女人久久久久久 | 午夜肉伦伦影院久久精品免费看国产一区二区三区| 色欲综合久久中文字幕网| 影音先锋女人AV鲁色资源网久久 | 曰曰摸天天摸人人看久久久|