Visual Basic - мастерская разработчика
Библиотеки

DirectX

Обзоры
DirectDraw
Direct3D
DirectX Audio
DirectPlay
DirectInput
Fido Topics
SourceCode
Tools&Libs

OpenGL

Статьи и учебники
Fido Topics
SourceCode
Tools&Libs

Архив по Glide

Движки

Обзоры
Учебники
SourceCode
Downloads

Создание игр

Ваши игры

Обзорные статьи
Учебники
Fido Topics
SourceCode
Download

Stuff

Программер-Чат

Псевдо-FTP
Disclaimer
Оффтопик

 

Пример по Direct3DIM (Direct3D непосредственному)

Раньше писать на Direct3DIM было очень сложно. Сейчас благодаря Microsoft появилось множество вспомогательных библиотек, работающих под Direct3DIM и входящих в состав DirectX SDK -библиотека загрузки и работы с Х файлами, библиотеки математических функций, готовый каркас приложения. Когда вы начинаете писать на Direct3DIM то вам уже не надо создавать каркас приложения: создание окна, обработка сообщений, инициализация и выбор видеорежимов, достаточно просто взять уже готовый каркас приложения (любой пример из DirectX SDK, заменить соответствующие функции и работать). Благодаря этому отпадает необходимость самому создавать окно, писать функции инициализации видеорежимов, вы сразу начинаете работать с 3D графикой не вникая в трудности создания каркаса приложения. Цель данного примера рассказать как можно подробно о работе в Direct3DIM, для примера я выбрал Dolphin из DirectX SDK. Это не самый лучший учебник по Direct3DIM, я понимаю, что будет трудно все это понять, если будут какие-то вопросы, обращайтесь за разьяснением.

//-----------------------------------------------------------------------------
// File: Dolphin.cpp
// Desc: Sample of swimming dolphin
// Note: This code uses the D3D Framework helper library.
// Copyright (c) 1998-1999 Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------

#define STRICT
#define D3D_OVERLOADS
#include <stdio.h>
#include "D3DApp.h"
#include "D3DUtil.h"
#include "D3DMath.h"
#include "D3DTextr.h"
#include "D3DFile.h"

// цвет воды
#define WATER_COLOR 0x00006688

//-----------------------------------------------------------------------------
// Name: class CMyD3DApplication
// Desc: Main class to run this application. Most functionality is inherited
// from the CD3DApplication base class.
//-----------------------------------------------------------------------------

class CMyD3DApplication : public CD3DApplication
{
// The DirectX file objects
// перед загрузкой файла необходимо обьявить переменную класса CD3DFile

CD3DFile* m_pDolphinGroupObject;
CD3DFile* m_pDolphinObject;
CD3DFile* m_pFloorObject;

// Vertex data from the file objects
// переменные, в которые мы в последствии загоняем вершины из файла

D3DVERTEX* m_pDolphinVertices;
D3DVERTEX* m_pDolphin1Vertices;
D3DVERTEX* m_pDolphin2Vertices;
D3DVERTEX* m_pDolphin3Vertices;
DWORD m_dwNumDolphinVertices;

D3DVERTEX* m_pFloorVertices;
DWORD m_dwNumFloorVertices;

public:
HRESULT OneTimeSceneInit();
HRESULT InitDeviceObjects();
HRESULT DeleteDeviceObjects();
HRESULT Render();
HRESULT FrameMove( FLOAT );
HRESULT FinalCleanup();

CMyD3DApplication();
};

//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Entry point to the program. Initializes everything, and goes into a
// message-processing loop. Idle time is used to render the scene.
//-----------------------------------------------------------------------------

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
{
CMyD3DApplication d3dApp;
if( FAILED( d3dApp.Create( hInst, strCmdLine ) ) )
return 0;
return d3dApp.Run();
}

//-----------------------------------------------------------------------------
// Name: CMyD3DApplication()
// Desc: Constructor
//-----------------------------------------------------------------------------

CMyD3DApplication::CMyD3DApplication()
:CD3DApplication()
{
// Override base class members
m_strWindowTitle = TEXT("Dolphin: Blending Meshes in Real Time");
m_bAppUseZBuffer = TRUE;
m_bAppUseStereo = TRUE;
m_bShowStats = TRUE;
m_fnConfirmDevice = NULL;

// Initialize member variables
m_pDolphinGroupObject = NULL;
m_pDolphinObject = NULL;
m_pFloorObject = NULL;
}

