流体模拟(三)

Marching Cube算法(2)

我们在之前的流体系统类里新加入一些函数和成员,用来引用我们的MC类,便可以获得生成有表面的流体模型了,效果如图:

添加简单的天空盒以及Phong氏光照模型边有效果:

流体系统类的更改:

    class FluidSystem{public:......//复制缓存void CuCopyArrayToDevice(float* device, const float* host, int offset, int size);// 隐式函数值计算virtual double GetImplicit(double x, double y, double z);virtual void CalImplicitField(int n[3], glm::vec3 minp, glm::vec3 d, float *hF);virtual void CalImplicitFieldDevice(int n[3], glm::vec3 minp, glm::vec3 d, float *dF);// 使用metaball隐式函数值double CalColorField(double x, double y, double z);float* getPointPosBuf(){return &posData[0];}     //获取点位置缓存float* getPolygonBuf();//获取三角面float* getSufPosBuf(){return &m_vrts[0].x;}//获取表面点void clearSuf(){m_nrms.clear();m_nrms.clear();m_face.clear();}int getSufVrtBufNum(){return (int)m_vrts.size();}int getPolyNum();private:......rxMCMesh m_mcMesh;//mc类型的成员float* m_field;//密度场std::vector<float> m_polyBuf;//三角面缓存//表面信息vector<glm::vec3> m_vrts;//表面点坐标vector<glm::vec3> m_nrms;//点法线vector<rxFace> m_face;//表面三角面float m_thre;// 隐函数阈值
}

我们用m_mcMesh来控制我们的表面生成,m_field保存密度场,m_thre则为隐函数阈值(阈值内为表面内点,阈值外为表面外点)。还用了m_vrts,m_nrms,m_face来保存表面信息。添加的函数中,主要用函数GetImplicit,CalImplicitField,CalImplicitFieldDevice去计算我们的网格密度值,获取到所有网格的密度值,便可以用mc类获取表面信息。

函数实现如下:

  void FluidSystem::tick(){m_gridContainer.insertParticles(&m_pointBuffer);//每帧刷新粒子位置glm::vec3 tem=m_sphWallBox.min;CalImplicitFieldDevice(m_rexSize, tem, glm::vec3(0.125/m_gridContainer.getDelta()), m_field);clearSuf();//清空表面数据m_mcMesh.CreateMeshV(m_field, tem, 0.125/m_gridContainer.getDelta(), m_rexSize, m_thre, m_vrts, m_nrms, m_face);_computerPressure();_computerForce();_advance();}void FluidSystem::_init(unsigned short maxPointCounts, const fBox3 &wallBox, const fBox3 &initFluidBox, const glm::vec3 &gravity){m_pointBuffer.reset(maxPointCounts);m_sphWallBox=wallBox;m_gravityDir=gravity;m_pointDistance=pow(m_pointMass/m_restDensity, 1.0/3.0);//计算粒子间距_addFluidVolume(initFluidBox, m_pointDistance/m_unitScale);m_mcMesh=rxMCMesh();m_gridContainer.init(wallBox, m_unitScale, m_smoothRadius*2.0, 1.0,m_rexSize);//设置网格尺寸(2r)//初始化标量场m_field=new float[(m_rexSize[0]+1)*(m_rexSize[1]+1)*(m_rexSize[2]+1)]();posData=std::vector<float>(3*m_pointBuffer.size(),0);}//-----------------------------------------------------------------------------// MARK:隐含的函数值//-----------------------------------------------------------------------------double FluidSystem::GetImplicit(double x, double y, double z){return CalColorField(x, y, z);}/*!*从粒子计算网格的隐含函数值* @param [in] n网格数* @param [in] minp网格的最小坐标* @param [in] d网格宽度* @param [out] hF隐含函数值(nx×ny×nz的数组)*/void FluidSystem::CalImplicitField(int n[3], glm::vec3 minp, glm::vec3 d, float *hF){int slice0 = n[0]+1;int slice1 = slice0*(n[1]+1);for(int k = 0; k < n[2]; ++k){for(int j = 0; j < n[1]; ++j){for(int i = 0; i < n[0]; ++i){int idx = k*slice1+j*slice0+i;glm::vec3 pos = minp+glm::vec3(i, j, k)*d;hF[idx] = GetImplicit(pos[0], pos[1], pos[2]);}}}}/*!*从粒子计算网格的隐含函数值* @param [in] pnx,pny,pnz的网格数* @param [in] minp网格的最小坐标* @param [in] d网格宽度* @param [out] hF隐含函数值(nx×ny×nz的数组)*/void FluidSystem::CalImplicitFieldDevice(int n[3], glm::vec3 minp, glm::vec3 d, float *dF){float *hF = new float[(n[0]+1)*(n[1]+1)*(n[2]+1)]();CalImplicitField(n, minp, d, hF);CuCopyArrayToDevice(dF, hF, 0, (n[0]+1)*(n[1]+1)*(n[2]+1)*sizeof(float));delete [] hF;}//计算颜色场(密度场)double FluidSystem::CalColorField(double x, double y, double z){// MRK:CalColorFieldfloat c = 0.0;glm::vec3 pos(x, y, z);if(pos[0] < m_sphWallBox.min[0]) return c;if(pos[0] > m_sphWallBox.max[0]) return c;if(pos[1] < m_sphWallBox.min[1]) return c;if(pos[1] > m_sphWallBox.max[1]) return c;if(pos[2] < m_sphWallBox.min[2]) return c;if(pos[2] > m_sphWallBox.max[2]) return c;float h = m_smoothRadius;int cell[8];m_gridContainer.findCells(pos, h/m_unitScale, cell);// 近傍粒子(各向同性)for(int i=0;i<8;i++){if(cell[i] < 0) continue;int pndx=m_gridContainer.getGridData(cell[i]);while(pndx!=-1){Point* p=m_pointBuffer.get(pndx);float r = glm::distance(pos,p->pos)*m_unitScale;float q = h*h-r*r;if(q>0){c += m_pointMass*m_kernelPoly6*q*q*q;}pndx=p->next;}}return c;}//获取三角片面缓存float* FluidSystem::getPolygonBuf(){m_polyBuf.clear();for(int i=0;i<m_face.size();i++){for(int j=0;j<m_face[i].vert_idx.size();j++) {glm::vec3 posTem=m_vrts[m_face[i].vert_idx[j]];m_polyBuf.push_back(posTem.x);m_polyBuf.push_back(posTem.y);m_polyBuf.push_back(posTem.z);}}return &m_polyBuf[0];}//获取顶点个数int FluidSystem::getPolyNum(){int tem=0;for(int i=0;i<m_face.size();i++){for(int j=0;j<m_face[i].vert_idx.size();j++){tem++;}}return 3*tem;}//保存所有网格隐函数值void FluidSystem::CuCopyArrayToDevice(float* device, const float* host, int offset, int size){memcpy(device+offset, host, size);}
}

