CHƯƠNG I .
TỔNG QUAN VỀ THỰC TẠI ẢO VÀ 3D ANIMATION TRONG THỰC 
TẠI ẢO .
1.1. Tổng quan về thực tại ảo 
1.1.1. Sơ lược lịch sử phát triển . 
1.1.2. Các lĩnh vực ứng dụng của Thực tại ảo.
1.2 Hành động của nhân vật (3D Animation) trong thực tại ảo. 
1.2.1. Animation trong thực tại ảo là gì? .
1.2.2. Hiệu ứng Animation trong thực tại ảo 
1.2.3. Cơ sở mô phỏng 3D Animation. 
1.2.4. Các vấn đề gặp phải trong quá trình nghiên cứu 
1.2.5. Hướng giải quyết 
CHƯƠNG II 
KỸ THUẬT MÔ PHỎNG 
2.1. Đặt vấn đề .
2.2. Kỹ thuật mô phỏng 
2.2.1 Khởi tạo nhân vật và trang phục 
2.2.2 Điều khiển mô phỏng các trạng thái hành động của nhân vật 
2.2.3 Các vấn đề liên quan tới camera và các phím điều khiển. 
CHƯƠNG III . 
CHƯƠNG TRÌNH MÔ PHỎNG.
3.1. Bài toán 
3.2. Mục đích và yêu cầu bài toán 
3.3. Phương pháp giải quyết bài toán .
3.4 Một số kết quả bài toán
                
              
                                            
                                
            
 
            
                 77 trang
77 trang | 
Chia sẻ: lvcdongnoi | Lượt xem: 3057 | Lượt tải: 0 
              
            Bạn đang xem trước 20 trang tài liệu Mô phỏng hành động nhân vật trong xây dựng mô hình 3d, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
r::set_animation_sequence(char *sequence_name, int 
transition_duration) 
{ 
DWORD anim3d = Morfit_object_get_3D_animation(m_player_object); 
DWORD sequence = Morfit_3D_sequence_get_using_name(anim3d, 
sequence_name); 
 if(sequence == NULL) 
 return(NULL); 
Morfit_object_set_3D_sequence(m_player_object, sequence, 
transition_duration); 
 return(sequence); 
} 
e. Hàm lựa chọn trình tự cho nhân vật 
Việc lựa chọn trình tự cho nhân vật được thực hiện khi ta thiết lập các 
trình tự đã có như trình tự đi bộ, trình tự tấn công bị thương, trình tự đứng,…Với 
mỗi trình tự sẽ được gắn một số id (m_sequence_id_num) vì vậy mà sẽ rất dễ 
dàng cho việc lựa chọn, quản lý các trình tự. 
Ở đây chúng ta sẽ cố gắng giữ m_sequence_id_num được cập nhập nhưng 
trong một số trường hợp thì không thể. Ví dụ nếu trình tự hiện tại 
(m_current_sequence) là trình tự tấn công (m_attack_sequence) và sẽ được phép 
làm như sau: 
Morfit_object_set_3D_sequence(m_player_object, m_attack_sequence, 0); 
Morfit_object_replace_3D_sequence_when_finished(m_player_object, 
m_stand_sequence,300); 
Trong trường hợp không biết chính xác thì trình đứng sẽ trở thành trình tự 
hiện tại. Vì vậy mà ở đây sẽ truy vấn tới trình tự hiện tại và sẽ cập nhập 
m_sequence_id_num và m_current_sequence phù hợp. Để hiểu rõ ý này xem 
đoạn mã sau: 
 30
DWORD sequence = Morfit_object_get_3D_sequence(m_player_object); 
 if(sequence == m_stand_sequence) 
 { 
 m_sequence_id_num = STAND; 
 m_current_sequence = m_stand_sequence; 
 } 
 else 
 { 
 if(sequence == m_walk_sequence) 
 m_sequence_id_num = WALK; 
 m_current_sequence = m_walk_sequence; 
 } 
Chú ý điều quan trọng là khi chúng ta thiết lập một trình tự riêng biệt 
(specific sequence) thì đầu tiên sẽ thiết lập một trạng thái trình tự hành động 
và chỉ sau khi trình tự trạng thái hành động kết thúc thì nó sẽ tự động thiết lập 
trình tự muốn có. Có nghĩa là nếu muốn tạo trình tự đi bộ (walk_sequence) ta 
sẽ gọi hàm 
Morfit_object_set_3D_sequence(m_player_object,walk_sequence); 
Và ngay sau đó gọi hàm : 
sequence=Morfit_object_get_3D_sequence(m_player_object); 
thì kết quả trình tự trả về sẽ nhận được không phải là trình tự đi bộ 
(sequence!=walk_sequence !!!). Chỉ sau khi trình tự trạng thái hành động kết 
thúc thì trình tự walk_sequence mới được sử dụng. 
 Sau đây là đoạn mã của quá trình lựa chọn một trình tự: 
void player::select_sequence() 
{ 
 DWORD sequence = 
Morfit_object_get_3D_sequence(m_player_object); 
 if(sequence == m_stand_sequence) 
 { 
 31
 m_sequence_id_num = STAND; 
 m_current_sequence = m_stand_sequence; 
 } 
 else 
 { 
 if(sequence == m_walk_sequence) 
 m_sequence_id_num = WALK; 
 m_current_sequence = m_walk_sequence; 
 } 
 if( (sequence == m_walk_sequence) && (m_speed < m_min_speed 
&& m_speed > -m_min_speed)) 
 { 
 m_current_sequence = 
set_animation_sequence("stand",100); 
 m_sequence_id_num = STAND; 
 } 
 else if((sequence == m_stand_sequence) && (m_speed >= 
m_min_speed || m_speed <= -m_min_speed)) 
 { 
 m_current_sequence = 
set_animation_sequence("walk",100); 
 m_sequence_id_num = WALK; 
 } 
 else if((sequence == m_fall_sequence) && (m_speed < 
m_min_speed && m_speed > -m_min_speed)) 
 { 
 //kiểm tra trình tự ngã (fall_sequence) đã kết thúc hay chưa 
DWORD anim3d = Morfit_object_get_3D_animation(m_player_object); 
 32
DWORD fall_sequence = Morfit_3D_sequence_get_using_name(anim3d, 
"death"); 
int num_of_frames = 
Morfit_3D_sequence_get_number_of_frames(fall_sequence); 
double current_position = 
Morfit_3D_sequence_get_current_frame(fall_sequence); 
 if(current_position >= num_of_frames - 2) 
 { 
 m_current_sequence = 
set_animation_sequence("stand",1000); 
 m_sequence_id_num = STAND; 
 } 
 } 
 if(m_sequence_id_num!=FALL) 
 { 
 //thiết lập một trình tự đúng 
 if(m_speed<0 ) 
 { 
 Morfit_3D_sequence_backwards_play(m_current_sequence,YES); 
 } 
 else 
 { 
 Morfit_3D_sequence_backwards_play(m_current_sequence,NO); 
 } 
 } 
 set_sequence_speed(); 
} 
 33
f. Hàm di chuyển trạng thái hành động của nhân vật 
Di chuyển trạng thái hành động của nhân vật là việc thực hiện các thao tác 
điều khiển cho nhân vật thực hiện một hành động để chuyển từ vị trí này sang vị 
trí khác như tiến lên trước, lùi về phía sau, sang phải, sang trái… 
Để thực hiện việc di chuyển cho nhân vật trước tiên phải xác định vị trí 
mà nhân vật cần đi tới. Việc này được thực hiện một cách dễ dàng qua hàm : 
Morfit_object_get_location(m_player_object,&save_location[0], 
 &save_location[1], &save_location[2]); 
