Skip to content

屏幕空间反射 - SSR

一种基于屏幕空间的反射效果实现,模拟光滑物体表面可以实时反射其周边物体影像的视觉效果。该反射效果优点为实时渲染,某一个物体发生移动,反射画面中物体也会发生移动;能精确的从每个像素反射。缺点为不能够反射出物体的背面,且屏幕范围外的物体也不能够被反射到其他的物体上。

ts
//初始化引擎
await Engine3D.init();

Engine3D.setting.render.postProcessing.ssr.fadeEdgeRatio = 0.2;
Engine3D.setting.render.postProcessing.ssr.rayMarchRatio = 0.5;
Engine3D.setting.render.postProcessing.ssr.fadeDistanceMin = 600;
Engine3D.setting.render.postProcessing.ssr.fadeDistanceMax = 2000;
Engine3D.setting.render.postProcessing.ssr.roughnessThreshold = 0.5;
Engine3D.setting.render.postProcessing.ssr.powDotRN = 0.2;

//创建渲染器
let renderJob = new ForwardRenderJob(this.scene);
renderJob.addPost(new SSRPost());
Engine3D.startRender(renderJob);

Engine3D.setting.render.postProcessing.ssr 配置参数。

参数类型描述
fadeEdgeRationumber渐变速率。
rayMarchRationumber光线步进速率。
fadeDistanceMinnumber消退距离最小值。
fadeDistanceMaxnumber消退距离最大值。
roughnessThresholdnumber粗糙度阈值。
powDotRNnumbernormal和reflection点积的pow参数。


Orillusion powered by WebGPU on Chrome/Edge 113+
Please upgrade to latest Chrome/Edge

<
ts
import {
  Camera3D,
  defaultTexture,
  DirectLight,
  Engine3D,
  ForwardRenderJob,
  GLTFParser,
  GUIHelp,
  LitMaterial,
  HoverCameraController,
  KelvinUtil,
  MeshRenderer,
  Object3D,
  PlaneGeometry,
  Scene3D,
  SphereGeometry,
  SSRPost,
  SSR_IS_Kernel,
  Time,
  CameraUtil,
  webGPUContext,
  GTAOPost,
  HDRBloomPost,
  TAAPost,
} from "@orillusion/core";

export class Sample_SSR {
  lightObj: Object3D;
  scene: Scene3D;
  mats: any[];

  constructor() {}

  async run() {
    Engine3D.setting.material.materialChannelDebug = false;
    Engine3D.setting.material.materialDebug = false;

    Engine3D.setting.shadow.shadowBound = 200;
    Engine3D.setting.shadow.shadowBias = 0.002;
    Engine3D.setting.shadow.debug = false;

    Engine3D.setting.shadow.autoUpdate = true;
    Engine3D.setting.shadow.updateFrameRate = 1;

    Engine3D.setting.render.postProcessing.taa.debug = false;
    Engine3D.setting.render.postProcessing.gtao.debug = false;
    Engine3D.setting.render.postProcessing.bloom.debug = false;
    await Engine3D.init({
      renderLoop: () => this.loop(),
    });

    GUIHelp.init();

    this.scene = new Scene3D();
    Camera3D.mainCamera = CameraUtil.createCamera3DObject(this.scene, "camera");
    Camera3D.mainCamera.perspective(60, webGPUContext.aspect, 1, 2000.0);
    let ctrl = Camera3D.mainCamera.object3D.addComponent(HoverCameraController);
    ctrl.setCamera(180, -5, 60);
    await this.initScene(this.scene);

    let renderJob = new ForwardRenderJob(this.scene);
    renderJob.addPost(new GTAOPost());
    renderJob.addPost(new SSRPost());
    renderJob.addPost(new TAAPost());
    renderJob.addPost(new HDRBloomPost());

    Engine3D.startRender(renderJob);
  }

