|
Načítání souborů MilkShape (*.ms3d)
|
|
|
Milk Shape 3D
je 3D editor animovaných modelů. Lze v něm načítat již vytvořené postavy z různých her
(Quake I, II, III, Half-Life, Unreal Tournament a další), vytvořit si vlastní animace a uložit
do MilkShape formátu (*.ms3d). Jak načítat tento formát do OpenGL? O tom bude tento tutorial.
Na specifikaci tohoto souboru se můžete mrknout zde.
Podle této specifikace jsem vytvořil struktury třídy K_CMilkshapeModel.
|
|
// Struktura hlavičky souboru
struct TMs3dHeader
{
char pc_id[10]; // Identifikace souboru, vždy "MS3D000000"
int i_version; // Verze souboru
};
// Informace o vrcholech
struct TMs3dVertex
{
byte by_flags; // Hodnota, zda je vrchol označen, nebo není (tuto hodnotu nebudem načítat)
float pf_vertex[3]; // Hodnota vrcholu x, y, z (x = f_vertex[0], y = f_vertex[1], z = f_vertex[2])
char c_bone_id; // Identifikační číslo kostry
byte by_ref_count; // Hodnota, která určuje, zda kostra existuje, či ne (-1 = neexistuje)(tuto hodnotu nebudem načítat)
};
// Informace o trojúhelnících
struct TMs3dTriangle
{
word w_flags; // Hodnota, zda je trojúhelník označen, nebo není (tuto hodnotu nebudem načítat)
word pw_vertex_indices[3]; // Identifikátor hodnot tří vrcholů trojúhelníka
float ppf_vertex_normals[3][3]; // Normálové vektory trojúhelníka
float pf_s[3], pf_t[3]; // Texturové koordinace trojúhelníka
byte by_smoothing_group; // Vyhlazení skupiny trojúhelníků (tuto hodnotu nebudem načítat, ale možná bude potřebná)
byte by_group_index; // Index skupiny (tuto hodnotu nebudem načítat, ale možná bude potřebná)
};
// Informace o materiálu
struct TMs3dMaterial
{
char pc_name[32]; // Jméno materiálu (tuto hodnotu nebudem načítat)
float pf_ambient[4]; // Ambientní hodnoty nasvíceného materiálu, viz. níže
float pf_diffuse[4]; // Difuzní hodnoty nasvíceného materiálu, viz. níže
float pf_specular[4]; // Specular hodnoty nasvíceného materiálu, viz. níže
float pf_emission[4]; // Emmision hodnoty nasvíceného materiálu, viz. níže
float f_shininess; // Emmision hodnoty nasvíceného materiálu, viz. níže
float f_transparency; // Transparentní hodnota zadává průhlednost (tuto hodnotu nebudem zatím načítat)
byte by_mode; // Mód (tuto hodnotu nebudem zatím načítat)
char pc_texture[128]; // Číslo textury
char pc_alphamap[128]; // Číslo alfa mapy (tuto hodnotu nebudem zatím načítat)
// Ambientní světlo se šíří všemy směry a svítí i když jsou ostatní světla vypnuta
// Difuzní světlo je světlo, které zdroj vyzařuje do okolí
// Specular světlo světlo, zrcadlově odražené
// Emmision světlo je světlo, které vyzařuje určitý objekt, nepůsobí však jako zdroj světla
// Shininess je, intenzita světelného odlesku, hodnoty jsou od 0.0f do 128.0f
};
// Informace o kloubech kostry
struct TMs3dJoint
{
byte by_flags; // Hodnota, zda je kloub označen, nebo není (tuto hodnotu nebudem načítat)
char pc_name[32]; // Jméno kloubu
char pc_parent_name[32]; // Jméno celé kostry
float pf_rotation[3]; // Rotace kloubu
float pf_translation[3]; // Posunutí kloubu
word w_num_key_frames_rot; // Počet snímků rotace
word w_num_key_frames_trans; // Počet snímků transformace
};
// Hodnoty rotace a translace animace
struct TMs3dKeyframe
{
float f_time; // Počet snímků
float pf_parameter[3]; // Hodnota vektoru rotace a transformace
};
|
Teď, když máme definované struktury souboru, zkusíme ho načíst.
|
|
// Načti data MilkShape modelu
bool K_CMilkshapeModel::LoadModelData( const char *pc_filename )
{
/////////////////////////
// Načti soubor *.ms3d //
/////////////////////////
ifstream input_file( pc_filename, ios::in | ios::binary | ios::nocreate ); // Zkontroluj soubor, jestli má odpovídající formát a ulož ho do ifstreamu (vstupní proud)
if ( input_file.fail()) // Pokud je formát špatný
{
cerr <
<
"Couldn't open the model file." <
<
endl; // Vyhoď chybovou hlášku
return false; // A opusť funkci
}
//////////////////////////////////////////////////
// Zjisti informace o umístění souboru na disku //
//////////////////////////////////////////////////
char c_drive[_MAX_DRIVE]; // Disk
char c_dir[_MAX_DIR]; // Cesta k souboru
char c_fname[_MAX_FNAME]; // Jméno souboru
char c_ext[_MAX_EXT]; // Přípona souboru
_splitpath( pc_filename, c_drive, c_dir, c_fname, c_ext ); // Načti informace
// Zatím potřebuji jen informaci o ceste k souboru,
// časem se možná hodí i další hodnoty
/////////////////////////////////
// Pokračuj v načítání souboru //
/////////////////////////////////
input_file.seekg( 0, ios::end ); // Nastav ukazatel na konec souboru
long l_file_size = input_file.tellg(); // Zjisti velikost celého souboru
input_file.seekg( 0, ios::beg ); // Nastav ukazatel na začátek souboru
byte *pby_buffer = new byte[l_file_size]; // Alokuj paměť pro celý soubor
input_file.read( pby_buffer, l_file_size ); // Načti do vytvořené paměti celý soubor
input_file.close(); // Vyčisti ifstream (vstupní proud)
const byte *pby_load_data = pby_buffer; // Soubor načtený v paměti přejmenuj na pLoadData
/////////////////////////////////
// Načti data hlavičky souboru //
/////////////////////////////////
TMs3dHeader *p_header = ( TMs3dHeader* )pby_load_data; // Načti ze souboru hodnoty typu MS3DHeader
pby_load_data += sizeof( TMs3dHeader ); // Posuň se v souboru na další hodnoty
if ( strncmp( p_header->pc_id, "MS3D000000", 10 ) != 0 ) // Porovnej data, jestli souhlasí
{
cerr <
<
"Not an MS3D file." <
<
endl; // Pokud nesouhlasí, tak vyhoď hlášku
return false; // A vrať funkci hodnotu false
}
if ( p_header->i_version <
3 ) // Jestliže je verze souboru menší než 3
{
cerr <
<
"I know nothing about MS3D v1.2" <
<
endl; // Vytoď hlášku, že soubor je starší verze
return false; // A vrať funkci hodnotu false
}
////////////////////////
// Načti data vrcholů //
////////////////////////
word w_num_vertices = *( word* )pby_load_data; // Načti ze souboru počet vrcholů
wNumVertices = w_num_vertices; // Předej hodnotu modelu
pVertices = new TModelVertex[w_num_vertices]; // Alokuj paměť pro počet vrcholů modelu
pby_load_data += sizeof( word ); // Posuň se v souboru na další hodnoty
for (int i = 0; i <
w_num_vertices; i++ ) // Cykluj podle počtu vrcholů
{
TMs3dVertex *p_vertex = ( TMs3dVertex* )pby_load_data; // Načti ze souboru hodnoty typu MS3DVertex
pVertices[i].c_bone_id = p_vertex->c_bone_id; // Načti hodnotu identifikačního čísla kostry
memcpy( pVertices[i].pf_vertex, p_vertex->pf_vertex, sizeof( float ) * 3 ); // Načti hodnotu vrcholu
pby_load_data += sizeof( TMs3dVertex ); // Posuň se v souboru na další hodnoty
}
/////////////////////////////
// Načti data trojúhelníků //
/////////////////////////////
word w_num_triangles = *( word* )pby_load_data; // Načti ze souboru počet trojúhelníků
wNumTriangles = w_num_triangles; // Předej hodnotu modelu
pTriangles = new TModelTriangle[w_num_triangles]; // Alokuj paměť pro počet trojúhelníků modelu
pby_load_data += sizeof( word ); // Posuň se v souboru na další hodnoty
for ( i = 0; i <
w_num_triangles; i++ ) // Cykluj podle počtu trojúhelníků
{
TMs3dTriangle *p_triangle = ( TMs3dTriangle* )pby_load_data; // Načti ze souboru hodnoty typu MS3DTriangle
float f_t[3] = { 1.0f - p_triangle->pf_t[0], 1.0f - p_triangle->pf_t[1], 1.0f - p_triangle->pf_t[2] }; // Otoč vertikální texturovou koordinaci
memcpy( pTriangles[i].ppf_vertex_normals, p_triangle->ppf_vertex_normals, sizeof( float ) * 3 * 3 ); // Načti hodnoty normálových vektorů každého vrcholu trojúhelníka
memcpy( pTriangles[i].pf_s, p_triangle->pf_s, sizeof( float ) * 3 ); // Načti hodnoty horizontální texturové koordinace
memcpy( pTriangles[i].pf_t, f_t, sizeof( float ) * 3 ); // Načti hodnoty vertikální texturové koordinace
memcpy( pTriangles[i].pw_vertex_indices, p_triangle->pw_vertex_indices, sizeof( word ) * 3 ); // Načti hodnoty identifikátorů vrcholů
pby_load_data += sizeof( TMs3dTriangle ); // Posuň se v souboru na další hodnoty
}
///////////////////////////////////////
// Načti hodnoty skupin trojúhelníků //
///////////////////////////////////////
word w_num_groups = *( word* )pby_load_data; // Načti ze souboru počet skupin
wNumGroups = w_num_groups; // Předej hodnotu modelu
pGroups = new TModelGroup[w_num_groups]; // Alokuj paměť pro počet skupin modelu
pby_load_data += sizeof( word ); // Posuň se v souboru na další hodnoty
for ( i = 0; i <
w_num_groups; i++ ) // Cykluj podle počtu skupin
{
pby_load_data += sizeof( byte ); // Přeskoč flags
pby_load_data += 32; // Přeskoč name
pGroups[i].w_num_triangles = *( word* )pby_load_data; // Načti hodnotu počtu trojúhelníků skupiny
pby_load_data += sizeof( word ); // Posuň se v souboru na další hodnoty
pGroups[i].pw_triangle_index = new word[pGroups[i].w_num_triangles]; // Alokuj paměť pro počet trojúhelníků skupiny modelu
for ( int j = 0; j <
pGroups[i].w_num_triangles; j++ ) // Cykluj podle počtu trojúhelníků skupiny
{
pGroups[i].pw_triangle_index[j] = *( word* )pby_load_data; // Načti skupinu skupiny trojúhelníků
pby_load_data += sizeof( word ); // Posuň se v souboru na další hodnoty
}
pGroups[i].i_material_index = *( char* )pby_load_data; // Načti ze souboru index materialu skupiny
pby_load_data += sizeof( char ); // Posuň se v souboru na další hodnoty
}
/////////////////////////////
// Načti hodnoty materiálu //
/////////////////////////////
word w_num_materials = *( word* )pby_load_data; // Načti hodnoty počtu materiálu
wNumMaterials = w_num_materials; // Předej hodnotu modelu
pMaterials = new TModelMaterial[w_num_materials]; // Alokuj paměť pro počet materiálů modelu
pby_load_data += sizeof( word ); // Posuň se v souboru na další hodnoty
for ( i = 0; i <
w_num_materials; i++ ) // Cykluj podle počtu materiálů
{
TMs3dMaterial *p_material = ( TMs3dMaterial* )pby_load_data; // Načti ze souboru hodnoty typu MS3DMaterial
memcpy( pMaterials[i].pf_ambient, p_material->pf_ambient, sizeof( float ) * 4 ); // Načti ambientní hodnoty materiálu
memcpy( pMaterials[i].pf_diffuse, p_material->pf_diffuse, sizeof( float ) * 4 ); // Načti difuzní hodnoty
memcpy( pMaterials[i].pf_specular, p_material->pf_specular, sizeof( float ) * 4 ); // Načti specular hodnoty
memcpy( pMaterials[i].pf_emissive, p_material->pf_emission, sizeof( float ) * 4 ); // Načti emission hodnoty
pMaterials[i].f_shininess = p_material->f_shininess; // Načti shininess hodnoty
pMaterials[i].pc_texture_filename = new char[strlen( p_material->pc_texture )+1]; // Alokuj paměť pro název textury
strcpy( pMaterials[i].pc_texture_filename, c_dir ); // Nakopíruj cestu k souboru
pMaterials[i].pc_texture_filename = strcat(pMaterials[i].pc_texture_filename, p_material->pc_texture); // K cestě k souboru připoj samotné jméno souboru
pby_load_data += sizeof( TMs3dMaterial ); // Posuň se v souboru na další hodnoty
}
ReloadTextures(); // Načti textury
///////////////////////////
// Načti animační kostru //
///////////////////////////
float f_anim_fps = *( float* )pby_load_data; // Načti rychlost animace kostry
pby_load_data += sizeof( float ); // Posuň se v souboru na další hodnoty
pby_load_data += sizeof( float ); // Přeskoč hodnotu aktuálního času
int i_total_frames = *( int* )pby_load_data; // Načti počet snímků
pby_load_data += sizeof( int ); // Posuň se v souboru na další hodnoty
dTotalTime = i_total_frames*1000.0 / f_anim_fps; // Vypočítej délku animace
wNumJoints = *( word* )pby_load_data; // Načti počet kloubů
pby_load_data += sizeof( word ); // Posuň se v souboru na další hodnoty
pJoints = new TModelJoint[wNumJoints]; // Alokuj paměť pro počet kloubů kostry modelu
struct TJointNameListRec // Vytvoř pomocnou strukturu pro načtení indexu a jména specifického kloubu
{
int i_joint_index; // Index kloubu
const char *pc_joint_name; // Jméno kloubu
};
const byte *pby_temp_load_data = pby_load_data; // Vytvoř další buffer pro načtení indexu a jména kloubu
TJointNameListRec *p_name_list = new TJointNameListRec[wNumJoints]; // Alokuj paměť pro počet indexů typu JoinNameRec
for ( i = 0; i <
wNumJoints; i++ ) // Cykluj podle počtu kloubů
{
TMs3dJoint *p_joint = ( TMs3dJoint* )pby_temp_load_data; // Načti ze souboru hodnoty typu MS3DJoint
pby_temp_load_data += sizeof( TMs3dJoint ); // Přeskoč hodnoty času sekundach
pby_temp_load_data += sizeof( TMs3dKeyframe ) * ( p_joint->w_num_key_frames_rot + p_joint->w_num_key_frames_trans ); // Přeskoč hodnoty rotace a posunutí, které budem načítat později
p_name_list[i].i_joint_index = i; // Načti index kloubu
p_name_list[i].pc_joint_name = p_joint->pc_name; // Načti jméno kloubu
}
for ( i = 0; i <
wNumJoints; i++ ) // Znova cykluj podle počtu kloubů
{
TMs3dJoint *p_joint = ( TMs3dJoint* )pby_load_data; // Znova načti ze souboru hodnoty typu MS3DJoint
pby_load_data += sizeof( TMs3dJoint ); // Posuň se v souboru na další hodnoty
int i_parent_index = -1; // Rodičovský index nastav na -1
if ( strlen( p_joint->pc_parent_name ) > 0 ) // Jestliže jméno rodičovského kloubu existuje
{
for (int j = 0; j <
wNumJoints; j++ ) // Cykluj opět podle počtu kloubů
{
if ( strcomp( p_name_list[j].pc_joint_name, p_joint->pc_parent_name ) == 0 ) // Pokud je jméno kloubu a jeho rodiče totožné
{
i_parent_index = p_name_list[j].i_joint_index; // Tak nastav stejný index rodiče a potomka
break; // A vyskoč z cyklu
}
}
if ( i_parent_index == -1 ) // Jestliže je rodičovský index -1, tak
{
MessageBox( NULL, "Unable to find parent bone in MS3D file", "Error", MB_OK | MB_ICONERROR ); // Vyhoď chybovou hlášku
return false; // A funkci předej false
}
}
memcpy( pJoints[i].pf_rotation, p_joint->pf_rotation, sizeof( float ) * 3 ); // Načti rotaci kloubu
memcpy( pJoints[i].pf_translation, p_joint->pf_translation, sizeof( float ) * 3 ); // Načti posun kloubu
pJoints[i].i_parent = i_parent_index; // Načti rodičovský index
pJoints[i].i_num_rotation_key_frames = p_joint->w_num_key_frames_rot; // Načti počet snímků rotace
pJoints[i].p_keyframe_rot = new TModelKeyframe[p_joint->w_num_key_frames_rot]; // Alokuj paměť podle počtu snímků rotace modelu
pJoints[i].i_num_translation_key_frames = p_joint->w_num_key_frames_trans; // Načti počet snímků translace
pJoints[i].p_keyframe_trans = new TModelKeyframe[p_joint->w_num_key_frames_trans]; // Alokuj paměť podle počtu snímků posunutí modelu
for ( int j = 0; j <
p_joint->w_num_key_frames_rot; j++ ) // Cykluj podle počtu snímků rotace
{
TMs3dKeyframe *p_key_frame = ( TMs3dKeyframe* )pby_load_data; // Načti ze souboru hodnoty typu TMs3dKeyframe
pby_load_data += sizeof( TMs3dKeyframe ); // Posuň se v souboru na další hodnoty
SetJointKeyframe( i, j, p_key_frame->f_time*1000.0f, p_key_frame->pf_parameter, true ); // Nastav hodnoty rotace kloubu
}
for ( j = 0; j <
p_joint->w_num_key_frames_trans; j++ ) // Cykluj podle počtu snímků translace
{
TMs3dKeyframe *p_key_frame = ( TMs3dKeyframe* )pby_load_data; // Načti ze souboru hodnoty typu TMs3dKeyframe
pby_load_data += sizeof( TMs3dKeyframe ); // Posuň se v souboru na další hodnoty
SetJointKeyframe( i, j, p_key_frame->f_time * 1000.0f, p_key_frame->pf_parameter, false ); // Nastav hodnoty posunutí kloubu
}
}
/////////////////////
// Ukonči načítání //
/////////////////////
delete[] p_name_list; // Vymaž buffer bufferu souboru (počel listů kloubu)
SetupJoints(); // Nastav matice rotace a translace kloubů
delete[] pby_buffer; // Vymaž buffer souboru
Restart(); // Restartuj animaci
return true; // Vrať funkci true
}
|
To je nářez co? Tuto funkci volám při načítání scény. Hodnoty se převádějí do hodnot modelu.
Struktury modelu musí být proto totožné se strukturou načteného souboru.
|
|
K_CModel *pmodel = NULL; // Ukazatel na MilkShape model nastav na NULL
//----------------------------------------------------------------------------------------------------//
void InitScene( void ) // Načti scénu
{
pmodel = new K_CMilkshapeModel(); // Alokuj paměť pro MilkShape model
if ( pmodel->LoadModelData( "models/bert/model.ms3d" ) == false ) // Zkus načíst MilkShape model, pokud se to nepodaří, tak
{
MessageBox( NULL, "Couldn't load the model: models/bert/model.ms3d", "Error", MB_OK | MB_ICONERROR ); // vyhoď hlášku // If Model Didn't Load Quit
}
...
...
...
}
|
Hodnoty se převádějí do hodnot modelu.
Struktury modelu musí být proto totožné se strukturou načteného souboru.
|
|
// Struktura informací o vrcholech
struct TModelVertex
{
char c_bone_id; // Identifikační číslo kostry
float pf_vertex[3]; // Hodnota vrcholu x, y, z (x = m_vertex[0], y = m_vertex[1], z = m_vertex[2])
};
// Informace o trojúhelnících
struct TModelTriangle
{
float ppf_vertex_normals[3][3]; // Normálové vektory trojúhelníka
float pf_s[3], pf_t[3]; // Texturové koordinace trojúhelníka
word pw_vertex_indices[3]; // Identifikátor hodnot tří vrcholů trojúhelníka
};
// Informace o skupinách trojúhelníků
struct TModelGroup
{
int i_material_index; // Index materiálu skupiny
word w_num_triangles; // Počet trojúhelníků ve skupině
word *pw_triangle_index; // Index trojúhelníků skupiny
};
// Informace o materiálu
struct TModelMaterial
{
float pf_ambient[4], pf_diffuse[4], pf_specular[4], pf_emissive[4]; // Hodnoty materiálu
float f_shininess; // Další hodnota materiálu
GLuint ui_texture; // Číslo textury
char *pc_texture_filename; // Jméno textury
};
// Hodnoty animace kloubu obsahující čas, rotaci a posunutí
struct TModelKeyframe
{
int i_joint_index; // Index kloubu
float f_time; // Čas v milisekundách
float pf_parameter[3]; // Základní hodnota podle kterého se počítá vektor rotace a posunutí
};
// Informace o kloubech kostry
struct TModelJoint
{
float pf_rotation[3]; // Lokální rotace
float pf_translation[3]; // Lokální posunutí
/*
* Absolutní, či relativní matice
* Když pohnu absolutní maticí, pohnu i relativní
* Když pohnu relativní maticí, tak absolutní se nemění
*/
K_CMatrix mat_absolute, mat_relative;
int i_num_rotation_key_frames, i_num_translation_key_frames; // Počet snímků rotace a posunutí
TModelKeyframe *p_keyframe_trans; // Ukazatel na animační hodnoty posunutí kloubu
TModelKeyframe *p_keyframe_rot; // Ukazatel na animační hodnoty rotace kloubu
int i_current_keyframe_trans, i_current_keyframe_rot; // Aktuální posunutí a rotace
K_CMatrix mat_final; // Konečná matice
int i_parent; // Rodičovský kloub
};
|
Teď si vytvoříme ukazatele na tyto struktury a další globální proměnné třídy K_CModel.
Třída K_CModel je veřejná proměnná třídy K_CMilkshapeModel, ve které jsme načítali soubor.
Hodnoty jsme ukládali do struktur třídy K_CModel.
|
|
// Informace o vrcholech
word wNumVertices;
TModelVertex *pVertices;
// Informace o trojuhelnících
word wNumTriangles;
TModelTriangle *pTriangles;
// Informace o skupinách trojúhelníků
word wNumGroups;
TModelGroup *pGroups;
// Informace o materiálech
word wNumMaterials;
TModelMaterial *pMaterials;
// Informace o kloubech kostry
word wNumJoints;
TModelJoint *pJoints;
// Časovač
K_CTimer *pTimer;
// Celkový čas animace
double dTotalTime;
// Animační cyklus
bool bLooping;
|
Některé fukce třídy K_CModel, slouží k načítání souboru. Jsou to:
SetJointKeyframe( int i_joint_index, int i_keyframe_index, float f_time, float *pf_parameter, bool b_rotation )
Nastaví hodnoty jednotlivých snímků pro jednotlivé klouby kostry
i_joint_index = Index snímků kloubu nastav
i_keyframe_index = podle maximálního počtu snímků
f_time = Čas je v milisekundách
pf_parameter = Parametr rotace a posunutí pro každý snímek
b_rotation = Identifikátor, zda se bude provádět rotace (posunutí)
SetupJoints()
Nastaví matice kloubů
ReloadTextures()
Načte textury
|
|
//----------------------------------------------------------------------------------------------------//
// Nastav hodnoty jednotlivých snímků pro jednotlivé klouby kostry
void K_CModel::SetJointKeyframe( int i_joint_index, int i_keyframe_index, float f_time, float *pf_parameter, bool b_rotation )
{
assert( wNumJoints > i_joint_index ); // Pokud je počet kloubů větší než index snímku kloubu tak pokračuj dál, jinak vyhoď chybovou hlášku
TModelKeyframe& keyframe = b_rotation ? pJoints[i_joint_index].p_keyframe_rot[i_keyframe_index] : // Zjisti, jestli jde o rotaci,
pJoints[i_joint_index].p_keyframe_trans[i_keyframe_index]; // nebo posunutí a nastav hodnoty příslušného snímku
keyframe.i_joint_index = i_joint_index; // Nastav index kloubu
keyframe.f_time = f_time; // Nastav čas (v milisekundách)
memcpy( keyframe.pf_parameter, pf_parameter, sizeof( float ) * 3 ); // Nastav základní hodnotu parametru, podle kterého se počítá vektor rotace s posunutí
}
//----------------------------------------------------------------------------------------------------//
// Nastav matice rotace a posunutí kloubů
void K_CModel::SetupJoints()
{
int i; // Proměnná cyklů
for ( i = 0; i <
wNumJoints; i++ ) // Cykluj podle počtu kloubů
{
TModelJoint& joint = pJoints[i]; // Vytvoř proměnnou joint typu ModelJoint
joint.mat_relative.SetRotationRadians( joint.pf_rotation ); // Nastav relativní rotační matici
joint.mat_relative.SetTranslation( joint.pf_translation ); // Nastav relativní matici posunutí
if ( joint.i_parent != -1 ) // Jestliže existuje rodičovský kloub, tak
{
joint.mat_absolute.Set( pJoints[joint.i_parent].mat_absolute.GetMatrix()); // Nastav absolutní matici rotace a posunutí
joint.mat_absolute.PostMultiply( joint.mat_relative ); // Vynásob absolutní matici maticí relativní (pohni relativnim kloubem)
}
else // Jinak
joint.mat_absolute.Set( joint.mat_relative.GetMatrix()); // Nastav jen absolutní matici
}
for ( i = 0; i <
wNumVertices; i++ ) // Cykluj podle počtu vrcholů
{
TModelVertex& vertex = pVertices[i]; // Vytvoř proměnnou vertex typu ModelVertex
if ( vertex.c_bone_id != -1 ) // Jestliže existuje identifikátor kloubu kostry
{
const K_CMatrix& mat = pJoints[vertex.c_bone_id].mat_absolute; // Vytvoř konstantu matrix typu Matrix (absolutní matice)
mat.InverseTranslateVect( vertex.pf_vertex ); // Otoč vektor posunutí, aby se vrchol neposouval opačným směrem než kloub
mat.InverseRotateVect( vertex.pf_vertex ); // Otoč vektor rotace, aby vrchol nerotoval opačným směrem než kloub
}
}
for ( i = 0; i <
wNumTriangles; i++ )
{ // Cykluj podle počtu trojúhelníků
TModelTriangle& triangle = pTriangles[i]; // Vytvoř proměnnou triangle typu ModelTriangle
for ( int j = 0; j <
3; j++ )
{ // Provejeď 3 cykly
const TModelVertex& vertex = pVertices[triangle.pw_vertex_indices[j]]; // Vytvoř konstantu vertex typu ModelVertex
if ( vertex.c_bone_id != -1 ) // Jestliže existuje identifikátor kloubu kostry, tak
{
const K_CMatrix& mat = pJoints[vertex.c_bone_id].mat_absolute; // Vytvoř konstantu matrix typu Matrix (absolutní matice)
mat.InverseRotateVect( triangle.ppf_vertex_normals[j] ); // Otoč vektor normálovych vektorů
}
}
}
}
//----------------------------------------------------------------------------------------------------//
// Načti textury modelu
void K_CModel::ReloadTextures()
{
K_CTexture tex;
for ( int i = 0; i <
wNumMaterials; i++ ) // Cykluj podle počtu materiálů
if ( strlen( pMaterials[i].pc_texture_filename ) > 0 ) // Jestliže existuje jméno textury, tak
{
pMaterials[i].ui_texture = tex.LoadGLTexture( pMaterials[i].pc_texture_filename ); // Načti texturu
}
else // Jinak
{
pMaterials[i].ui_texture = 0; // Nastav texturu na 0
}
}
//----------------------------------------------------------------------------------------------------//
|
Vykreslování objektu provádí funkce Draw() třídy K_CModel
|
|
// Vykresli model
void K_CModel::Draw()
{
Animation(); // Rozjeď animaci
GLboolean glb_tex_enabled = glIsEnabled( GL_TEXTURE_2D ); // Otestuj, jestli je zapnuto texturování
// Vykresluj podle počtu skupin trojúhelníků
for ( int i = 0; i <
wNumGroups; i++ )
{
int i_material_index = pGroups[i].i_material_index; // Vytvoř pomocnou proměnnou indexu materiálu
if ( i_material_index >= 0 ) // Jestliže existuje index tak
{
glMaterialfv( GL_FRONT, GL_AMBIENT, pMaterials[i_material_index].pf_ambient ); // Nastav ambient material
glMaterialfv( GL_FRONT, GL_DIFFUSE, pMaterials[i_material_index].pf_diffuse ); // Nastav diffuse material
glMaterialfv( GL_FRONT, GL_SPECULAR, pMaterials[i_material_index].pf_specular ); // Nastav specular material
glMaterialfv( GL_FRONT, GL_EMISSION, pMaterials[i_material_index].pf_emissive ); // Nastav emission material
glMaterialf( GL_FRONT, GL_SHININESS, pMaterials[i_material_index].f_shininess ); // Nastav shininess material
if ( pMaterials[i_material_index].ui_texture > 0 ) // Jestli materiál obsahuje texturu
{
glBindTexture( GL_TEXTURE_2D, pMaterials[i_material_index].ui_texture ); // Otexturuj skupinu trojúhelníků
glEnable( GL_TEXTURE_2D ); // Zapni texturování
}
else // Jinak
glDisable( GL_TEXTURE_2D ); // Vypni texturování
}
else // Jestlize neexistuje index materialu
{
glDisable( GL_TEXTURE_2D ); // Tak taky vypni texturování
}
glBegin( GL_TRIANGLES ); // Začni vykreslovat trojúhelníky
{
for ( int j = 0; j <
pGroups[i].w_num_triangles; j++ ) // Cykluj podle počtu trojúhelníku skupiny
{
int i_material_index = pGroups[i].pw_triangle_index[j]; // Vytvoř pomocnou proměnnou indexu trojúhelníků
const TModelTriangle* pModelTriangle = &pTriangles[i_material_index]; // Vytvoř ukazatel na strukturu ModelTriangle
for ( int k = 0; k <
3; k++ ) // Projeď 3 cykly (x, y, z hodnoty)
{
int i_index = pModelTriangle->pw_vertex_indices[k]; // Vytvoř pomocnou proměnnou index vrcholu trojuhelnika skupiny
if ( pVertices[i_index].c_bone_id == -1 ) // Jestliže neexistuje kostra, tak vykresli staticky model
{
glTexCoord2f( pModelTriangle->pf_s[k], pModelTriangle->pf_t[k] ); // Texturová koordinace
glNormal3fv( pModelTriangle->ppf_vertex_normals[k] ); // Normálový vektor
glVertex3fv( pVertices[i_index].pf_vertex ); // Vrchol trojuhelníka
}
else // Jestliže kostra existuje, tak pohybuj vrcholy, podle kloubů kostry
{
const K_CMatrix& mat_final = pJoints[pVertices[i_index].c_bone_id].mat_final; // Vytvoř konstantu konečné matice rotace, posunutí
glTexCoord2f( pModelTriangle->pf_s[k], pModelTriangle->pf_t[k] ); // Texturová koordinace
K_CVector v_new_normal( pModelTriangle->ppf_vertex_normals[k] ); // Vytvoř nový normálový vektor typu K_CVector
v_new_normal.Transform3( mat_final ); // Vypočítej normálový vektor podle konečné matice rotace, posunutí
v_new_normal.Normalize(); // Normalizuj vektor
glNormal3fv( v_new_normal.GetVector()); // Nastav normálový vektor
K_CVector v_new_vertex( pVertices[i_index].pf_vertex ); // Vytvoř nový vrchol typu K_CVector
v_new_vertex.Transform( mat_final ); // Přesuň vertex podle konečné matice rotaca, posunutí
glVertex3fv( v_new_vertex.GetVector()); // Nastav vrchol
}
}
}
}
glEnd(); // Konec vykreslování trojúhelníků
}
if ( glb_tex_enabled ) // Jestliže je hodnota texEnabled pravdivá
glEnable( GL_TEXTURE_2D ); // Zapni texturování
// Jinak
else
glDisable( GL_TEXTURE_2D ); // Vypni texturování
}
|
která volá funkci Animation(). Funkce Animation() animuje
všechny vrchloly modelu, podle kloubů kostry modelu.
|
|
// Animuj model
void K_CModel::Animation()
{
double d_time = pTimer->GetTime(); // Zjisti hodnotu času
if ( d_time > dTotalTime ) // Jestliže je čas větší než délka animace
{
if ( bLooping ) // Jestliže je zapnuto cyklování, tak
{
Restart(); // Restartuj animaci
d_time = 0; // Nastav čas na 0
}
else // Jinak
d_time = dTotalTime; // Nastav čas na délku animace
}
for ( int i = 0; i <
wNumJoints; i++ ) // Cykluj podle počtu kloubů kostry
{
float f_trans_vect[3]; // Pomocná proměnná vektoru posunutí
K_CMatrix mat_transform; // Proměnná typu Matrix, matice posunutí
int i_frame; // Proměnná snímku
TModelJoint *p_joint = &pJoints[i]; // Ukazatel na kloub kostry
if ( p_joint->i_num_rotation_key_frames == 0 && p_joint->i_num_translation_key_frames == 0 ) // Jestliže se rotace, nebo posunutí snímku rovná 0, tak
{
p_joint->mat_final.Set( p_joint->mat_absolute.GetMatrix()); // Resetuj konečnou matici
continue; // A pokračuj dále
}
// Nastavení posunutí
i_frame = p_joint->i_current_keyframe_trans; // Nastav aktuální posunutí snímku
while ( i_frame <
p_joint->i_num_translation_key_frames && p_joint->p_keyframe_trans[i_frame].f_time <
d_time ) // Cykluj pokud je současné posunutí snímku menší než počet posunutí snímku
{ // a zároveň čas posunutí snímku je menší než aktuální čas
i_frame++; // Přičti snímek
}
p_joint->i_current_keyframe_trans = i_frame; // Nastav aktuální posunutí snímku
if ( i_frame == 0 ) // Jestliže je snímek roven 0, tak
memcpy( f_trans_vect, p_joint->p_keyframe_trans[0].pf_parameter, sizeof ( float )*3 ); // Nastav vektor posunutí, podle základní hodnoty 0 parametru posunutí
else if ( i_frame == p_joint->i_num_translation_key_frames ) //, nebo jestiže je snímek roven počtu posunutí snímku, tak
memcpy( f_trans_vect, p_joint->p_keyframe_trans[i_frame-1].pf_parameter, sizeof ( float )*3 ); // Nastav vektor posunutí, podle základní hodnoty -1 parametru posunutí
else // Jinak
{
assert( i_frame > 0 && i_frame <
p_joint->i_num_translation_key_frames ); // Jestliže je snímek větší než 0 a zároveň je snímek menší, než hodnota rotace snímku, tak pokračuj dále,
// jinak vyhoď chybovou hlášku
const K_CModel::TModelKeyframe& keyframe_curr = p_joint->p_keyframe_trans[i_frame]; // Nastav hodnotu posunutí aktuálního snímku
const K_CModel::TModelKeyframe& keyframe_prev = p_joint->p_keyframe_trans[i_frame-1]; // Nastav hodnotu posunutí předešlého snímku
float f_time_delta = keyframe_curr.f_time - keyframe_prev.f_time; // Vypočti čas delta odečtením předešlého snímku od snímku aktuálního
float f_interp_value = ( float )(( d_time - keyframe_prev.f_time ) / f_time_delta ); // Vypočti interpolační hodnotu
// Vypočti vektor posunutí
f_trans_vect[0] = keyframe_prev.pf_parameter[0] + ( keyframe_curr.pf_parameter[0] - keyframe_prev.pf_parameter[0] ) * f_interp_value;
f_trans_vect[1] = keyframe_prev.pf_parameter[1] + ( keyframe_curr.pf_parameter[1] - keyframe_prev.pf_parameter[1] ) * f_interp_value;
f_trans_vect[2] = keyframe_prev.pf_parameter[2] + ( keyframe_curr.pf_parameter[2] - keyframe_prev.pf_parameter[2] ) * f_interp_value;
}
// Nastavení rotace
i_frame = p_joint->i_current_keyframe_rot; // Nastav aktuální rotaci snímku
while ( i_frame <
p_joint->i_num_rotation_key_frames && p_joint->p_keyframe_rot[i_frame].f_time <
d_time ) // Cykluj pokud je současná rotace snímku menší než počet rotace snímku
{ // a zároveň čas rotace snímku je menší než aktuální čas
i_frame++; // Přičti snímek
}
p_joint->i_current_keyframe_rot = i_frame; // Nastav aktuální rotaci snímku
if ( i_frame == 0 ) // Jestliže je snímek roven 0, tak
mat_transform.SetRotationRadians( p_joint->p_keyframe_rot[0].pf_parameter ); // Nastav vektor rotace, podle základní hodnoty 0 parametru posunutí
else if ( i_frame == p_joint->i_num_rotation_key_frames ) //, nebo jestiže je snímek roven počtu rotace snímku, tak
mat_transform.SetRotationRadians( p_joint->p_keyframe_rot[i_frame-1].pf_parameter ); // Nastav vektor rotace, podle základní hodnoty -1 parametru rotace
else // Jinak
{
assert( i_frame > 0 && i_frame <
p_joint->i_num_rotation_key_frames ); // Jestliže je snímek větší než 0 a zároveň je snímek menší, než hodnota rotace snímku, tak pokračuj dále,
// jinak vyhoď chybovou hlášku
const K_CModel::TModelKeyframe& keyframe_curr = p_joint->p_keyframe_rot[i_frame]; // Nastav hodnotu rotace aktuálního snímku
const K_CModel::TModelKeyframe& keyframe_prev = p_joint->p_keyframe_rot[i_frame-1]; // Nastav hodnotu rotace předešlého snímku
float f_time_delta = keyframe_curr.f_time - keyframe_prev.f_time; // Vypočti čas delta odečtením předešlého snímku od snímku aktuálního
float f_interp_value = ( float )(( d_time - keyframe_prev.f_time ) / f_time_delta ); // Vypočti interpolační hodnotu
assert( f_interp_value >= 0 && f_interp_value <
= 1 ); // Jestliže je interpolační hodnota větší než 0 a zároveň je menší nebo rovno 1, tak pokračuj, jinak vyhoď chybovou hlášku
#if 1 // Jestliže je 1, funguje Quaternion (rychlejší výpočet)
K_CQuaternion qua_prev( keyframe_prev.pf_parameter ); // Vypočti předchozí quaternion podle předešlé hodnoty parametru snímku
K_CQuaternion qua_curr( keyframe_curr.pf_parameter ); // Vypočti aktuální quaternion podle aktuální hodnoty parametru snímku
K_CQuaternion qua_final( qua_prev, qua_curr, f_interp_value ); // Vypočti konečný quaternion pomocí interpolace mezi předchozím a aktuálním quaternionem
mat_transform.SetRotationQuaternion( qua_final ); // Převeď quaternion na rotační matici (rychlejší výpočet pomocí quaternionu)
#else // Jestliže je 0 funguje obyčejný vektor
float f_rot_vect[3]; // Proměnná rotace vektoru
// Vypočti rotační matici
f_rot_vect[0] = keyframe_prev.f_parameter[0] + ( keyframe_curr.f_parameter[0] - keyframe_prev.f_parameter[0] ) * f_interp_value;
f_rot_vect[1] = keyframe_prev.f_parameter[1] + ( keyframe_curr.f_parameter[1] - keyframe_prev.f_parameter[1] ) * f_interp_value;
f_rot_vect[2] = keyframe_prev.f_parameter[2] + ( keyframe_curr.f_parameter[2] - keyframe_prev.f_parameter[2] ) * f_interp_value;
m_transform.SetRotationRadians( f_rot_vect ); // Nastav rotační matici (pomalejší výpočet)
#endif // Konec definic výpočtů rotace
}
mat_transform.SetTranslation( f_trans_vect ); // Mastav matici posunutí
K_CMatrix mat_relative_final( p_joint->mat_relative ); // Vytvoř proměnnou relativeFinal typu Matrix. Jde o relativní matici
mat_relative_final.PostMultiply( mat_transform ); // Vynásob konečnou relativní matici maticí posunutí
if ( p_joint->i_parent == -1 ) // Jestliže kloub neni rodičovský (absolutní matice), tak
p_joint->mat_final.Set( mat_relative_final.GetMatrix()); // Nastav konečnou relativní matici
else // Jinak
{
p_joint->mat_final.Set( pJoints[p_joint->i_parent].mat_final.GetMatrix() ); // Nastav absolutní matici
p_joint->mat_final.PostMultiply( mat_relative_final ); // Vynásob konečnou matici maticí relativní
}
}
}
|
Funkce Draw() se volá v nekonečné smyčce
|
|
|
Rotaci kloubů modelu můžeme vytvořit dvěma způsoby. Pomocí rotačních matic X, Y, Z osy, nebo pomocí
tzv. Quaternionů. Výpočet rotace pomocí Quaternionů je méně náročné na výpočet (rychlejší překreslování), protože pracuje
s tranformační maticí, která je jednodužší, než matice rotační. Princip je takový, že se transformační matice
převede na quaternion, pak se provede sférická interpolace quaternionu. Nakonec se výsledný quaternion
převede zpět na tranformační matici. Více o quaternionech si můžete přečíst zde
Pro výpočet rotace kloubů modelu pomocí quaternionů jsem napsal tyto následující funkce.
|
|
//----------------------------------------------------------------------------------------------------//
/*
* Převeď úhel zadaný ve stupních na quaternion podle tohoto vzorce
*
* sin_a = sin( angle / 2 );
* cos_a = cos( angle / 2 );
*
* X = axis->x * sin_a;
* Y = axis->y * sin_a;
* Z = axis->z * sin_a;
* W = cos_a;
*
* Tento výpočet proveď pro všechny osy X, Y, Z
* p_axisAngle[0] se rovná ose X
* p_axisAngle[1] se rovná ose Y
* p_axisAngle[2] se rovná ose Z
*/
void K_CQuaternion::FromAxisAngle( const float *pf_axis_angle )
{
float f_angle;
double d_sin_x, d_sin_y, d_sin_z, d_cos_x, d_cos_y, d_cos_z;
f_angle = pf_axis_angle[0] * 0.5f;
d_sin_x = sin( f_angle );
d_cos_x = cos( f_angle );
f_angle = pf_axis_angle[1] * 0.5f;
d_sin_y = sin( f_angle );
d_cos_y = cos( f_angle );
f_angle = pf_axis_angle[2] * 0.5f;
d_sin_z = sin( f_angle );
d_cos_z = cos( f_angle );
double d_cos_x_cos_y = d_cos_x * d_cos_y;
double d_sin_x_sin_y = d_sin_x * d_sin_y;
pfQuat[0] = ( float )( d_sin_x * d_cos_y * d_cos_z - d_cos_x * d_sin_y * d_sin_z );
pfQuat[1] = ( float )( d_cos_x * d_sin_y * d_cos_z + d_sin_x * d_cos_y * d_sin_z );
pfQuat[2] = ( float )( d_cos_x_cos_y * d_sin_z - d_sin_x_sin_y * d_cos_z );
pfQuat[3] = ( float )( d_cos_x_cos_y * d_cos_z + d_sin_x_sin_y * d_sin_z );
}
//----------------------------------------------------------------------------------------------------//
// Proveď lineární interpolaci mezi quaterniony
void K_CQuaternion::Slerp( const K_CQuaternion& qua_1, K_CQuaternion& qua_2, float f_interp )
{
// Vypočítej, jestli není druhý quaternion opačný
float f_a = 0, f_b = 0;
for (int i = 0; i <
4; i++ ) // Cykluj podle rozměru quaternionu
{
f_a += ( qua_1[i] - qua_2[i] ) * ( qua_1[i] - qua_2[i] );
f_b += ( qua_1[i] + qua_2[i] ) * ( qua_1[i] + qua_2[i] );
}
if ( f_a > f_b ) // Pokud je druhý quaternion opačný
qua_2.Inverse(); // Tak ho otoč správným směrem
// Vypočítej interpolace
float f_cosom = qua_1[0] * qua_2[0] + qua_1[1] * qua_2[1] + qua_1[2] * qua_2[2] + qua_1[3] * qua_2[3]; // Sečti quaterniony
double d_sclq1, d_sclq2; // Pomocné interpolační hodnoty
if (( 1.0 + f_cosom ) > 0.00000001 ) // Pokud je 1 + součet quaternionů větší než 0.00000001, tak
{
if (( 1.0 - f_cosom ) > 0.00000001 ) // Jestiže je 1 - součet quaternionů větší než 0.00000001, tak
{
/*
* Protože je hodota součtu quaternionů moc velká, tak normalizuj
* a vytvoř odpovídající rozmezí pro interpolační křivku
*/
double d_omega = acos( f_cosom );
double d_sinom = sin( d_omega );
d_sclq1 = sin(( 1.0 - f_interp ) * d_omega ) / d_sinom;
d_sclq2 = sin( f_interp * d_omega ) / d_sinom;
}
else // Jinak
{
// Vytvoř odpovídající rozmezí pro interpolační křivku
d_sclq1 = 1.0 - f_interp;
d_sclq2 = f_interp;
}
for ( i = 0; i <
4; i++ ) // Cykluj podle rozměru quaternionu
pfQuat[i] = ( float )( d_sclq1 * qua_1[i] + d_sclq2 * qua_2[i] ); // Výsledné quaterniony vynásob původními a ulož jako nový quaternion
}
else // Jinak
{
// Proveď konjugaci quaternionu
pfQuat[0] = -qua_1[1];
pfQuat[1] = qua_1[0];
pfQuat[2] = -qua_1[3];
pfQuat[3] = qua_1[2];
// Vytvoř odpovídající rozmezí pro interpolační křivku
d_sclq1 = sin(( 1.0 - f_interp ) * 0.5 * PI );
d_sclq2 = sin( f_interp * 0.5 * PI );
for (int i = 0; i <
3; i++ ) // Cykluj do 3, aby se vytvořil 3d quaternion
pfQuat[i] = ( float )( d_sclq1 * qua_1[i] + d_sclq2 * pfQuat[i] ); // Výsledné quaterniony vynásob původními a ulož jako nový quaternion
}
}
//----------------------------------------------------------------------------------------------------//
// Nastav opačný quaternion
inline void K_CQuaternion::Inverse()
{
pfQuat[0] = -pfQuat[0];
pfQuat[1] = -pfQuat[1];
pfQuat[2] = -pfQuat[2];
pfQuat[3] = -pfQuat[3];
}
//----------------------------------------------------------------------------------------------------//
|
TGA soubory jsou buď nekomprimované, nebo komprimované. Následující dvě funkce třídy K_CTexture tyto
dva druhy TGA souborů načítají.
|
|
//----------------------------------------------------------------------------------------------------//
// Načti nekomprimovaný soubor *.tga
bool K_CTexture::LoadUncompressedTGA( TTexture *ptexture, FILE *pfile_tga )
{
if( fread( tga.puc_header, sizeof( tga.puc_header ), 1, pfile_tga ) == 0) // Zkus načíst TGA hlavičku, jinak
{
MessageBox( NULL, "Could not read info header", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
if( pfile_tga != NULL ) // Jestliže je soubor otevřen
{
fclose( pfile_tga ); // Tak ho zavři
}
return false; // Ukonči funkci
}
ptexture->i_width = tga.puc_header[1] * 256 + tga.puc_header[0]; // Vypočti šířku textury
ptexture->i_height = tga.puc_header[3] * 256 + tga.puc_header[2]; // Vypočti výšku textury
ptexture->i_bpp = tga.puc_header[4]; // Získej bitovou hloubku barev textury
tga.i_width = ptexture->i_width; // Kopíruj šířku do lokální struktury
tga.i_height = ptexture->i_height; // Kopíruj výšku do lokální struktury
tga.i_bpp = ptexture->i_bpp; // Kopíruj bitovou hloubku barev do lokální struktury
if(( ptexture->i_width <
= 0 ) || ( ptexture->i_height <
= 0 ) || (( ptexture->i_bpp != 24 ) && ( ptexture->i_bpp !=32 ))) // Jestliže existuje jedna z techto podmínek, tak
{
MessageBox( NULL, "Invalid texture information", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
if( pfile_tga != NULL ) // Jestliže je soubor otevřen
{
fclose( pfile_tga ); // Tak ho zavři
}
return false; // Ukonči funkci
}
if( ptexture->i_bpp == 24 ) // Jestliže je 24 bitová hloubka barev
{
ptexture->i_type = GL_RGB; // Nastav typ textury na GL_RGB
}
else // Jinak, pokud je 32 bitová
{
ptexture->i_type = GL_RGBA; // Nastav typ textury na GL_RGBA
}
tga.i_bytes_perpixel = ( tga.i_bpp / 8 ); // Vypočítej počet bytu na pixel
tga.i_image_size = ( tga.i_bytes_perpixel * tga.i_width * tga.i_height ); // Vypočítej velikost souboru
ptexture->puc_image_data = ( GLubyte* ) malloc( tga.i_image_size ); // Alokuj pamět pro soubor
if( ptexture->puc_image_data == NULL ) // Jestliže se nealokovala žádná paměť
{
MessageBox( NULL, "Could not allocate memory for image", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
fclose( pfile_tga ); // Zavři soubor
return false; // Ukonči funkci
}
if( fread( ptexture->puc_image_data, 1, tga.i_image_size, pfile_tga) != tga.i_image_size ) // Jestliže nejdou data přečíst
{
MessageBox( NULL, "Could not allocate memory for image", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
if( ptexture->puc_image_data != NULL ) // Jestliže alokovaná paměť pro soubor obsahuje nejaká data
{
free( ptexture->puc_image_data ); // Tak je vymaž
}
fclose( pfile_tga ); // Zavři soubor
return false; // Ukonči funkci
}
// Prohoď byty barev z BGR to RGB
for( GLuint cswap = 0; cswap <
( int )tga.i_image_size; cswap += tga.i_bytes_perpixel )
{
tga.uc_temp = ptexture->puc_image_data[cswap];
ptexture->puc_image_data[cswap] = ptexture->puc_image_data[cswap + 2];
ptexture->puc_image_data[cswap + 2] = tga.uc_temp;
}
fclose( pfile_tga ); // Zavři soubor
return true; // Ukonči funkci
}
//----------------------------------------------------------------------------------------------------//
// Načti komprimovaný soubor *.tga
bool K_CTexture::LoadCompressedTGA( TTexture *ptexture, FILE *pfile_tga )
{
if( fread( tga.puc_header, sizeof( tga.puc_header ), 1, pfile_tga ) == 0) // Zkus načíst TGA hlavičku, jinak
{
MessageBox( NULL, "Could not read info header", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
if( pfile_tga != NULL ) // Jestliže je soubor otevřen
{
fclose( pfile_tga ); // Tak ho zavři
}
return false; // Ukonči funkci
}
ptexture->i_width = tga.puc_header[1] * 256 + tga.puc_header[0]; // Vypočti šířku textury
ptexture->i_height = tga.puc_header[3] * 256 + tga.puc_header[2]; // Vypočti výšku textury
ptexture->i_bpp = tga.puc_header[4]; // Získej bitovou hloubku barev textury
tga.i_width = ptexture->i_width; // Kopíruj šířku do lokální struktury
tga.i_height = ptexture->i_height; // Kopíruj výšku do lokální struktury
tga.i_bpp = ptexture->i_bpp; // Kopíruj bitovou hloubku barev do lokální struktury
if(( ptexture->i_width <
= 0 ) || ( ptexture->i_height <
= 0 ) || (( ptexture->i_bpp != 24 ) && ( ptexture->i_bpp !=32 ))) // Jestliže existuje jedna z techto podmínek, tak
{
MessageBox( NULL, "Invalid texture information", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
if( pfile_tga != NULL ) // Jestliže je soubor otevřen
{
fclose( pfile_tga ); // Tak ho zavři
}
return false; // Ukonči funkci
}
tga.i_bytes_perpixel = ( tga.i_bpp / 8 ); // Vypočítej počet bytu na pixel
tga.i_image_size = ( tga.i_bytes_perpixel * tga.i_width * tga.i_height ); // Vypočítej velikost souboru
ptexture->puc_image_data = ( GLubyte* ) malloc( tga.i_image_size ); // Alokuj pamět pro soubor
if( ptexture->puc_image_data == NULL ) // Jestliže se nealokovala žádná paměť
{
MessageBox( NULL, "Could not allocate memory for image", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
fclose( pfile_tga ); // Zavři soubor
return false; // Ukonči funkci
}
GLuint i_pixelcount = tga.i_height * tga.i_width; // Počet pixelů v obrázku
GLuint i_currentpixel = 0; // Základní pixel pro čtení nastav na 0
GLuint i_currentbyte = 0; // Základní byte nastav na 0
GLubyte *puc_colorbuffer = ( GLubyte* )malloc( tga.i_bytes_perpixel ); // Alokuj paměť pro 1 pixel
do // Cykluj dokud neprojedeš všechny pixely
{
GLubyte chunkheader = 0; // Hlavičku nastav na 0
if( fread( &chunkheader, sizeof( GLubyte ), 1, pfile_tga ) == 0 ) // Zkus načíst 1 bytovou hlavičku, jinak
{
MessageBox( NULL, "Could not read RLE header", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
if( pfile_tga != NULL ) // Jestliže je soubor otevřený
{
fclose( pfile_tga ); // Tak ho zavři
}
if( ptexture->puc_image_data != NULL ) // Jestliže alokovaná paměť pro soubor obsahuje nejaká data
{
free( ptexture->puc_image_data ); // Tak je vymaž
}
return false; // Ukonči funkci
}
// Jestliže velikost hlavičky je menší než 128, tak to znamená,
// že jde o RAW kompresi barevné palety
// Následující barva je v hodnotě hlavičky o 1 vyšší
if( chunkheader <
128 )
{
chunkheader++; // Přidej 1 pro následující hodnoty barvy
// Čti RAW hodnoty barev
for( short counter = 0; counter <
chunkheader; counter++ )
{
if( fread( puc_colorbuffer, 1, tga.i_bytes_perpixel, pfile_tga ) != tga.i_bytes_perpixel ) // Zkus číst jeden pixel, jinak
{
MessageBox( NULL, "Could not read image data", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
if( pfile_tga != NULL ) // Jestliže je soubor otevřen
{
fclose( pfile_tga ); // Tak ho zavři
}
if( puc_colorbuffer != NULL ) // Jestliže alokovaná paměť pro data v paměti barev obsahuje nějaká data
{
free( puc_colorbuffer ); // Tak je vymaž
}
if( ptexture->puc_image_data != NULL ) // Jestliže alokovaná paměť pro soubor obsahuje nějaká data
{
free( ptexture->puc_image_data ); // Tak je vymaž
}
return false; // Ukonči funkci
}
// Zapiš data do paměti a prohoď byty barev z BGR to RGB
ptexture->puc_image_data[i_currentbyte] = puc_colorbuffer[2];
ptexture->puc_image_data[i_currentbyte + 1] = puc_colorbuffer[1];
ptexture->puc_image_data[i_currentbyte + 2] = puc_colorbuffer[0];
if( tga.i_bytes_perpixel == 4 ) // Jestliže jsou 4 byty na pixel, tak jde o 32 bitovou hloubku barev
{
ptexture->puc_image_data[i_currentbyte + 3] = puc_colorbuffer[3]; // Proto kopíruj čtvrtý byt
}
i_currentbyte += tga.i_bytes_perpixel; // Pričti k aktuálnímu bytu počet bytu na pixel
i_currentpixel++; // Přičti aktuálnímu pixelu 1
if( i_currentpixel > i_pixelcount ) // Jestliže je počet aktuálních pixelů větší než celkový počet pixelů obrázku, tak
{
MessageBox( NULL, "Too many pixels read", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
if( pfile_tga != NULL ) // Jestliže je soubor otevřen
{
fclose( pfile_tga ); // Tak ho zavři
}
if( puc_colorbuffer != NULL ) // Jestliže alokovaná paměť pro data v paměti barev obsahuje nějaká data
{
free( puc_colorbuffer ); // Tak je vymaž
}
if( ptexture->puc_image_data != NULL ) // Jestliže alokovaná paměť pro soubor obsahuje nějaká data
{
free( ptexture->puc_image_data ); // Tak je vymaž
}
return false; // Ukonči funkci
}
}
}
else
{
// Jestliže velikost hlavičky je větší než 128, tak to znamená,
// že jde o RLE kompresi barevné palety
// Následující barva je v hodnotě hlavičky mínus 127
chunkheader -= 127; // Odečti od hodnoty hlavičky 127
if( fread( puc_colorbuffer, 1, tga.i_bytes_perpixel, pfile_tga ) != tga.i_bytes_perpixel ) // Zkus načíst následující hodnoty, jinak
{
MessageBox( NULL, "Could not read from file", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
if( pfile_tga != NULL ) // Jestliže je soubor otevřen
{
fclose( pfile_tga ); // Tak ho zavři
}
if( puc_colorbuffer != NULL ) // Jestliže alokovaná paměť pro data v paměti barev obsahuje nějaká data
{
free( puc_colorbuffer ); // Tak je vymaž
}
if( ptexture->puc_image_data != NULL ) // Jestliže alokovaná paměť pro soubor obsahuje nějaká data
{
free( ptexture->puc_image_data ); // Tak je vymaž
}
return false; // Ukonči funkci
}
// Čti RLE hodnoty barev podle hodnoty hlavičky
for( short counter = 0; counter <
chunkheader; counter++ )
{
// Zapiš data do paměti a prohoď byty barev z BGR to RGB
ptexture->puc_image_data[i_currentbyte] = puc_colorbuffer[2];
ptexture->puc_image_data[i_currentbyte + 1] = puc_colorbuffer[1];
ptexture->puc_image_data[i_currentbyte + 2] = puc_colorbuffer[0];
if( tga.i_bytes_perpixel == 4 ) // Jestliže jsou 4 byty na pixel, tak jde o 32 bitovou hloubku barev
{
ptexture->puc_image_data[i_currentbyte + 3] = puc_colorbuffer[3]; // Proto kopíruj čtvrtý byt
}
i_currentbyte += tga.i_bytes_perpixel; // Přičti k aktuálnímu bytu počet bytu na pixel
i_currentpixel++; // Přičti aktuálnímu pixelu 1
if( i_currentpixel > i_pixelcount ) // Jestliže je počet aktuálních pixelů větší než celkový počet pixelů obrázku, tak
{
MessageBox( NULL, "Too many pixels read", "Error", MB_OK | MB_ICONERROR ); // Zobraz chybovou zprávu
if( pfile_tga != NULL ) // Jestliže je soubor otevřen
{
fclose( pfile_tga ); // Tak ho zavři
}
if( puc_colorbuffer != NULL ) // Jestliže alokovaná paměť pro data v paměti barev obsahuje nějaká data
{
free( puc_colorbuffer ); // Tak je vymaž
}
if( ptexture->puc_image_data != NULL ) // Jestliže alokovaná paměť pro soubor obsahuje nějaká data
{
free( ptexture->puc_image_data ); // Tak je vymaž
}
return false; // Ukonči funkci
}
}
}
}
while( i_currentpixel <
i_pixelcount ); // Cykluj dokud neprojedeš všechny pixely
fclose( pfile_tga ); // Zavři soubor
return true; // Vrať funkci, že vše proběhlo OK
}
//----------------------------------------------------------------------------------------------------//
|
Funkce LoadGLTexture( char *pc_filename ) vytváří z načtených dat texturu.
|
|
// Vytvoř textury načtením z obrazových souborů (*.tga, *.bmp)
GLuint K_CTexture::LoadGLTexture( char *pc_filename )
{
///////////////////////////////
// Načítání ze souboru *.tga //
///////////////////////////////
TTexture texture; // Lokální proměnná struktury TTexture
char c_drive[_MAX_DRIVE]; // Informace na kterém disku je uložen načítaný soubor
char c_dir[_MAX_DIR]; // Informace ve kterém adresáři je uložen načítaný soubor
char c_fname[_MAX_FNAME]; // Informace o jménu načítaného souboru
char c_ext[_MAX_EXT]; // Informace o příponě načítaného souboru
_splitpath( pc_filename, c_drive, c_dir, c_fname, c_ext ); // Získej všechny tyto informace
if ( !strcomp( c_ext, ".tga" )) // Převeď řetězce na malá písmena a porovnej jestli má načítaný soubor příponu *.tga
{
if ( !LoadTGA( &texture, const_cast<
char*>( pc_filename ))) // Zkus načíst soubor *.tga
{
return 0; // Jinak vrať funkci 0
}
glGenTextures( 1, &texture.i_tex_id ); // Vytvoř texturu
// Začátek generování textury
glBindTexture( GL_TEXTURE_2D, texture.i_tex_id ); // Nastav texturový List s následujícími parametry
// Parametry 2D textury
glTexImage2D( GL_TEXTURE_2D, 0, 3, texture.i_width, texture.i_height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture.puc_image_data );
// Lineárně rozlož (roztáhni) texturu do celého objektu, pokud je textura menší nez plocha objektu
glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR );
// Lineárně rozlož (zmenši) texturu, pokud je textura větší než plocha objektu
glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR );
// Konec generování textury
if ( texture.puc_image_data ) // Jestliže existuje obraz textury
{
free( texture.puc_image_data ); // Tak obraz textury smaž
}
return texture.i_tex_id; // Vrať funkci hodnotu identifikátoru texturu
}
|
U nové kamery jsem místo funkce gluLookAt() použil pro transformaci a rotaci kamery
transformační a rotační matice glTranslatef() a glRotatef().
Názvy funkcí třídy K_CCamera zůstaly totožné, akorát algoritmy jsou jiné a myslím, že jednodužší.
|
|
//----------------------------------------------------------------------------------------------------//
#ifndef PI
# define PI 3.1415926535897932384626433832795 // Definuj hodnotu PI
#endif
#ifndef DEG
# define DEG PI/180 // Převeď úhel RAD na DEG
#endif
//----------------------------------------------------------------------------------------------------//
// Konstruktor třídy K_CCamera
K_CCamera::K_CCamera()
{
fSpeed = 1.1f; // Rychlost pohybu kamery
pfAngle[0] = 0; // X rotace kamery
pfAngle[1] = 0; // Y rotace kamery
pfAngle[2] = 0; // z rotace kamery
pfPosition[0] = 0; // X pozice kamery
pfPosition[1] = 0; // Y pozice kamery
pfPosition[2] = -200; // Z pozice kamery
}
//----------------------------------------------------------------------------------------------------//
// Destruktor třídy K_CCamera
K_CCamera::~K_CCamera()
{
}
//----------------------------------------------------------------------------------------------------//
// Pohni kamerou vpřed, nebo vzad podle hodnoty speed (+ nebo -)
void K_CCamera::MoveCamera( float f_speed )
{
pfPosition[0] -= ( float ) ( f_speed * sin( -pfAngle[1] * DEG )); // Vypočítej novou pozici X
pfPosition[2] -= ( float ) ( f_speed * cos( pfAngle[1] * DEG )); // Vypočítej novou pozici Z
}
//----------------------------------------------------------------------------------------------------//
// Rotuj kamerou pomocí myši (First person view)
void K_CCamera::MouseRotate()
{
POINT tagp_mouse_pos; // Pozice kurzoru myši
int i_middle[2]; // X, Y stred obrazovky
i_middle[0] = SCREEN_WIDTH >> 1; // X střed obrazovky. Bitový posun doprava, způsobí dělení dvěma šířky obrazovky
i_middle[1] = SCREEN_HEIGHT >> 1; // Y střed obrazovky. Bitový posun doprava, způsobí dělení dvěma výšky obrazovky
float f_angle[2]; // Rotace kolem os (x,y)
f_angle[0] = 0.0f; // Rotace kolem osy X, otočení kamery nahoru a dolu
f_angle[1] = 0.0f; // Rotace kolem osy Y, otočení kamery doprava a doleva
GetCursorPos( &tagp_mouse_pos ); // Získej X,Y pozici kurzoru myši
// Pokud je kurzor mimo okno, tak ho hoď doprostřed okna a dál nic nepočítej
if(( tagp_mouse_pos.x > SCREEN_WIDTH ) && ( tagp_mouse_pos.y > SCREEN_HEIGHT ))
{
SetCursorPos( i_middle[0], i_middle[1] );
return;
}
// Pokud je kurzor stále uprostřed okna, nic by se nemělo hýbat, proto opusť funkci
if(( tagp_mouse_pos.x == i_middle[0] ) && ( tagp_mouse_pos.y == i_middle[1] )) return;
// Jinak vrať kurzor zpět do středu okna
SetCursorPos( i_middle[0], i_middle[1] );
// Získej úhel X a Y podle směru pohybu kurzoru
f_angle[0] = ( float )( ( i_middle[1] - tagp_mouse_pos.y ) ) / 5.0f;
f_angle[1] = ( float )( ( i_middle[0] - tagp_mouse_pos.x ) ) / 5.0f;
pfAngle[0] -= f_angle[0]; // Vypočítej úhel rotace X
pfAngle[1] -= f_angle[1]; // Vypočítej úhel rotace Y
if ( pfAngle[0] >= 90 ) // Jestliže je úhel X větší, nebo rovno 90 stupňů, tak
{
pfAngle[0] = 90; // Nastav úhel X na 90 stupnu
}
if ( pfAngle[0] <
= -90 ) // Jestliže je úhel X menší, nebo rovno -90 stupňů, tak
{
pfAngle[0] = -90; // Nastav úhel X na 90 stupňů
}
if ( pfAngle[1] >= 360 ) // Jestliže je úhel Y větší, nebo rovno 360 stupňů, tak
{
pfAngle[1] = pfAngle[1] - 360; // Odečti 360 stupňů
}
if ( pfAngle[1] <
0 ) // Jestliže je úhel Y menší než 0 stupňů, tak
{
pfAngle[1] = pfAngle[1] + 360; // Přičti 360 stupňů
}
}
//----------------------------------------------------------------------------------------------------//
// Pohni kamerou dopředu
void K_CCamera::GoForward()
{
MoveCamera( -fSpeed );
}
//----------------------------------------------------------------------------------------------------//
// Pohni kamerou dozadu
void K_CCamera::GoBackward()
{
MoveCamera( fSpeed );
}
//----------------------------------------------------------------------------------------------------//
// Pohni kamerou nahoru
void K_CCamera::GoUp()
{
pfPosition[1] -= fSpeed; // Vypočítej novou pozici Y
}
//----------------------------------------------------------------------------------------------------//
// Pohni kamerou dolu
void K_CCamera::GoDown()
{
pfPosition[1] += fSpeed; // Vypočítej novou pozici Z
}
//----------------------------------------------------------------------------------------------------//
// Pohni kamerou doleva
void K_CCamera::StrafeLeft()
{
pfPosition[0] -= ( float ) ( fSpeed * sin(( pfAngle[1] - 90 ) * DEG )); // Vypočítej novou pozici X
pfPosition[2] += ( float ) ( fSpeed * cos(( pfAngle[1] - 90 ) * DEG )); // Vypočítej novou pozici Z
}
//----------------------------------------------------------------------------------------------------//
// Pohni kamerou doprava
void K_CCamera::StrafeRight()
{
pfPosition[0] += ( float ) ( fSpeed * sin(( pfAngle[1] - 90 ) * DEG )); // Vypočítej novou pozici X
pfPosition[2] -= ( float ) ( fSpeed * cos(( pfAngle[1] - 90 ) * DEG )); // Vypočítej novou pozici Z
}
//----------------------------------------------------------------------------------------------------//
// Otoč kamerou doleva
void K_CCamera::TurnLeft()
{
pfAngle[1] -= fSpeed; // Vypočítej nový úhel Y
}
//----------------------------------------------------------------------------------------------------//
// Otoč kamerou doprava
void K_CCamera::TurnRight()
{
pfAngle[1] += fSpeed; // Vypočítej nový úhel Y
}
//----------------------------------------------------------------------------------------------------//
// Otoč kamerou nahoru
void K_CCamera::TurnUp()
{
pfAngle[0] -= fSpeed; // Vypočítej nový úhel X
if ( pfAngle[0] >= 90 ) // Jestliže je úhel X větší, nebo rovno 90 stupňů, tak
{
pfAngle[0] = 90; // Nastav úhel X na 90 stupnu
}
if ( pfAngle[0] <
= -90 ) // Jestliže je úhel X menší, nebo rovno -90 stupňů, tak
{
pfAngle[0] = -90; // Nastav úhel X na 90 stupňů
}
}
//----------------------------------------------------------------------------------------------------//
// Otoč kamerou dolu
void K_CCamera::TurnDown()
{
pfAngle[0] += fSpeed; // Vypočítej nový úhel X
if ( pfAngle[0] >= 90 ) // Jestliže je úhel X větší, nebo rovno 90 stupňů, tak
{
pfAngle[0] = 90; // Nastav úhel X na 90 stupnu
}
if ( pfAngle[0] <
= -90 ) // Jestliže je úhel X menší, nebo rovno -90 stupňů, tak
{
pfAngle[0] = -90; // Nastav úhel X na 90 stupňů
}
}
//----------------------------------------------------------------------------------------------------//
// Pohybuj kamerou pomocí trasformační a rotační matice
void K_CCamera::Look()
{
MouseRotate(); // Vypočítej rotaci kamery pomocí myši
glRotatef( pfAngle[0], 1, 0, 0 ); // Rotace kolem osy X
glRotatef( pfAngle[1], 0, 1, 0 ); // Rotace kolem osy Y
glTranslatef( pfPosition[0], pfPosition[1], pfPosition[2] ); // Pozice kamery
}
//----------------------------------------------------------------------------------------------------//
|
Tyto funkce jsou volány po stlačení daných kláves, které jsou definovány ve vstupní funkci aplikace
WinMain(). Volání funkci třídy K_CCamera je stejné jako v předchozích
tutorialech, takže se tím dále nebudem zabývat.
|
|
|
Základní nastavení světla se provádí v konstruktoru třídy K_CLight
|
|
// Konstruktor třídy K_CCamera
K_CLight::K_CLight()
{
// Nastav ambientní světlo, světlo které září i když jsou světla vypnuta
pfAmbient[0] = 0.2f;
pfAmbient[1] = 0.2f;
pfAmbient[2] = 0.2f;
pfAmbient[3] = 1.0f;
// Nastav difuzní světlo, barvu světla které zdroj vyzařuje do okolí
pfDiffuse[0] = 0.8f;
pfDiffuse[1] = 0.8f;
pfDiffuse[2] = 0.8f;
pfDiffuse[3] = 1.0f;
// Nastav specular světlo, zrcadlový odraz světla
pfSpecular[0] = 0.0f;
pfSpecular[1] = 0.0f;
pfSpecular[2] = 0.0f;
pfSpecular[3] = 1.0f;
// Nastav hodnotu intenzity odlesku
pfShininess = new float[1];
pfShininess[0] = 0;
// Nastav pozici světla
pfPosition[0] = 0.0f;
pfPosition[1] = 0.0f;
pfPosition[2] = 1.0f;
pfPosition[3] = 0.0f;
// Nastav směr světelného kužele
pfDirection[0] = 0.0f;
pfDirection[1] = 0.0f;
pfDirection[2] = -1.0f;
// Nastav emission světlo. Světlo, které vyzařuje určitý objekt, nepůsobí jako zdroj světla
pfEmission[0] = 0.0f;
pfEmission[1] = 0.0f;
pfEmission[2] = 0.0f;
pfEmission[3] = 1.0f;
// Nastav hodnotu lineárního slábnutí intenzity světla
pfLinearAttenuation = new float[1];
pfLinearAttenuation[0] = 0.2f;
// Nastav charakter způsob rozptylu světla při odrazu
pfSpotExponent = new float[1];
pfSpotExponent[0] = 1;
// Nastav úhel, nímž se kužel světla rozevírá od své osy
pfSpotCutoff = new float[1];
pfSpotCutoff[0] = 180;
}
|
Funkce DrawLight(), nám vykreslí světlo, podle zadaných hodnot.
|
|
// Vykresli světlo
void K_CLight::DrawLight()
{
// Zadej hodnoty světla
glLightfv(GL_LIGHT0, GL_AMBIENT, pfAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, pfDiffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, pfSpecular);
glLightfv(GL_LIGHT0, GL_SHININESS, pfShininess);
glLightfv(GL_LIGHT0, GL_POSITION, pfPosition);
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, pfDirection);
glLightfv(GL_LIGHT0, GL_EMISSION, pfEmission);
glLightfv(GL_LIGHT0, GL_LINEAR_ATTENUATION, pfLinearAttenuation);
glLightfv(GL_LIGHT0, GL_SPOT_EXPONENT, pfSpotExponent);
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, pfSpotCutoff);
glEnable(GL_LIGHTING); // Zapni osvětlování
glEnable(GL_LIGHT0); // Zapni první světlo
}
|
Funkce DrawLight()se volá při iniciaci scény. Protože vykreslujeme světlo,
před výpočtem pohybu kamery, tak světlo chodí s kamerou. Pokud budeme chtít, aby
světlo nereagovalo na kameru, jednoduše ho vykreslíme až po výpočtu kamery.
|
|
K_CLight *plig; // Světlo
//----------------------------------------------------------------------------------------------------//
// Načti scénu
void InitScene( void )
{
...
...
...
plig = new K_CLight(); // Alokuj paměť pro světlo
plig->DrawLight(); // Vykresli světlo
}
//----------------------------------------------------------------------------------------------------//
|
A to je vše. Samozřejmě jsem vše nevymyslel sám. Nejvíce mi pomohl Brett Porter,
z jehož tutorialů jsem čerpal nejvíce informací. Model jsem také nevytvářel já.
Autorem je Bart Secker. Tímto oběma děkuji.
Příště zkusíme načíst modely 3d Studia Max (*.3ds).
Kwan
|
|
Home