【CG物理模擬系列】流體模擬--粒子法之SPH(程式碼講解)
沒有繪製水面,只是實現了最基本的SPH演算法原理,以供參考。#include "sph_system.h" #include "sph_header.h" SPHSystem::SPHSystem() { max_particle=30000; num_particle=0; kernel=0.04f; mass=0.02f; //初始化空間大小,並計算網格size world_size.x=0.64f; world_size.y=0.64f; world_size.z=0.64f; cell_size=kernel; grid_size.x=(uint)ceil(world_size.x/cell_size); grid_size.y=(uint)ceil(world_size.y/cell_size); grid_size.z=(uint)ceil(world_size.z/cell_size); tot_cell=grid_size.x*grid_size.y*grid_size.z; gravity.x=0.0f; gravity.y=-6.8f; gravity.z=0.0f; wall_damping=-0.5f; rest_density=1000.0f; //初始密度 gas_constant=1.0f; //氣體系數 viscosity=6.5f; time_step=0.003f; surf_norm=6.0f; surf_coe=0.1f; poly6_value=315.0f/(64.0f * PI * pow(kernel, 9));; spiky_value=-45.0f/(PI * pow(kernel, 6)); visco_value=45.0f/(PI * pow(kernel, 6)); grad_poly6=-945/(32 * PI * pow(kernel, 9)); lplc_poly6=-945/(8 * PI * pow(kernel, 9)); kernel_2=kernel*kernel; self_dens=mass*poly6_value*pow(kernel, 6); self_lplc_color=lplc_poly6*mass*kernel_2*(0-3/4*kernel_2); mem=(Particle *)malloc(sizeof(Particle)*max_particle); cell=(Particle **)malloc(sizeof(Particle *)*tot_cell); sys_running=0; } SPHSystem::~SPHSystem() { free(mem); free(cell); } void SPHSystem::update() { if(sys_running == 0) { return; } build_table(); comp_dens_pres(); comp_force_adv(); advection(); } void SPHSystem::init_system() { float3 pos; float3 vel; vel.x=0.0f; vel.y=0.0f; vel.z=0.0f; for(pos.x=world_size.x*0.2f; pos.x<world_size.x*0.8f; pos.x+=(kernel*0.5f)) { for(pos.y=world_size.y*0.5f; pos.y<world_size.y*0.9f; pos.y+=(kernel*0.5f)) { for(pos.z=world_size.z*0.2f; pos.z<world_size.z*0.8f; pos.z+=(kernel*0.5f)) { add_particle(pos, vel); } } } printf("Init Particle: %u\n", num_particle); } //新增粒子 void SPHSystem::add_particle(float3 pos, float3 vel) { Particle *p=&(mem[num_particle]); p->id=num_particle; p->pos=pos; p->vel=vel; p->acc.x=0.0f; p->acc.y=0.0f; p->acc.z=0.0f; p->ev.x=0.0f; p->ev.y=0.0f; p->ev.z=0.0f; p->dens=rest_density; p->pres=0.0f; p->next=NULL; num_particle++; } void SPHSystem::build_table() { Particle *p; uint hash; for(uint i=0; i<tot_cell; i++) { cell[i]=NULL; } //建立hash表 for(uint i=0; i<num_particle; i++) { p=&(mem[i]); hash=calc_cell_hash(calc_cell_pos(p->pos)); if(cell[hash] == NULL) { p->next=NULL; cell[hash]=p; } else { p->next=cell[hash]; cell[hash]=p; } } } void SPHSystem::comp_dens_pres() { Particle *p; //當前粒子 Particle *np; //周圍粒子 int3 cell_pos; //粒子所屬cell座標 int3 near_pos; //周圍粒子座標 uint hash; float3 rel_pos; float r2; for(uint i=0; i<num_particle; i++) { p=&(mem[i]); cell_pos=calc_cell_pos(p->pos); p->dens=0.0f; p->pres=0.0f; for(int x=-1; x<=1; x++) { for(int y=-1; y<=1; y++) { for(int z=-1; z<=1; z++) { near_pos.x=cell_pos.x+x; near_pos.y=cell_pos.y+y; near_pos.z=cell_pos.z+z; hash=calc_cell_hash(near_pos); if(hash == 0xffffffff) { continue; } np=cell[hash]; //掃描kernel_2範圍內的粒子 while(np != NULL) { rel_pos.x=np->pos.x-p->pos.x; rel_pos.y=np->pos.y-p->pos.y; rel_pos.z=np->pos.z-p->pos.z; r2=rel_pos.x*rel_pos.x+rel_pos.y*rel_pos.y+rel_pos.z*rel_pos.z; if(r2<INF || r2>=kernel_2) { np=np->next; continue; } p->dens=p->dens + mass * poly6_value * pow(kernel_2-r2, 3); np=np->next; } } } } //密度及壓力 p->dens=p->dens+self_dens; p->pres=(pow(p->dens / rest_density, 7) - 1) *gas_constant; //這裡使用了Tait方程,詳見理論那篇文章 } } void SPHSystem::comp_force_adv() { Particle *p; //當前粒子 Particle *np; //周圍粒子 int3 cell_pos; //所屬cell位置 int3 near_pos; //檢測周圍粒子位置 uint hash; float3 rel_pos; float3 rel_vel; float r2; float r; float kernel_r; float V; float pres_kernel; float visc_kernel; float temp_force; float3 grad_color; float lplc_color; for(uint i=0; i<num_particle; i++) { p=&(mem[i]); cell_pos=calc_cell_pos(p->pos); p->acc.x=0.0f; p->acc.y=0.0f; p->acc.z=0.0f; grad_color.x=0.0f; grad_color.y=0.0f; grad_color.z=0.0f; lplc_color=0.0f; for(int x=-1; x<=1; x++) { for(int y=-1; y<=1; y++) { for(int z=-1; z<=1; z++) { near_pos.x=cell_pos.x+x; near_pos.y=cell_pos.y+y; near_pos.z=cell_pos.z+z; hash=calc_cell_hash(near_pos); if(hash == 0xffffffff) { continue; } np=cell[hash]; while(np != NULL) { rel_pos.x=p->pos.x-np->pos.x; rel_pos.y=p->pos.y-np->pos.y; rel_pos.z=p->pos.z-np->pos.z; r2=rel_pos.x*rel_pos.x+rel_pos.y*rel_pos.y+rel_pos.z*rel_pos.z; if(r2 < kernel_2 && r2 > INF) { r=sqrt(r2); V=mass/np->dens/2; kernel_r=kernel-r; //計算壓力項 pres_kernel=spiky_value * kernel_r * kernel_r; temp_force=V * (p->pres+np->pres) * pres_kernel; p->acc.x=p->acc.x-rel_pos.x*temp_force/r; p->acc.y=p->acc.y-rel_pos.y*temp_force/r; p->acc.z=p->acc.z-rel_pos.z*temp_force/r; rel_vel.x=np->ev.x-p->ev.x; rel_vel.y=np->ev.y-p->ev.y; rel_vel.z=np->ev.z-p->ev.z; //計算粘性項 visc_kernel=visco_value*(kernel-r); temp_force=V * viscosity * visc_kernel; p->acc.x=p->acc.x + rel_vel.x*temp_force; p->acc.y=p->acc.y + rel_vel.y*temp_force; p->acc.z=p->acc.z + rel_vel.z*temp_force; float temp=(-1) * grad_poly6 * V * pow(kernel_2-r2, 2); grad_color.x += temp * rel_pos.x; grad_color.y += temp * rel_pos.y; grad_color.z += temp * rel_pos.z; lplc_color += lplc_poly6 * V * (kernel_2-r2) * (r2-3/4*(kernel_2-r2)); } np=np->next; } } } } lplc_color+=self_lplc_color/p->dens; p->surf_norm=sqrt(grad_color.x*grad_color.x+grad_color.y*grad_color.y+grad_color.z*grad_color.z); if(p->surf_norm > surf_norm) { p->acc.x+=surf_coe * lplc_color * grad_color.x / p->surf_norm; p->acc.y+=surf_coe * lplc_color * grad_color.y / p->surf_norm; p->acc.z+=surf_coe * lplc_color * grad_color.z / p->surf_norm; } } } void SPHSystem::advection() { Particle *p; for(uint i=0; i<num_particle; i++) { p=&(mem[i]); //速度及位置更新 p->vel.x=p->vel.x+p->acc.x*time_step/p->dens+gravity.x*time_step; p->vel.y=p->vel.y+p->acc.y*time_step/p->dens+gravity.y*time_step; p->vel.z=p->vel.z+p->acc.z*time_step/p->dens+gravity.z*time_step; p->pos.x=p->pos.x+p->vel.x*time_step; p->pos.y=p->pos.y+p->vel.y*time_step; p->pos.z=p->pos.z+p->vel.z*time_step; //牆壁 if(p->pos.x >= world_size.x-BOUNDARY) { p->vel.x=p->vel.x*wall_damping; p->pos.x=world_size.x-BOUNDARY; } if(p->pos.x < 0.0f) { p->vel.x=p->vel.x*wall_damping; p->pos.x=0.0f; } if(p->pos.y >= world_size.y-BOUNDARY) { p->vel.y=p->vel.y*wall_damping; p->pos.y=world_size.y-BOUNDARY; } if(p->pos.y < 0.0f) { p->vel.y=p->vel.y*wall_damping; p->pos.y=0.0f; } if(p->pos.z >= world_size.z-BOUNDARY) { p->vel.z=p->vel.z*wall_damping; p->pos.z=world_size.z-BOUNDARY; } if(p->pos.z < 0.0f) { p->vel.z=p->vel.z*wall_damping; p->pos.z=0.0f; } p->ev.x=(p->ev.x+p->vel.x)/2; p->ev.y=(p->ev.y+p->vel.y)/2; p->ev.z=(p->ev.z+p->vel.z)/2; } } //計算粒子p所屬的cell位置 int3 SPHSystem::calc_cell_pos(float3 p) { int3 cell_pos; cell_pos.x = int(floor((p.x) / cell_size)); cell_pos.y = int(floor((p.y) / cell_size)); cell_pos.z = int(floor((p.z) / cell_size)); return cell_pos; } //cell hash值計算 uint SPHSystem::calc_cell_hash(int3 cell_pos) { if(cell_pos.x<0 || cell_pos.x>=(int)grid_size.x || cell_pos.y<0 || cell_pos.y>=(int)grid_size.y || cell_pos.z<0 || cell_pos.z>=(int)grid_size.z) { return (uint)0xffffffff; } cell_pos.x = cell_pos.x & (grid_size.x-1); cell_pos.y = cell_pos.y & (grid_size.y-1); cell_pos.z = cell_pos.z & (grid_size.z-1); return ((uint)(cell_pos.z))*grid_size.y*grid_size.x + ((uint)(cell_pos.y))*grid_size.x + (uint)(cell_pos.x); }
以上~~
參考文獻
Matthias Müller, David Charypar, and Markus Gross, Particle-Based Fluid Simulation for Interactive Applications, SCA 2003.
相關推薦
【CG物理模擬系列】流體模擬--粒子法之SPH(程式碼講解)
#include "sph_system.h" #include "sph_header.h" SPHSystem::SPHSystem() { max_particle=30000; num_particle=0; kernel=0.04f; mass=0.02f; //初始化空間大小,並計算
【CG物理模擬系列】流體模擬--粒子法之MPS法(理論)
MPS法 前面的文章裡我們講過SPH曾是為了解決壓縮性流體問題而提出的方法,與之相對,這一篇來說說用粒子法處理非壓縮性流體的研究方法--Moving Particle Semi-implici
【CG物理模擬系列】流體模擬--粒子法之SPH(實現)
鄰域搜尋的效率化 SPH等粒子法,由於需要考慮到鄰域粒子帶來的影響,通常鄰域搜尋都會消耗大量時間。如果我們只是單純的計算所有粒子組合的歐氏距離的話,計算時間只會呈指數增加。 而空間分割法的出現,使鄰域搜尋實現了效率化。 空間分割法是一種,把希望檢索到的物體存在的空
【CG物理模擬系列】流體模擬--粒子法之Position Based Fluids
[1] M. Macklin and M. Muller, "Position based fluids" ACM Trans. Graph., 32, pp.104:1-104:12, 2013. [2] M. Muller, B. Heidelberger, M. Hennix and J. Ratcl
【NOIP2017模擬賽】二分圖+狀態壓縮DP Graph(好題)
題解 這道題其實是一個NP完全問題(23333),但是由於資料小啊,我們可以搞一搞。很容易發現,如果我們將一個點拆成兩個點,一個代表出點,一個代表入點。當增加了一條有向邊,就出點向入點連一條邊
【NOIP2017模擬賽】思維+轉化+圖論 徒然Children(好題)
題目描述 全世界都在談戀愛,只有我深愛著學習。——前言。 2333身為單身狗卻意外喜歡的吃狗糧的yuki堅信著:“自古紅藍出cp,黑白天生是夫妻,最是銷魂紅綠配,天然金紫成雙對,生死相隨紅與黃,白紫一逢春滿堂,千里緣牽白與綠,紅黑生來為相聚。”的cp配對原則
【學會Matlab走遍天下】如何畫正弦餘弦曲線和(學習筆記)
常用命令: clc %清屏 clear + 變數 %將變數擦除 註釋符:% 矩陣建立 邏輯語法 sum=0;i=1; while(i<=100) sum=sum+i;i=i+1; sum
【MYSQL學習筆記02】MySQL的高階應用之Explain(完美詳細版,看這一篇就夠了)
版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/wx1528159409 最近學習MySQL的高階應用Explain,寫一篇學習心得與總結,目錄腦圖如下: 一、Explain基本概念 1. Explain定義 · 我們知道M
【Java入門提高篇】Day34 Java容器類詳解(十五)WeakHashMap詳解
public class WeakHashMapTest { public static void main(String[] args){ testWeakHashMap(); } private static void testWeakHashMap
【從原始碼看Android】03Android MessageQueue訊息迴圈處理機制(epoll實現)
1 enqueueMessage handler傳送一條訊息 mHandler.sendEmptyMessage(1);經過層層呼叫,進入到sendMessageAtTime函式塊,最後呼叫到enqueueMessageHandler.java public bool
【拔刀吧TensorFlow】Ubuntu16.04系統安裝問題總結(已更新)
重大更新!!!!! 因為You do not appear to be using the NVIDIA X driver. 這樣的報錯,感覺雖然安裝了nvidia驅動,但是並沒有呼叫起來驅動,遂決定再次重做系統。這次重做的步驟如下: 1. 重做系統。 2. 重啟之後發現可以雙屏顯示,解析度正
【休閒遊戲 實戰1】推箱子PC端小遊戲(附原始碼)
效果圖:第100關有些難度,用了449步才過關(我用的是可跳關版的,直接玩的最後一關)原始碼解讀原始碼一共3個檔案:index.html(遊戲介面載入,核心功能),js/mapdata100.js(100個16階矩陣,通過0,1,2,3,4分別對應遊戲中5個元素的圖片來定義每
【C語言簡單說】八:分支結構之if(1)
今天貌似更了很多章了,現在感覺累覺不愛。。。 ┐(—__—)┌ 你說我有啥米辦法咧~(要不叫別人替我更一下?) 繼續更。。。 這一節我們來說一下if語句;這個東西可是很常用的呀;在此之前我們來舉個
【OCP題庫-12c】最新CUUG OCP 071考試題庫(70題)
values mman ble ans delete best cau save first 70、(31-2)choose the best answer: View the Exhibit and examine the structure of the Book ta
【OCP題庫-12c】最新CUUG OCP 071考試題庫(69題)
sel query dual 試題 owin ans lua The select 69、(31-1)choose the best answer: Evaluate the following query: SELECT INTERVAL ‘300‘ MONTH, INT
【OCP題庫-12c】最新CUUG OCP 071考試題庫(71題)
試題 nts 考試題庫 point choose com ued transacti mit 71、(32-18) choose three Which three statements indicate the end of a transaction? (Choose
【OCP題庫-12c】最新CUUG OCP 071考試題庫(72題)
reg ive answer statement splay and ren 考試 display 72、View the exhibit for the structure of the STUDENTand FACULTYtables. STUDENT Name Nul
【編程訓練-PAT】A1119 Pre- and Post-order Traversals (30 分)
lse vector txt cif sap push_back you any nodes 1119 Pre- and Post-order Traversals (30 分) Suppose that all the keys in a binary tree are
【NOIP 模擬賽】鐘 模擬+鏈表
color blog 不常用 get 循環鏈表 fig problem bsp 常用 biubiu~~ 這道題實際上就是優化模擬,就是找到最先死的讓他死掉,運用時間上的加速,題解上說,要用堆優化,也就是這個意思。 對於鏈表,單項鏈表和循環鏈表都不常用,最常用的是雙向鏈表
【模擬登陸】github模擬登陸,列印資訊流
目的:動態獲取cookie 第一:分析登陸過程 1、開啟開發者工具,檢視各自請求 2、可以看到name為session的請求【方式post,傳入的data】 3、檢視name為login的請求,原始碼中獲得token,作為上一個請求中的data的一部分