Add relative-to-camera rendering for large worlds

This commit is contained in:
Wojtek Figat
2022-06-21 20:03:13 +02:00
parent f3bd0e469c
commit 134c8b99aa
35 changed files with 331 additions and 195 deletions

View File

@@ -17,7 +17,7 @@ void BoxVolume::SetSize(const Vector3& value)
const auto prevBounds = _box;
_size = value;
OrientedBoundingBox::CreateCentered(Vector3::Zero, _size, _bounds);
_bounds.Transform(_transform.GetWorld());
_bounds.Transform(_transform);
_bounds.GetBoundingBox(_box);
BoundingSphere::FromBox(_box, _sphere);
OnBoundsChanged(prevBounds);
@@ -142,7 +142,7 @@ void BoxVolume::OnTransformChanged()
const auto prevBounds = _box;
OrientedBoundingBox::CreateCentered(Vector3::Zero, _size, _bounds);
_bounds.Transform(_transform.GetWorld());
_bounds.Transform(_transform);
_bounds.GetBoundingBox(_box);
BoundingSphere::FromBox(_box, _sphere);
OnBoundsChanged(prevBounds);

View File

@@ -189,10 +189,15 @@ Viewport Camera::GetViewport() const
void Camera::GetMatrices(Matrix& view, Matrix& projection) const
{
GetMatrices(view, projection, GetViewport());
GetMatrices(view, projection, GetViewport(), Vector3::Zero);
}
void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewport) const
{
GetMatrices(view, projection, viewport, Vector3::Zero);
}
void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewport, const Vector3& origin) const
{
// Create projection matrix
if (_usePerspective)
@@ -207,10 +212,11 @@ void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewp
// Create view matrix
const Float3 direction = GetDirection();
const Vector3 target = _transform.Translation + direction;
Vector3 up;
Vector3::Transform(Vector3::Up, GetOrientation(), up);
Matrix::LookAt(_transform.Translation, target, up, view);
const Float3 position = _transform.Translation - origin;
const Float3 target = position + direction;
Float3 up;
Float3::Transform(Float3::Up, GetOrientation(), up);
Matrix::LookAt(position, target, up, view);
}
#if USE_EDITOR
@@ -253,16 +259,19 @@ void Camera::Draw(RenderContext& renderContext)
&& _previewModel
&& _previewModel->IsLoaded())
{
Matrix world;
renderContext.View.GetWorldMatrix(_transform, world);
GeometryDrawStateData drawState;
Mesh::DrawInfo draw;
draw.Buffer = &_previewModelBuffer;
draw.World = &_previewModelWorld;
draw.World = &world;
draw.DrawState = &drawState;
draw.Lightmap = nullptr;
draw.LightmapUVs = nullptr;
draw.Flags = StaticFlags::Transform;
draw.DrawModes = (DrawPass)((DrawPass::Depth | DrawPass::GBuffer | DrawPass::Forward) & renderContext.View.Pass);
BoundingSphere::FromBox(_previewModelBox, draw.Bounds);
draw.Bounds.Center -= renderContext.View.Origin;
draw.PerInstanceRandom = GetPerInstanceRandom();
draw.LODBias = 0;
draw.ForcedLOD = -1;
@@ -288,32 +297,33 @@ void Camera::OnDebugDrawSelected()
void Camera::UpdateCache()
{
// Update view and projection matrix
GetMatrices(_view, _projection);
// Calculate view and projection matrices
Matrix view, projection;
GetMatrices(view, projection);
// Update frustum and bounding box
_frustum.SetMatrix(_view, _projection);
_frustum.SetMatrix(view, projection);
_frustum.GetBox(_box);
BoundingSphere::FromBox(_box, _sphere);
#if USE_EDITOR
// Update editor preview model cache
Matrix rot, world;
_transform.GetWorld(world);
Matrix rot, tmp, world;
_transform.GetWorld(tmp);
Matrix::RotationY(PI * -0.5f, rot);
Matrix::Multiply(rot, world, _previewModelWorld);
Matrix::Multiply(rot, tmp, world);
// Calculate snap box for preview model
if (_previewModel && _previewModel->IsLoaded())
{
_previewModelBox = _previewModel->GetBox(_previewModelWorld);
_previewModelBox = _previewModel->GetBox(world);
}
else
{
Vector3 min(-10.0f), max(10.0f);
min = Vector3::Transform(min, _previewModelWorld);
max = Vector3::Transform(max, _previewModelWorld);
min = Vector3::Transform(min, world);
max = Vector3::Transform(max, world);
_previewModelBox = BoundingBox(min, max);
}

View File

@@ -35,7 +35,6 @@ API_CLASS(Sealed) class FLAXENGINE_API Camera : public Actor
API_PROPERTY() static Camera* GetMainCamera();
private:
Matrix _view, _projection;
BoundingFrustum _frustum;
// Camera Settings
@@ -50,27 +49,10 @@ private:
AssetReference<Model> _previewModel;
ModelInstanceEntries _previewModelBuffer;
BoundingBox _previewModelBox;
Matrix _previewModelWorld;
int32 _sceneRenderingKey = -1;
#endif
public:
/// <summary>
/// Gets the view matrix.
/// </summary>
API_PROPERTY() FORCE_INLINE Matrix GetView() const
{
return _view;
}
/// <summary>
/// Gets the projection matrix.
/// </summary>
API_PROPERTY() FORCE_INLINE Matrix GetProjection() const
{
return _projection;
}
/// <summary>
/// Gets the frustum.
/// </summary>
@@ -218,8 +200,17 @@ public:
/// </summary>
/// <param name="view">The result camera view matrix.</param>
/// <param name="projection">The result camera projection matrix.</param>
/// <param name="viewport">The custom output viewport. Use null to skip it.</param>
API_FUNCTION() virtual void GetMatrices(API_PARAM(Out) Matrix& view, API_PARAM(Out) Matrix& projection, API_PARAM(Ref) const Viewport& viewport) const;
/// <param name="viewport">The custom output viewport.</param>
API_FUNCTION() void GetMatrices(API_PARAM(Out) Matrix& view, API_PARAM(Out) Matrix& projection, API_PARAM(Ref) const Viewport& viewport) const;
/// <summary>
/// Calculates the view and the projection matrices for the camera. Support using custom viewport and view origin.
/// </summary>
/// <param name="view">The result camera view matrix.</param>
/// <param name="projection">The result camera projection matrix.</param>
/// <param name="viewport">The custom output viewport.</param>
/// <param name="origin">The rendering view origin (for relative-to-camera rendering).</param>
API_FUNCTION() void GetMatrices(API_PARAM(Out) Matrix& view, API_PARAM(Out) Matrix& projection, API_PARAM(Ref) const Viewport& viewport, API_PARAM(Ref) const Vector3& origin) const;
#if USE_EDITOR
// Intersection check for editor picking the camera

View File

@@ -18,13 +18,14 @@ void DirectionalLight::Draw(RenderContext& renderContext)
{
float brightness = Brightness;
AdjustBrightness(renderContext.View, brightness);
const Float3 position = GetPosition() - renderContext.View.Origin;
if (Brightness > ZeroTolerance
&& (renderContext.View.Flags & ViewFlags::DirectionalLights) != 0
&& renderContext.View.Pass & DrawPass::GBuffer
&& (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, GetPosition()) < ViewDistance * ViewDistance))
&& (ViewDistance < ZeroTolerance || Float3::DistanceSquared(renderContext.View.Position, position) < ViewDistance * ViewDistance))
{
RendererDirectionalLightData data;
data.Position = GetPosition(); // TODO: large-worlds
data.Position = position;
data.MinRoughness = MinRoughness;
data.ShadowsDistance = ShadowsDistance;
data.Color = Color.ToFloat3() * (Color.A * brightness);

View File

@@ -103,15 +103,16 @@ void PointLight::Draw(RenderContext& renderContext)
{
float brightness = ComputeBrightness();
AdjustBrightness(renderContext.View, brightness);
const Float3 position = GetPosition() - renderContext.View.Origin;
const float radius = GetScaledRadius();
if ((renderContext.View.Flags & ViewFlags::PointLights) != 0
&& brightness > ZeroTolerance
&& renderContext.View.Pass & DrawPass::GBuffer
&& radius > ZeroTolerance
&& (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, GetPosition()) < ViewDistance * ViewDistance))
&& (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, position) < ViewDistance * ViewDistance))
{
RendererPointLightData data;
data.Position = GetPosition(); // TODO: large-worlds
data.Position = position;
data.MinRoughness = MinRoughness;
data.ShadowsDistance = ShadowsDistance;
data.Color = Color.ToFloat3() * (Color.A * brightness);

View File

@@ -22,7 +22,7 @@ void PostFxVolume::Collect(RenderContext& renderContext)
if (_isBounded)
{
Real distance;
if (_bounds.Contains(renderContext.View.Position, &distance) == ContainmentType::Contains)
if (_bounds.Contains(renderContext.View.WorldPosition, &distance) == ContainmentType::Contains)
{
if (_blendRadius > 0.0f)
weight = Math::Saturate((float)distance / _blendRadius) * weight;

View File

@@ -100,13 +100,14 @@ void SkyLight::Draw(RenderContext& renderContext)
{
float brightness = Brightness;
AdjustBrightness(renderContext.View, brightness);
const Float3 position = GetPosition() - renderContext.View.Origin;
if ((renderContext.View.Flags & ViewFlags::SkyLights) != 0
&& renderContext.View.Pass & DrawPass::GBuffer
&& brightness > ZeroTolerance
&& (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, GetPosition()) < ViewDistance * ViewDistance))
&& (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, position) < ViewDistance * ViewDistance))
{
RendererSkyLightData data;
data.Position = GetPosition(); // TODO: large-worlds
data.Position = position;
data.Color = Color.ToFloat3() * (Color.A * brightness);
data.VolumetricScatteringIntensity = VolumetricScatteringIntensity;
data.CastVolumetricShadow = CastVolumetricShadow;

View File

@@ -136,7 +136,7 @@ void SplineModel::OnSplineUpdated()
for (int32 j = 0; j < meshes.Count(); j++)
{
const auto& mesh = meshes[j];
mesh.GetCorners(corners);
mesh.GetBox().GetCorners(corners);
for (int32 i = 0; i < 8; i++)
{

View File

@@ -151,6 +151,7 @@ void SpotLight::Draw(RenderContext& renderContext)
{
float brightness = ComputeBrightness();
AdjustBrightness(renderContext.View, brightness);
const Float3 position = GetPosition() - renderContext.View.Origin;
const float radius = GetScaledRadius();
const float outerConeAngle = GetOuterConeAngle();
if ((renderContext.View.Flags & ViewFlags::SpotLights) != 0
@@ -158,10 +159,10 @@ void SpotLight::Draw(RenderContext& renderContext)
&& brightness > ZeroTolerance
&& radius > ZeroTolerance
&& outerConeAngle > ZeroTolerance
&& (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, GetPosition()) < ViewDistance * ViewDistance))
&& (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, position) < ViewDistance * ViewDistance))
{
RendererSpotLightData data;
data.Position = GetPosition(); // TODO: large-worlds
data.Position = position;
data.MinRoughness = MinRoughness;
data.ShadowsDistance = ShadowsDistance;
data.Color = Color.ToFloat3() * (Color.A * brightness);

View File

@@ -18,7 +18,6 @@
StaticModel::StaticModel(const SpawnParams& params)
: ModelInstanceActor(params)
, _world(Matrix::Identity)
, _scaleInLightmap(1.0f)
, _boundsScale(1.0f)
, _lodBias(0)
@@ -210,16 +209,9 @@ void StaticModel::UpdateBounds()
{
if (Model && Model->IsLoaded())
{
Matrix world;
if (Math::IsOne(_boundsScale))
world = _world;
else
{
Transform t = _transform;
t.Scale *= _boundsScale;
t.GetWorld(world);
}
_box = Model->GetBox(world);
Transform transform = _transform;
transform.Scale *= _boundsScale;
_box = Model->GetBox(transform);
}
else
{
@@ -240,17 +232,21 @@ void StaticModel::Draw(RenderContext& renderContext)
const DrawPass drawModes = (DrawPass)(DrawModes & renderContext.View.Pass);
if (!Model || !Model->IsLoaded() || !Model->CanBeRendered() || drawModes == DrawPass::None)
return;
Matrix world;
renderContext.View.GetWorldMatrix(_transform, world);
if (renderContext.View.Pass == DrawPass::GlobalSDF)
{
GlobalSignDistanceFieldPass::Instance()->RasterizeModelSDF(this, Model->SDF, _world, _box);
GlobalSignDistanceFieldPass::Instance()->RasterizeModelSDF(this, Model->SDF, world, _box);
return;
}
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
{
GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, _world, Model->LODs.Last().GetBox());
GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, world, Model->LODs.Last().GetBox());
return;
}
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, _world);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
// Flush vertex colors if need to
if (_vertexColorsDirty)
@@ -282,18 +278,19 @@ void StaticModel::Draw(RenderContext& renderContext)
#if USE_EDITOR
// Disable motion blur effects in editor without play mode enabled to hide minor artifacts on objects moving
if (!Editor::IsPlayMode)
_drawState.PrevWorld = _world;
_drawState.PrevWorld = world;
#endif
Mesh::DrawInfo draw;
draw.Buffer = &Entries;
draw.World = &_world;
draw.World = &world;
draw.DrawState = &_drawState;
draw.Lightmap = _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex);
draw.LightmapUVs = &Lightmap.UVsArea;
draw.Flags = _staticFlags;
draw.DrawModes = drawModes;
draw.Bounds = _sphere;
draw.Bounds.Center -= renderContext.View.Origin;
draw.PerInstanceRandom = GetPerInstanceRandom();
draw.LODBias = _lodBias;
draw.ForcedLOD = _forcedLod;
@@ -301,7 +298,7 @@ void StaticModel::Draw(RenderContext& renderContext)
Model->Draw(renderContext, draw);
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, _world);
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
}
bool StaticModel::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)
@@ -311,7 +308,7 @@ bool StaticModel::IntersectsItself(const Ray& ray, Real& distance, Vector3& norm
if (Model != nullptr && Model->IsLoaded())
{
Mesh* mesh;
result = Model->Intersects(ray, _world, distance, normal, &mesh);
result = Model->Intersects(ray, _transform, distance, normal, &mesh);
}
return result;
@@ -473,7 +470,7 @@ bool StaticModel::IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distan
for (int32 i = 0; i < meshes.Count(); i++)
{
const auto& mesh = meshes[i];
if (mesh.GetMaterialSlotIndex() == entryIndex && mesh.Intersects(ray, _world, distance, normal))
if (mesh.GetMaterialSlotIndex() == entryIndex && mesh.Intersects(ray, _transform, distance, normal))
return true;
}
@@ -500,7 +497,7 @@ bool StaticModel::IntersectsEntry(const Ray& ray, Real& distance, Vector3& norma
const auto& mesh = meshes[i];
Real dst;
Vector3 nrm;
if (mesh.Intersects(ray, _world, dst, nrm) && dst < closest)
if (mesh.Intersects(ray, _transform, dst, nrm) && dst < closest)
{
result = true;
closest = dst;
@@ -520,7 +517,6 @@ void StaticModel::OnTransformChanged()
// Base
ModelInstanceActor::OnTransformChanged();
_transform.GetWorld(_world);
UpdateBounds();
}

View File

@@ -14,7 +14,6 @@ API_CLASS() class FLAXENGINE_API StaticModel : public ModelInstanceActor
{
DECLARE_SCENE_OBJECT(StaticModel);
private:
Matrix _world;
GeometryDrawStateData _drawState;
float _scaleInLightmap;
float _boundsScale;
@@ -50,15 +49,6 @@ public:
LightmapEntry Lightmap;
public:
/// <summary>
/// Gets the model world matrix transform.
/// </summary>
/// <param name="world">The result world matrix.</param>
FORCE_INLINE void GetWorld(Matrix* world) const
{
*world = _world;
}
/// <summary>
/// Gets the model scale in lightmap (applied to all the meshes).
/// </summary>