Sau đó sẽ tạo một trình tự cho nhân vật qua hàm: 
DWORD sequence = Morfit_object_get_3D_sequence(m_player_object); 
Có nghĩa là giả sử m_sequence_id_num==WALK là một trình tự đi bộ 
hoặc là một vài trình tự vận chuyển ban đầu của trình tự đi bộ, nếu ta có thể thay 
thế sequence==m_walk_sequence thì nó sẽ không thể bắt kịp sự chuyển vận từ 
trạng thái đứng sang trạng thái đi bộ được. Nên nhớ rằng trình tự vận chuyển đã 
được phát sinh một cách tự động bởi các engine vì vậy mà việc chuyển đổi từ 
một trình tự này sang một trình tự khác được thực hiện một cách mềm mại và 
nhịp nhàng. Nếu không muốn trình tự vận chuyển phát sinh một cách tự động thì 
đơn giản có thể gọi hàm sau : 
Morfit_object_set_3D_sequence( ,0); 
Trong đó với 0 là khoảng thời gian tồn tại cho sự vận chuyển. 
Cũng như vậy trong quá trình di chuyển phải xác định lực đã sử dụng hay 
chính xác hơn chính là lực tác dụng vào nhân vật, vì vậy mà biến int 
muscle_force_used = NO; được khai báo có ý nghĩa ban đầu là chưa có lực nào 
tác dụng. Như đã nói ở trên thì tốc độ của nhân vật phụ thuộc vào các thành phần 
lực vì vậy mà dựa vào đó mà có thể thấy rõ sự nhanh hay chậm của nhân vật 
trong từng trình tự trạng thái chuyển động. 
Sau đây là một đoạn chương trình mô phỏng việc dịch chuyển tiến phía 
trước, lùi phía sau, sang trái, sang phải của nhân vật: 
void player::move(void) 
{ 
 34
 int muscle_force_used = NO; // ko có lực tác dụng 
 double save_location[3]; 
 //Xác định vị trí nhân vật cần di chuyển tới 
 Morfit_object_get_location(m_player_object, &save_location[0], 
&save_location[1], &save_location[2]); 
DWORD sequence = Morfit_object_get_3D_sequence(m_player_object); 
if(m_sequence_id_num == WALK || sequence == m_stand_sequence) 
 { 
 //tiến phía trước 
 if(GetAsyncKeyState(VK_UP) < 0) 
 { 
 m_speed += m_acceleration; 
 muscle_force_used = YES; 
 } 
 //lùi phía sau 
 if(GetAsyncKeyState(VK_DOWN) < 0) 
 { 
 muscle_force_used = YES; 
 m_speed -= m_acceleration; 
 } 
 } 
 if(m_sequence_id_num == WALK || sequence == 
m_stand_sequence || sequence == m_attack_sequence || sequence == 
m_pain_sequence) 
 { 
 //sang trái 
 if(GetAsyncKeyState(VK_LEFT) < 0) 
 { 
 Morfit_object_rotate_z(m_player_object, 6, WORLD_SPACE); 
 } 
 35
 //sang phải 
 if(GetAsyncKeyState(VK_RIGHT) < 0) 
 { 
 Morfit_object_rotate_z(m_player_object, -6, WORLD_SPACE); 
 } 
 } 
// xác định vận tốc và lực đã sử dụng 
double gravity_and_friction_factor = get_friction_and_gravity_factor(); 
 if(muscle_force_used == NO || fabs(m_speed) > m_min_speed) 
 { 
 m_speed *= gravity_and_friction_factor; 
 if(muscle_force_used == YES) 
 if(fabs(m_speed) < fabs(m_min_speed)) 
 m_speed = m_min_speed * m_speed / fabs(m_speed); 
 } 
 if(m_speed > m_max_speed) 
 m_speed = m_max_speed; 
 if(m_speed < -m_max_speed) 
 m_speed = -m_max_speed; 
Morfit_object_move(m_player_object,OBJECT_SPACE, -m_speed,0,0); 
 // Lựa chọn trình tự đúng 
 select_sequence(); 
 // Xác địn vùng nền dưới 
 double point_below[3]; 
 get_polygon_below(point_below); 
 // Xác định một trạng thái mới 
 if(new_altitude > save_location[2] + m_height / 3) 
 { 
 36
Morfit_object_set_location(m_player_object,save_location[0], 
 save_location[1], save_location[2]); 
 m_speed = -m_speed * 0.5; 
 } 
 else 
 { 
 double location[3]; 
 Morfit_object_get_location(m_player_object, &location[0], 
 &location[1], &location[2]); 
 Morfit_object_set_location(m_player_object, location[0], 
 location[1], new_altitude); 
 } 
} 
g. Một số trạng thái chuyển động của nhân vật 
* Trạng thái tấn công (Attack) 
Ở đây sẽ mô phỏng nhân vật trong tư thế dùng vũ khí tấn công một đối 
tượng khác. Một trình tự tấn công thực tế được xây dựng từ rất nhiều các trình tự 
tấn công khác. Như tấn công với súng, phóng đạn, bắn trúng mục tiêu với cùng 
một điều khiển…Trong game thì nó rất dễ dàng có được các trạng thái riêng biệt 
đối với các trình tự khác nhau. Có thể tham khảo đoạn mã sau để hiểu rõ hơn về 
một trình tự trạng thái tấn công: 
void player::attack(void) 
{ 
 if(m_attack_sequence==NULL) 
 return; 
 Morfit_object_set_3D_sequence(m_player_object, 
m_attack_sequence, 0); 
 Morfit_object_replace_3D_sequence_when_finished(m_player_obj
ect, m_stand_sequence,300); 
 m_current_sequence=m_attack_sequence; 
 37
 m_sequence_id_num=ATTACK; 
} 
* Trạng thái bị thương 
Cũng giống như trạng thái tấn công thì trạng thái bị thương sẽ mô phỏng 
khi nhân vật bị trúng đạn và nó cũng được tạo lên bằng hàng loạt các trình tự bị 
thương khác như sẽ giảm tốc độ, có thể khụy xuống và hiện chỗ thương trúng 
đạn tại vị trí đó. Và sau đây là đoạn mã mô phỏng trạng thái bị thương: 
void player::pain(void) 
{ 
 if(m_pain_sequence==NULL) 
 return; 
 Morfit_object_set_3D_sequence(m_player_object, 
m_pain_sequence, 0); 
 Morfit_object_replace_3D_sequence_when_finished(m_player_obj
ect, m_stand_sequence,400); 
 m_current_sequence=m_pain_sequence; 
 m_sequence_id_num=PAIN; 
} 
* Cập nhập theo một trạng thái hành động mới 
Như đã nói khi một trạng thái được thay đổi thì các tham số hành động 
một hành động của nhân vật sẽ thay đổi theo sao cho phù hợp với từng trình tự 
mô phỏng hành động đó. Ở đây có thể “load” chúng khi mà cần tới những ảnh 
mô phỏng đó trong khi các “engine” sẽ không đủ nhanh để “load” những ảnh đã 
có sẵn trong bộ nhớ. Có thể theo dõi đoạn mã sau để thấy được sự thay đổi giữa 
các trạng thái: 
int player::update_according_to_new_animation(void) 
{ 
 char buff[MAX_PATH]; 
 strcpy(buff,m_bitmap_path); 
 38
 strcat(buff,"\\skin.bmp"); 
 m_skin_bitmap = Morfit_bitmap_load(buff,-1); 
 strcpy(buff,m_bitmap_path); 
 strcat(buff,"\\pain.bmp"); 
 m_pain_bitmap = Morfit_bitmap_load(buff,-1); 
 //Thiết lập trang phục 
 Morfit_object_set_bitmap(m_player_object, m_skin_bitmap); 
 // Thiết lập tham số theo tỉ lệ kích thước 
 set_parameters_according_to_scale(); 
 m_current_sequence = set_animation_sequence("stand", 0); 
 m_sequence_id_num = STAND; 
 m_stand_sequence = m_current_sequence; 
DWORD anim3d = Morfit_object_get_3D_animation(m_player_object); 
m_fall_sequence = Morfit_3D_sequence_get_using_name(anim3d, "death"); 
 if(m_fall_sequence != NULL) 
 { 
 int num_of_frames = 
Morfit_3D_sequence_get_number_of_frames(m_fall_sequence); 
 //Dừng quá trình đang ngã trong một trạng thái riêng. 
 Morfit_3D_sequence_set_frame_duration(m_fall_sequence, 
num_of_frames-2, 1000000); 
 Morfit_3D_sequence_set_speed(m_fall_sequence,0.5); 
 } 
m_walk_sequence = Morfit_3D_sequence_get_using_name(anim3d, "walk"); 
 if(m_walk_sequence == NULL) 
 return(VR_ERROR); 
 m_attack_sequence = 
Morfit_3D_sequence_get_using_name(anim3d, "attak"); 
m_pain_sequence = Morfit_3D_sequence_get_using_name(anim3d, "pain"); 
return(OK); 
} 
 39
