使用raymarching实现体积雾

前段时间在学习rayMarching技术,看到许多大佬搞的体积雾。我也做了一个简单的。

RayMarching原理

RayMarching(光线步进)严格上来说应该是后期的一种。
一个简单的实现是在屏幕上绘制球体:从光线原点射出光线,先以原点为中心调用一次距离函数,计算出此点到球形表面的最短距离。如果小于设置好的误差值,就视为接触到物体,返回距离值。如果判断没接触到,则沿着光线向量前进刚刚计算出的距离值得到新的圆心继续求距离,直到判定为接触物体。如果前进步数过多,超出设定最高步数或者前进距离超出最远距离,就视为无法接触物体。
在这里插入图片描述
如果要像上图那样检测多个物体,就可以分别计算原点到多个物体表面的距离,然后取最小值,就能同时检测多个物体。如果取最大值则是将图形取并集,再合理地对距离值取负值,就能完美地完成几何体的布尔运算。你也可以在这个网站中找到许多几何体的距离函数和一些有趣的融合算法。
如果我们对每个像素都进行上述的步进操作,就能得到物体的深度值,也就能开始着色了。法线的计算是根据计算附近像素点的深度值得出。如果想要仅仅显示几何体,做到这一步就能按照传统的光照方案计算出图案,值得注意的是,由于RayMarching技术是后期处理,因此要考虑到如何与背景图像进行融合。

float3 getNormal(float3 p)//近似计算出法线
{
float2 offset = float2(0.001f,0.0f);
//float d = getDist(p);
float3 n= float3(
    getDist(p+offset.xyy)-getDist(p-offset.xyy),
    getDist(p+offset.yxy)-getDist(p-offset.yxy),
    getDist(p+offset.yyx)-getDist(p-offset.yyx)
);
return normalize(n);
}

简单体积雾运算

接下来就可以按照乐乐老师的shadertoy项目的体积雾运算再次进行颜色绘制。这是一个简单的体积雾颜色绘制。基本原理就是在计算好的几何体内,按照几乎相同的步长进行步进操作,按照一定的噪声算法对像素增加不透明度,并且按照当前点到球心的距离进行着色。很显然。这并不是一个基于物理的体积雾着色,但是效果非常不错。我在引入着色代码后进行了一定的更改:

float3 raymarchingCloud(float3 ro, float3 rd, float t,float3 backCol,float depth)
	{
	float4 sum = float4(0.0,0.0,0.0,0.0);
	float3 pos = ro + rd * t;
	for (int i = 0; i < 30; i++) {
		float4 col;
		float radiusSum = 0;
		for(int i=0; i<_SphereNum; i++)
		{
			radiusSum += _SpherePositions[i].w;
		}
		radiusSum /= _SphereNum;
		float dist = radiusSum+_Fog*getDist(pos);
		if ( sum.a > 0.99 || t>depth ) continue;
		float den = density(pos, dist);
		col = float4(color(den, dist), den*_FogDensity);
		col.rgb *= col.a;
		sum = sum + col*(1.0 - sum.a); 
		t += max(0.05, 0.02 * t);
		pos = ro + rd * t;
	}
	sum = clamp(sum, 0.0, 1.0);
	backCol = lerp(backCol, sum.xyz, sum.a);
	return backCol;
}

我将原算法中对当前点到球心的距离算法改为了到几何体表明的距离。这样就能兼容不同几何形状的烟雾,甚至多个烟雾效果。同时我也增加了两个能够管理烟雾浓度的参数,方便使用。
在这里插入图片描述
上面就算体积雾的效果。效果优点:
1简单快速,占用较少
2深度检测,能较好的与环境融合
3支持多个烟雾
4效果优秀
5使用Object和脚本进行烟雾管理
缺点:
1并非基于物理,并不能很好的与光照进行交互
2z轴的烟雾融合并不算很好
为了解决以上两个问题,还准备找个时间做个基于物理体积雾系统。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,让我来回答你的问题。 首先,让我们来简单了解一下Marching Cubes算法是什么。Marching Cubes算法是一种体绘制技术,将三维体数据转换为表面网格,从而实现可视化的目的。这个算法可以用于任何三维数据集,包括医学图像、地质勘探数据、气象数据等等。在Marching Cubes算法中,我们需要输入一个三维的体数据集,然后根据这个数据集的数值,生成一个表面网格。 接下来,我们来谈一下使用vtk实现Marching Cubes算法绘制自由面信息的步骤: 1. 首先,我们需要读取VOF场数据集。我们可以使用vtkImageData类来读取VOF场数据集,然后使用vtkContourFilter类将数据集转化为等值面。vtkContourFilter类可以根据一组等值线来绘制出等值面。等值线是一条连接相同数值的点的线,等值面则是由多个等值线构成的面。 2. 然后,我们需要根据VOF场数据集的数值,计算出等值面的位置和法向量。这个过程可以使用Marching Cubes算法来实现。Marching Cubes算法将三维体数据集划分为一个个小的立方体,然后根据每个立方体的数值和边界情况,决定等值面的位置和法向量。 3. 最后,我们可以使用vtkActor和vtkRenderer类来将等值面添加到场景中,并使用vtkRenderWindow类将场景渲染到屏幕上。vtkActor类表示一个三维模型,可以设置其颜色、材质等属性。vtkRenderer类表示一个渲染器,可以设置其渲染的视角、光照等属性。vtkRenderWindow类表示一个窗口,可以将渲染结果显示在屏幕上。 总之,使用vtk实现Marching Cubes算法绘制自由面信息的步骤包括读取数据集、计算等值面位置和法向量、添加等值面到场景中以及渲染场景。需要注意的是,这个过程可能会比较复杂,需要一定的编程技巧和经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值