青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天行健 君子當自強而不息

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 閱讀(1297) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


公告

導航

統計

常用鏈接

隨筆分類(178)

3D游戲編程相關鏈接

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            免费久久精品视频| 在线观看日韩专区| 国产日韩一区二区| 亚洲国产成人精品久久| 日韩午夜av| 久久综合久久综合九色| 亚洲午夜三级在线| 欧美中文字幕| 欧美一级片一区| 一本色道久久综合亚洲精品小说| 欧美精品一区二区三区久久久竹菊 | 午夜精品久久久久久久久久久久久 | 影音先锋久久久| 亚洲精品无人区| 亚洲二区免费| 国产日本欧美视频| 亚洲在线第一页| 国产精品久久毛片a| 在线综合视频| 先锋影音国产一区| 国产亚洲一区在线播放| 性欧美18~19sex高清播放| 亚洲免费中文字幕| 久久都是精品| 久久视频精品在线| 久久免费观看视频| 99视频精品| 国产精品久久久久久久免费软件 | 国产精品激情偷乱一区二区∴| 亚洲第一中文字幕在线观看| 亚洲国产欧美不卡在线观看 | 老司机午夜精品| 一区二区三区在线免费观看| 亚洲精品一品区二品区三品区| 亚洲免费高清视频| 午夜激情综合网| 久久久午夜精品| 国产伦理一区| 噜噜噜在线观看免费视频日韩 | 1000部精品久久久久久久久| 亚洲狼人综合| 欧美成人一区二区在线| 女人色偷偷aa久久天堂| 亚洲片在线资源| 欧美一区二区视频网站| 国产精品久久久久久五月尺| 91久久精品久久国产性色也91 | 国产精品麻豆va在线播放| 亚洲第一偷拍| 在线观看精品| 亚洲国产经典视频| 国产欧美日韩一区| 欧美午夜片在线免费观看| 欧美a一区二区| 亚洲免费小视频| 麻豆91精品91久久久的内涵| 欧美日韩日日骚| 一区二区三区蜜桃网| 欧美一区二区三区免费在线看| 亚洲香蕉伊综合在人在线视看| 亚洲黄色影院| 亚洲伦理中文字幕| 99精品99| 最近看过的日韩成人| 99国产一区| 一本色道久久综合亚洲精品婷婷 | 国产精品一区二区三区久久| 久久躁日日躁aaaaxxxx| 欧美与欧洲交xxxx免费观看| 欧美四级伦理在线| 久久国产精品一区二区三区| 久久婷婷综合激情| 欧美久久久久久| 欧美不卡一卡二卡免费版| 欧美国产一区在线| 久久久久久久网站| 欧美一区二区视频观看视频| 一本不卡影院| 欧美成人午夜激情在线| 国产欧美日韩不卡| 一本久道久久综合婷婷鲸鱼| 国产亚洲a∨片在线观看| 欧美日韩一区二区在线| 狠狠色噜噜狠狠色综合久| 亚洲视频免费| 亚洲无玛一区| 欧美亚洲专区| 99热免费精品| 亚洲网址在线| 午夜一区二区三视频在线观看 | 亚洲综合成人婷婷小说| 欧美成人免费小视频| 久久综合九色欧美综合狠狠| 久久香蕉国产线看观看av| 国产精品一区视频| 亚洲午夜羞羞片| 一区二区三区www| 欧美视频网址| 午夜亚洲福利| 欧美一区91| 欧美一区二区在线看| 国产美女精品视频免费观看| 亚洲精品黄色| 欧美大片免费观看在线观看网站推荐| 欧美高清视频一区| 欧美成人在线网站| 在线一区二区三区做爰视频网站 | 久久久久久久尹人综合网亚洲| 99精品欧美一区二区三区综合在线 | 亚洲国产精品久久久久秋霞不卡| 亚洲国产mv| 午夜视频在线观看一区二区| 国产精品久久久久久久免费软件| 久久青草欧美一区二区三区| 欧美77777| 久久久久久国产精品一区| 欧美一区免费| 一区二区激情视频| 美女视频一区免费观看| 国产精品久久久久国产a级| 久久精品欧美| 欧美日韩国内| 亚洲少妇一区| 亚洲欧美在线磁力| 一区二区av在线| 久久久久综合网| 欧美在线不卡| 国产日韩欧美一区| 亚洲免费黄色| 亚洲欧美国产不卡| 欧美jizz19性欧美| 国产精品区二区三区日本| 一本高清dvd不卡在线观看| 狠狠色狠狠色综合| 欧美激情视频一区二区三区在线播放| 欧美日韩国产在线看| 久久国产精品99国产| 国产精品日日摸夜夜摸av| 亚洲另类在线一区| 亚洲综合日韩| 国产欧美激情| 免费日韩成人| 亚洲美女在线观看| 国产精品草莓在线免费观看| 久久综合色婷婷| 亚洲精品美女免费| 香蕉久久夜色精品国产使用方法 | 欧美私人啪啪vps| 亚洲毛片网站| 亚洲精品激情| 欧美视频在线免费| 久久精品人人做人人爽电影蜜月| 日韩一区二区精品葵司在线| 欧美一级一区| 亚洲一区在线看| 欧美黄色日本| 欧美成人免费视频| 精品成人国产| 韩国成人福利片在线播放| 欧美大香线蕉线伊人久久国产精品| 久久视频一区二区| 亚洲综合日韩| 伊人久久大香线蕉综合热线| 国产精品久久一区二区三区| 一区二区三区黄色| 99视频有精品| 99re66热这里只有精品4| 久久中文字幕导航| 亚洲手机成人高清视频| 亚洲欧洲精品天堂一级| 欧美成人一区在线| 久热精品在线| 一本色道久久综合| 欧美一区二区视频免费观看 | 久久精品视频在线播放| 欧美色精品在线视频| 亚洲欧美日韩精品久久久| 夜夜爽www精品| 可以看av的网站久久看| 一本久道久久综合中文字幕| 国产视频一区二区在线观看| 久久综合伊人77777| 欧美成人一区在线| 欧美一区二区三区视频免费播放| 亚洲欧美国产77777| 午夜国产精品影院在线观看| 久久久久久久久久久成人| 亚洲欧美国产精品va在线观看| 麻豆精品视频在线观看| 亚洲国产99精品国自产| 亚洲精品资源美女情侣酒店| 欧美一进一出视频| 亚洲欧美一区二区三区极速播放 | 免费在线观看成人av| 亚洲综合国产精品| 中文国产一区| 91久久夜色精品国产网站| 国产一区二区电影在线观看| 一区二区三区日韩精品视频| 久久野战av|