RayMarching 光线步进:
光线步进,又称为球体追踪(sphere tracing):
组件:
Camera:
输入:
- uv坐标:告诉我们哪一个像素是我们的目标的渲染像素
- Pos:坐标
- lookat:方向
- Zoom:相机到屏幕的垂直距离
输出:
- ViewRay:视角光线
Ray Intersection(光线相交):
光线与场景中的物体相交
输入:
- Ray:视角光线
输出:
- Distance:距离,相机到与光线相交的物体表面的交点的距离
Material & lighting:
输入:
- Material:材质属性
- Distance:距离
- light:光线
输出:
- pixel color:像素的颜色
算法:
函数构成:
GetDist:
输入某一点的坐标,输出该点与场景中最近物体的距离。
float GetDist(vec3 p)
{
vec4 s = vec4(0,1,6,1);
float sphereDist = length(p-s.xyz)-s.w;//坐标点p与圆心的向量的长度减去圆的半径 -->得到坐标点p到圆的最短距离
float planeDist = p.y;//坐标点p离平面的最短距离 -->坐标点的y值
float d = min(sphereDist,planeDist);//取二者的最小值
return d;
}
GetNormal:
输入某点坐标,输出该点的法线方向向量
vec3 GetNormal(vec3 p)
{
vec2 e = vec2(0.01f, 0.0f);
float d = GetDist(p);
vec3 n = vec3(
d - GetDist(p - e.xyy),
d - GetDist(p - e.yxy),
d - GetDist(p - e.yyx));
return normalize(n);
}
GetLight:
输入视角向量与空间中物体的交点的坐标,计算该点的漫反射颜色,将颜色值作为该uv像素的颜色
float GetLight(vec3 p)
{
vec3 lightPos = vec3(0, 5, 6);
vec3 l = normalize(lightPos - p);//光线方向向量
vec3 n = GetNormal(p);
float diff = clamp(dot(n ,l), 0., 1.);
//阴影,将p点作为原始点,沿着光线的方向向量,得到与空间中物体的距离
float d = RayMarching(p + n * SURFACE_DIST*2, l);
if(d < length(lightPos - p))//如果距离小于光源到点p的距离说明二者之间有物体也就是p处于阴影中
diff *= .1;
return diff;
}
RayMarch:
输入一个点的坐标,以及一个方向向量,输出从该点出发沿着方向向量,与物体的交点的距离
#define SURFACE_DIST .01 //接近相交点的判断值。如果小于该值表示已经近似得到交点到摄像机的距离
#define MAX_DIST 100.//最大的距离
#define MAX_STEPS 100//最大的步长
float RayMarch(vec3 ro, vec3 rd) {
float depth = 0.0f;//距离
for(int i = 0 ;i < MAX_STEPS; i ++) {
vec3 pos = ro + depth * rd;//更新位置,点在视角光线上进行移动
float dist = GetDist(pos);//获取点到物体的最近距离
depth += dist;//点的移动距离
if(dist < SURFACE_DIST || depth > MAX_DIST)//如果交点与摄像机点的距离超过最远距离,或者 dist小于判断值表示已经近似得到了摄像机与交点的距离
break;
}
return depth;
}
主函数:
//部分
float d= RayMarch(ro,rd);
vec3 p=ro+rd*d;
float diff=GetLight(p);
vec3 col=vec3(diff);
fragcolor=vec4(col,1.0)
参考资料:https://www.bilibili.com/video/BV1QJ411v7J5?from=search&seid=1569927975704725649