  /**
   * @ch asdasda
   * @en asdasdas
   * @param scene
   * @returns
   */
  async initScene(scene: Scene3D) {
    /******** light *******/
    {
      this.lightObj = new Object3D();
      this.lightObj.rotationX = 15;
      this.lightObj.rotationY = 110;
      this.lightObj.rotationZ = 0;
      let lc = this.lightObj.addComponent(DirectLight);
      lc.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
      lc.castShadow = true;
      lc.intensity = 27;
      lc.debug();
      scene.addChild(this.lightObj);
    }

    // 加载外部模型文件;
    let minimalObj = await Engine3D.res.loadGltf(
      "https://cdn.orillusion.com/PBR/ToyCar/ToyCar.gltf"
    );
    minimalObj.scaleX = minimalObj.scaleY = minimalObj.scaleZ = 1000;
    scene.addChild(minimalObj);

    await this.createPlane(scene);
    return true;
  }

  private sphere: Object3D;

  private async createPlane(scene: Scene3D) {
    let mat = new LitMaterial();
    mat.baseMap = defaultTexture.grayTexture;
    mat.normalMap = defaultTexture.normalTexture;
    mat.aoMap = defaultTexture.whiteTexture;
    mat.emissiveMap = defaultTexture.blackTexture;
    mat.roughness = 0.2;
    mat.roughness_max = 0.1;
    mat.metallic = 0.5;

    {
      let floorMaterial = new LitMaterial();
      floorMaterial.baseMap = defaultTexture.grayTexture;
      floorMaterial.normalMap = defaultTexture.normalTexture;
      floorMaterial.aoMap = defaultTexture.whiteTexture;
      floorMaterial.emissiveMap = defaultTexture.blackTexture;
      floorMaterial.roughness = 0.5;
      floorMaterial.roughness_max = 0.1;
      floorMaterial.metallic = 0.5;

      let planeGeometry = new PlaneGeometry(200, 200);
      let floor: Object3D = new Object3D();
      let mr = floor.addComponent(MeshRenderer);
      mr.material = floorMaterial;
      mr.geometry = planeGeometry;
      scene.addChild(floor);

      GUIHelp.add(floorMaterial, "roughness", 0, 1, 0.01);
      GUIHelp.add(floorMaterial, "metallic", 0, 1, 0.01);
    }

    {
      let sphereGeometry = new SphereGeometry(10, 50, 50);
      let obj: Object3D = new Object3D();
      let mr = obj.addComponent(MeshRenderer);
      mr.material = mat;
      mr.geometry = sphereGeometry;
      obj.x = 30;
      obj.y = 10;
      scene.addChild(obj);
      this.sphere = obj;
    }

    {
      let sphereGeometry = new SphereGeometry(2, 50, 50);
      for (let i = 0; i < 10; i += 2) {
        for (let j = 0; j < 10; j += 2) {
          let rmMaterial = new LitMaterial();
          rmMaterial.baseMap = defaultTexture.grayTexture;
          rmMaterial.normalMap = defaultTexture.normalTexture;
          rmMaterial.aoMap = defaultTexture.whiteTexture;
          rmMaterial.emissiveMap = defaultTexture.blackTexture;
          rmMaterial.roughness = j / 10;
          rmMaterial.roughness_max = 1;
          rmMaterial.metallic = i / 10;

          let obj: Object3D = new Object3D();
          let mr = obj.addComponent(MeshRenderer);
          mr.material = rmMaterial;
          mr.geometry = sphereGeometry;

          obj.y = j * 5 + 10;
          obj.x = 50;
          obj.z = i * 5 - 25;
          scene.addChild(obj);
        }
      }
    }
  }

  private loop(): void {
    if (this.sphere) {
      this.sphere.x = Math.sin(Time.time * 0.0001) * 30;
      this.sphere.z = Math.cos(Time.time * 0.0001) * 30;
    }
  }
}

new Sample_SSR().run();