可以看到我们的密度场由CalColorField函数计算,它依旧用了公式3.3:

获取所有网格的密度值。我们在_init函数里添加了对标量场的初始化。在tick函数里多了CalImplicitFieldDevice操作,用来先计算所有网格的密度值,然后调用clearSuf函数清除所有表面数据,然后根据m_mcMesh.CreateMeshV函数,用密度场重新计算新的表面数据,以生成表面。

当所有的计算完成时,我们的m_vrts,m_nrms以及m_face都有了新的数据,在opengl中将其传入VBO便可以绘制出有表面的粒子和网格效果如下:

加上天空盒和简单的Phong氏光照后,效果勉强还过得去:

完成了表面绘制后,其实这里的流体表面还是有一些问题,较为明显的则是表面不够光滑,如上图就可以看出流体表面有强烈的颗粒感,Yu, Jihun 等人的“Reconstructing surfaces of particle-based fluids using anisotropic kernels”这篇文章则非常好的解决了这个问题,他利用了给每个粒子构建了各项异性的缩放旋转矩阵,能够使流体达到一个非常光滑的形态,该算法下节会详细介绍。

SPH(光滑粒子流体动力学)流体模拟实现三:Marching Cube算法(2)相关推荐

  1. SPH(光滑粒子流体动力学)流体模拟实现三:Marching Cube算法(1)

    流体模拟(三) Marching Cube算法(1) 我们在 实现流体表面重建时,需要事先在空间中划分网格,我们的流体系统正好已经完成了此项工作.其次利用Marching Cube算法计算出构成表面的 ...

  2. SPH(光滑粒子流体动力学)流体模拟实现六:Position Based Fluid(PBF)

    SPH(光滑粒子流体动力学)流体模拟实现六:Position Based Fluid(PBF) PBF方法和前篇提到的PCISPH方法类似,都属于迭代矫正法.PCISPH是通过迭代预测压力,通过压力变 ...

  3. SPH(光滑粒子流体动力学)流体模拟实现七:屏幕空间流体渲染(SSF)

    SPH(光滑粒子流体动力学)流体模拟实现七:屏幕空间流体渲染(SSF) 之前都是用的Marching Cube重建流体表面的方法.近来为了做对比实验,尝试了屏幕空间流体渲染的方法.发现屏幕空间的方法不 ...

  4. SPH(光滑粒子流体动力学)流体模拟实现:算法总览

    流体模拟(一) 流体模拟算法总体流程: 流体现象广泛存在于自然界.日常生活以及工 业生产中,对流体的模拟即流体动画, 一直是基于物理的动画以及计算机图形学的重要研究内容.目前, 基于物理模拟的流体动画 ...

  5. SPH(光滑粒子流体动力学)流体模拟实现二:SPH算法(4)-算法实现2

    流体模拟(二) SPH算法实现2: 在前面一节我们完成了粒子缓存类,网格类和邻接表类.我们现在可以正式的整合在我们的流体系统类中了. 流体系统类 class FluidSystem{public:Fl ...

  6. SPH(光滑粒子流体动力学)流体模拟实现二:SPH算法(4)-算法实现1

    流体模拟(二) SPH算法实现1: 由于我们计算每个粒子的状态时,都需要获得在它光滑核半径内(邻域内)的所有粒子信息.我们如果遍历每个粒子,计算欧式距离的话,那开销就过于庞大了.因此我们可以将我们的空 ...

  7. SPH(光滑粒子流体动力学)流体模拟实现二:SPH算法(3)-光滑核函数

    流体模拟(二) 光滑核函数: sph中涉及的光滑核可以理解为:在一定的光滑核半径内,所受的力受距离权重的影响,距离越近所受影响越大.其表现形式如图所示. 这里我们便可以将流体看成一个个粒子的集合,每一 ...

  8. SPH(光滑粒子流体动力学)流体模拟实现二:SPH算法(2)-粒子受力分析

    流体模拟(二) SPH算法的粒子受力分析: SPH算法的基本设想,就是将连续的流体想象成一个个相互作用的微粒,这些粒子相互影响,共同形成了复杂的流体运动.其实现的原理则是我们在初始空间里创建多个粒子, ...

  9. SPH(光滑粒子流体动力学)流体模拟实现四:各向异性(Anisotropic)表面光滑(1)

    流体模拟四: 各向异性(Anisotropic)表面光滑(1) 表面的表示与定义 我们是以隐式表面来表示流体表面.定义一个足够大的参考域,它完全包含粒子表示的流体所在的空间D,即.流体表面隐含的定义为 ...

最新文章

  1. Hive表联合查询语句参考
  2. 《中国人工智能学会通讯》——6.25 日落的教训
  3. PAT—— 害死人不偿命的(3n+1)猜想 (1001)
  4. 机器学习(监督学习) 项目流程模板
  5. mysql批量添加报错_技术分享 | MySQL 在批量插入时捕捉错误信息
  6. 利用Referer请求头防止“盗链”
  7. 源码推荐-380套大型商业源码
  8. speex java_JAVA版-微信高清语音.speex转.wav格式
  9. 优秀!3位95后硕士一作发表Nature!
  10. FlowNet 2.0的阅读笔记
  11. 安装Kylin Linux Advanced Server V10操作系统
  12. from collections import Counter计数器
  13. C语言————鸡兔共有30只,脚共有90只,下面的程序段是计算鸡和兔共有多少只?
  14. 奇数阶魔方阵算法分析
  15. Android UI 字体库(.ttf文件)的使用 -- xml方式
  16. 服务器被劫持了,该怎么办?
  17. 在codecademy上学习Python
  18. The Shawshank Redemption-17
  19. 网络基础——牛客网刷题第四波
  20. 工程伦理--4.1 解决伦理困境的一般步骤

热门文章

  1. Windows下修改pip install 的镜像源
  2. 为什么同现矩阵*评分矩阵=推荐结果?
  3. python下绘制叠加区域图和叠加柱状图
  4. php上传图片并显示代码,php图片上传代码(完整版已测试)
  5. C++ 偏微分数值计算库_一文带你了解计算流体力学CFD及其应用领域
  6. 前端如何查看音频的长度_Android音频可视化
  7. excel文件无法打印提示内存不足_U盘拷贝文件提示目标文件过大无法复制怎么解决...
  8. java p=x,Java-Tutorial/20、javac和javap.md at master · allenchenx/Java-Tutorial · GitHub
  9. java vim ide_把VIM配置成IDE开发环境 | 学步园
  10. 湖南科技大学计算机男女比例,湖师大文学院新生男女比例1:9 成了“女儿国”...