Add relative-to-camera rendering for large worlds
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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++)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user