You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Terrain/Code/Source/TerrainRenderer/ClipmapBounds.h

161 lines
7.5 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/base.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/std/containers/vector.h>
#include <TerrainRenderer/Vector2i.h>
#include <TerrainRenderer/Aabb2i.h>
namespace Terrain
{
struct ClipmapBoundsDescriptor
{
//! Width and height of the clipmap in texels.
uint32_t m_size = 1024;
//! Current center location of the clipmap in world space
AZ::Vector2 m_worldSpaceCenter = AZ::Vector2::CreateZero();
// Updates to the clipmap will be produced in multiples of this value. This
// allows for larger but less frequent updates, and gives some wiggle room
// for each movement before an update is triggered.
// Note: This also means that whatever uses this clipmap should only ever
// display m_size - (2 * m_clipmapUpdateMultiple) pixels from the clipmap.
// Use GetWorldSpaceSafeDistance() to get the safe distance from center.
uint32_t m_clipmapUpdateMultiple = 4;
//! Scale of the clip map compared to the world. A scale of 0.5 means that
//! a clipmap of size 1024 would cover 512 meters.
float m_clipToWorldScale = 1.0f;
};
struct ClipmapBoundsRegion
{
//! The world bounds of the updated region. Z is ignored.
AZ::Aabb m_worldAabb;
//! The clipmaps bounds of the updated region. Will always be between 0 and size.
//! Min inclusive, max exclusive.
Aabb2i m_localAabb;
bool operator==(const ClipmapBoundsRegion& other) const;
bool operator!=(const ClipmapBoundsRegion& other) const;
};
// This class manages a single clipmap region. A clipmap is a virtual view into a much larger
// region, where the clipmap view is centered around a point like the current camera position.
// The clipmap texture wraps to form a repeating grid and never moves, but only data within
// the clipmap bounds is actually valid. This makes looking up data in the clipmap trivial
// since it's just the world coordinate scaled by some amount. This technique also allows for
// only the edge areas of the clipmap to be updated as the center point moves around the world.
//
// The edges of the clipmap bounds will typically run through the texture, dividing it into 4
// regions, except in cases where the clipmap bounds happen to be aligned with the underlying
// grid. This means whenever some bounding box needs to be updated in the clipmap, it may actually
// translate to 4 different areas of the underlying texture - one for each quadrant.
//
// This class aids in figuring out which areas of a clipmap need to be updated as its center point
// moves around in the world, and can map a single region that needs to be updated into several
// separate regions for each quadrant.
/*
___________________________
| | | | | Clipmap Clipmap
| | | | | Bounds Texture (Tiled)
|______|______|______|______| ______ ______
| | _|____ | | | | | |____|_|
| | | | | | | |_|_*__| | | |
|______|____|_|_*__|_|______| |_|____| |_*__|_|
| | |_|____| | |
| | | | |
|______|______|______|______|
| | | | |
| | | | |
|______|______|______|______|
*/
class ClipmapBounds
{
public:
ClipmapBounds() = default;
explicit ClipmapBounds(const ClipmapBoundsDescriptor& desc);
~ClipmapBounds() = default;
using ClipmapBoundsRegionList = AZStd::vector<ClipmapBoundsRegion>;
//! Updates the clipmap bounds using a world coordinate center position and returns
//! 0-2 regions that need to be updated due to moving beyond the margins. These update
//! regions will always be at least the size of the margin, and will represent horizontal
//! and/or vertical strips along the edges of the clipmap. An optional untouched region
//! aabb can be passed to this function to get an aabb of areas inside the bounds of the
//! clipmap but not updated by the center moving. This can be useful in cases where part
//! of the bounds of the clipmap is dirty, but areas that will already be updated due
//! to the center moving shouldn't be updated twice.
ClipmapBoundsRegionList UpdateCenter(const AZ::Vector2& newCenter, AZ::Aabb* untouchedRegion = nullptr);
//! Updates the clipmap bounds using a position in clipmap space (no scaling) and returns
//! 0-2 regions that need to be updated due to moving beyond the margins. These update
//! regions will always be at least the size of the margin, and will represent horizontal
//! and/or vertical strips along the edges of the clipmap. An optional untouched region
//! aabb can be passed to this function to get an aabb of areas inside the bounds of the
//! clipmap but not updated by the center moving. This can be useful in cases where part
//! of the bounds of the clipmap is dirty, but areas that will already be updated due
//! to the center moving shouldn't be updated twice.
ClipmapBoundsRegionList UpdateCenter(const Vector2i& newCenter, AZ::Aabb* untouchedRegion = nullptr);
//! Takes in a single world space region and transforms it into 0-4 regions in the clipmap clamped
//! to the bounds of the clipmap.
ClipmapBoundsRegionList TransformRegion(AZ::Aabb worldSpaceRegion);
//! Takes in a single unscaled clipmap space region and transforms it into 0-4 regions in the clipmap clamped
//! to the bounds of the clipmap.
ClipmapBoundsRegionList TransformRegion(Aabb2i clipSpaceRegion);
//! Returns the bounds covered by this clipmap in world space. Z component is always 0.
AZ::Aabb GetWorldBounds() const;
//! Returns the safe x and y distance from the center in world space. This is based on the scale,
//! clipmap size, and m_clipmapUpdateMultiple. For example, a clipmap size 1024 with scale
//! 0.25 and margin of 4 would have a safe distance of (1024 * 0.5 - 4) * 0.25 = 127.0f.
float GetWorldSpaceSafeDistance() const;
private:
//! Returns the center point snapped to a multiple of m_clipmapUpdateMultiple. This isn't
//! a simple rounding operation. The value returned will only be different from the curernt
//! center if the value passed in is greater than m_clipmapUpdateMultiple away from the center.
Vector2i GetSnappedCenter(const Vector2i& center);
//! Returns the bounds covered by the clipmap in local space
Aabb2i GetLocalBounds() const;
//! Applies scale and averages a world space vector to get a clip space vector.
Vector2i GetClipSpaceVector(const AZ::Vector2& worldSpaceVector) const;
//! Applies inverse scale to get a world aabb from clip space aabb.
AZ::Aabb GetWorldSpaceAabb(const Aabb2i& clipSpaceAabb) const;
Vector2i m_center;
Vector2i m_modCenter;
int32_t m_size;
int32_t m_halfSize;
int32_t m_clipmapUpdateMultiple;
float m_scale;
float m_rcpScale;
};
}