RayMarching 入门

原理

RayMarching和传统的RayTracing很相似,在RayTracer,根据方程确定物体表面交点,从而直接获得表面位置等信息进行光照渲染,但是如果我想渲染体积云,液体,地表,分形等等多边形难以表达的效果,传统光线追踪就很难完成了,所以对于某些效果参数化描述比三角面片描述简洁很多, raymarching就是专门来解决这些问题的

首先RayMarching是按照摄像机方向(Ray)逐步前进(March) 进行采样,是以迭代方式一步一步向前步进的,那如何确认步长呢,如果以固定步长去运算的话,步长设置的很大很容易直接穿过物体不能达到物体表面,如果步长设置的很小又会很浪费运算需要跑很多次运算才能达到物体表面。

如果步进太大直接穿过,步进太小浪费运算

这里引入一个很重要的概念"距离场"按距离物体表面最小距离进行迭代的步进, 如果出现某些射线在步进一次并没有达到表面时,可以以此时距离物体的距离场再次按照原方向进行步进。如果某条线在步进多次后一直逐渐远离,也就是说明这根射线永远无法与物体相交,如果一根射线在步进多次后距离场的值越来越小,如果设值为0.01,那么就可以确定这个点的位置就是物体表面。

介绍

1.1 绘制一个地板和球体

c 复制代码
precision highp float;
#define MAX_STEP 100
#define MAX_DEPTH 10.0
#define SURF_DIST 0.01

uniform vec2 u_resolution;

struct Ray {
    vec3 origin;
    vec3 dir;
};





float getDist(vec3 p){
    vec4 sphere=vec4(0.0,0.0,6.0,1.0);
    float sphereDist=length(p-sphere.xyz)-sphere.w;
    float planeDist=length(p.y+1.0);
    return min(sphereDist,planeDist);
}

float RayMarch(Ray ray){
    float depth=0.0;
    for(int i=0;i<MAX_STEP;i++){
        vec3 p=ray.origin+depth*ray.dir;
        float dist=getDist(p);
        depth+=dist;
        if(dist>MAX_DEPTH||dist<SURF_DIST) break;
    }

    return depth;
}

void main(){
    vec2 uv=(gl_FragCoord.xy-u_resolution*0.5)/u_resolution.y;
    Ray ray;
    ray.origin=vec3(0.0,0.0,0.0);
    ray.dir=normalize(vec3(uv,1));
    float depth=RayMarch(ray);   
    gl_FragColor=vec4( vec3(depth),1.0);
}

1.2 添加光照

c 复制代码
vec3 getNormal(vec3 p){
    float d=getDist(p);
    vec3 normal=d-vec3(
        getDist(p-vec3(0.001,0,0)),
        getDist(p-vec3(0,0.001,0)),
        getDist(p-vec3(0.0,0,0.001))
    );
    return normalize(normal);
}

float getLight(vec3 p){
    //灯光位置
    vec3 lightPos=vec3(0,3,7);
    lightPos.xz+=vec2(sin(u_time)*3.0,cos(u_time)*3.0);
    vec3 lightDir=normalize(lightPos-p);
    vec3 normal=getNormal(p);
    float diffuse=dot(lightDir,normal);
     return diffuse;
}
...
 vec3 p=ray.origin+depth*ray.dir;
    //计算漫反射
float light=getLight(p);
gl_FragColor=vec4( vec3(light),1.0);

1.3 添加阴影

c 复制代码
float getShadow(vec3 p,vec3 lightPos,vec3 normal){
    //计算点p到太阳的距离,
    float distLight=length(lightPos-p);
    //计算p在太阳方向上的最近距离
    Ray ray_light;
    ray_light.dir=normalize(lightPos-p);
    ray_light.origin=p+SURF_DIST*normal*2.0;
    float dist=RayMarch(ray_light);
    // return dist;
    //在阴影中
    if(distLight-dist>0.0){
        return 0.6;
    }else{
        return 1.0;
    }
    
}

float getLight(vec3 p){
    //灯光位置
    vec3 lightPos=vec3(0,3,7);
    lightPos.xz+=vec2(sin(u_time)*3.0,cos(u_time)*3.0);
    vec3 lightDir=normalize(lightPos-p);
    vec3 normal=getNormal(p);
    float diffuse=dot(lightDir,normal);
     float shadow=getShadow(p,lightPos,normal);
    return shadow*diffuse;

}
相关推荐
平头哥~1 分钟前
Day 15 | 不改一行 HTML,给页面加上引号、角标和标签
前端·javascript·css·html·css3·学习资料
风骏时光牛马5 分钟前
后端系统性能监控与异常告警管理
前端
Fluxart.ai1 小时前
GPT Image 2 国内怎么用?在 Flux Art 完成图片生成与编辑
前端·javascript·gpt
tanzongbiao1 小时前
Dorado7文件上传 解决HttpServletResponse返回值中文乱码的问题
java·服务器·前端
郑州光合科技余经理5 小时前
本地生活服务系统:成品模块和定制接口怎么划界
java·前端·人工智能·后端·系统架构·php·ai编程
平头哥~9 小时前
Day 07 _ 那条 1px 的线,为什么在手机上忽粗忽细
前端·css·样式·学习资料
小江的记录本9 小时前
【CSS】CSS 动画:transition、animation、transform、CSS3 新特性(附《思维导图》)
前端·css·安全·spring·前端框架·css3·动画
circuitsosk9 小时前
任务规划器的三种范式对比:ReAct、Plan-and-Execute 与 Tree-of-Thought 在真实业务中的取舍
前端·javascript·python·react.js·llm·ai agent
hzxpaipai10 小时前
企业官网技术架构拆解:前端、后台、数据库、服务器如何协同
前端·数据库·架构