Realistycznie oświetlone wirtualne obiekty w scenie

Dowiedz się, jak używać szacowania oświetlenia w swoich aplikacjach.

Wymagania wstępne

Zanim przejdziesz dalej, upewnij się, że rozumiesz podstawowe pojęcia związane z AR i wiesz, jak skonfigurować sesję ARCore.

Skonfiguruj interfejs API raz na sesję w odpowiednim trybie.

Skonfiguruj szacowanie oświetlenia raz na sesję w przypadku trybu, którego chcesz używać.

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)

Konfigurowanie trybu ENVIRONMENTAL_HDR

Aby skonfigurować tryb ENVIRONMENTAL_HDR, uzyskaj oszacowanie światła dla każdej klatki, a następnie pobierz komponenty oświetlenia środowiskowego HDR, których chcesz użyć.

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.
  }
}

Konfigurowanie trybu AMBIENT_INTENSITY

Jeśli planujesz używać komponentu korekcji kolorów w AMBIENT_INTENSITY trybie, najpierw unikaj przydzielania korekcji kolorów w każdej klatce, ponownie wykorzystując wspólne przydzielanie.

Java

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

Kotlin

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

Uzyskaj oszacowanie oświetlenia dla każdej klatki, a następnie pobierz komponenty intensywności otoczenia, których chcesz użyć.

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)
}

Zapewnianie oszczędzania energii za pomocą interfejsów Environmental HDR API

Zasada zachowania energii mówi, że światło odbite od powierzchni nigdy nie będzie bardziej intensywne niż przed uderzeniem w tę powierzchnię. Ta reguła jest wymuszana w renderowaniu opartym na fizyce, ale zwykle jest pomijana w starszych potokach renderowania używanych w grach wideo i aplikacjach mobilnych.

Jeśli używasz potoku renderowania opartego na fizyce z szacowaniem oświetlenia środowiskowego HDR, po prostu upewnij się, że w wirtualnych obiektach używasz materiałów opartych na fizyce.

Jeśli jednak nie używasz potoku opartego na fizyce, masz kilka opcji:

  • Najlepszym rozwiązaniem jest przejście na potok oparty na fizyce.

  • Jeśli to niemożliwe, dobrym rozwiązaniem jest pomnożenie wartości albedo z materiału nieopartego na fizyce przez współczynnik zachowania energii. Dzięki temu można mieć pewność, że co najmniej model cieniowania BRDF może zostać przekonwertowany na model fizyczny. Każda funkcja BRDF ma inny współczynnik – na przykład w przypadku odbicia rozproszonego jest to 1/Pi.