Cái này trả lời lonelyheart trong thread Demo...
Hìhì, lonelyheart làm game gì bí mật á? Bạn dùng DirectX phải ko? Hồi trước mình cũng bị mắc cái khúc mưa tuyết này, mình làm bằng OpenGL nhưng mà cách làm thì cũng ko khác lắm đâu.
Quan trọng của render rain và snow là fps hay bị giảm kinh khủng, đó là do 2 chuyện: tính toán (cập nhật trạng thái các hạt nhiều) và render (dễ bị pixel overdraw). Hai chuyện này ko dễ nhưng mà cũng có thể giải quyết được phần nào.
Mình hay làm mí hiệu ứng này bằng design mí cái particle system đơn giản. Trong trường hợp đơn giản này, mỗi particle của mình chỉ cần 2 toạ độ trước và hiện thời, tốc độ và góc quay (rot) là đủ. Mưa ko cần rot còn tuyết thì ko cần toạ độ sau. Vẽ mưa bằng line nên cần 2 toạ độ, còn tuyết thì bạn đòi nó "quay quay" nên cần rot nữa, đúng ko?
Tối ưu tính toán: Chuyện này phải tối ưu rùi. Bạn tính cho 1000 particle có thể nói là khá ít, mưa kiểu này là mưa phùn rùi , nhưng mà nếu ko tối ưu cách cập nhật thì cũng chậm như thường. Chỉ cái gì cần tính thì tính thui, tối ưu phép tính tối đa (cứ mỗi phép tính dư sẽ bị nhân lên 1000 lần, chậm đáng kể). Bạn làm scale, location làm gì, dư nhiều nên chậm đúng tùi. Chỉ cần các bước sau:
- Cập nhật:
prev_loc=current_loc
- Cập nhật trạng thái:
speed=speed+gravity*delta_t
- Tính toạ độ mới của mưa, thêm tốc độ gió để làm khi hiệu ứng chuyển động, mưa sẽ bị rơi xiên xiên...
current_loc.X=prev_loc.X-Windspeed.X*delta_t
current_loc.Y=prev_loc.Y-Windspeed.Y*delta_t
current_loc.Y=prev_loc.Y-(Windspeed.Y-speed)*delta_t
- Kiểm tra xem mưa có rơi khỏi vùng kiểm soát ko, nếu có, tạo lại hạt mưa mới (dùng random cho loc và speed)
Đối với tuyết, bạn cập nhật thêm rot=rot*delta_t với giá trị ban đầu là random, Hiệu ứng này làm bông tuyết xoay tròn khá ngẫu nhiên, giá trị rot ban đầu nên chọn từ 0 cho đến khoảng 30deg/s, nhanh quá nhìn ko ra tuyết gì đâu...
Vẽ mưa dùng blended line (line từ prev_loc đến current_loc), còn tuyết dùng billboard texture, dễ phải ko?
Mình tối ưu cách tính toán như cách trên thì ct của mình có thể cập nhật khoảng thêm >>20000 particle mà fps drop chỉ khoảng cỡ 20 mà thui (ct mình đạt 60 fps ở 1024x768x16bit). Tuy nhiên hiện thời mình có thể tính cho khoảng >>27000 particle mà fps ko drop tí nào, mình dùng một cái mẹo nhỏ, bạn thử xem, kết quả ko ngờ.
Mình dùng một particle system khoảng 3000 hạt, tính khá nhanh, ko giảm fps đoi tí nào, nhưng mà 3000 particle chỉ tạo được mưa phùn thui, cho nên mình dùng một hệ này, vẽ 9 lần xung quanh vị trí hiện thời, như vậy mình chỉ cần update hệ hạt một lần mà được hẳn 27000 hạt, đã quá phải ko? Bạn cứ thử xem trên máy bạn, mình dùng AthlonXP nên tính nhanh, bạn thử dùng hệ 100 hạt rồi vẽ 25 lần thử xem?
Nhìn từ trên xuống:
x x x
x X x
x x x
với: X: vị trí hiện thời. x: các vị trí vẽ hệ.
Tuyết cay hơn nhiều vì dùng texture mờ, nhưng mà với thuật toán trên cũng khá tốt, dùng y chang (chỉ đổi code vẽ mưa thành tuyết, fps mình bị giảm 20, còn khoảng 50fps, có thể chấp nhận được tốt!!!).
Tối ưu render: Dùng Frustum Culling. Mình nghe nói DirectX cho hàm Frustum Culling à? OpenGL thì phải tự viết. Làm theo cách trên thì mình test xem các hệ ở các vị trí (9 vị trí) có nằm trong tầm nhìn ko. Ko test sẽ làm fps giảm còn một nửa nên phải thực hiện bước này, nhất là với tuyết. Billboard của mình tự viết, ko cần tính toán lại cho mỗi quad nên khá nhanh, ko biết billboard của bạn ra sao? Nếu billboard tính nhiều thì nên viết lại, chẳng hạn vẽ vài ngàn quad billboard và ko billboard mà thấy fps giảm nhiều quá thì nên viết lại cho chắc.
Chúc bạn thành công. Mình dùng thuật toán trên trong Flight Simulation của mình, bạn xem thử 2 screen shot sau, 27000 particle được cập nhật và render nếu được ở mỗi bước. Cái này là mưa...
Bookmarks