From d6dc966c04e7bc9dd6d43a61ebfaab3f4fbc89f4 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Sun, 9 Aug 2026 02:02:51 -0700 Subject: [PATCH] Support planar reflections on physically based materials. PiperOrigin-RevId: 961670546 Change-Id: Ifa69b8251c5f3fae6a76427f13df9c688370c741 --- src/render/filament/CMakeLists.txt | 2 + .../filament/assets/pbr_packed_reflect.mat | 66 ++++++++++++++++++ src/render/filament/assets/pbr_reflect.mat | 69 +++++++++++++++++++ src/render/filament/core/material_manager.cc | 10 +++ src/render/filament/core/object_manager.cc | 3 + src/render/filament/core/object_manager.h | 2 + 6 files changed, 152 insertions(+) create mode 100644 src/render/filament/assets/pbr_packed_reflect.mat create mode 100644 src/render/filament/assets/pbr_reflect.mat diff --git a/src/render/filament/CMakeLists.txt b/src/render/filament/CMakeLists.txt index ac2ae35e..f6945da6 100644 --- a/src/render/filament/CMakeLists.txt +++ b/src/render/filament/CMakeLists.txt @@ -103,6 +103,8 @@ set(MATERIAL_FILES pbr_transparent.mat pbr_packed.mat pbr_packed_transparent.mat + pbr_reflect.mat + pbr_packed_reflect.mat phong_2d_fade.mat phong_2d.mat phong_2d_reflect.mat diff --git a/src/render/filament/assets/pbr_packed_reflect.mat b/src/render/filament/assets/pbr_packed_reflect.mat new file mode 100644 index 00000000..2541dbf7 --- /dev/null +++ b/src/render/filament/assets/pbr_packed_reflect.mat @@ -0,0 +1,66 @@ +// Copyright 2026 DeepMind Technologies Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +material { + name : pbr_packed_reflect, + shadingModel : lit, + postLightingBlending : add, + flipUV: false, + parameters : [ + { type : sampler2d, name : BaseColor }, + { type : sampler2d, name : Normal }, + { type : sampler2d, name : ORM }, + { type : sampler2d, name : Emissive }, + { type : float4, name : BaseColorFactor }, + { type : float, name : MetallicFactor }, + { type : float, name : RoughnessFactor }, + { type : float, name : EmissiveFactor }, + { type : float, name : Reflectance }, + { type : sampler2d, name : Reflection } + ], + requires : [ + uv0 + ] +} + +fragment { + void material(inout MaterialInputs material) { + vec2 uv = getUV0(); + vec2 screen_uv = gl_FragCoord.xy * getResolution().zw; + + material.normal = texture(materialParams_Normal, uv).xyz * 2.0 - 1.0; + prepareMaterial(material); + + material.baseColor = materialParams.BaseColorFactor; + material.baseColor *= texture(materialParams_BaseColor, uv); + material.ambientOcclusion = texture(materialParams_ORM, uv).r; + material.roughness = materialParams.RoughnessFactor; + material.roughness *= texture(materialParams_ORM, uv).g; + material.metallic = materialParams.MetallicFactor; + material.metallic *= texture(materialParams_ORM, uv).b; + material.emissive = texture(materialParams_Emissive, uv); + material.emissive.rgb *= materialParams.EmissiveFactor; + material.emissive.a = (1.0 - material.emissive.a) * + materialParams.EmissiveFactor; + + // Planar reflection: radiance from the mirror direction, weighted by the + // Fresnel term and added after lighting. F0 is the material reflectance for + // dielectrics and the base color for metals, which reflect their own tint. + vec4 reflection = texture(materialParams_Reflection, screen_uv); + vec3 f0 = mix(vec3(materialParams.Reflectance), material.baseColor.rgb, + material.metallic); + vec3 fresnel = f0 + (1.0 - f0) * pow(1.0 - getNdotV(), 5.0); + material.postLightingColor = vec4(reflection.rgb * fresnel, 0.0); + } +} diff --git a/src/render/filament/assets/pbr_reflect.mat b/src/render/filament/assets/pbr_reflect.mat new file mode 100644 index 00000000..73ed3b79 --- /dev/null +++ b/src/render/filament/assets/pbr_reflect.mat @@ -0,0 +1,69 @@ +// Copyright 2025 DeepMind Technologies Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +material { + name : pbr_reflect, + shadingModel : lit, + postLightingBlending : add, + flipUV: false, + parameters : [ + { type : sampler2d, name : BaseColor }, + { type : sampler2d, name : Normal }, + { type : sampler2d, name : Occlusion }, + { type : sampler2d, name : Roughness }, + { type : sampler2d, name : Metallic }, + { type : sampler2d, name : Emissive }, + { type : float4, name : BaseColorFactor }, + { type : float, name : MetallicFactor }, + { type : float, name : RoughnessFactor }, + { type : float, name : EmissiveFactor }, + { type : float, name : Reflectance }, + { type : sampler2d, name : Reflection } + + ], + requires : [ + uv0 + ] +} + +fragment { + void material(inout MaterialInputs material) { + vec2 uv = getUV0(); + vec2 screen_uv = gl_FragCoord.xy * getResolution().zw; + + material.normal = texture(materialParams_Normal, uv).xyz * 2.0 - 1.0; + prepareMaterial(material); + + material.baseColor = materialParams.BaseColorFactor; + material.baseColor *= texture(materialParams_BaseColor, uv); + material.ambientOcclusion = texture(materialParams_Occlusion, uv).r; + material.roughness = materialParams.RoughnessFactor; + material.roughness *= texture(materialParams_Roughness, uv).r; + material.metallic = materialParams.MetallicFactor; + material.metallic *= texture(materialParams_Metallic, uv).r; + material.emissive = texture(materialParams_Emissive, uv); + material.emissive.rgb *= materialParams.EmissiveFactor; + material.emissive.a = (1.0 - material.emissive.a) * + materialParams.EmissiveFactor; + + // Planar reflection: radiance from the mirror direction, weighted by the + // Fresnel term and added after lighting. F0 is the material reflectance for + // dielectrics and the base color for metals, which reflect their own tint. + vec4 reflection = texture(materialParams_Reflection, screen_uv); + vec3 f0 = mix(vec3(materialParams.Reflectance), material.baseColor.rgb, + material.metallic); + vec3 fresnel = f0 + (1.0 - f0) * pow(1.0 - getNdotV(), 5.0); + material.postLightingColor = vec4(reflection.rgb * fresnel, 0.0); + } +} diff --git a/src/render/filament/core/material_manager.cc b/src/render/filament/core/material_manager.cc index 6d75c195..e5e945cc 100644 --- a/src/render/filament/core/material_manager.cc +++ b/src/render/filament/core/material_manager.cc @@ -133,30 +133,40 @@ MaterialManager::MaterialType MaterialManager::GetMaterialType( } else if (material.orm_texture) { if (material.opacity_texture) { return ObjectManager::kPbrPackedTransparent; + } else if (material.reflectance > 0) { + return ObjectManager::kPbrPackedReflect; } else { return ObjectManager::kPbrPacked; } } else if (material.metallic_texture) { if (material.opacity_texture) { return ObjectManager::kPbrPackedTransparent; + } else if (material.reflectance > 0) { + return ObjectManager::kPbrReflect; } else { return ObjectManager::kPbr; } } else if (material.roughness_texture) { if (material.color[3] < 1.0f) { return ObjectManager::kPbrTransparent; + } else if (material.reflectance > 0) { + return ObjectManager::kPbrReflect; } else { return ObjectManager::kPbr; } } else if (material.metallic >= 0) { if (material.color[3] < 1.0f) { return ObjectManager::kPbrTransparent; + } else if (material.reflectance > 0) { + return ObjectManager::kPbrReflect; } else { return ObjectManager::kPbr; } } else if (material.roughness >= 0) { if (material.color[3] < 1.0f) { return ObjectManager::kPbrTransparent; + } else if (material.reflectance > 0) { + return ObjectManager::kPbrReflect; } else { return ObjectManager::kPbr; } diff --git a/src/render/filament/core/object_manager.cc b/src/render/filament/core/object_manager.cc index f51c64f5..44565f0a 100644 --- a/src/render/filament/core/object_manager.cc +++ b/src/render/filament/core/object_manager.cc @@ -57,6 +57,9 @@ ObjectManager::ObjectManager(filament::Engine* engine) : engine_(engine) { materials_[kPbrTransparent] = LoadMaterial(engine, "pbr_transparent.filamat"); materials_[kPbrPackedTransparent] = LoadMaterial(engine, "pbr_packed_transparent.filamat"); + materials_[kPbrReflect] = LoadMaterial(engine, "pbr_reflect.filamat"); + materials_[kPbrPackedReflect] = + LoadMaterial(engine, "pbr_packed_reflect.filamat"); materials_[kPhong2d] = LoadMaterial(engine, "phong_2d.filamat"); materials_[kPhong2dFade] = LoadMaterial(engine, "phong_2d_fade.filamat"); materials_[kPhong2dReflect] = diff --git a/src/render/filament/core/object_manager.h b/src/render/filament/core/object_manager.h index adfc2152..ca60e107 100644 --- a/src/render/filament/core/object_manager.h +++ b/src/render/filament/core/object_manager.h @@ -44,6 +44,8 @@ class ObjectManager { kPbrTransparent, kPbrPacked, kPbrPackedTransparent, + kPbrReflect, + kPbrPackedReflect, kPhong2d, kPhong2dFade, kPhong2dReflect,