|
发表于 2022-12-10 07:24:00
|
显示全部楼层
一,What is Ray Marching
光线从起点出发,一步步前进,每到达一步,光线就停下来做一次计算,然后继续前进,直到逼近重点.
注意:不同场景,光线步进指代的内容不同,从摄像机向屏幕上的每一个像素发射一条光线,光线按照一定步长前进,检测当前光线距离物体表面的距离,并且根据这个距离调整光线的步长,直到抵达物体表面


二,How to do Ray marching

首先我们看到这张图,我们可以发现,构建RM需要大致四步
1.定义摄像机的位置,光线的方向;
2.定义场景:场景包含一个球体和平面;
3.定义灯光的方向;
4.计算法线的方向;
可以简单理解为:定位摄像机,由摄像机发出射线,根据一定的频率(步长)检测射线周围有无物体(这一部分叫射线检测,检测的是方向和深度,方向是由像素点决定的)。然后这里这个球,叫做球形检测,球形检测会基于当前的像素点作为圆心,进行画圆,这里就引入了RM的核心公式
float RayMarching(vec3 ro vec3 rd)//ro=cameraposition rd = cameravector
{
float do = 0;//射线长度
for(int i = 0;i <MAX_STEPS;i++)
{
vec3 p = ro +do * rd;
float ds = GetDist(p);//自定义一个用来获取当前监测点到物体距离深度的函数
do += ds;
if(ds <SUPFACE_DIST||do>MAX_DIST)
break;
}
return do;
}

然后我们说一下这里自定义的GetDist函数,就是这张图片的这两个公式,求一个plane以及Sphere,主要目的就是:输入空间中某一点的坐标,返回此点与空间中最近物体的距离
float GetDist(vec3 p)//先定义一个p值
{
vec4 sphere = vec4(0,1,6,1);//再定义一个圆心坐标
float ds = length(p-sphere.xyz)-sphere.w;//w作为缩放值
float dp = p.y;
float d = min(ds,dp);//利用plane和sphere的深度,取一个离摄像机最近的距离
return d;
}三,SDF
SDF 即 Signed Distance Field, 在RayMarching中,我们使用的GetDist实际上就是一个有向距离场,它描述空间中的任一点到达最近的物体的距离

可以简单粗暴的理解为,我们需要给这个rm限制一个距离场,这里可以用于指定其形状,常用物体的SDF方程,大家都可以在网络上搜得到
四,案例:基于Ray marching的史莱姆
这里直接拿之前做的独立游戏比赛的案例在讲解
https://zhuanlan.zhihu.com/p/587209449

我们根据之前的理论知识点,确定这个自定义节点需要输入哪些东西,再通过代码进行一个编写,代码主要分为几个部分




- 注意,这里需要一个额外的算法,这个算法可以自己去尝试一下,为什么这里能做到平滑

最后就能得到这样的效果

https://www.zhihu.com/video/1583072795034107904 |
|