为虚拟对象添加逼真的光照

了解如何在您自己的应用中使用光照估计

前提条件

在继续操作之前,请务必了解基本的 AR 概念以及如何配置 ARCore 会话

使用适当的模式为每个会话配置一次 API

针对要使用的模式,在每个会话中配置一次光照估计。

Java

// Configure the session with the Lighting Estimation API in ENVIRONMENTAL_HDR mode.
Config config = session.getConfig();
config.setLightEstimationMode(LightEstimationMode.ENVIRONMENTAL_HDR);
session.configure(config);

// Configure the session with the Lighting Estimation API in AMBIENT_INTENSITY mode.
Config config = session.getConfig();
config.setLightEstimationMode(LightEstimationMode.AMBIENT_INTENSITY);
session.configure(config);

// Configure the session with the Lighting Estimation API turned off.
Config config = session.getConfig();
config.setLightEstimationMode(LightEstimationMode.DISABLED);
session.configure(config);

Kotlin

// Configure the session with the Lighting Estimation API in ENVIRONMENTAL_HDR mode.
Config config = session.config
config.lightEstimationMode = LightEstimationMode.ENVIRONMENTAL_HDR
session.configure(config)

// Configure the session with the Lighting Estimation API in AMBIENT_INTENSITY mode.
Config config = session.config
config.lightEstimationMode = LightEstimationMode.AMBIENT_INTENSITY
session.configure(config)

// Configure the session with the Lighting Estimation API turned off.
Config config = session.config
config.lightEstimationMode = LightEstimationMode.DISABLED
session.configure(config)

配置 ENVIRONMENTAL_HDR 模式

如需配置 ENVIRONMENTAL_HDR 模式,请获取每一帧的光照估计值,然后获取要使用的环境 HDR 光照组件。

Java

void update() {
  // Get the current frame.
  Frame frame = session.update();

  // Get the light estimate for the current frame.
  LightEstimate lightEstimate = frame.getLightEstimate();

  // Get intensity and direction of the main directional light from the current light estimate.
  float[] intensity = lightEstimate.getEnvironmentalHdrMainLightIntensity(); // note - currently only out param.
  float[] direction = lightEstimate.getEnvironmentalHdrMainLightDirection();
  app.setDirectionalLightValues(intensity, direction); // app-specific code.

  // Get ambient lighting as spherical harmonics coefficients.
  float[] harmonics = lightEstimate.getEnvironmentalHdrAmbientSphericalHarmonics();
  app.setAmbientSphericalHarmonicsLightValues(harmonics); // app-specific code.

  // Get HDR environmental lighting as a cubemap in linear color space.
  Image[] lightmaps = lightEstimate.acquireEnvironmentalHdrCubeMap();
  for (int i = 0; i < lightmaps.length /*should be 6*/; ++i) {
    app.uploadToTexture(i, lightmaps[i]);  // app-specific code.
  }
}

Kotlin

fun update() {
  // Get the current frame.
  val frame = session.update()

  // Get the light estimate for the current frame.
  val lightEstimate = frame.lightEstimate

  // Get intensity and direction of the main directional light from the current light estimate.
  val intensity = lightEstimate.environmentalHdrMainLightIntensity
  val direction = lightEstimate.environmentalHdrMainLightDirection
  app.setDirectionalLightValues(intensity, direction) // app-specific code.

  // Get ambient lighting as spherical harmonics coefficients.
  val harmonics = lightEstimate.environmentalHdrAmbientSphericalHarmonics
  app.ambientSphericalHarmonicsLightValues = harmonics // app-specific code.

  // Get HDR environmental lighting as a cubemap in linear color space.
  val lightMaps = lightEstimate.acquireEnvironmentalHdrCubeMap();
  for ((index, lightMap) in lightMaps.withIndex()) { // 6 maps total.
    app.uploadToTexture(index, lightMap); // app-specific code.
  }
}

配置 AMBIENT_INTENSITY 模式

如果您打算使用 AMBIENT_INTENSITY 模式的色彩校正组件,请先通过重复使用共享分配来避免在每个帧上分配色彩校正。

Java

 // Avoid allocation on every frame.
float[] colorCorrection = new float[4];

Kotlin

val colorCorrection = floatArrayOf(0.0f, 0.0f, 0.0f, 0.0f)

获取每个帧的光照估计值,然后获取要使用的环境光强度分量。

Java

void update() {
  // Get the current frame.
  Frame frame = session.update();

  // Get the light estimate for the current frame.
  LightEstimate lightEstimate = frame.getLightEstimate();

  // Get the pixel intensity of AMBIENT_INTENSITY mode.
  float pixelIntensity = lightEstimate.getPixelIntensity();

  // Read the pixel color correction of AMBIENT_INTENSITY mode into colorCorrection.
  lightEstimate.getColorCorrection(colorCorrection, 0);
}

Kotlin

fun update() {
    // Get the current frame.
  val frame = session.update()

  // Get the light estimate for the current frame.
  val lightEstimate = frame.lightEstimate

  // Get the pixel intensity of AMBIENT_INTENSITY mode.
  val pixelIntensity = lightEstimate.pixelIntensity

  // Read the pixel color correction of AMBIENT_INTENSITY mode into colorCorrection.
  lightEstimate.getColorCorrection(colorCorrection, 0)
}

利用环境 HDR API 确保节能

能量守恒是指从表面反射的光的强度永远不会高于照射到表面之前的强度。此规则在基于物理的渲染中强制执行,但通常在视频游戏和移动应用中使用的旧版渲染流水线中省略。

如果您使用的是基于物理的渲染流水线并进行环境 HDR 光照估计,只需确保在虚拟对象中使用基于物理的材质即可。

不过,如果您未使用基于物理的流水线,则有以下几种选择:

  • 最理想的解决方案是迁移到基于物理的流水线。

  • 不过,如果无法实现这一点,一个不错的解决方法是将非基于物理的材质的反射率值乘以能量守恒系数。这样可以确保至少将 BRDF 着色模型转换为基于物理的着色模型。每种 BRDF 都有不同的系数,例如,对于漫反射,该系数为 1/Pi。