//-----------------------------------------------------------------------------
// Name: OneTimeSceneInit()
// Desc: Called during initial app startup, this function performs all the
// permanent initialization.
//-----------------------------------------------------------------------------

HRESULT CMyD3DApplication::OneTimeSceneInit()
{
HRESULT hr;
// создаем обьект класса для загрузки файла
m_pDolphinGroupObject = new CD3DFile();
m_pDolphinObject = new CD3DFile();
m_pFloorObject = new CD3DFile();

// загружаем файл
hr = m_pDolphinGroupObject->Load( "dolphin_group.x" );
// тут получаем вершины файла (из сетки "Dolph01")
hr |= m_pDolphinGroupObject->GetMeshVertices( "Dolph01",
&m_pDolphin1Vertices, &m_dwNumDolphinVertices );

получаем вершины файла из сетки-набора вершин "Dolph02" (в одном файле может быть несколько сеток, в этом случае мы знаем их имена и знаем что их 3

hr |= m_pDolphinGroupObject->GetMeshVertices( "Dolph02",
&m_pDolphin2Vertices, &m_dwNumDolphinVertices );

получаем вершины из сетки, вершины загоняем в переменную &m_pDolphin3Vertices а число, которое содержит количество вершин загоняем в переменную &m_dwNumDolphinVertices

hr |= m_pDolphinGroupObject->GetMeshVertices( "Dolph03",
&m_pDolphin3Vertices, &m_dwNumDolphinVertices );
// если возникла ошибка, тогда выводим сообщение
if( FAILED(hr) )
{
MessageBox( NULL, TEXT("Error loading DOLPHIN_GROUP.X file"),
TEXT("Dolphins"), MB_OK|MB_ICONERROR );
return E_FAIL;
}
// загружаем еще один файл
hr = m_pDolphinObject->Load( "dolphin.x" );

получаем вершины этого файла из сетки "Dolph02" точно так-же как в предыдущем случае

hr |= m_pDolphinObject->GetMeshVertices( "Dolph02", &m_pDolphinVertices,

&m_dwNumDolphinVertices );
// не произошла ли ошибка
if( FAILED(hr) )
{
MessageBox( NULL, TEXT("Error loading DOLPHIN.X file"),
TEXT("Dolphins"), MB_OK|MB_ICONERROR );
return E_FAIL;
}
// загружаем файл ландшафта
hr = m_pFloorObject->Load( "seafloor.x" );
// получаем его вершины и число, содержащее количество вершин
hr |= m_pFloorObject->GetMeshVertices( "SeaFloor", &m_pFloorVertices,
&m_dwNumFloorVertices );
if( FAILED(hr) )
{
MessageBox( NULL, TEXT("Error loading SEAFLOOR.X file"),
TEXT("Dolphins"), MB_OK|MB_ICONERROR );
return E_FAIL;
}

вызываем функции создания текстур из файлов (в каком Х файле есть имя соответствующей текстуры, на тот файл текстура и наложиться с помощью этих 2 функций

D3DTextr_CreateTextureFromFile( "seafloor.bmp" );
D3DTextr_CreateTextureFromFile( "dolphin.bmp" );

srand(5);
// Увеличиваем размер сетки ландшафта
// Scale the sea floor vertices, and add some bumpiness

for( DWORD i=0; i<m_dwNumFloorVertices; i++ )
{
m_pFloorVertices[i].y += (rand()/(FLOAT)RAND_MAX);
m_pFloorVertices[i].y += (rand()/(FLOAT)RAND_MAX);
m_pFloorVertices[i].y += (rand()/(FLOAT)RAND_MAX);
m_pFloorVertices[i].tu *= 10;
m_pFloorVertices[i].tv *= 10;
}

увеличиваем размер сетки дельфина (вообще для обьектов класса CD3DFile есть метод Scale() который увеличивает или уменьшает обьект по 3 осям

// Scale the dolphin vertices (the model file is too big)
for( i=0; i<m_dwNumDolphinVertices; i++ )
{
D3DVECTOR vScale( 0.01f, 0.01f, 0.01f );
*((D3DVECTOR*)(&m_pDolphin1Vertices[i])) *= vScale;
*((D3DVECTOR*)(&m_pDolphin2Vertices[i])) *= vScale;
*((D3DVECTOR*)(&m_pDolphin3Vertices[i])) *= vScale;
}
return S_OK;
}

//-----------------------------------------------------------------------------
// Name: BlendMeshes()
// Desc: Does a linear interpolation between all vertex positions and normals
// in two source meshes and outputs the result to the destination mesh.
// This function assumes that all strided vertices have the same stride,
// and that each mesh contains the same number of vertices
//-----------------------------------------------------------------------------

VOID BlendMeshes( D3DVERTEX* pDstMesh, D3DVERTEX* pSrcMesh1,
D3DVERTEX* pSrcMesh2, DWORD dwNumVertices, FLOAT fWeight )

Эта функция отвечает за то, чтобы дельфин изгибался и хвостом махал, а по кругу его гоняет другая функция. Принцип такой, что мы задаем параметры изгиба сетки вершин дельфина, короче прибавляем в цикле к каждой вершине определенное значение. Мы загружаем вначале ведь 2 файла, в одном дельфин выгнут спиной вверх, в другом файле дельфин выгнут спиной вниз, мы получаем сетку вершин обоих файлов, в этой функции мы "изгибаем" сетку вершин обоих файлов и в дальнейшем это дело прорисовывается. Это дело морфингом называется при первом прочтении не старайтесь понять эту функцию, сразу не поймете. Привожу описание принципа морфинга. Пускай у нас есть две 3-х мерные модели src1 и src2. Мы хотим получить третий объект mesh того же типа, но полученный морфингом из src1 и src2. Введем переменную weight типа float и лежащую в диапазоне от 0 до 1. Эта переменная отвечает степень морфинга, т.е. насколько наша модель morph будет похожа на src1 и на src2. Например, при значении weight=0.5 наш морфированый объект будет являться чем-то средним между src1 и src2, а при weight=0.8 mesh будет слабо отличаться от src2, при weight равном нулю или единице mesh полностью морфируется в src1 или src2 соответственно. Введем также переменную antiweight=1-weight. Пускай s1[n].x,s1[n].y,s1[n].z - координата n-ой вершины в объекте src1 , s2[n].x,s2[n].y,s2[n].z - координата n-ой вершины объекта src2 ,и, наконец m[n].x,m[n].y.m[n].z - координата n-ой вершины в объекте mesh. Тогда

m1[n].x=s1[n].x*weight+s2[n].x*antiweight
m1[n].y=s1[n].y*weight+s2[n].y*antiweight
m1[n].z=s1[n].z*weight+s2[n].z*antiweight

Это принцип морфинга.

{
FLOAT fInvWeight = 1.0f - fWeight;

// LERP positions and normals
for( DWORD i=0; i<dwNumVertices; i++ )
{
pDstMesh->x = fWeight*pSrcMesh1->x + fInvWeight*pSrcMesh2->x;
pDstMesh->y = fWeight*pSrcMesh1->y + fInvWeight*pSrcMesh2->y;
pDstMesh->z = fWeight*pSrcMesh1->z + fInvWeight*pSrcMesh2->z;
pDstMesh->nx = fWeight*pSrcMesh1->nx + fInvWeight*pSrcMesh2->nx;
pDstMesh->ny = fWeight*pSrcMesh1->ny + fInvWeight*pSrcMesh2->ny;
pDstMesh->nz = fWeight*pSrcMesh1->nz + fInvWeight*pSrcMesh2->nz;

pDstMesh++;
pSrcMesh1++;
pSrcMesh2++;
}
}

//-----------------------------------------------------------------------------
// Name: FrameMove()
// Desc: Called once per frame, the call is the entry point for animating
// the scene.
//-----------------------------------------------------------------------------

HRESULT CMyD3DApplication::FrameMove( FLOAT fTimeKey )

эта функция активна все время работы приложения, поэтому обьекты перемещаются постоянно

{
FLOAT fKickFreq = 2*fTimeKey;
// Animate the dolphin mesh
FLOAT fWeight = (FLOAT)sin(fKickFreq);

тут мы вызываем нашу функцию морфинга, передавая ей в качестве параметров вершины наших двух файлов

if( fWeight < 0.0f )
{
BlendMeshes( m_pDolphinVertices, m_pDolphin3Vertices,
m_pDolphin2Vertices, m_dwNumDolphinVertices, -fWeight );
}
else
{
BlendMeshes( m_pDolphinVertices, m_pDolphin1Vertices,
m_pDolphin2Vertices, m_dwNumDolphinVertices, fWeight );
}

Теперь один из самых важных моментов в Direct3D. Перемещение и повороты обьектов.
Move the dolphin in a circle. Тут мы хватаем из файла так называемый фрейм, что-то типа идентификатора сетки вершин короче откройте файл dolphin.x и в начале увидите фрейм "x3ds_Dolph02"

CD3DFileObject* pObject = m_pDolphinObject->FindObject( "x3ds_Dolph02" );
// если нашли фрейм в файле тогда
if( pObject )
{
// получаем матрицу файла
D3DMATRIX* pmatDolphin = pObject->GetMatrix();
FLOAT fPhase = fTimeKey/3;

// обьявляем переменные матриц вращения и перемещения
D3DMATRIX matTrans1, matRotate1, matRotate2;

говорим куда повернуться по оси Z, matRotate1- матрица, которую надо повернуть, а -(FLOAT)cos(fKickFreq)/6 угол, на который надо повернуть обьект

D3DUtil_SetRotateZMatrix( matRotate1, -(FLOAT)cos(fKickFreq)/6 );

так-же задаем параметры поворота по оси У (заметь, пока не поворачиваем, а только ЗАДАЕМ ПАРАМЕТРЫ ПОВОРОТА!!!!!)

D3DUtil_SetRotateYMatrix( matRotate2, fPhase );

а тут задаем параметры перемещения обьекта, где matTrans1 матрица, которую будем перемещать, а -5*(FLOAT)sin(fPhase), (FLOAT)sin(fKickFreq)/2, 10-10*(FLOAT)cos(fPhase) это координаты x, y, z на которые надо переместить обьект

D3DUtil_SetTranslateMatrix( matTrans1, -5*(FLOAT)sin(fPhase),
(FLOAT)sin(fKickFreq)/2, 10-10*(FLOAT)cos(fPhase) );
// обнуляем матрицу, которая учавствует в трансформации
D3DUtil_SetIdentityMatrix( *pmatDolphin );

и наконец само перемещение, в предыдущих фрагментах мы задали только параметры перемещения, а тут мы перемещаем обьект путем умножения матриц

D3DMath_MatrixMultiply( *pmatDolphin, matTrans1, *pmatDolphin );
D3DMath_MatrixMultiply( *pmatDolphin, matRotate2, *pmatDolphin );
D3DMath_MatrixMultiply( *pmatDolphin, matRotate1, *pmatDolphin );
}
return S_OK;
}

//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Called once per frame, the call is the entry point for 3d
// rendering. This function sets up render states, clears the
// viewport, and renders the scene.
//-----------------------------------------------------------------------------

HRESULT CMyD3DApplication::Render()
{
// функция перерисовки сцены
// Clear the viewport
// чистим вьюпорт с указанием цвета фона

m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
WATER_COLOR, 1.0f, 0L );

// Begin the scene
// начало командных скобок прорисовки сцены

if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
{

для каждого обьекта, загруженного из Х файла необходимо вызвать метод Render иначе обьект не нарисуется

m_pFloorObject->Render( m_pd3dDevice );
m_pDolphinObject->Render( m_pd3dDevice );

// End the scene.
//конец коммандных скобок прорисовки сцены

m_pd3dDevice->EndScene();
}
return S_OK;
}

//-----------------------------------------------------------------------------
// Name: InitDeviceObjects()
// Desc: Initialize scene objects.
//-----------------------------------------------------------------------------

HRESULT CMyD3DApplication::InitDeviceObjects()
{
// установки инициализации
// Set up the lighting states
// держит ли наша видеокарта определенные цветовые параметры

if( m_pDeviceInfo->ddDeviceDesc.dwVertexProcessingCaps &
D3DVTXPCAPS_DIRECTIONALLIGHTS )
// если держит, тогда устанавливаем сложный источник света
{
D3DLIGHT7 light;// переменная источника света
// инициализируем источник света с указанием его ориентации

D3DUtil_InitLight( light, D3DLIGHT_DIRECTIONAL, 0.0f, -1.0f, 0.0f );
m_pd3dDevice->SetLight( 0, &light );
m_pd3dDevice->LightEnable( 0, TRUE );
m_pd3dDevice->SetRenderState( D3DRENDERSTATE_LIGHTING, TRUE );
}
// если наша карта не держит определенные параметры, тогда устанавливаем простой источник света
m_pd3dDevice->SetRenderState( D3DRENDERSTATE_AMBIENT, 0x33333333 );

// этот фрагмент отвечает за установку точки взгляда
// Set the transform matrices

D3DVIEWPORT7 vp;
m_pd3dDevice->GetViewport(&vp);
// получаем отношение между шириной и высотой вьюпорта
FLOAT fAspect = ((FLOAT)vp.dwHeight) / vp.dwWidth;

D3DVECTOR vEyePt = D3DVECTOR( 0.0f, 0.0f, -10.0f );
D3DVECTOR vLookatPt = D3DVECTOR( 0.0f, 0.0f, 0.0f );
D3DVECTOR vUpVec = D3DVECTOR( 0.0f, 1.0f, 0.0f );
D3DMATRIX matWorld, matProj;

D3DUtil_SetIdentityMatrix( matWorld );
SetViewParams( &vEyePt, &vLookatPt, &vUpVec , 0.1f);
// устанавливаем матрицу проекции
D3DUtil_SetProjectionMatrix( matProj, g_PI/3, fAspect, 1.0f, 1000.0f );
// эта команда прорисовывает все наши заданные параметры
m_pd3dDevice->SetTransform( D3DTRANSFORMSTATE_WORLD, &matWorld );
m_pd3dDevice->SetTransform( D3DTRANSFORMSTATE_PROJECTION, &matProj );

// обновляем все текстуры
// Set up textures

D3DTextr_RestoreAllTextures( m_pd3dDevice );

// задаем параметры текстурирования
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTFN_LINEAR );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR );

// установки воспроизведения
// Set default render states

m_pd3dDevice->SetRenderState( D3DRENDERSTATE_DITHERENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRENDERSTATE_SPECULARENABLE, FALSE );
m_pd3dDevice->SetRenderState( D3DRENDERSTATE_ZENABLE, TRUE );

// тут мы включаем туман
// Turn on fog
// начало тумана

FLOAT fFogStart = 1.0f;
// конец тумана
FLOAT fFogEnd = 50.0f;
// параметры тумана
m_pd3dDevice->SetRenderState( D3DRENDERSTATE_FOGENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRENDERSTATE_FOGCOLOR, WATER_COLOR );
m_pd3dDevice->SetRenderState( D3DRENDERSTATE_FOGTABLEMODE, D3DFOG_NONE );
m_pd3dDevice->SetRenderState( D3DRENDERSTATE_FOGVERTEXMODE, D3DFOG_LINEAR );
m_pd3dDevice->SetRenderState( D3DRENDERSTATE_FOGSTART, *((DWORD *)(&fFogStart)) );
m_pd3dDevice->SetRenderState( D3DRENDERSTATE_FOGEND, *((DWORD *)(&fFogEnd)) );

return S_OK;
}

