光线步进——RayMarching入门

暑期实习笔试结束了,IGG笔试题比我想象的要难,听群里说比腾讯笔试难得多,不知道结果如何。。五一假期写写结课论文,看看番,有时间打算研究一下体积云,然后就走到了RayMarching这儿。

关于光线步进

RayMarching 是一种用于实时场景的快速渲染方法,我的理解是,模拟摄像机位置,根据视椎体的扩张角度,以摄像机位置为原点,进步式发射射线,当射线碰撞到物体之后,返回其深度信息,如果到视椎体的最大距离之前都没有返回,那么可以以此判断该像素点没有对于物体,最后根据返回的信息计算光照。
可以看出,RayMarching是有误差的,如果提高精度,减少步长,循环次数又太多,导致效率很低。
感觉RayMarching目前用来渲染云,雾这些类似的体积渲染比较多。

入门实现

光线步进——RayMarching入门_第1张图片
先用RayMarching描绘一个球体,最后在进行光照计算
参考:https://www.shadertoy.com/view/llt3R4

模拟摄像机射线
float3 rayDirection(float filedOfView, float2 size, float2 fragCoord){
   
    float2 xy=fragCoord-size/2;
    float z=size.y/tan(radians(filedOfView)/2.0);
    return normalize(float3(xy,-z));
}

首先,把屏幕中心设置为坐标原点(0.0,0.0),射线的z值都是固定的,其中filedOfView可以看成视椎体两条棱的夹角,返回归一化的射线向量。

对射线进行碰撞检测
float sphereSDF(float3 samplePoint){
   
    return length(samplePoint) - 1.0;
}
float shortestDistanceToSurface(float3 eye,float3 marchingDirection,float start,float end){
   
    float depth = start;
    for(int i=0;i<maxMarchingSteps;i++){
   
        float dist=sphereSDF(eye+depth*marchingDirection);
        if(dist < epsilon){
   
            return depth;
        }

        depth+=dist;
        if(depth>=end){
   
            return end;
        }
    }
    return end;
}

以eye坐标为起点,沿着模拟射线的方向进行碰撞检测,返回碰撞点的深度,如果到最大深度仍然没有碰撞,则发挥最大深度

根据深度返回颜色
 float dist=shortestDistanceToSurface(eye,dir,minDist,maxDist);
 if(dist>=maxDist-epsilon){
   
      return float4(0.0,0.0,0.0,0.0);
  }
 float value=floor(dist*10.0)*_StepValue;
 return float4(1-value,sin(value*10.0),0.0,1.0);
存在问题

球体的碰撞检测是比较容易的,如果我们想放一个立方体到“场景”里,怎么搞?

  float cubeSDF(float3 samplePoint){
   
      float3 d=abs(samplePoint)-float3(0.5

你可能感兴趣的:(Unity,RayMarching,光线步进,Unity)