Непосредственная обработка буфера вершин меша является, наверное, самым простым способом работы с морфингом. Для этого метода вам потребуется третий меш, который будет содержать результирующие координаты каждой вершины после морфирования, и именно этот меш вы визуализируете.

Для создания третьего меша, который я назвал результирующим морфированным мешем, вам необходимо скопировать исходный меш и изменять его.

// Объявить третий меш, используемый для результирующего // морфированного меша ID3DXMesh *pResultMesh = NULL;

// скопировать меш, используя исходный меш pSourceMesh pSourceMesh->CloneMeshFVF(0, pSourceMesh->GetFVF(), \ pDevice, &pResultMesh);

После создания результирующего морфированного меша (pResultMesh) вы можете начинать обрабатывать морфируемую анимацию, заблокировав буферы вершин исходного, целевого и результирующего морфированного мешей. Однако прежде чем это сделать вам необходимо объявить общую структуру вершин, которая будет содержать только их координаты, к которым вы получаете доступ при блокировке каждого буфера вершин.

typedef struct {

D3DXVECTOR3 vecPos; } sGenericVertex;

Также вам необходимо вычислить размер каждой структуры вершин, используемых вершинами меша, потому что каждый буфер вершин содержит вершины различных размеров (например, у исходного могут быть нормали, в то время как у целевого нет). Вы можете сделать это, используя функцию D3DXGetFVFVertexSize.

// pSourceMesh = объект исходного меша // pTargetMesh = объект целевого меша

// pResultMesh = объект результирующего морфированного меша DWORD SourceSize = D3DXGetFVFVertexSize(pSourceMesh->GetFVF()); DWORD TargetSize = D3DXGetFVFVertexSize(pTargetMesh->GetFVF()); DWORD ResultSize = D3DXGetFVFVertexSize(pResultMesh->GetFVF());

Теперь вы можете заблокировать буферы вершин и присвоить им указатели.

// Объявить указатели вершин

char *pSourcePtr, *pTargetPtr, *pResultPtr; pSourceMesh->LockVertexBuffer(D3DLOCK_READONLY, \

(void**)&pSourcePtr) ; pTargetMesh->LockVertexBuffer(D3DLOCK_READONLY, \

(void**)&pTargetPtr) ; pResultMesh->LockVertexBuffer(0, (void**)&pResultPtr);

Заметили, как я присваиваю буферам вершин указатели char* вместо использования определенной структуры вершин? Вам необходимо поступать таким же бразом, потому что буферы вершин могут быть любого размера, помните? Как только вам необходимо получить доступ к вершине, вы приводите указатель к определенной структуре вершин и получаете доступ к данным. Для того чтобы перейти к следующей вершине, просто добавьте размер структуры вершин к указателю. Поняли? Если нет, не волнуйтесь, следующий ниже код поможет вам сделать это.

После того как вы заблокировали буферы, вы можете просматривать все вершины, получать их координаты и, используя вычисления из предыдущего раздела, рассчитывать положения морфированных вершин. Полагая, что продолжительность анимации хранится в Length, а текущее время в Time, следующий код иллюстрирует выполнение этих вычислений.

// Length = вещественное значение, содержащее длительность // анимации в миллисекундах

// Time = вещественное значение, содержащее текущее время в анимации

// Вычислить скаляр, используемый в вычислениях float Scalar = Time / Length;

// Перебрать все вершины

for(DWORD i=0;i<pSourceMesh->GetNumVertices();i++) {

// Привести указатели буферов вершин к общей структуре вершин sGenericVertex *pSourceVertex = (sGenericVertex*)pSourcePtr; sGenericVertex *pTargetVertex = (sGenericVertex*)pTargetPtr; sGenericVertex *pResultVertex = (sGenericVertex*)pResultPtr;

// Получить исходные координаты и масштабировать их D3DXVECTOR3 vecSource = pSourceVertex->vecPos; vecSource *= (1.0f - Scalar);

// Получить целевые координаты и масштабировать их

D3DXVECTOR3 vecTarget = pTargetVertex->vecPos;

vecTarget *= Scalar;

// Сохранить сумму координат в результирующем морфированном меше pResultVertex->vecPos = vecSource + vecTarget;

// Перейти к следующей вершине в каждом буфере pSourcePtr += SourceSize; pTargetPtr += TargetSize; pResultPtr += ResultSize;

}

До этого момента я пропускал тему нормалей вершин, потому что используемые для морфирования нормалей значения скаляра и обратного скаляра применяются таким же образом, как и для вершин.

В предыдущем коде вы можете вычислить морфируемые нормали, сначала проверив, существуют ли они у меша. Если да, то при обработке всех вершин возьмите нормали исходной и целевой вершин, умножьте их на скаляр и обратный скаляр и сохраните результат. Посмотрите на код, выполняющий эти действия.

// Length = вещественное значение, содержащее длителвноств // анимации в миллисекундах

// Time = вещественное значение, содержащее текущее время в анимации

// Вычислить скаляр, используемый в вычислениях float Scalar = Time / Length;

// Установить флаг, если используются нормали BOOL UseNormals = FALSE;

if(pSourceMesh->GetFVF() & D3DFVF_NORMAL && \ pTargetMesh->GetFVF() & D3DFVF_NORMAL)

UseNormals = TRUE;

// Перебрать все вершины

for(DWORD i=0;i<pSourceMesh->GetNumVertices();i++) {

// Привести указатель на буфер вершин к общей структуре вершин sGenericVertex *pSourceVertex = (sGenericVertex*)pSourcePtr; sGenericVertex *pTargetVertex = (sGenericVertex*)pTargetPtr;

sGenericVertex *pResultVertex = (sGenericVertex*)pResultPtr;

// Получить исходные координаты и масштабировать их D3DXVECTOR3 vecSource = pSourceVertex->vecPos; vecSource *= (1.0f - Scalar);

// Получить целевые координаты и масштабировать их D3DXVECTOR3 vecTarget = pTargetVertex->vecPos; vecTarget *= Scalar;

// Сохранить сумму координат в результирующем морфированном меше pResultVertex->vecPos = vecSource + vecTarget;

// Обработать нормали, если флаг установлен

if(UseNormals == TRUE) {

// Настроить соответствующие указатели структур вершин, для

// получения доступа к нормалям, которые следуют за координатами

pSourceVertex++; pTargetVertex++; pResultVertex++;

// Получить нормали и применить скаляр и обратный скаляр D3DXVECTOR3 vecSource = pSourceVertex->vecPos; vecSource *= (1.0f - Scalar);

D3DXVECTOR3 vecTarget = pTargetVertex->vecPos; vecTarget *= Scalar;

pResultVertex->vecPos = vecSource + vecTarget;

}

// Перейти к следующей вершине в каждом буфере и продолжить pSourcePtr += SourceSize; pTargetPtr += TargetSize; pResultPtr += ResultSize;

}

Все выглядит замечательно! Все, что вам остается сделать, - это разблокировать буферы вершин и визуализировать результирующий меш! Я пропущу код, разблокирующий буферы, и сразу перейду к визуализации мешей.

Морфинг мешей || Оглавление || Визуализация морфированных мешей