Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move stereoscopic debug options to Settings framework #7347

Merged
merged 6 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion filament/include/filament/Engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,10 @@ class UTILS_PUBLIC Engine {

/*
* The number of eyes to render when stereoscopic rendering is enabled. Supported values are
* between 1 and CONFIG_MAX_STEREOSCOPIC_EYES (inclusive).
* between 1 and Engine::getMaxStereoscopicEyes() (inclusive).
*
* @see View::setStereoscopicOptions
* @see Engine::getMaxStereoscopicEyes
*/
uint8_t stereoscopicEyeCount = 2;
};
Expand Down Expand Up @@ -562,6 +563,29 @@ class UTILS_PUBLIC Engine {
*/
bool isStereoSupported() const noexcept;

/**
* Retrieves the configuration settings of this Engine.
*
* This method returns the configuration object that was supplied to the Engine's
* Builder::config method during the creation of this Engine. If the Builder::config method was
* not explicitly called (or called with nullptr), this method returns the default configuration
* settings.
*
* @return a Config object with this Engine's configuration
* @see Builder::config
*/
const Config& getConfig() const noexcept;

/**
* Returns the maximum number of stereoscopic eyes supported by Filament. The actual number of
* eyes rendered is set at Engine creation time with the Engine::Config::stereoscopicEyeCount
* setting.
*
* @return the max number of stereoscopic eyes supported
* @see Engine::Config::stereoscopicEyeCount
*/
static size_t getMaxStereoscopicEyes() noexcept;

/**
* @return EntityManager used by filament
*/
Expand Down
5 changes: 3 additions & 2 deletions filament/include/filament/View.h
Original file line number Diff line number Diff line change
Expand Up @@ -670,11 +670,12 @@ class UTILS_PUBLIC View : public FilamentAPI {
* - punctual lights
*
* Stereo rendering depends on device and platform support. To check if stereo rendering is
* supported, use Engine::isStereoSupported().
* supported, use Engine::isStereoSupported(). If stereo rendering is not supported, then the
* stereoscopic options have no effect.
*
* @param options The stereoscopic options to use on this view
*/
void setStereoscopicOptions(StereoscopicOptions const& options);
void setStereoscopicOptions(StereoscopicOptions const& options) noexcept;

/**
* Returns the stereoscopic options associated with this View.
Expand Down
8 changes: 8 additions & 0 deletions filament/src/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,10 +327,18 @@ size_t Engine::getMaxAutomaticInstances() const noexcept {
return downcast(this)->getMaxAutomaticInstances();
}

const Engine::Config& Engine::getConfig() const noexcept {
return downcast(this)->getConfig();
}

bool Engine::isStereoSupported() const noexcept {
return downcast(this)->isStereoSupported();
}

size_t Engine::getMaxStereoscopicEyes() noexcept {
return FEngine::getMaxStereoscopicEyes();
}

#if defined(__EMSCRIPTEN__)
void Engine::resetBackendState() noexcept {
downcast(this)->resetBackendState();
Expand Down
2 changes: 1 addition & 1 deletion filament/src/View.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ bool View::isStencilBufferEnabled() const noexcept {
return downcast(this)->isStencilBufferEnabled();
}

void View::setStereoscopicOptions(const StereoscopicOptions& options) {
void View::setStereoscopicOptions(const StereoscopicOptions& options) noexcept {
return downcast(this)->setStereoscopicOptions(options);
}

Expand Down
4 changes: 4 additions & 0 deletions filament/src/details/Engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ class FEngine : public Engine {

bool isStereoSupported() const noexcept { return getDriver().isStereoSupported(); }

static size_t getMaxStereoscopicEyes() noexcept {
return CONFIG_MAX_STEREOSCOPIC_EYES;
}

PostProcessManager const& getPostProcessManager() const noexcept {
return mPostProcessManager;
}
Expand Down
4 changes: 1 addition & 3 deletions filament/src/details/View.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1126,9 +1126,7 @@ View::PickingQuery& FView::pick(uint32_t x, uint32_t y, backend::CallbackHandler
return *pQuery;
}

void FView::setStereoscopicOptions(const StereoscopicOptions& options) {
ASSERT_PRECONDITION(!options.enabled || mIsStereoSupported,
"Stereo rendering is not supported.");
void FView::setStereoscopicOptions(const StereoscopicOptions& options) noexcept {
mStereoscopicOptions = options;
}

Expand Down
6 changes: 4 additions & 2 deletions filament/src/details/View.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ class FView : public View {
bool hasDPCF() const noexcept { return mShadowType == ShadowType::DPCF; }
bool hasPCSS() const noexcept { return mShadowType == ShadowType::PCSS; }
bool hasPicking() const noexcept { return mActivePickingQueriesList != nullptr; }
bool hasInstancedStereo() const noexcept { return mStereoscopicOptions.enabled; }
bool hasInstancedStereo() const noexcept {
return mIsStereoSupported && mStereoscopicOptions.enabled;
}

FrameGraphId<FrameGraphTexture> renderShadowMaps(FEngine& engine, FrameGraph& fg,
CameraInfo const& cameraInfo, math::float4 const& userTime,
Expand All @@ -188,7 +190,7 @@ class FView : public View {

bool isStencilBufferEnabled() const noexcept { return mStencilBufferEnabled; }

void setStereoscopicOptions(StereoscopicOptions const& options);
void setStereoscopicOptions(StereoscopicOptions const& options) noexcept;

FCamera const* getDirectionalLightCamera() const noexcept {
return mShadowMapManager.getDirectionalLightCamera();
Expand Down
3 changes: 3 additions & 0 deletions libs/viewer/include/viewer/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ using TemporalAntiAliasingOptions = filament::View::TemporalAntiAliasingOptions;
using VignetteOptions = filament::View::VignetteOptions;
using VsmShadowOptions = filament::View::VsmShadowOptions;
using GuardBandOptions = filament::View::GuardBandOptions;
using StereoscopicOptions = filament::View::StereoscopicOptions;
using LightManager = filament::LightManager;

// These functions push all editable property values to their respective Filament objects.
Expand Down Expand Up @@ -192,6 +193,7 @@ struct ViewSettings {
VignetteOptions vignette;
VsmShadowOptions vsmShadowOptions;
GuardBandOptions guardBand;
StereoscopicOptions stereoscopicOptions;

// Custom View Options
ColorGradingSettings colorGrading;
Expand Down Expand Up @@ -231,6 +233,7 @@ struct ViewerOptions {
float cameraISO = 100.0f;
float cameraNear = 0.1f;
float cameraFar = 100.0f;
float cameraEyeOcularDistance = 0.0f;
float groundShadowStrength = 0.75f;
bool groundPlaneEnabled = false;
bool skyboxEnabled = true;
Expand Down
5 changes: 0 additions & 5 deletions libs/viewer/include/viewer/ViewerGui.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,6 @@ class UTILS_PUBLIC ViewerGui {

int getCurrentCamera() const { return mCurrentCamera; }

float getOcularDistance() const { return mOcularDistance; }

private:
using SceneMask = gltfio::NodeManager::SceneMask;

Expand Down Expand Up @@ -268,9 +266,6 @@ class UTILS_PUBLIC ViewerGui {
SceneMask mVisibleScenes;
bool mShowingRestPose = false;

// Stereoscopic debugging
float mOcularDistance = 0.0f;

// 0 is the default "free camera". Additional cameras come from the gltf file (1-based index).
int mCurrentCamera = 0;

Expand Down
21 changes: 21 additions & 0 deletions libs/viewer/src/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, ViewSett
i = parse(tokens, i + 1, jsonChunk, &out->vsmShadowOptions);
} else if (compare(tok, jsonChunk, "postProcessingEnabled") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->postProcessingEnabled);
} else if (compare(tok, jsonChunk, "stereoscopicOptions") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->stereoscopicOptions);
} else {
slog.w << "Invalid view setting key: '" << STR(tok, jsonChunk) << "'" << io::endl;
i = parse(tokens, i + 1);
Expand Down Expand Up @@ -500,6 +502,8 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, ViewerOp
i = parse(tokens, i + 1, jsonChunk, &out->cameraNear);
} else if (compare(tok, jsonChunk, "cameraFar") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->cameraFar);
} else if (compare(tok, jsonChunk, "cameraEyeOcularDistance") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->cameraEyeOcularDistance);
} else if (compare(tok, jsonChunk, "groundShadowStrength") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->groundShadowStrength);
} else if (compare(tok, jsonChunk, "groundPlaneEnabled") == 0) {
Expand Down Expand Up @@ -572,6 +576,7 @@ void applySettings(Engine* engine, const ViewSettings& settings, View* dest) {
dest->setShadowType(settings.shadowType);
dest->setVsmShadowOptions(settings.vsmShadowOptions);
dest->setGuardBandOptions(settings.guardBand);
dest->setStereoscopicOptions(settings.stereoscopicOptions);
dest->setPostProcessingEnabled(settings.postProcessingEnabled);
}

Expand Down Expand Up @@ -646,6 +651,20 @@ void applySettings(Engine* engine, const ViewerOptions& settings, Camera* camera
camera->setFocusDistance(settings.cameraFocusDistance);
}
engine->setAutomaticInstancingEnabled(settings.autoInstancingEnabled);

// Eyes are rendered from left-to-right, i.e., eye 0 is rendered to the left side of the
// window.
// For testing, we want to render a side-by-side layout so users can view with
// "cross-eyed" stereo.
// For cross-eyed stereo, Eye 0 is really the RIGHT eye, while Eye 1 is the LEFT eye.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, is there any reason why we didn't match the order of the eyes on the screen with the order of the array?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in fact we do, and maybe my comment is a little confusing. But eye 0 is always rendered to the left side of the screen, and eye 1 is rendered to the right side:

0 | 1

What this comment alludes to, is the fact that to render cross-eyed stereo, the left and right eyes need to be flipped.

const auto od = settings.cameraEyeOcularDistance;
const auto eyeCount = engine->getConfig().stereoscopicEyeCount;
const mat4 rightEye = mat4::translation(double3{ od, 0.0, 0.0}); // right eye
const mat4 leftEye = mat4::translation(double3{-od, 0.0, 0.0}); // left eye
const mat4 modelMatrices[2] = { rightEye, leftEye };
for (int i = 0; i < eyeCount; i++) {
camera->setEyeModelMatrix(i, modelMatrices[i % 2]);
}
}

constexpr ToneMapper* createToneMapper(const ColorGradingSettings& settings) noexcept {
Expand Down Expand Up @@ -857,6 +876,7 @@ static std::ostream& operator<<(std::ostream& out, const ViewerOptions& in) {
<< "\"cameraISO\": " << (in.cameraISO) << ",\n"
<< "\"cameraNear\": " << (in.cameraNear) << ",\n"
<< "\"cameraFar\": " << (in.cameraFar) << ",\n"
<< "\"cameraEyeOcularDistance\": " << (in.cameraEyeOcularDistance) << ",\n"
<< "\"groundShadowStrength\": " << (in.groundShadowStrength) << ",\n"
<< "\"groundPlaneEnabled\": " << to_string(in.groundPlaneEnabled) << ",\n"
<< "\"skyboxEnabled\": " << to_string(in.skyboxEnabled) << ",\n"
Expand Down Expand Up @@ -894,6 +914,7 @@ static std::ostream& operator<<(std::ostream& out, const ViewSettings& in) {
<< "\"shadowType\": " << (in.shadowType) << ",\n"
<< "\"vsmShadowOptions\": " << (in.vsmShadowOptions) << ",\n"
<< "\"guardBand\": " << (in.guardBand) << ",\n"
<< "\"stereoscopicOptions\": " << (in.stereoscopicOptions) << ",\n"
<< "\"postProcessingEnabled\": " << to_string(in.postProcessingEnabled) << "\n"
<< "}";
}
Expand Down
10 changes: 3 additions & 7 deletions libs/viewer/src/ViewerGui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1067,13 +1067,9 @@ void ViewerGui::updateUserInterface() {
ImGui::ListBox("Cameras", &mCurrentCamera, cstrings.data(), cstrings.size());
}

StereoscopicOptions stereoOptions = mView->getStereoscopicOptions();
ImGui::Checkbox("Instanced stereo", &stereoOptions.enabled);
if (stereoOptions.enabled) {
ImGui::SliderFloat("Ocular distance", &mOcularDistance, 0.0f, 10.0f);

}
mView->setStereoscopicOptions(stereoOptions);
ImGui::Checkbox("Instanced stereo", &mSettings.view.stereoscopicOptions.enabled);
ImGui::SliderFloat(
"Ocular distance", &mSettings.viewer.cameraEyeOcularDistance, 0.0f, 1.0f);

ImGui::Unindent();
}
Expand Down
19 changes: 0 additions & 19 deletions samples/gltf_viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1003,25 +1003,6 @@ int main(int argc, char** argv) {
camera->setScaling({1.0 / aspectRatio, 1.0});
}

if (view->getStereoscopicOptions().enabled) {
Camera& c = view->getCamera();
auto od = app.viewer->getOcularDistance();
// Eyes are rendered from left-to-right, i.e., eye 0 is rendered to the left side of the
// window.
// For testing, we want to render a side-by-side layout so users can view with
// "cross-eyed" stereo.
// For cross-eyed stereo, Eye 0 is really the RIGHT eye, while Eye 1 is the LEFT eye.
const mat4 rightEye = mat4::translation(double3{ od, 0.0, 0.0}); // right eye
const mat4 leftEye = mat4::translation(double3{-od, 0.0, 0.0}); // left eye
const mat4 modelMatrices[4] = { rightEye, leftEye, rightEye, leftEye };
for (int i = 0; i < std::min(app.config.stereoscopicEyeCount, 4); i++) {
c.setEyeModelMatrix(i, modelMatrices[i]);
}
} else {
for (int i = 0; i < app.config.stereoscopicEyeCount; i++) {
view->getCamera().setEyeModelMatrix(i, {});
}
}
static bool stereoscopicEnabled = false;
if (stereoscopicEnabled != view->getStereoscopicOptions().enabled) {
// Stereo was turned on/off.
Expand Down
Loading