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:
committed by
Mathias Agopian
parent
dada291f6b
commit
f4f9f331c0
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user