CameraInfo cleanups

- add getUserViewMatrix() on CameraInfo, the "user" view matrix is the 
view matrix before we apply the world origin transform, it is needed in
 a few places, so we make it a  method so that in the future we could 
precompute it if we wanted to.

- remove worldOffset which is just the last column of worldOrigin
This commit is contained in:
Mathias Agopian
2022-04-22 12:32:40 -07:00
committed by Mathias Agopian
parent dada291f6b
commit f4f9f331c0
9 changed files with 44 additions and 33 deletions

View File

@@ -81,7 +81,7 @@ void PerViewUniforms::prepareCamera(const CameraInfo& camera) noexcept {
s.clipFromWorldMatrix = clipFromWorld; // projection * view
s.worldFromClipMatrix = worldFromClip; // 1/(projection * view)
s.cameraPosition = float3{ camera.getPosition() };
s.worldOffset = camera.worldOffset;
s.worldOffset = camera.getWorldOffset();
s.cameraFar = camera.zf;
s.oneOverFarMinusNear = 1.0f / (camera.zf - camera.zn);
s.nearOverFarMinusNear = camera.zn / (camera.zf - camera.zn);

View File

@@ -531,8 +531,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
data.history = builder.sample(history);
}
},
[this, projection = cameraInfo.projection, viewMatrix = cameraInfo.view,
worldOrigin = cameraInfo.worldOrigin, uvFromClipMatrix, historyProjection,
[this, projection = cameraInfo.projection,
userViewMatrix = cameraInfo.getUserViewMatrix(), uvFromClipMatrix, historyProjection,
options, &uniforms, renderPass = pass]
(FrameGraphResources const& resources, auto const& data, DriverApi& driver) mutable {
// set structure sampler
@@ -542,7 +542,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
// set screen-space reflections and screen-space refractions
mat4f uvFromViewMatrix = uvFromClipMatrix * projection;
mat4f reprojection = mat4f{ uvFromClipMatrix * historyProjection
* inverse(viewMatrix * worldOrigin) };
* inverse(userViewMatrix) };
// the history sampler is a regular texture2D
TextureHandle history = data.history ?
@@ -805,11 +805,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
mi->setParameter("ssctConeAngleTangeant", std::tan(options.ssct.lightConeRad * 0.5f));
mi->setParameter("ssctContactDistanceMaxInv", 1.0f / options.ssct.contactDistanceMax);
// light direction in view space
// (note: this is actually equivalent to using the camera view matrix -- before the
// world matrix is accounted for)
const mat4f m{ cameraInfo.view * cameraInfo.worldOrigin };
const mat4f view{ cameraInfo.getUserViewMatrix() };
const float3 l = normalize(
mat3f::getTransformForNormals(m.upperLeft())
mat3f::getTransformForNormals(view.upperLeft())
* options.ssct.lightDirection);
mi->setParameter("ssctIntensity",
options.ssct.enabled ? options.ssct.intensity : 0.0f);
@@ -2464,7 +2462,7 @@ void PostProcessManager::prepareTaa(FrameGraph& fg, filament::Viewport const& sv
auto& current = frameHistory.getCurrent().*pTaa;
// compute projection
current.projection = mat4f{ inoutCameraInfo->projection * (inoutCameraInfo->view * inoutCameraInfo->worldOrigin) };
current.projection = mat4f{ inoutCameraInfo->projection * inoutCameraInfo->getUserViewMatrix() };
current.frameId = previous.frameId + 1;
// sample position within a pixel [-0.5, 0.5]
@@ -2561,7 +2559,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
float2 d = sampleOffsets[i] - current.jitter;
d *= 1.0f / taaOptions.filterWidth;
// this is a gaussian fit of a 3.3 Blackman Harris window
// see: "High Quality Temporal Supersampling" by Bruan Karis
// see: "High Quality Temporal Supersampling" by Brian Karis
weights[i] = std::exp2(-3.3f * (d.x * d.x + d.y * d.y));
sum += weights[i];
}

View File

@@ -318,7 +318,7 @@ void ShadowMap::updateDirectional(const FScene::LightSoa& lightData, size_t inde
if (params.options.stable) {
// Use the world origin as reference point, fixed w.r.t. the camera
snapLightFrustum(s, o, Mv, camera.worldOrigin[3].xyz,
snapLightFrustum(s, o, Mv, -camera.getWorldOffset(),
1.0f / mShadowMapInfo.shadowDimension);
}

View File

@@ -275,7 +275,7 @@ CameraInfo::CameraInfo(FCamera const& camera) noexcept {
zn = camera.getNear();
zf = camera.getCullingFar();
ev100 = Exposure::ev100(camera);
f = camera.getFocalLength();
f = (float)camera.getFocalLength();
A = f / camera.getAperture();
d = std::max(zn, camera.getFocusDistance());
}
@@ -286,14 +286,13 @@ CameraInfo::CameraInfo(FCamera const& camera, const math::mat4& worldOriginCamer
cullingProjection = mat4f{ camera.getCullingProjectionMatrix() };
model = mat4f{ modelMatrix };
view = mat4f{ inverse(modelMatrix) };
worldOrigin = worldOriginCamera;
zn = camera.getNear();
zf = camera.getCullingFar();
ev100 = Exposure::ev100(camera);
f = camera.getFocalLength();
f = (float)camera.getFocalLength();
A = f / camera.getAperture();
d = std::max(zn, camera.getFocusDistance());
worldOffset = camera.getPosition();
worldOrigin = worldOriginCamera;
}
} // namespace filament

View File

@@ -209,18 +209,18 @@ struct CameraInfo {
math::mat4f projection; // projection matrix for drawing (infinite zfar)
math::mat4f cullingProjection; // projection matrix for culling
math::mat4f model; // camera model matrix
math::mat4f view; // camera view matrix
math::mat4f view; // camera view matrix (inverse(model))
math::mat4 worldOrigin; // world origin transform (already applied to model and view)
float zn{}; // distance (positive) to the near plane
float zf{}; // distance (positive) to the far plane
float ev100{}; // exposure
float f{}; // focal length [m]
float A{}; // f-number or f / aperture diameter [m]
float d{}; // focus distance [m]
math::float3 worldOffset{}; // world offset, API-level camera position
math::mat4 worldOrigin; // this is already applied to model and view
math::float3 const& getPosition() const noexcept { return model[3].xyz; }
math::float3 getForwardVector() const noexcept { return normalize(-model[2].xyz); }
math::float3 getWorldOffset() const noexcept { return -worldOrigin[3].xyz; }
math::mat4 getUserViewMatrix() const noexcept { return view * worldOrigin; }
};
FILAMENT_UPCAST(Camera)

View File

@@ -608,8 +608,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
FrameGraphId<FrameGraphTexture> history;
};
// FIXME: should we use the TAA-modified cameraInfo here or not? (we are).
auto projection = mat4f{
cameraInfo.projection * (cameraInfo.view * cameraInfo.worldOrigin) };
auto projection = mat4f{ cameraInfo.projection * cameraInfo.getUserViewMatrix() };
fg.addPass<ExportSSRHistoryData>("Export SSR history",
[&](FrameGraph::Builder& builder, auto& data) {
// We need to use sideEffect here to ensure this pass won't be culled.

View File

@@ -407,8 +407,8 @@ void FView::prepareLighting(FEngine& engine, FEngine::DriverApi& driver, ArenaSc
mHasDirectionalLight = directionalLight.isValid();
}
CameraInfo FView::computeCameraInfo(FEngine& engine) noexcept {
FScene* const scene = getScene();
CameraInfo FView::computeCameraInfo(FEngine& engine) const noexcept {
FScene const* const scene = getScene();
/*
* We apply a "world origin" to "everything" in order to implement the IBL rotation.
@@ -451,11 +451,25 @@ void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena,
* and in particular their world-space AABB.
*/
FScene* const scene = getScene();
auto getFrustum = [this, &cameraInfo]() -> Frustum {
if (UTILS_LIKELY(mViewingCamera == nullptr)) {
// In the common case when we don't have a viewing camera, cameraInfo.view is
// already the culling view matrix
return Frustum{ mat4f{ highPrecisionMultiply(cameraInfo.projection, cameraInfo.view) }};
} else {
// Otherwise, we need to recalculate it from the culling camera.
// Note: it is correct to always do the math from mCullingCamera, but it hides the
// intent of the code, which is that we should only depend on CameraInfo here.
// This is an extremely uncommon case.
const mat4 projection = mCullingCamera->getCullingProjectionMatrix();
const mat4 view = inverse(cameraInfo.worldOrigin * mCullingCamera->getModelMatrix());
return Frustum{ mat4f{ projection * view }};
}
};
mCullingFrustum = Frustum(mat4f{
mCullingCamera->getCullingProjectionMatrix() *
inverse(cameraInfo.worldOrigin * mCullingCamera->getModelMatrix()) });
const Frustum cullingFrustum = getFrustum();
FScene* const scene = getScene();
/*
* Gather all information needed to render this scene. Apply the world origin to all
@@ -470,9 +484,9 @@ void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena,
JobSystem::Job* prepareVisibleLightsJob = nullptr;
if (scene->getLightData().size() > FScene::DIRECTIONAL_LIGHTS_COUNT) {
prepareVisibleLightsJob = js.runAndRetain(js.createJob(nullptr,
[this, &engine, &arena, &cameraInfo, scene](JobSystem&, JobSystem::Job*) {
[&cullingFrustum, &engine, &arena, &cameraInfo, scene](JobSystem&, JobSystem::Job*) {
FView::prepareVisibleLights(engine.getLightManager(), arena,
cameraInfo.view, mCullingFrustum, scene->getLightData());
cameraInfo.view, cullingFrustum, scene->getLightData());
}));
}
@@ -489,7 +503,7 @@ void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena,
* (this will set the VISIBLE_RENDERABLE bit)
*/
prepareVisibleRenderables(js, mCullingFrustum, renderableData);
prepareVisibleRenderables(js, cullingFrustum, renderableData);
/*

View File

@@ -119,7 +119,7 @@ public:
void terminate(FEngine& engine);
CameraInfo computeCameraInfo(FEngine& engine) noexcept;
CameraInfo computeCameraInfo(FEngine& engine) const noexcept;
void prepare(FEngine& engine, backend::DriverApi& driver, ArenaScope& arena,
filament::Viewport const& viewport, CameraInfo const& cameraInfo,
@@ -500,11 +500,11 @@ private:
backend::Handle<backend::HwBufferObject> mRenderableUbh;
FScene* mScene = nullptr;
// The camera set by the user, used for culling and viewing
FCamera* mCullingCamera = nullptr;
// The optional (debug) camera, used only for viewing
FCamera* mViewingCamera = nullptr;
Frustum mCullingFrustum{};
mutable Froxelizer mFroxelizer;
Viewport mViewport;

View File

@@ -580,6 +580,7 @@ int main(int argc, char** argv) {
debug.getPropertyAddress<bool>("d.renderer.doFrameCapture");
*captureFrame = true;
}
ImGui::Checkbox("Camera at origin", debug.getPropertyAddress<bool>("d.view.camera_at_origin"));
auto dataSource = debug.getDataSource("d.view.frame_info");
if (dataSource.data) {
ImGuiExt::PlotLinesSeries("FrameInfo", 6,