Skip to content

Commit 15bb295

Browse files
committed
A new froxel grid vizualization for FilamentApp
FilamentApp now has debugging options to enable or disable the camera and directional shadow frustums, as well as the new "froxel grid" visualization. "froxel grid" is automatically enabled when "froxel debugging" is enabled in the debug gui in gltf_viewer. New corresponding debugging APIs were added to View.
1 parent cea178a commit 15bb295

File tree

13 files changed

+458
-27
lines changed

13 files changed

+458
-27
lines changed

filament/include/filament/View.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <utils/FixedCapacityVector.h>
2828

2929
#include <math/mathfwd.h>
30+
#include <math/mat4.h>
3031

3132
#include <utility>
3233

@@ -760,6 +761,27 @@ class UTILS_PUBLIC View : public FilamentAPI {
760761
//! debugging: enable or disable froxel visualisation for this view.
761762
void setFroxelVizEnabled(bool enabled) noexcept;
762763

764+
//! debugging: returns information about the froxel configuration
765+
struct FroxelConfigurationInfo {
766+
uint8_t width;
767+
uint8_t height;
768+
uint8_t depth;
769+
uint32_t viewportWidth;
770+
uint32_t viewportHeight;
771+
math::uint2 froxelDimension;
772+
float zLightFar;
773+
float linearizer;
774+
math::mat4f p;
775+
math::float4 clipTransform;
776+
};
777+
778+
struct FroxelConfigurationInfoWithAge {
779+
FroxelConfigurationInfo info;
780+
uint32_t age;
781+
};
782+
783+
FroxelConfigurationInfoWithAge getFroxelConfigurationInfo() const noexcept;
784+
763785
/** Result of a picking query */
764786
struct PickingQueryResult {
765787
utils::Entity renderable{}; //! RenderableManager Entity at the queried coordinates

filament/src/Froxelizer.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,20 @@ size_t Froxelizer::getFroxelBufferByteCount(FEngine::DriverApi& driverApi) noexc
124124
return std::min(FROXEL_BUFFER_MAX_ENTRY_COUNT * sizeof(FroxelEntry), targetSize);
125125
}
126126

127+
View::FroxelConfigurationInfo Froxelizer::getFroxelConfigurationInfo() const noexcept {
128+
return { uint8_t(getFroxelCountX()),
129+
uint8_t(getFroxelCountY()),
130+
uint8_t(getFroxelCountZ()),
131+
mViewport.width,
132+
mViewport.height,
133+
mFroxelDimension,
134+
mZLightFar,
135+
mLinearizer[0],
136+
mProjection,
137+
mClipTransform
138+
};
139+
}
140+
127141
Froxelizer::Froxelizer(FEngine& engine)
128142
: mArena("froxel", PER_FROXELDATA_ARENA_SIZE),
129143
mZLightNear(FROXEL_FIRST_SLICE_DEPTH),
@@ -198,10 +212,14 @@ void Froxelizer::setProjection(const mat4f& projection,
198212
bool Froxelizer::prepare(
199213
FEngine::DriverApi& driverApi, RootArenaScope& rootArenaScope,
200214
filament::Viewport const& viewport,
201-
const mat4f& projection, float const projectionNear, float const projectionFar) noexcept {
215+
const mat4f& projection, float const projectionNear, float const projectionFar,
216+
float4 const& clipTransform) noexcept {
202217
setViewport(viewport);
203218
setProjection(projection, projectionNear, projectionFar);
204219

220+
// Only for debugging
221+
mClipTransform = clipTransform;
222+
205223
bool uniformsNeedUpdating = false;
206224
if (UTILS_UNLIKELY(mDirtyFlags)) {
207225
uniformsNeedUpdating = update();
@@ -361,8 +379,10 @@ bool Froxelizer::update() noexcept {
361379
getFroxelBufferEntryCount(), viewport);
362380

363381
mFroxelDimension = froxelDimension;
364-
mClipToFroxelX = (0.5f * float(viewport.width)) / float(froxelDimension.x);
365-
mClipToFroxelY = (0.5f * float(viewport.height)) / float(froxelDimension.y);
382+
// note: because froxelDimension is a power-of-two and viewport is an integer, mClipFroxel
383+
// is an exact value (which is not true for 1/mClipToFroxelX, btw)
384+
mClipToFroxelX = float(viewport.width) / float(2 * froxelDimension.x);
385+
mClipToFroxelY = float(viewport.height) / float(2 * froxelDimension.y);
366386

367387
uniformsNeedUpdating = true;
368388

@@ -408,8 +428,7 @@ bool Froxelizer::update() noexcept {
408428
}
409429

410430
// for the inverse-transformation (view-space z to z-slice)
411-
mLinearizer = 1.0f / linearizer;
412-
mZLightFar = zLightFar;
431+
mLinearizer = { linearizer, 1.0f / linearizer };
413432

414433
mParamsZ[0] = 0; // updated when camera changes
415434
mParamsZ[1] = 0; // updated when camera changes
@@ -466,7 +485,7 @@ bool Froxelizer::update() noexcept {
466485
// ==> i = log2(z_screen * (far/near)) * (-1/linearizer) + zcount
467486
mParamsZ[0] = mZLightFar / Pw;
468487
mParamsZ[1] = 0.0f;
469-
mParamsZ[2] = -mLinearizer;
488+
mParamsZ[2] = -mLinearizer[1];
470489
} else {
471490
// orthographic projection
472491
// z_view = (1 - z_screen) * (near - far) - near
@@ -476,7 +495,7 @@ bool Froxelizer::update() noexcept {
476495
// Pw = far / (far - near)
477496
mParamsZ[0] = -1.0f / (Pz * mZLightFar); // -(far-near) / mZLightFar
478497
mParamsZ[1] = Pw / (Pz * mZLightFar); // far / mZLightFar
479-
mParamsZ[2] = mLinearizer;
498+
mParamsZ[2] = mLinearizer[1];
480499
}
481500
uniformsNeedUpdating = true;
482501
}
@@ -507,7 +526,7 @@ size_t Froxelizer::findSliceZ(float const z) const noexcept {
507526

508527
// This whole function is now branch-less.
509528

510-
int s = int( fast::log2(-z / mZLightFar) * mLinearizer + float(mFroxelCountZ) );
529+
int s = int( fast::log2(-z / mZLightFar) * mLinearizer[1] + float(mFroxelCountZ) );
511530

512531
// there are cases where z can be negative here, e.g.:
513532
// - the light is visible, but its center is behind the camera

filament/src/Froxelizer.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "details/Scene.h"
2323
#include "details/Engine.h"
2424

25+
#include <filament/View.h>
2526
#include <filament/Viewport.h>
2627

2728
#include <backend/Handle.h>
@@ -31,6 +32,7 @@
3132
#include <utils/Slice.h>
3233

3334
#include <math/mat4.h>
35+
#include <math/vec2.h>
3436
#include <math/vec4.h>
3537

3638
namespace filament {
@@ -112,7 +114,8 @@ class Froxelizer {
112114
* return true if updateUniforms() needs to be called
113115
*/
114116
bool prepare(backend::DriverApi& driverApi, RootArenaScope& rootArenaScope, Viewport const& viewport,
115-
const math::mat4f& projection, float projectionNear, float projectionFar) noexcept;
117+
const math::mat4f& projection, float projectionNear, float projectionFar,
118+
math::float4 const& clipTransform) noexcept;
116119

117120
Froxel getFroxelAt(size_t x, size_t y, size_t z) const noexcept;
118121
size_t getFroxelCountX() const noexcept { return mFroxelCountX; }
@@ -161,6 +164,8 @@ class Froxelizer {
161164

162165
static size_t getFroxelBufferByteCount(FEngine::DriverApi& driverApi) noexcept;
163166

167+
View::FroxelConfigurationInfo getFroxelConfigurationInfo() const noexcept;
168+
164169
private:
165170
size_t getFroxelBufferEntryCount() const noexcept {
166171
return mFroxelBufferEntryCount;
@@ -260,9 +265,10 @@ class Froxelizer {
260265
uint16_t mFroxelCountZ = 0;
261266
uint32_t mFroxelCount = 0;
262267
math::uint2 mFroxelDimension = {};
268+
math::float4 mClipTransform = { 1, 1, 0, 0 };
263269

264270
math::mat4f mProjection;
265-
float mLinearizer = 0.0f;
271+
math::float2 mLinearizer{};
266272
float mClipToFroxelX = 0.0f;
267273
float mClipToFroxelY = 0.0f;
268274
backend::BufferObjectHandle mRecordsBuffer;

filament/src/View.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ void View::setFroxelVizEnabled(bool const enabled) noexcept {
8181
downcast(this)->setFroxelVizEnabled(enabled);
8282
}
8383

84+
View::FroxelConfigurationInfoWithAge View::getFroxelConfigurationInfo() const noexcept {
85+
return downcast(this)->getFroxelConfigurationInfo();
86+
}
87+
8488
void View::setShadowingEnabled(bool const enabled) noexcept {
8589
downcast(this)->setShadowingEnabled(enabled);
8690
}

filament/src/details/View.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,10 +659,12 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
659659
if (hasDynamicLighting()) {
660660
auto& froxelizer = mFroxelizer;
661661
if (froxelizer.prepare(driver, rootArenaScope, viewport,
662-
cameraInfo.projection, cameraInfo.zn, cameraInfo.zf)) {
662+
cameraInfo.projection, cameraInfo.zn, cameraInfo.zf,
663+
cameraInfo.clipTransform)) {
663664
// TODO: might be more consistent to do this in prepareLighting(), but it's not
664665
// strictly necessary
665666
getColorPassDescriptorSet().prepareDynamicLights(mFroxelizer, mFroxelVizEnabled);
667+
mFroxelConfigurationAge++;
666668
}
667669
// We need to pass viewMatrix by value here because it extends the scope of this
668670
// function.
@@ -1434,6 +1436,10 @@ void FView::setStereoscopicOptions(const StereoscopicOptions& options) noexcept
14341436
mStereoscopicOptions = options;
14351437
}
14361438

1439+
View::FroxelConfigurationInfoWithAge FView::getFroxelConfigurationInfo() const noexcept {
1440+
return { mFroxelizer.getFroxelConfigurationInfo(), mFroxelConfigurationAge };
1441+
}
1442+
14371443
void FView::setMaterialGlobal(uint32_t const index, float4 const& value) {
14381444
FILAMENT_CHECK_PRECONDITION(index < 4)
14391445
<< "material global variable index (" << +index << ") out of range";

filament/src/details/View.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,8 @@ class FView : public View {
244244
mFroxelVizEnabled = enabled;
245245
}
246246

247+
FroxelConfigurationInfoWithAge getFroxelConfigurationInfo() const noexcept;
248+
247249
void setRenderTarget(FRenderTarget* renderTarget) noexcept {
248250
assert_invariant(!renderTarget || !mMultiSampleAntiAliasingOptions.enabled ||
249251
!renderTarget->hasSampleableDepth());
@@ -557,6 +559,7 @@ class FView : public View {
557559
mutable Froxelizer mFroxelizer;
558560
utils::JobSystem::Job* mFroxelizerSync = nullptr;
559561
bool mFroxelVizEnabled = false;
562+
uint32_t mFroxelConfigurationAge = 0;
560563

561564
Viewport mViewport;
562565
bool mCulling = true;

filament/test/filament_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ TEST(FilamentTest, FroxelData) {
672672

673673
Froxelizer froxelData(*engine);
674674
froxelData.setOptions(5, 100);
675-
froxelData.prepare(engine->getDriverApi(), scope, vp, p, 0.1, 100);
675+
froxelData.prepare(engine->getDriverApi(), scope, vp, p, 0.1, 100, {1,1,0,0});
676676

677677
Froxel f = froxelData.getFroxelAt(0,0,0);
678678

libs/filamentapp/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ set(MATERIAL_DIR "${GENERATION_ROOT}/generated/material")
2020
set(PUBLIC_HDRS
2121
include/filamentapp/Config.h
2222
include/filamentapp/Cube.h
23+
include/filamentapp/Grid.h
2324
include/filamentapp/FilamentApp.h
2425
include/filamentapp/IBL.h
2526
include/filamentapp/IcoSphere.h
@@ -30,6 +31,7 @@ set(PUBLIC_HDRS
3031

3132
set(SRCS
3233
src/Cube.cpp
34+
src/Grid.cpp
3335
src/FilamentApp.cpp
3436
src/IBL.cpp
3537
src/IcoSphere.cpp

libs/filamentapp/include/filamentapp/FilamentApp.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,15 @@ class FilamentApp {
111111

112112
void loadIBL(std::string_view path);
113113

114+
115+
// debugging: enable/disable the froxel grid
116+
void setCameraFrustumEnabled(bool enabled) noexcept;
117+
void setDirectionalShadowFrustumEnabled(bool enabled) noexcept;
118+
void setFroxelGridEnabled(bool enabled) noexcept;
119+
bool isCameraFrustumEnabled() const noexcept;
120+
bool isDirectionalShadowFrustumEnabled() const noexcept;
121+
bool isFroxelGridEnabled() const noexcept;
122+
114123
FilamentApp(const FilamentApp& rhs) = delete;
115124
FilamentApp(FilamentApp&& rhs) = delete;
116125
FilamentApp& operator=(const FilamentApp& rhs) = delete;
@@ -262,6 +271,10 @@ class FilamentApp {
262271
float mCameraNear = 0.1f;
263272
float mCameraFar = 100.0f;
264273
bool mReconfigureCameras = false;
274+
uint8_t mFroxelInfoAge = 0x42;
275+
uint8_t mFroxelGridEnabled = 0;
276+
uint8_t mDirectionalShadowFrustumEnabled = 0x2;
277+
uint8_t mCameraFrustumEnabled = 0x2;
265278

266279
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
267280
filament::backend::VulkanPlatform* mVulkanPlatform = nullptr;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef TNT_FILAMENT_SAMPLE_GRID_H
18+
#define TNT_FILAMENT_SAMPLE_GRID_H
19+
20+
#include <filament/Engine.h>
21+
#include <filament/Box.h>
22+
#include <filament/Camera.h>
23+
#include <filament/Material.h>
24+
#include <filament/MaterialInstance.h>
25+
26+
#include <math/mat4.h>
27+
#include <math/vec3.h>
28+
29+
#include <utils/Entity.h>
30+
31+
#include <functional>
32+
33+
class Grid {
34+
public:
35+
36+
Grid(filament::Engine& engine, filament::Material const* material,
37+
filament::math::float3 linearColor);
38+
39+
Grid(Grid const&) = delete;
40+
Grid& operator=(Grid const&) = delete;
41+
42+
Grid(Grid&& rhs) noexcept;
43+
44+
utils::Entity getWireFrameRenderable() const {
45+
return mWireFrameRenderable;
46+
}
47+
48+
~Grid();
49+
50+
using Generator = std::function<float(int index)>;
51+
52+
void update(uint32_t width, uint32_t height, uint32_t depth);
53+
54+
void update(uint32_t width, uint32_t height, uint32_t depth,
55+
Generator const& genWidth, Generator const& genHeight, Generator const& genDepth);
56+
57+
void mapFrustum(filament::Engine& engine, filament::Camera const* camera);
58+
void mapFrustum(filament::Engine& engine, filament::math::mat4 const& transform);
59+
void mapAabb(filament::Engine& engine, filament::Box const& box);
60+
61+
private:
62+
filament::Engine& mEngine;
63+
filament::VertexBuffer* mVertexBuffer = nullptr;
64+
filament::IndexBuffer* mIndexBuffer = nullptr;
65+
filament::Material const* mMaterial = nullptr;
66+
filament::MaterialInstance* mMaterialInstanceWireFrame = nullptr;
67+
utils::Entity mWireFrameRenderable{};
68+
};
69+
70+
71+
#endif // TNT_FILAMENT_SAMPLE_GRID_H

0 commit comments

Comments
 (0)