//-----------------------------------------------------------------------------
// Name: DeleteDeviceObjects()
// Desc: Called when the app is exitting, or the device is being changed,
// this function deletes any device dependant objects.
//-----------------------------------------------------------------------------

HRESULT CMyD3DApplication::DeleteDeviceObjects()
{
// вызывается перед завершением приложения
D3DTextr_InvalidateAllTextures();

return S_OK;
}

//-----------------------------------------------------------------------------
// Name: FinalCleanup()
// Desc: Called before the app exits, this function gives the app the chance
// to cleanup after itself.
//-----------------------------------------------------------------------------

HRESULT CMyD3DApplication::FinalCleanup()
{
// вызывается перед завершением приложения
// удаляем все наши файловые обьекты

SAFE_DELETE( m_pDolphinGroupObject );
SAFE_DELETE( m_pDolphinObject );
SAFE_DELETE( m_pFloorObject );
return S_OK;
}


Источник: http://gameprogrammer.webservis.ru

Posted: 09.02.2k1
Author: Boris Yatsenko
<ybv@chat.ru>

 

 


Проект
Создание Народного Учебника по OpenGL

Участвовать!
Поиск
Найдите статью или файл:


Рассылка
Новости сайта
La Vision в вашем почтовом ящике








Программирование на С++ Delphi и Паскаль
Центр демо-искусства в России