GAMES202——作业3 Screen Space Ray Tracing(间接光照)

任务

        为场景实现屏幕空间的全局光照效果

        1.直接光照:  实现ssrFragmentShader中的EvalDiffuse(wi, wo, uv) EvalDirectionalLight(uv) 函数,并在 main 函数中实现直接光照的效果。

        2.屏幕空间光线求交:实现RayMarch(ori, dir, out hitPos) 函数。RayMarch 函数的返回值为是否相交,当相交的时候需要将参数 hitPos设置为交点。参数 ori dir 为世界坐标系中的值,分别代表光线的起点和方向,其中方向向量为单位向量。

        3.间接光照:在 main 函数中实现间接光照,使用蒙特卡洛方法求解渲染方程。

实现

        EvalDiffuse

        该函数是计算diffuse材质的BSDF的,功能简单,其实就是之前101的内容。这里将EvalDiffuse看作渲染方程的f,但是由于计算间接光照的伪代码没有给出cos项,因此这里多乘以一个cos项。另外提一下,这里的INV_PI是PI的倒数,因为在计算机里乘法计算比除法计算更快,因此预定义一个INV_PI能加速渲染。

vec3 EvalDiffuse(vec3 wi, vec3 wo, vec2 uv) {
  vec3 diffuse  = GetGBufferDiffuse(uv);
  vec3 normal = GetGBufferNormalWorld(uv);
  float cos = max(0., dot(normal, wi));
  return diffuse * cos * INV_PI;
}
        EvalDirectionLight

        直接使用题目提供的API,简短两行

vec3 EvalDirectionalLight(vec2 uv) {
  float visibility = GetGBufferuShadow(uv);
  return visibility * uLightRadiance;
}
        RayMarch

        按照202课上的原理,在着色点的位置开始,以某个方向射出光线,一步步向前试探找到交点。有交点的条件是:试探的点的深度比屏幕空间的该位置的深度更深(也就是在屏幕空间一直走直到被遮挡住,这时候说明有交点)。

      

bool RayMarch(vec3 ori, vec3 dir, out vec3 hitPos) {
  //定义一个最大步数防止没有找到交点而无限前进
  const int maxStep = 100;
  float stepSize = 0.05;
  vec3 stepDir = normalize(dir) * stepSize;

  for(int step=0; step< maxStep ; step++){
    float depth = GetDepth(ori);
    vec2 screenUV = GetScreenCoordinate(ori);
    float screenDepth = GetGBufferDepth(screenUV);

    if(depth > screenDepth + 0.0001){
      hitPos = ori;
      return true;
    }

    ori += dir;
  }

  return false;
}
        main里用蒙特卡洛方法解渲染方程

        这里渲染方程没有cos项,cos项在上面的EvalDiffuse已经实现。

        将其转化为代码,这里有需要注意的地方就是direction是局部坐标系的。在101中的作业3里做bumper时,我们使用TBN矩阵来将切线坐标系转化为世界坐标系。将切线坐标系转化为世界坐标系其实还需要uv坐标来确定,因为需要知道某个三角形在纹理上的位置。而这里只涉及方向的转化不涉及位置,所以直接使用TBN矩阵就能获得direction转化到世界坐标的朝向。作业框架里给我们提供了LocalBasis函数来获取两个切线。因此获取坐标系的三个方向后,使用它们创建一个TBN矩阵。

vec3 inDirectLight = vec3(0.0);
  for(int i =0;i<SAMPLE_NUM;i++){
    float pdf;
    vec3 direction = SampleHemisphereUniform(s,pdf);

    vec3 b1,b2;
    LocalBasis(normal,b1,b2);
    mat3 rotateMatrix = mat3(normal,b1,b2);
    direction = normalize(rotateMatrix * direction);
    vec3 hitPos;
    if(RayMarch(pos,direction,hitPos)){
      vec2 hitUV = GetScreenCoordinate(hitPos);
      inDirectLight += EvalDiffuse(direction,wo,uv)/pdf * EvalDiffuse(wi,direction,hitUV) * EvalDirectionalLight(hitUV);
    }
  }
  inDirectLight /= float(SAMPLE_NUM);
  L += inDirectLight;

        整个的main代码

vec3 EvalReflect(vec3 wi,vec3 wo,vec2 uv){
  vec3 pos = GetGBufferPosWorld(uv);
  vec3 normal = GetGBufferNormalWorld(uv);

  vec3 dir = normalize(reflect(-wo,normal) );
  vec3 hitPos;
  if(RayMarch(pos,dir,hitPos)){
    vec2 hitUV = GetScreenCoordinate(hitPos);
    return GetGBufferDiffuse(hitUV);
  }

  return vec3(0.0,0.0,0.0);
}

