filament: SurfaceOrientation doesn't duplicate vertices when generating flat normals
Describe the bug I am having two (separate I believe) issues rendering some meshes in Filament. I’m only opening one issue because they are both related to the same mesh type. We generate many meshes of this type, and the issue is not confined to this specific mesh, but all meshes of this type. First, this is what the mesh looks like in scenekit:

Issue 1
The Filament directional lights only illuminate parts of the scene. This is clear if I light the scene with only a directional light. This issue appears in our viewer as well as the sample-gltf iOS viewer. As you can see a large chunk of the ground plane is not illuminated by the light (maybe there is a setting to fix this, but I played with all that seemed relevant)
At first I thought it was maybe an issue on our side with the triangulation, but as you can see in meshlab the ground plane only has two triangles and appear to be unrelated to the illumination boundaries

*** Issue 2 ***
The colors for the mesh are pretty far off from what they are in all other viewers (SceneKit, MeshLab, ThreeJS). In particular they appear to be much less saturated. I have tried adjusting the colors and intensity of the lights but this did not fix it. Here is what it looks like in Filament when I adjusted the directional and indirect lights to be as good as I could make them
To Reproduce
Load this .glb in filament and observe the issues:
These were my exact lighting settings:
math::float3 harmonics[1];
harmonics[0] = math::float3(1.0f, 1.0f, 1.0f);
indirect_light_ = IndirectLight::Builder().irradiance(1, harmonics).intensity(24000).build(*engine_);
if (indirect_light_ == nullptr) {
throw std::runtime_error("Creating a filament indirect light failed!");
}
scene_->setIndirectLight(indirect_light_);
// Lights and shadows for room mode captures
utils::Entity light = utils::EntityManager::get().create();
LightManager::ShadowOptions shadowOptions;
shadowOptions.shadowCascades = 3;
shadowOptions.mapSize = 4096;
shadowOptions.vsm.blurWidth = 120;
shadowOptions.vsm.msaaSamples = 16;
LightManager::Builder(LightManager::Type::DIRECTIONAL)
.color(Color::toLinear<ACCURATE>({0.98f, 0.9f, 0.86f}))
.intensity(38000)
.direction({0.2, -1, -0.3})
.castShadows(true)
.shadowOptions(shadowOptions)
.build(*engine_, light);
scene_->addEntity(light);
Expected behavior A clear and concise description of what you expected to happen.
Screenshots If applicable, add screenshots to help explain your problem.
Logs If applicable, copy logs from your console here. Please do not use screenshots of logs, copy them as text.
Desktop (please complete the following information):
- OS: tested on iOS, Mac, Android and WebGL
- GPU: All tested
- Backend: Tested on OpenGL, Metal and WebGL
Smartphone (please complete the following information):
- Device: [e.g. Pixel 2]
- OS: [e.g. Android Pie 9.0]
Additional context Add any other context about the problem here.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 19 (1 by maintainers)
Commits related to this issue
- geometry: Add TangentSpaceMesh class outline - Defined class with documentation in comments - Implemented algorithm selection - No actual algorithms written yet Part of google/filament#6358 — committed to google/filament by poweifeng a year ago
- geometry: Add TangentSpaceMesh class outline - Defined class with documentation in comments - Implemented algorithm selection - No actual algorithms written yet Part of google/filament#6358 — committed to google/filament by poweifeng a year ago
- geometry: Add TangentSpaceMesh class outline - Defined class with documentation in comments - Implemented algorithm selection - No actual algorithms written yet Part of google/filament#6358 — committed to google/filament by poweifeng a year ago
- geometry: Add TangentSpaceMesh class outline - Defined class with documentation in comments - Implemented algorithm selection - No actual algorithms written yet Part of google/filament#6358 — committed to google/filament by poweifeng a year ago
- geometry: Add TangentSpaceMesh class outline (#6476) - Defined class with documentation in comments - Implemented algorithm selection - No actual algorithms written yet Part of google/filamen... — committed to google/filament by poweifeng a year ago
- geometry: Add TangentSpaceMesh class outline (#6476) - Defined class with documentation in comments - Implemented algorithm selection - No actual algorithms written yet Part of google/filamen... — committed to plepers/filament by poweifeng a year ago
- gltfio: use tangent space mesh - Fix missing attributes in TangentSpaceMesh - Fix missing reference in MikktspaceImpl.cpp - Add gltfio/src/extended to implement an alternate loader for primitiv... — committed to google/filament by poweifeng 5 months ago
- gltfio: use tangent space mesh - Fix missing attributes in TangentSpaceMesh - Fix missing reference in MikktspaceImpl.cpp - Add gltfio/src/extended to implement an alternate loader for primitiv... — committed to google/filament by poweifeng 5 months ago
- gltfio: use tangent space mesh - Fix missing attributes in TangentSpaceMesh - Fix missing reference in MikktspaceImpl.cpp - Add gltfio/src/extended to implement an alternate loader for primitiv... — committed to google/filament by poweifeng 5 months ago
- gltfio: enable extended implementation This change will enable proper flat-shading and MikkTSpace. Fixes #6358, #7444 — committed to google/filament by poweifeng 2 months ago
- gltfio: enable extended implementation This change will enable proper flat-shading and MikkTSpace. Caveats: - Only for disk-local glTF resources - iOS, Web, Android do not work as of now Fixes #6... — committed to google/filament by poweifeng 2 months ago
- gltfio: enable extended implementation This change will enable proper flat-shading and MikkTSpace. Caveats: - Only for disk-local glTF resources - iOS, Web, Android do not work as of now Fixes #6... — committed to google/filament by poweifeng 2 months ago
- gltfio: enable extended implementation (#7776) This change will enable proper flat-shading and MikkTSpace. Caveats: - Only for disk-local glTF resources - iOS, Web, Android do not work as of n... — committed to google/filament by poweifeng 2 months ago
I’ll reopen it so we can fix this issue on our end
This file contains a glb that isolates the issue: flat_normals_bug.zip
Flat normals are computed per triangle but we don’t duplicate vertices. So adjacent triangles erase each other’s normals in
SurfaceOrientation.cpp/OrientationBuilderImpl::buildWithFlatNormals(), which in turns creates degenerate tangent frames inbuildWithNormalsOnly()in the same file. The fix is to makebuildWithFlatNormals()properly duplicate shared vertices when generating the flat normals.The current workaround is to generate glTF files with normals in them.
The problem is that per the glTF spec we apply flat shading when no normals are provided. Unfortunately the code that does that does not duplicate shared vertices, which means we share normals and tangents across faces that are not coplanar.
If you are using the same tone mapper as in the other renderers, it should look very similar. The only other thing I can think about is that Filament also outputs in properly encoded sRGB (but it should be the case of those other renderers as well). Of course also making sure you use the same light and exposure setup (you can make FIlament behave like non-photometric based renderers by calling Camera.setExposure(1f) and then the light intensities are relative, so you’d set the directional light’s intensity to 1 for instance instead of 38,000. Also make sure your light colors are correct: all Filament APIs expect to be fed colors in “linear sRGB” but we provide conversion APIs (like you did in your sample).