2.2.3 Các vấn đề liên quan tới camera và các phím điều khiển. 
a. Các vấn đề liên quan tới camera. 
Camera là thành phần vô cùng quan trọng trong kĩ thuật mô phỏng vì nó 
quyết định tới góc nhìn, khoảng cách nhìn, không gian nhìn đối với các đối tượng 
trong không gian thới giới ảo. Việc liên kết giữa camera và đối tượng sẽ làm cho 
quá trình mô phỏng sẽ được linh động hơn, mềm mại và chân thật hơn đối với 
người quan sát. Với mỗi chế độ camera khác nhau ta cũng có các hiệu ứng khác 
nhau vì vậy mà sau đây là một số chế độ camera và hiệu ứng cơ bản về camera 
đã sử dụng để mô phỏng nhân vật trong đề tài này: 
* Thiết lập camera ở chế độ chase_flexible 
Ở chế độ này camera sẽ di chuyển mềm mại, uyển chuyển theo đối tượng 
mà nó bám theo. Chúng ta có thể thiết lập kiểu theo cho đối tượng bằng hàm: 
STATE_object_set_chase_type(Handle,chase_type) 
Với kiểu theo là flexible, ta có thể thiết lập độ mềm dẻo của đường rẽ 
bằng hàm STATE_object_set_chase_softness(object_handle,softness) và tương 
tự có hàm lấy sự mềm dẻo hiện tại của đối tượng theo là: 
STATE_object_get_chase_softness(object_handle). Giá trị softness nằm trong 
khoảng [0-1]. 
Khoảng cách theo (chase offset): Chase offset xác định khoảng cách từ 
đối tượng theo đến đối tượng bị theo. Ví dụ: char offset là [0,0,10] có nghĩa là 
đối tượng theo sẽ theo đối tượng nhưng nó sẽ ở bên trên đối tượng cách đối 
tượng 10 đơn vị. 
Ta có thể thiết lập char offset bằng hàm sau: 
STATE_object_set_chase_offset(object_handle,offset[3]). 
Ta cũng có thể lấy char offset hiện tại của đối tượng bằng hàm sau: 
STATE_object_get_chase_offset(object_handle,offset[3]). 
Sau đây là đoạn mã mô phỏng thiết lập camera ở chế độ chase_flexible: 
void camera::set_ chase_flexible_mode(void) 
{ 
 40
 Morfit_camera_set_chase_type(m_camera_handle, 
CHASE_FLEXIBLE); 
 double chase_offset[3] = {0,0,0}; 
 Morfit_camera_set_chase_offset(m_camera_handle, chase_offset); 
 update_chase_params(); 
} 
* Thiết lập camera ở chế độ chase_location 
Cũng giống như ở chế độ chase_flexible nó cũng có nhiệm vụ bám theo 
đối tượng và tính khoảng cách tới đối tượng xong có sự khác biệt ở đây là camera 
sẽ không quay khi đối tượng bị theo quay. Sau đây là đoạn mã mô phỏng thiết 
lập camera ở chế độ chase_location: 
void camera::set_chase_location_mode(void) 
{ 
 Morfit_camera_set_chase_type(m_camera_handle, 
CHASE_LOCATION); 
 double box[2][3]; 
 Morfit_object_get_bounding_box(m_object_to_chase, box); 
 double height = box[1][2] - box[0][2]; 
 double distance = height * 1.5 + 40; 
// double scale[3]; 
// Morfit_object_get_scale(m_camera_handle, scale); 
// double distance=scale[2]*100+100; 
 double direction[3]; 
 Morfit_object_get_direction(m_object_to_chase,&direction[0], 
&direction[1], &direction[2]); 
Double chase_offset[3] = {-direction[0]*distance, -direction[1]*distance, 20}; 
 41
Morfit_camera_set_chase_offset(m_camera_handle, chase_offset); 
double location[3];Morfit_object_get_location(m_object_to_chase, 
&location[0], &location[1], &location[2]); 
Morfit_camera_point_at(m_camera_handle,location[0],location[1], 
location[2]); 
} 
* Tạm dừng một chế độ camera (stop_chasing): 
Việc tạm dừng một chế độ camera theo đối tượng được thực hiện một 
cách đơn giản khi dùng hàm sau : 
Morfit_camera_set_chase_type(m_camera_handle, NO_CHASE); 
* Thiết lập camera ở chế độ zoom_in và zoom_out: 
Thiết lập camera ở chế độ zoom_out là quá trình di chuyển camera ra xa 
từ đối tượng bị theo. Chú ý rằng ở đây không phải là một zoom_out thực sư, để 
tạo một zoom_out thực sự thì có thể sự dụng hàm sau: 
Morfit_camera_set_field_of_view() 
Sau đây là đoạn mã mô phỏng thiết lập camera ở chế độ zoom_out: 
void camera::zoom_out(void) 
{ 
int chase_type = Morfit_camera_get_chase_type(m_camera_handle); 
 if(chase_type == CHASE_LOCATION) 
 { 
 // chase_distance không thích hợp ở chế độ CHASE_LOCATION 
 double chase_offset[3]; 
 Morfit_camera_get_chase_offset(m_camera_handle, chase_offset); 
 chase_offset[0] *= 1.1; 
 chase_offset[1] *= 1.1; 
 chase_offset[2] *= 1.1; 
 Morfit_camera_set_chase_offset(m_camera_handle, chase_offset); 
 return; 
 42
 } 
 if(chase_type == CHASE_FLEXIBLE) 
 { 
double distance = Morfit_camera_get_chase_distance(m_camera_handle); 
 Morfit_camera_set_chase_distance(m_camera_handle,distance*1.1); 
 return; 
 } 
} 
Thiết lập camera ở chế độ zoom_in là quá trình đưa camera lại gần đối 
tượng bị theo. Chú ý rằng ở đây cũng như chế độ zoom_out thì đây cũng không 
phải là một chế độ zoom_in thực sự, để tạo một zoom_out thực sự thì có thể sự 
dụng hàm sau: Morfit_camera_set_field_of_view() 
Sau đây là đoạn mã mô phỏng thiết lập camera ở chế độ zoom_in: 
void camera::zoom_in(void) 
{ 
int chase_type = Morfit_camera_get_chase_type(m_camera_handle); 
 if(chase_type == CHASE_LOCATION) 
 { 
 // chase_distance không thích hợp ở chế độ CHASE_LOCATION 
 double chase_offset[3]; 
 Morfit_camera_get_chase_offset(m_camera_handle, chase_offset); 
 chase_offset[0] *= 0.9; 
 chase_offset[1] *= 0.9; 
 chase_offset[2] *= 0.9; 
 Morfit_camera_set_chase_offset(m_camera_handle, chase_offset); 
 return; 
 } 
 if(chase_type == CHASE_FLEXIBLE) 
 { 
 43
double distance = Morfit_camera_get_chase_distance(m_camera_handle); 
Morfit_camera_set_chase_distance(m_camera_handle,distance*0.9); 
return; 
 } 
} 
b. Các vần đề liên quan tới các phím điều khiển. 
Trong quá trình mô phỏng trạng thái hành động của nhân vật thì việc dùng 
các phím điều khiển để thay đổi các tùy chọn, thiết lập hoặc điều khiển di chuyển 
của nhân vật là rất cần thiết. Chính vì vậy để cho quá trình sử dụng chương trình 
một cách dễ dàng mà trong chương trình đã thiết lập cài đặt sử dụng các phím 
điều khiển tương ứng với các nhiệm vụ và tác dụng của nó như sau: 
+ Phím “A” : Zoom out với camera. 
+ Phím “Z” : Zoom in với camera 
+ Phím “S” : Phóng to kích thước tương ứng với kích thước của nhân vật 
+ Phím “X” : Thu nhỏ thước tương ứng với kích thước của nhân vật 
+ Phím “W” : Thiết lập tỉ lệ kích thước mặc định 
+ Phím “D” : Tỉ lệ kích thước theo trục X (tạo cho nhân vật “mập” lên) 
+ Phím “C” : Tỉ lệ kích thước theo trục X (tạo cho nhân vật “gầy” xuống) 
+ Phím “G” : Tỉ lệ kích thước theo trục Y (tạo cho nhân vật “rộng” lên) 
+ Phím “B” : Tỉ lệ kích thước theo trục Y (tạo cho nhân vật “hẹp” xuống) 
+ Phím “H” : Tỉ lệ kích thước theo trục Z (tạo cho nhân vật “cao” lên) 
+ Phím “N” : Tỉ lệ kích thước theo trục Z (tạo cho nhân vật “Thấp” xuống) 
+ Phím “F” : Không sử dụng chế độ full_screen (màn hình 800x600) 
+ Phím “V” : Sử dụng chế độ full_screen (màn hình 800x600) 
+ Phím “R” : Không sử dụng card đồ họa thiết lập cửa sổ mặc định 
(240,180,400,400) 
+ Phím “1” : Thiết lập camera ở chế độ chase_location 
+ Phím “2” : Thiết lập camera ở chế độ chase_flexible 
+ Phím “3” : Thiết lập camera ở chế độ stop_chasing 
+ Phím “4” : Thiết lập nhân vật ở trạng thái tấn công (attack) 
 44
