Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
DirectX. Продвинутая Анимация (2004) [rus].pdf
Скачиваний:
335
Добавлен:
16.08.2013
Размер:
8.39 Mб
Скачать

248

Глава 8

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

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

Scalar = Time / Length;

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

Уже второй раз я говорю о создании морфируемого меша, так что я больше не буду тянуть. Читайте далее, чтобы узнать, как создавать морфируемый меш, который вы можете использовать для визуализации. Хотя ранее я и замечал об использовании вершинных шейдеров, сначала я покажу вам самый простой путь создания морфируемых мешей - непосредственной обработкой буфера вершин меша.

Создание морфированного меша при помощи обработки

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

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

//Объявить третий меш, используемый для результирующего

//морфированного меша

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* вместо использования определенной структуры вершин? Вам необходимо поступать таким же бразом, потому что буферы вершин могут быть любого размера, помните? Как только вам необходимо получить доступ к вершине, вы приводите указатель к определенной структуре вершин и получаете доступ к данным. Для того чтобы перейти к следующей вершине, просто добавьте размер структуры вершин к указателю. Поняли? Если нет, не волнуйтесь, следующий ниже код поможет вам сделать это.

250

Глава 8

После того как вы заблокировали буферы, вы можете просматривать все вершины, получать их координаты и, используя вычисления из предыдущего раздела, рассчитывать положения морфированных вершин. Полагая, что продолжительность анимации хранится в 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;

}

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

Соседние файлы в предмете Программирование на C++