#define SAMPLE_NUM 3

void main() {
  float s = InitRand(gl_FragCoord.xy);

  vec3 pos = vPosWorld.xyz;
  vec2 uv = GetScreenCoordinate(pos);
  vec3 wi = normalize(uLightDir);
  vec3 wo = normalize(uCameraPos - pos );
  vec3 normal = GetGBufferNormalWorld(uv);


  //vec3 L = vec3(0.0);
  //L = GetGBufferDiffuse(GetScreenCoordinate(vPosWorld.xyz));  //初始的无阴影着色

  vec3 L = EvalDiffuse(wi,wo,uv) * EvalDirectionalLight(uv);  //用于调试带阴影的着色
  //L = ( L + EvalReflect(wi,wo,uv) ) / 2.0;  //用于调试反射

  vec3 inDirectLight = vec3(0.0);
  for(int i =0;i<SAMPLE_NUM;i++){
    float pdf;
    vec3 direction = SampleHemisphereUniform(s,pdf);

    vec3 b1,b2;
    LocalBasis(normal,b1,b2);
    mat3 rotateMatrix = mat3(normal,b1,b2);
    direction = normalize(rotateMatrix * direction);
    vec3 hitPos;
    if(RayMarch(pos,direction,hitPos)){
      vec2 hitUV = GetScreenCoordinate(hitPos);
      inDirectLight += EvalDiffuse(direction,wo,uv)/pdf * EvalDiffuse(wi,direction,hitUV) * EvalDirectionalLight(hitUV);
    }
  }
  inDirectLight /= float(SAMPLE_NUM);
  L += inDirectLight; 

  vec3 color = pow(clamp(L, vec3(0.0), vec3(1.0)), vec3(1.0 / 2.2));
  gl_FragColor = vec4(vec3(color.rgb), 1.0);
}

结果

        无阴影的结果

        含阴影的结果

        调试反射的结果,上面彩色格子的是正方体的面,这里反射的是地板的光。下面灰色的是地板面,反射的是正方体的光照。

        调试间接光照的结果,这里在engine里将cube1换成了cube2。调试cave时,cave是有自己的摄像机属性和光源属性的,需要额外调一下。

        原来硬阴影的cube2

        间接光照的cube2

        硬阴影的cave

实现了间接光照的cave

bonus部分没做了,原理不会很难,就是对RayMarch的优化。但是看其他大佬的作业,大家需要改动的地方特别多,最近没什么时间就没去做了= =

  • 17
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
森林防火应急联动指挥系统是一个集成了北斗定位/GPS、GIS、RS遥感、无线网络通讯、4G网络等技术的现代化智能系统,旨在提高森林火灾的预防和扑救效率。该系统通过实时监控、地图服务、历史数据管理、调度语音等功能,实现了现场指挥调度、语音呼叫通讯、远程监控、现场直播、救火人员生命检测等工作的网络化、智能化、可视化。它能够在火灾发生后迅速组网,确保现场与指挥中心的通信畅通,同时,系统支持快速部署,适应各种极端环境,保障信息的实时传输和历史数据的安全存储。 系统的设计遵循先进性、实用性、标准性、开放性、安全性、可靠性和扩展性原则,确保了技术的领先地位和未来的发展空间。系统架构包括应急终端、无线专网、应用联动应用和服务组件,以及安全审计模块,以确保用户合法性和数据安全性。部署方案灵活,能够根据现场需求快速搭建应急指挥平台,支持高并发视频直播和大容量数据存储。 智能终端设备具备三防等级,能够在恶劣环境下稳定工作,支持北斗+GPS双模定位,提供精确的位置信息。设备搭载的操作系统和处理器能够处理复杂的任务,如高清视频拍摄和数据传输。此外,设备还配备了多种传感器和接口,以适应不同的使用场景。 自适应无线网络是系统的关键组成部分,它基于认知无线电技术,能够根据环境变化动态调整通讯参数,优化通讯效果。网络支持点对点和点对多点的组网模式,具有低功耗、长距离覆盖、强抗干扰能力等特点,易于部署和维护。 系统的售后服务保障包括安装实施服务、系统维护服务、系统完善服务、培训服务等,确保用户能够高效使用系统。提供7*24小时的实时故障响应,以及定期的系统优化和维护,确保系统的稳定运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值