+ Phím “5” : Thiết lập nhân vật ở trạng thái tấn bị thương (pain) 
+ Phím “6” : Thiết lập lại trang phục cho nhân vật (replace_skin) 
+ Phím “7” : Thiết lập lại bề ngoài cho nhân vật (replace_shape) 
+ Phím “F1” : Gọi một bảng HELP 
Sau đây là toàn bộ mã chương trình đặt chế độ điều khiển tương ứng với 
các phím như mô tả trên: 
void settings(camera *camera1, player *player1, DWORD anim1, 
DWORD anim2) 
{ 
 //Zoom out với camera 
 if(GetAsyncKeyState('A')<0) 
 { 
 camera1->zoom_out(); 
 } 
 else if(GetAsyncKeyState('Z')<0) //Zoom in với camera 
 { 
 camera1->zoom_in(); 
 } 
 int scale_flag = 0; 
 //Tỉ lệ kích thước tương ứng với kích thước của nhân vật 
 if( GetAsyncKeyState('S')<0 ) 
 { 
 player1->scale(1.1, X_AXIS|Y_AXIS|Z_AXIS); 
 scale_flag++; 
 } 
 else if( GetAsyncKeyState('X')<0 ) 
 { 
 player1->scale(0.9, X_AXIS|Y_AXIS|Z_AXIS); 
 scale_flag++; 
 } 
 45
else if(GetAsyncKeyState('W')<0) //Thiết lập tỉ lệ kích thước mặc định 
{ 
 player1->scale_default(); 
 scale_flag++; 
} 
//Tỉ lệ kích thước theo trục X (tạo cho nhân vật mập lên) 
if( GetAsyncKeyState('D')<0) 
{ 
 player1->scale(1.1, X_AXIS); 
 scale_flag++; 
} 
else if( GetAsyncKeyState('C')<0) 
{ 
 player1->scale(0.9, X_AXIS); 
 scale_flag++; 
} 
//Tỉ lệ kích thước nhân vật theo trục Y (tạo cho nhân vật “rộng lên”) 
 if( GetAsyncKeyState('G')<0) 
 { 
 player1->scale(1.1, Y_AXIS); 
 scale_flag++; 
 } 
 else if( GetAsyncKeyState('B')<0) 
 { 
 player1->scale(0.9, Y_AXIS); 
 scale_flag++; 
 } 
 // Tỉ lệ kích thước nhân vật theo trục Z (tạo cho nhân vật “cao lên”) 
 if( GetAsyncKeyState('H')<0) 
 { 
 46
 player1->scale(1.1, Z_AXIS); 
 scale_flag++; 
} 
else if( GetAsyncKeyState('N')<0) 
{ 
 player1->scale(0.9, Z_AXIS); 
 scale_flag++; 
} 
if(scale_flag) 
 camera1->update_chase_params(); 
if( (GetAsyncKeyState('F')&1) && (GetAsyncKeyState('F')<0)) 
{ 
 if(Morfit_3D_card_is_used() ==NO || 
Morfit_3D_card_is_full_screen_mode() == NO) 
{ 
 if(Morfit_3D_card_set_full_screen_mode(800,600) == 
VR_ERROR) 
 { 
 if(Morfit_3D_card_check_hardware_support() == YES) 
 { 
 MessageBox(NULL, "Failed to initialize your 3D card.\n This 
sample only works with hardware rendering\nPlease check that you have a 3D 
card and DirectX 6.1 and above\n","No 3D card", MB_OK); 
 } 
 } 
 } 
} 
else if((GetAsyncKeyState('V')&1) && (GetAsyncKeyState('V')<0)) 
 { 
 47
 if(Morfit_3D_card_is_used() == NO || 
Morfit_3D_card_is_full_screen_mode() == YES) 
 { 
Morfit_engine_maximize_default_rendering_window(); 
 if(Morfit_3D_card_set_window_mode() == VR_ERROR) 
 { 
 if(Morfit_3D_card_check_hardware_support() == YES) 
 { 
MessageBox(NULL, "Failed to initialize your 3D card.\n This sample 
only works with hardware rendering\nPlease check that you have a 3D card and 
DirectX 6.1 and above\n","No 3D card", MB_OK); 
 } 
 } 
 } 
} 
else if((GetAsyncKeyState('R')&1)&& (GetAsyncKeyState('R')<0)) 
{ 
 Morfit_3D_card_use(NO); 
Morfit_engine_set_default_rendering_window_size(240,180,400,400); 
 } 
 if(GetAsyncKeyState('1')<0) 
 { 
 camera1->set_chase_location_mode(); 
 } 
 else if(GetAsyncKeyState('2')<0) 
 { 
 camera1->set_chase_flexible_mode(); 
 } 
 else if(GetAsyncKeyState('3')<0) 
 { 
 48
 camera1->stop_chasing(); 
 } 
 if(GetAsyncKeyState('4')<0) 
 { 
 player1->attack(); 
 } 
 else if(GetAsyncKeyState('5')<0) 
 { 
 player1->pain(); 
 } 
 if(GetAsyncKeyState('6')&1) 
 { 
 player1->replace_skin(); 
 } 
 static int anim_toggle = 0; 
 if(GetAsyncKeyState('7')&1) 
 { if(anim_toggle == 0) 
 { 
 player1->replace_shape(anim2, 
"..\\..\\..\\..\\..\\Worlds\\player2"); 
 anim_toggle = 1; 
 } 
 else 
 { 
 player1->replace_shape(anim1, 
"..\\..\\..\\..\\..\\Worlds\\player1"); 
 anim_toggle = 0; 
 } 
 } 
 if(GetAsyncKeyState(VK_F1)&1) 
 { 
 help_popup(); 
 } 
} 
 49
CHƯƠNG III 
CHƯƠNG TRÌNH MÔ PHỎNG 
3.1. Bài toán 
Sau một thời gian tìm hiểu về Thực tại ảo và 3D animation trong Thực tại 
ảo, tác giả xin đưa ra một ứng dụng nhỏ; xây dựng một số hiệu ứng cho nhân vật 
trong môi trường thực tại ảo. 
Bài toán tác giả đưa ra trong đồ án này là bài toán mô phỏng một số hiệu 
ứng 3D animation trong môi trường thựct ại ảo. 
3.2. Mục đích và yêu cầu bài toán. 
Mục đích của bài toán: Từ bài toán trên ta nhận thấy mục đích của bài 
toán bao gồm: 
+Nhằm giới thiệu một phương pháp tiếp cận mới đối với 3D animation, 
đó là phương pháp tiếp cận và xử lý dựa trên ảnh. 
+ Nhằm giới thiệu một số thuật toán trong quá trình xây dựng các hiệu 
ứng 3D animation. 
+ Nhằm giới thiệu một hướng nghiên cứu và xây dựng mới về hiệu ứng 
3D trong môi trường thực tại ảo, đó chính là hiệu ứng 3D animation. 
Yêu cầu của bài toán: Từ mục đích của bài toán chúng ta nhận thấy 
những yêu cầu của bài toán như sau: 
+ Vì bài toán mang mục đích tìm hiểu và giới thiệu phương pháp xây dựng 
mô phỏng hành động nhân vật trong môi trường thực tại ảo, vì vậy bài toán phải 
mang tính điển hình rễ hiểu và đáp ứng được những mục đích mà bài toán đề ra. 
+ Bài toán phải cho thấy được vai trò cũng như tầm quan trọng của việc mô 
phỏng trong các hiệu ứng 3D animation nói riêng và trong môi trường thực tại ảo 
nói chung. 
+ Bài toán phải thể hiện được một số hiệu ứng cơ bản của các hành động 
của nhân vật trong môi trường thực tại ảo. 
3.3. Phương pháp giải quyết bài toán 
Từ những yêu cầu và mục đích trên tác giả đề ra phương hướng giải quyêt 
 50
bài toán như sau: 
Vì bài toán nhằm mục đích tìm hiểu về các hành động của nhân vật được 
mô phỏng trong môi trường thực tại ảo. Vì vậy tác giả đi mô phỏng các hiệu ứng 
mang tính đơn giả, dễ mô phỏng. 
Kết hợp các ảnh của nhân vật để mô phỏng các hiệu ứng . 
Ta sử dụng hai ngôn ngữ là Morfit 3D và Virsual C++ để mô phỏng và 
điều khiển các hành động nhân vật. 
3.4 Một số kết quả bài toán. 
Các ảnh đầu vào: 
Ảnh mặt trước và sau của skin và pain: 
Các ảnh này được ghép vào các đa giác của khối hình nhân vật tạo từ 3dsmax. 
Cửa sổ Help hiện ra để hướng dẫn khi bắt đầu chạy chương trình hoặc khi ấn F1 
 51
Hình nhân vật khi khởi động chương trình ở trạng thái đứng yên: 
Một số hình ảnh về trạng thái tấn công, thương, lên dốc, xuống dốc của 
nhân vật. 
 52
 53
 54
 55
KẾT LUẬN 
Sau một thời gian nghiên cứu, tìm hiểu thì đồ án đã hoàn thành và đạt 
được một số kết quả như sau: 
* Giới thiệu và tổng quan về thực tại ảo và 3D animation trong thực tại ảo. 
* Giới thiệu cách thức để khởi tạo một đối tượng trong thực tại ảo. 
* Giới thiệu một số thuật toán cơ bản trong quá trình điều khiển đố tượng. 
* Giới thiệu một số trạng thái của đối tượng. 
* Giới thiệu một số chế độ điều khiển camera và sự chuyển đổi giữa các 
chế độ đó. 
* Xây dựng một chương trình nhỏ mô phỏng hành động của nhân vật 
với một số hiệu ứng 3D animation trong môi trường thực tại ảo với các trạng 
thái cụ thể. 
 56
HƯỚNG PHÁT TRIỂN ĐỀ TÀI 
 Trong tương lai tác giả sẽ cố gắng phát triển theo hướng sâu hơn, với 
quy mô lớn hơn và có tính thực tế cao hơn. Sẽ cố gắng hoàn thành và phát triển 
một game với ứng dụng của việc mô phỏng các hành động nhân vật với nhiều 
nhân vật và tương tác hơn với môi trường thế giới ảo. 
 57
PHỤ LỤC 
// player.h 
#ifndef PLAYER_H 
#define PLAYER_H 
#define ACCELERATION 4 
#define MAX_SPEED 50 
#define MIN_SPEED 2 
#define STAND 0 
#define WALK 1 
#define FALL 2 
#define ATTACK 3 
#define PAIN 4 
#define X_AXIS 1 
#define Y_AXIS 2 
#define Z_AXIS 4 
//#include "Engine\\mrft_api.h" 
#include 
class player 
{ 
public: 
 player(); 
 virtual ~player(); 
 int init(char *file_name, char *bitmap_path); 
 //di chuyen nhan vat 
 void move(void); 
 //ti le kich thuoc nhan vat theo cac truc x,y,x hoac co the ket hop giua cac truc 
 void scale(double factor, int axis); 
 //Thiet lap ti le kich thuoc mac dinh 
 void scale_default(void); 
 //trang thai tan cong 
 void attack(void); 
 //trang thai bi thuong 
 void pain(void); 
 //Lay lai trang phuc cho nhan vat,chinh la chuyen doi giua cac anh 
 void replace_skin(void); 
 //Lay lai hinh dang ban dau cho nhan vat 
 void replace_shape(DWORD new_3d_animation, char *bitmap_path); 
 DWORD m_player_object; 
private: 
 58
 double m_speed; 
 DWORD m_current_sequence; 
 int m_sequence_id_num; 
 DWORD m_walk_sequence, m_stand_sequence, m_fall_sequence, 
m_attack_sequence, m_pain_sequence; 
 DWORD m_skin_bitmap, m_pain_bitmap; 
 double m_acceleration; 
 int m_effort; //su dung thiet lap nhip tho khi nhan vat dang dung 
 double m_friction; 
 double m_max_speed; 
 double m_min_speed; 
 int m_skin_id; // 0 khi su dung skin bitmap. 1 khi su dung pain bitmap 
 double m_height; 
 char m_bitmap_path[MAX_PATH]; 
 //Tao cong thuc tinh luc ma sat va trong luc len nhan vat 
 double get_friction_and_gravity_factor(void); 
 DWORD set_animation_sequence(char *sequence_name, int 
transition_duration); 
 //Thiet lap cac them so theo ti le kich thuoc 
 //Khi trang thai nhan vat thay doi thi cac thuoc tinh cung thay doi 
 void set_parameters_according_to_scale(void); 
 //Lua chon mot trinh tu dung de mo phong tai mot vi tri 
 //Nhu chuyen doi tu mot trang thai dang chay thanh trang thai dung 
 void select_sequence(); 
 //Tao trinh tu tho khi nhan vat dang dung 
 double get_standing_sequence_speed(void); 
 //Thiet lap trinh tu toc do 
 void set_sequence_speed(void); 
 //lap lai hanh dong nhan vat theo moi thoi gian co the 
 int update_according_to_new_animation(void); 
 //Xac dinh mot diem duoi nen 
 DWORD get_polygon_below(double point_below[3]); 
}; 
#endif // PLAYER_H 
// camera.h 
#ifndef CAMERA_H 
#define CAMERA_H 
//#include "mrft_api.h" 
#include 
 59
class camera 
{ 
public: 
 camera(); 
 virtual ~camera(); 
 int init(DWORD object_to_chase); 
 void move(void); 
 void zoom_out(void); 
 void zoom_in(void); 
 void set_chase_flexible_mode(void); 
 void set_chase_location_mode(void); 
 void stop_chasing(void); 
 void update_chase_params(void); 
 DWORD m_camera_handle; 
private: 
 DWORD m_object_to_chase; 
}; 
#endif // CAMERA_H 
/ anim3d.cpp 
////////////////////////////////////////////////////////////////////// 
#include 
#include 
#include 
//#include 
#include "..\\..\\..\\..\\..\\Engine\\Include\\mrft_api.h" 
#include "player.h" 
#include "camera.h" 
int init_stuff(player *player1, player *player2, camera *camera1, DWORD 
*animation1, DWORD *animation2); 
void settings(camera *camera1, player *player1, DWORD anim1, DWORD anim2); 
void help_popup(void); 
void set_vector(double vector[3], double x, double y, double z); 
void main() 
{ 
 player player1, player2; //thu voi player 1 
 camera camera1; 
 DWORD animation1, animation2; 
 60
 help_popup(); 
 if(init_stuff(&player1,&player2, &camera1, &animation1, 
&animation2)==VR_ERROR) 
 { 
 printf("Co loi trong khi thiet lap the gioi\nAn mot nut bat ki de thoat"); 
 getch(); 
 return; 
 } 
 while( (GetAsyncKeyState(VK_ESCAPE)&1) ==0 ) //GetAsyncKeyState() la 
mot ham API cua WIN32 (not Morfit) 
 { 
 //Ham nay kiem tra xem nut Escape da duoc an chua 
 player1.move(); 
 camera1.move(); 
 Morfit_engine_render(NULL,camera1.m_camera_handle); //Dua 1 anh 
toi camera va dat no vao cua so mo phong mac dinh 
 settings(&camera1, &player1, animation1, animation2); //scan keyboard 
and thay doi global theo thiet lap 
 } 
 Morfit_engine_close(); 
} 
void help_popup(void) 
{ 
 if(Morfit_3D_card_is_used() == YES && 
Morfit_3D_card_is_full_screen_mode() == YES) 
 return; 
 int file_size; 
 char *buff = (char *)Morfit_utilities_file_to_memory("help.txt", &file_size); 
 MessageBox(NULL,buff,"Help", MB_ICONINFORMATION); 
 Morfit_utilities_free_file_memory(buff); 
} 
//Thay doi thiet lap chuong trinh theo dau vao cua ban phim 
void settings(camera *camera1, player *player1, DWORD anim1, DWORD anim2) 
{ 
 //Zoom out voi camera 
 if(GetAsyncKeyState('A')<0) 
 { 
 camera1->zoom_out(); 
 } 
 61
 else if(GetAsyncKeyState('Z')<0) //Zoom in voi camera 
 { 
 camera1->zoom_in(); 
 } 
 int scale_flag = 0; 
 //Ti le kich thuoc tuong ung voi kich thuoc nhan vat 
 if( GetAsyncKeyState('S')<0 ) 
 { 
 player1->scale(1.1, X_AXIS|Y_AXIS|Z_AXIS); 
 scale_flag++; 
 } 
 else if( GetAsyncKeyState('X')<0 ) 
 { 
 player1->scale(0.9, X_AXIS|Y_AXIS|Z_AXIS); 
 scale_flag++; 
 } 
 else if(GetAsyncKeyState('W')<0) //Thiet lap ti le kich thuoc mac dinh 
 { 
 player1->scale_default(); 
 scale_flag++; 
 } 
 //Ti le kich thuoc theo truc X(tao cho nhan vat map len hay gay xuong) 
 if( GetAsyncKeyState('D')<0) 
 { 
 player1->scale(1.1, X_AXIS); 
 scale_flag++; 
 } 
 else if( GetAsyncKeyState('C')<0) 
 { 
 player1->scale(0.9, X_AXIS); 
 scale_flag++; 
 } 
 //Ti le kich thuoc theo truc Y(tao cho nhan vat rong len hay hep di) 
 if( GetAsyncKeyState('G')<0) 
 { 
 player1->scale(1.1, Y_AXIS); 
 scale_flag++; 
 } 
 62
 else if( GetAsyncKeyState('B')<0) 
 { 
 player1->scale(0.9, Y_AXIS); 
 scale_flag++; 
 } 
 //Ti le kich thuoc theo truc Z(tao cho nhan vat cao len hay thap xuong) 
 if( GetAsyncKeyState('H')<0) 
 { 
 player1->scale(1.1, Z_AXIS); 
 scale_flag++; 
 } 
 else if( GetAsyncKeyState('N')<0) 
 { 
 player1->scale(0.9, Z_AXIS); 
 scale_flag++; 
 } 
 if(scale_flag) 
 camera1->update_chase_params(); 
 if( (GetAsyncKeyState('F')&1) && (GetAsyncKeyState('F')<0)) 
 { 
 if(Morfit_3D_card_is_used() == NO || 
Morfit_3D_card_is_full_screen_mode() == NO) 
 { 
 if(Morfit_3D_card_set_full_screen_mode(800,600) == VR_ERROR) 
 { 
 if(Morfit_3D_card_check_hardware_support() == YES) 
 { 
 MessageBox(NULL, "Loi cai dat 3D card.\n \nVui long kiem tra 3D card 
and DirectX 6.1 \n","No 3D card", MB_OK); 
 } 
 } 
 } 
 } 
 else if((GetAsyncKeyState('V')&1) && (GetAsyncKeyState('V')<0)) 
 { 
 if(Morfit_3D_card_is_used() == NO || 
Morfit_3D_card_is_full_screen_mode() == YES) 
 { 
 63
 Morfit_engine_maximize_default_rendering_window(); 
 if(Morfit_3D_card_set_window_mode() == VR_ERROR) 
 { 
 if(Morfit_3D_card_check_hardware_support() == YES) 
 { 
 MessageBox(NULL, "Loi cai dat 3D card.\n \nVui 
long kiem tra 3D card and DirectX 6.1 \n","No 3D card", MB_OK); 
 } 
 } 
 } 
 } 
 else if((GetAsyncKeyState('R')&1)&& (GetAsyncKeyState('R')<0)) 
 { 
 Morfit_3D_card_use(NO); 
 Morfit_engine_set_default_rendering_window_size(240,180,400,400); 
 } 
 if(GetAsyncKeyState('1')<0) 
 { 
 camera1->set_chase_location_mode(); 
 } 
 else if(GetAsyncKeyState('2')<0) 
 { 
 camera1->set_chase_flexible_mode(); 
 } 
 else if(GetAsyncKeyState('3')<0) 
 { 
 camera1->stop_chasing(); 
 } 
 if(GetAsyncKeyState('4')<0) 
 { 
 player1->attack(); 
 } 
 else if(GetAsyncKeyState('5')<0) 
 { 
 player1->pain(); 
 } 
 if(GetAsyncKeyState('6')&1) 
 64
 { 
 player1->replace_skin(); 
 } 
 static int anim_toggle = 0; 
 if(GetAsyncKeyState('7')&1) 
 { 
 if(anim_toggle == 0) 
 { 
 player1->replace_shape(anim2, "..\\..\\..\\..\\..\\Worlds\\player2"); 
 anim_toggle = 1; 
 } 
 else 
 { 
 player1->replace_shape(anim1, "..\\..\\..\\..\\..\\Worlds\\player1"); 
 anim_toggle = 0; 
 } 
 } 
 if(GetAsyncKeyState(VK_F1)&1) 
 { 
 help_popup(); 
 } 
} 
int init_stuff(player *player1, player *player2, camera *camera1,DWORD 
*animation1, DWORD *animation2) 
{ 
 //Morfit_3D_card_use(YES); 
 int rc = Morfit_engine_load_world("..\\..\\..\\..\\..\\worlds\\country.wld", NULL, 
 "..\\..\\..\\..\\..\\worlds\\bitmaps", USER_DEFINED_BEHAVIOR); 
 if(rc != OK) 
 return(VR_ERROR); 
 // Morfit_3D_sequence_duplicate() 
 if(player1->init("..\\..\\..\\..\\..\\Worlds\\player1\\player.md2", 
"..\\..\\..\\..\\..\\Worlds\\player1") == VR_ERROR) 
 return(VR_ERROR); 
 if(player2->init("..\\..\\..\\..\\..\\Worlds\\player2\\player.md2", 
"..\\..\\..\\..\\..\\Worlds\\player2") == VR_ERROR) 
 return(VR_ERROR); 
 *animation1 = Morfit_object_get_3D_animation(player1->m_player_object); 
 65
 *animation2 = Morfit_object_get_3D_animation(player2->m_player_object); 
 //disable player2 
 Morfit_object_disable(player2->m_player_object); 
 //Xac dinh vi tri nhan vat 
 //Trong truong hop Z==10000 la vi itri cua nhan vat o duoi nen 
 //Sau do nhan vat se duoc dieu chinh toi mot vi tri tot hon. 
 Morfit_object_move(player1->m_player_object,OBJECT_SPACE, -
1000,0,10000); 
 if(camera1->init(player1->m_player_object) != OK) 
 return(VR_ERROR); 
 //Vai thiet lap voi cua so 
 // 
 //Cac hieu ung nay chi tren pm mo phong 
 Morfit_engine_set_picture_quality(640*480); 
 Morfit_engine_maximize_default_rendering_window(); 
 Morfit_engine_set_default_rendering_window_title("Do an tot nghiep. Cac 
phim dieu khien: F1, A,Z,X,S,W,1,2,3,4,5,6,7, V,F,R,D,C,H,N, ESC"); 
 Morfit_engine_set_atmospheric_effect_intensity(0); 
 ShowCursor(FALSE); 
 if(Morfit_3D_card_set_window_mode() == VR_ERROR) 
 { 
 if(Morfit_3D_card_check_hardware_support() == YES) 
 { 
 MessageBox(NULL, "Failed to initialize your 3D card.\n This sample only 
works with hardware rendering\nPlease check that you have a 3D card and DirectX 6.1 
and above\n","No 3D card", MB_OK); 
 } 
 //Tao ra mot cua so nho cho pm mo phong 
 Morfit_engine_set_default_rendering_window_size(240,180,400,400); 
 } 
 Morfit_engine_hide_log_window(); 
 return(OK); 
} 
//Ham tao vecto toa do 
void set_vector(double vector[3], double x, double y, double z) 
{ 
 vector[0] = x; 
 vector[1] = y; 
 vector[2] = z; 
 66
} 
// player.cpp 
// 
////////////////////////////////////////////////////////////////////// 
#include 
#include 
#include "player.h" 
#include "..\\..\\..\\..\\..\\Engine\\Include\\mrft_api.h" 
//Ham tao vecto toa do 
void set_vector(double vector[3], double x, double y, double z); 
player::player() 
{ 
} 
player::~player() 
{ 
} 
int player::init(char *file_name, char *bitmap_path) 
{ 
 m_speed = 0; 
 m_friction = 0.8; 
 m_max_speed = 50; 
 m_min_speed = 2; 
 m_skin_id = 0; 
 m_player_object = Morfit_object_create_from_file(file_name); 
 if(m_player_object == NULL) 
 return(VR_ERROR); 
 double scale[3] = {3,3,3}; 
 Morfit_object_set_scale(m_player_object, scale); 
 strcpy(m_bitmap_path, bitmap_path); 
 return(update_according_to_new_animation()); 
} 
int player::update_according_to_new_animation(void) 
{ 
 //load chung khi can toi anh. engine se ko du de load cac anh da co san trong bo nho 
 char buff[MAX_PATH]; 
 strcpy(buff,m_bitmap_path); 
 strcat(buff,"\\skin.bmp"); 
 m_skin_bitmap = Morfit_bitmap_load(buff,-1); 
 strcpy(buff,m_bitmap_path); 
 67
 strcat(buff,"\\pain.bmp"); 
 m_pain_bitmap = Morfit_bitmap_load(buff,-1); 
 //thiet lap trang phuc 
 Morfit_object_set_bitmap(m_player_object, m_skin_bitmap); 
 set_parameters_according_to_scale(); 
 m_current_sequence = set_animation_sequence("stand", 0); 
 m_sequence_id_num = STAND; 
 m_stand_sequence = m_current_sequence; 
 DWORD anim3d = Morfit_object_get_3D_animation(m_player_object); 
 m_fall_sequence = Morfit_3D_sequence_get_using_name(anim3d, "death"); 
 if(m_fall_sequence != NULL) 
 { 
 int num_of_frames = 
Morfit_3D_sequence_get_number_of_frames(m_fall_sequence); 
 //dung trinh tu nga trong mot trang thai rieng 
 Morfit_3D_sequence_set_frame_duration(m_fall_sequence, 
num_of_frames-2, 1000000); 
 Morfit_3D_sequence_set_speed(m_fall_sequence,0.5); //times nhanh 
hon 2 lan 
 } 
 m_walk_sequence = Morfit_3D_sequence_get_using_name(anim3d, "walk"); 
 if(m_walk_sequence == NULL) 
 return(VR_ERROR); 
 m_attack_sequence = Morfit_3D_sequence_get_using_name(anim3d, "attak"); 
 m_pain_sequence = Morfit_3D_sequence_get_using_name(anim3d, "pain"); 
 return(OK); 
} 
//Thiet lap cac them so theo ti le kich thuoc 
//Khi trang thai nhan vat thay doi thi cac thuoc tinh cung thay doi 
void player::set_parameters_according_to_scale() 
{ 
 double scale[3]; 
 Morfit_object_get_scale(m_player_object, scale); 
 m_acceleration = ACCELERATION * scale[2] / 5; 
 if(m_acceleration < ACCELERATION) 
 m_acceleration = ACCELERATION; 
 m_max_speed = MAX_SPEED * scale[2] / 3; 
 m_min_speed = MIN_SPEED * scale[2] / 3; 
 //thiet lap chieu cao 
 68
 double box[2][3]; 
 Morfit_object_get_bounding_box(m_player_object, box); 
 m_height = box[1][2] - box[0][2]; 
} 
DWORD player::set_animation_sequence(char *sequence_name, int 
transition_duration) 
{ 
 DWORD anim3d = Morfit_object_get_3D_animation(m_player_object); 
 DWORD sequence = Morfit_3D_sequence_get_using_name(anim3d, 
sequence_name); 
 if(sequence == NULL) 
 return(NULL); 
 Morfit_object_set_3D_sequence(m_player_object, sequence, 
transition_duration); 
 return(sequence); 
} 
void player::move(void) 
{ 
 int muscle_force_used = NO; 
 double save_location[3]; 
 //ghi lai vi tri trong truong hop nhan vat muon toi. 
 Morfit_object_get_location(m_player_object, &save_location[0], 
&save_location[1], &save_location[2]); 
 DWORD sequence = Morfit_object_get_3D_sequence(m_player_object); 
 if(m_sequence_id_num == WALK || sequence == m_stand_sequence) 
 { 
 //tien phia truoc 
 if(GetAsyncKeyState(VK_UP) < 0) 
 { 
 m_speed += m_acceleration; 
 muscle_force_used = YES; 
 } 
 //lui phia sau 
 if(GetAsyncKeyState(VK_DOWN) < 0) 
 { 
 muscle_force_used = YES; 
 m_speed -= m_acceleration; 
 } 
 } 
 69
 if(m_sequence_id_num == WALK || sequence == m_stand_sequence || sequence 
== m_attack_sequence || sequence == m_pain_sequence) 
 { 
 //sang trai 
 if(GetAsyncKeyState(VK_LEFT) < 0) 
 { 
 Morfit_object_rotate_z(m_player_object, 6, WORLD_SPACE); 
 } 
 //sang phai 
 if(GetAsyncKeyState(VK_RIGHT) < 0) 
 { 
 Morfit_object_rotate_z(m_player_object, -6, WORLD_SPACE); 
 } 
 } 
 double gravity_and_friction_factor = get_friction_and_gravity_factor(); 
 if(muscle_force_used == NO || fabs(m_speed) > m_min_speed) 
 { 
 m_speed *= gravity_and_friction_factor; 
 if(muscle_force_used == YES) 
 if(fabs(m_speed) < fabs(m_min_speed)) 
 m_speed = m_min_speed * m_speed / fabs(m_speed); 
 } 
 if(m_speed > m_max_speed) 
 m_speed = m_max_speed; 
 if(m_speed < -m_max_speed) 
 m_speed = -m_max_speed; 
 Morfit_object_move(m_player_object,OBJECT_SPACE, -m_speed,0,0); 
 select_sequence(); 
 // xac dinh mot diem duoi cung nen 
double point_below[3]; 
 get_polygon_below(point_below); 
 //chieu cao giua cua nhan vat co the la chieu cao len + chieu cao than tinh 
 // tu giua xuong duoi (m_height/2) 
 double new_altitude = point_below[2] + m_height / 2; 
 if(new_altitude > save_location[2] + m_height / 3) 
 { 
 Morfit_object_set_location(m_player_object, save_location[0], 
save_location[1], save_location[2]); 
 70
 m_speed = -m_speed * 0.5; 
 } 
 else 
 { 
 double location[3]; 
 Morfit_object_get_location(m_player_object, &location[0], 
&location[1], &location[2]); 
 Morfit_object_set_location(m_player_object, location[0], location[1], 
new_altitude); 
 } 
} 
double player::get_friction_and_gravity_factor() 
{ 
 //cong thuc tinh trong luc 
 // player_mass*earth_gravity*sin(alpha) 
 double plane[4]; 
 double point_below[3]; 
 DWORD polygon = get_polygon_below(point_below); 
 if(polygon==NULL) 
 return(m_friction); 
 Morfit_polygon_get_plane(polygon, plane); 
 double gravity_direction[3]; 
 double z_vector[3] = {0,0,1}; 
 Morfit_math_cross(plane, z_vector, gravity_direction); 
 Morfit_math_cross( plane, gravity_direction, gravity_direction); 
 Morfit_math_normalize_vector(gravity_direction); 
 if(plane[2] 1) 
 return(m_friction); //khong co gi xay ra 
 double cos_alpha = plane[2]; 
 double alpha = acos(cos_alpha); 
 double gravity_force = sin(alpha); //m*g*sin(alpha) . m*g==80. m==mass. 
g==earth gravity 
 double direction[3]; 
 Morfit_object_get_direction(m_player_object, &direction[0], &direction[1], 
&direction[2]); 
 double gravity_factor = Morfit_math_product(gravity_direction, direction); 
 if(m_speed < 0) 
 gravity_factor = -gravity_factor; 
 71
 //nhan vat nga xuong khi toc do qua cao hoac luc tac dung qua lon 
 if((m_sequence_id_num != FALL) && (gravity_factor * gravity_force > 0.3) 
&& (fabs(m_speed) > 0.8 * m_max_speed)) 
 { 
 m_current_sequence = set_animation_sequence("death",300); 
 m_sequence_id_num = FALL; 
 } 
 double result = m_friction+gravity_factor * gravity_force; 
 if(result < 0) 
 result = 0; 
 return(result); 
} 
void player::select_sequence() 
{ 
 DWORD sequence = Morfit_object_get_3D_sequence(m_player_object); 
 if(sequence == m_stand_sequence) 
 { 
 m_sequence_id_num = STAND; 
 m_current_sequence = m_stand_sequence; 
 } 
 else 
 { 
 if(sequence == m_walk_sequence) 
 m_sequence_id_num = WALK; 
 m_current_sequence = m_walk_sequence; 
 } 
 // chi mot trinh tu ket thuc thi trinh tu khac moi duoc bat dau 
 // trinh tu van chuyen duoc tao ra tu dong 
 if( (sequence == m_walk_sequence) && (m_speed < m_min_speed && 
m_speed > -m_min_speed)) 
 { 
 m_current_sequence = set_animation_sequence("stand",100); 
 m_sequence_id_num = STAND; 
 } 
 else if((sequence == m_stand_sequence) && (m_speed >= m_min_speed || 
m_speed <= -m_min_speed)) 
 { 
 m_current_sequence = set_animation_sequence("walk",100); 
 m_sequence_id_num = WALK; 
 72
 } 
 else if((sequence == m_fall_sequence) && (m_speed < m_min_speed && 
m_speed > -m_min_speed)) 
 { 
 //kiem tra trinh tu nga da ket thuc hay chua 
 DWORD anim3d = Morfit_object_get_3D_animation(m_player_object); 
 DWORD fall_sequence = 
Morfit_3D_sequence_get_using_name(anim3d, "death"); 
 int num_of_frames = 
Morfit_3D_sequence_get_number_of_frames(fall_sequence); 
 double current_position = 
Morfit_3D_sequence_get_current_frame(fall_sequence); 
 if(current_position >= num_of_frames - 2) 
 { 
 m_current_sequence = set_animation_sequence("stand",1000); 
 m_sequence_id_num = STAND; 
 } 
 } 
 if(m_sequence_id_num!=FALL) 
 { 
 //thiet lap mot trinh tu dung 
 if(m_speed<0 ) 
 { 
 Morfit_3D_sequence_backwards_play(m_current_sequence,YES); 
 } 
 else 
 { 
 Morfit_3D_sequence_backwards_play(m_current_sequence,NO); 
 } 
 } 
 set_sequence_speed(); 
} 
void player::set_sequence_speed() 
{ 
 double sequence_speed=1; 
 if(m_sequence_id_num==FALL || m_sequence_id_num==ATTACK || 
m_sequence_id_num==PAIN) 
 return; 
 73
 if(m_sequence_id_num==STAND) 
 sequence_speed=get_standing_sequence_speed(); 
 else 
 { 
 double abs_speed=m_speed; 
 if(abs_speed<0) 
 abs_speed=-abs_speed; 
 m_effort++; 
 //xay dung moi lien ket giua toc do va trinh tu toc do 
 // sequence_speed=F(player_speed); 
 //toc do nhan vat la 1 thi trinh tu toc do se la 0.7 
 //toc do nhan vat la to m_max_speed tthi trinh tu toc do se la 0.25 
 //thay doi cac thiet lap de nhin thay su thay doi cac hieu ung 
 double seq_speed1=0.7; //trinh tu toc do khi toc do nguoi choi la 1. 
 double seq_speed_max=0.35; 
 //trinh tu toc do khi toc do nguoi choi la m_max_speed. 
//cap nhap toc do theo ti le kich thuoc nhan vat 
 double scale[3]; 
 Morfit_object_get_scale(m_player_object, scale); 
 seq_speed1*=(1+scale[2]/200); 
 seq_speed_max*=(1+scale[2]/200); 
 //pt duong thang y=a*x+b 
 if((m_max_speed-1) <=0) 
 return; //bao dam de ko chia cho 0 
 double a=(seq_speed_max-seq_speed1)/(m_max_speed -1); 
 double b=seq_speed1-a; 
 sequence_speed=a*abs_speed+b; 
 if(sequence_speed<seq_speed_max) 
 sequence_speed=seq_speed_max; 
 } 
 Morfit_3D_sequence_set_speed(m_current_sequence, sequence_speed); 
} 
//Tao trinh tu tho khi nhan vat dang dung 
double player::get_standing_sequence_speed() 
{ 
 //This formula gives tempo==0.1 when effort=0 
 //and tempo 0.1 when effort==400 
 double tempo=-(double)m_effort/400+0.8; 
 if(tempo<0.1) 
 74
 tempo=0.1; 
 m_effort=m_effort-1; 
 if(m_effort<0) 
 m_effort=0; 
 if(m_effort>500) 
 m_effort=500; 
 return(tempo); 
} 
//Xac dinh vung duoi nen 
DWORD player::get_polygon_below(double point_below[3]) 
{ 
 double location[3]; 
 Morfit_object_get_location(m_player_object, &location[0], &location[1], 
&location[2]); 
 double up_location[3], down_location[3]; 
 set_vector(up_location, location[0], location[1], 1000000); 
 set_vector(down_location, location[0], location[1], -1000000); 
 DWORD terrain_poly, blocking_object; 
 int flag=Morfit_object_is_movement_possible(m_player_object, up_location, 
down_location, &terrain_poly, point_below, &blocking_object); 
 if(flag==YES) 
 { 
 printf("An error occurred, there is now ground below !!!\n"); 
 return(NULL); 
 } 
 return(terrain_poly); 
} 
//Thiet lap ti le kich thuoc mac dinh 
void player::scale_default(void) 
{ 
 double scale[3]={3,3,3}; 
 Morfit_object_set_scale(m_player_object,scale); 
 set_parameters_according_to_scale(); 
} 
//ti le kich thuoc nhan vat theo cac truc x,y,x hoac co the ket hop giua cac truc 
void player::scale(double factor, int axis) 
{ 
 double scale[3]; 
 75
 Morfit_object_get_scale(m_player_object,scale); 
 if(axis & X_AXIS) 
 scale[0]*=factor; 
 if(axis & Y_AXIS) 
 scale[1]*=factor; 
 if(axis & Z_AXIS) 
 scale[2]*=factor; 
 Morfit_object_set_scale(m_player_object,scale); 
 set_parameters_according_to_scale(); 
} 
//trang thai tan cong 
void player::attack(void) 
{ 
 if(m_attack_sequence==NULL) 
 return; 
 //trinh tu tan cong duoc xay dung boi rat nhieu trang thai tan cong nhu cam 
sung,ban.... 
 Morfit_object_set_3D_sequence(m_player_object, m_attack_sequence, 0); 
 Morfit_object_replace_3D_sequence_when_finished(m_player_object, 
m_stand_sequence,300); 
 m_current_sequence=m_attack_sequence; 
 m_sequence_id_num=ATTACK; 
} 
//trang thai bi thuong 
void player::pain(void) 
{ 
 if(m_pain_sequence==NULL) 
 return; 
 Morfit_object_set_3D_sequence(m_player_object, m_pain_sequence, 0); 
 Morfit_object_replace_3D_sequence_when_finished(m_player_object, 
m_stand_sequence,400); 
 m_current_sequence=m_pain_sequence; 
 m_sequence_id_num=PAIN; 
} 
//Lay lai trang phuc cho nhan vat,chinh la chuyen doi giua cac anh 
void player::replace_skin(void) 
{ 
 if(m_skin_id==0) 
 { 
 76
 Morfit_object_set_bitmap(m_player_object, m_pain_bitmap); 
 m_skin_id=1; 
 return; 
 } 
 Morfit_object_set_bitmap(m_player_object, m_skin_bitmap); 
 m_skin_id=0; 
} 
//Lay lai hinh dang ban dau cho nhan vat 
void player::replace_shape(DWORD anim3d, char *bitmap_path) 
{ 
 Morfit_object_set_3D_animation(m_player_object, anim3d); 
 strcpy(m_bitmap_path, bitmap_path); 
 update_according_to_new_animation(); 
} 
 77
TÀI LIỆU THAM KHẢO 
[1]. Nguyễn Văn Huân- Vũ Đức Thái, Kỹ thuật lập trình mô phỏng thế giới thực 
dựa trên Morfit 
[2]. Một số trang web như: 
http:// www.3dnews.com 
 - The site for the Morfit VC++ developers, run by Bucky 
(Brad Buchanan). 
 - Morfit Developer Mailing List 
- The Morfit official mailing list. 
http:// www.3dng.com - Morfit 3D for Euphoria Web Page. Run by Mark Brown. 
 - Morfit for Borland Builder C++ users. 
 - Beros 3D World - One of the most promising arcade 
games under development. Visit to see screenshots and a demo. 
 - Morfit Projects - This page includes links 
and information on different Morfit projects. 
            Các file đính kèm theo tài liệu này:
 Mô phỏng hành động nhân vật trong xây dựng mô hình 3d.pdf Mô phỏng hành động nhân vật trong xây dựng mô hình 3d.pdf