Merge branch 'terrainscripting' of https://github.com/Withaust/FlaxEngine into Withaust-terrainscripting
# Conflicts: # Source/Engine/Terrain/Terrain.h # Source/Engine/Terrain/TerrainPatch.h
This commit is contained in:
@@ -20,7 +20,7 @@ bool TerrainTools::TryGetPatchCoordToAdd(Terrain* terrain, const Ray& ray, Int2&
|
||||
{
|
||||
CHECK_RETURN(terrain, true);
|
||||
result = Int2::Zero;
|
||||
const float patchSize = terrain->GetChunkSize() * TERRAIN_UNITS_PER_VERTEX * TerrainPatch::CHUNKS_COUNT_EDGE;
|
||||
const float patchSize = terrain->GetChunkSize() * TERRAIN_UNITS_PER_VERTEX * Terrain::ChunksCountEdge;
|
||||
|
||||
// Try to pick any of the patch edges
|
||||
for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++)
|
||||
@@ -179,7 +179,7 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches
|
||||
terrain->AddPatches(numberOfPatches);
|
||||
|
||||
// Prepare data
|
||||
const auto heightmapSize = terrain->GetChunkSize() * TerrainPatch::CHUNKS_COUNT_EDGE + 1;
|
||||
const auto heightmapSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
|
||||
Array<float> heightmapData;
|
||||
heightmapData.Resize(heightmapSize * heightmapSize);
|
||||
|
||||
@@ -380,7 +380,7 @@ bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder)
|
||||
const auto firstPatch = terrain->GetPatch(0);
|
||||
|
||||
// Calculate texture size
|
||||
const int32 patchEdgeVertexCount = terrain->GetChunkSize() * TerrainPatch::CHUNKS_COUNT_EDGE + 1;
|
||||
const int32 patchEdgeVertexCount = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
|
||||
const int32 patchVertexCount = patchEdgeVertexCount * patchEdgeVertexCount;
|
||||
|
||||
// Find size of heightmap in patches
|
||||
|
||||
@@ -84,7 +84,7 @@ bool cacheStaticGeometryTree(Actor* actor, ShadowsOfMordor::Builder::SceneBuildC
|
||||
{
|
||||
auto patch = terrain->GetPatch(patchIndex);
|
||||
entry.AsTerrain.PatchIndex = patchIndex;
|
||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
auto chunk = patch->Chunks[chunkIndex];
|
||||
entry.AsTerrain.ChunkIndex = chunkIndex;
|
||||
|
||||
@@ -165,7 +165,7 @@ void ShadowsOfMordor::Builder::onJobRender(GPUContext* context)
|
||||
Matrix::Transpose(world, shaderData.WorldMatrix);
|
||||
shaderData.LightmapArea = chunk->Lightmap.UVsArea;
|
||||
shaderData.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
|
||||
chunk->GetHeightmapUVScaleBias(&shaderData.HeightmapUVScaleBias);
|
||||
shaderData.HeightmapUVScaleBias = chunk->GetHeightmapUVScaleBias();
|
||||
|
||||
// Extract per axis scales from LocalToWorld transform
|
||||
const float scaleX = Float3(world.M11, world.M12, world.M13).Length();
|
||||
|
||||
@@ -59,7 +59,7 @@ void Terrain::CacheNeighbors()
|
||||
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
||||
{
|
||||
const auto patch = _patches[pathIndex];
|
||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
patch->Chunks[chunkIndex].CacheNeighbors();
|
||||
}
|
||||
@@ -215,7 +215,7 @@ void Terrain::DrawPatch(const RenderContext& renderContext, const Int2& patchCoo
|
||||
auto patch = GetPatch(patchCoord);
|
||||
if (patch)
|
||||
{
|
||||
for (int32 i = 0; i < TerrainPatch::CHUNKS_COUNT; i++)
|
||||
for (int32 i = 0; i < Terrain::ChunksCount; i++)
|
||||
patch->Chunks[i].Draw(renderContext, material, lodIndex);
|
||||
}
|
||||
}
|
||||
@@ -544,7 +544,7 @@ void Terrain::Draw(RenderContext& renderContext)
|
||||
Matrix localToWorld, worldToLocal;
|
||||
BoundingSphere chunkSphere;
|
||||
BoundingBox localBounds;
|
||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
TerrainChunk* chunk = &patch->Chunks[chunkIndex];
|
||||
chunk->GetTransform().GetWorld(localToWorld); // TODO: large-worlds
|
||||
@@ -574,7 +574,7 @@ void Terrain::Draw(RenderContext& renderContext)
|
||||
continue;
|
||||
|
||||
// Frustum vs Box culling for chunks
|
||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
auto chunk = &patch->Chunks[chunkIndex];
|
||||
chunk->_cachedDrawLOD = 0;
|
||||
@@ -592,7 +592,7 @@ void Terrain::Draw(RenderContext& renderContext)
|
||||
else
|
||||
{
|
||||
// Reset cached LOD for chunks (prevent LOD transition from invisible chunks)
|
||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
auto chunk = &patch->Chunks[chunkIndex];
|
||||
chunk->_cachedDrawLOD = 0;
|
||||
@@ -620,10 +620,10 @@ void Terrain::OnDebugDrawSelected()
|
||||
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
||||
{
|
||||
const auto patch = _patches[pathIndex];
|
||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
auto chunk = &patch->Chunks[chunkIndex];
|
||||
DebugDraw::DrawBox(chunk->_bounds, Color(chunk->_x / (float)TerrainPatch::CHUNKS_COUNT_EDGE, 1.0f, chunk->_z / (float)TerrainPatch::CHUNKS_COUNT_EDGE));
|
||||
DebugDraw::DrawBox(chunk->_bounds, Color(chunk->_x / (float)Terrain::ChunksCountEdge, 1.0f, chunk->_z / (float)Terrain::ChunksCountEdge));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -44,6 +44,22 @@ API_CLASS(Sealed) class FLAXENGINE_API Terrain : public PhysicsColliderActor
|
||||
friend TerrainPatch;
|
||||
friend TerrainChunk;
|
||||
|
||||
/// <summary>
|
||||
/// Various defines regarding terrain configuration.
|
||||
/// </summary>
|
||||
API_ENUM() enum Config
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum allowed amount of chunks per patch.
|
||||
/// </summary>
|
||||
ChunksCount = 16,
|
||||
|
||||
/// <summary>
|
||||
/// The maximum allowed amount of chunks per chunk.
|
||||
/// </summary>
|
||||
ChunksCountEdge = 4,
|
||||
};
|
||||
|
||||
private:
|
||||
char _lodBias;
|
||||
char _forcedLod;
|
||||
@@ -223,7 +239,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="patchCoord">The patch location (x and z).</param>
|
||||
/// <returns>The patch.</returns>
|
||||
TerrainPatch* GetPatch(const Int2& patchCoord) const;
|
||||
API_FUNCTION() TerrainPatch* GetPatch(API_PARAM(Ref) const Int2& patchCoord) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the patch at the given location.
|
||||
@@ -231,7 +247,7 @@ public:
|
||||
/// <param name="x">The patch location x.</param>
|
||||
/// <param name="z">The patch location z.</param>
|
||||
/// <returns>The patch.</returns>
|
||||
TerrainPatch* GetPatch(int32 x, int32 z) const;
|
||||
API_FUNCTION() TerrainPatch* GetPatch(int32 x, int32 z) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the zero-based index of the terrain patch in the terrain patches collection.
|
||||
@@ -245,7 +261,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="index">The index.</param>
|
||||
/// <returns>The patch.</returns>
|
||||
FORCE_INLINE TerrainPatch* GetPatch(int32 index) const
|
||||
API_FUNCTION() FORCE_INLINE TerrainPatch* GetPatch(int32 index) const
|
||||
{
|
||||
return _patches[index];
|
||||
}
|
||||
@@ -316,7 +332,6 @@ public:
|
||||
|
||||
public:
|
||||
#if TERRAIN_EDITING
|
||||
|
||||
/// <summary>
|
||||
/// Setups the terrain. Clears the existing data.
|
||||
/// </summary>
|
||||
@@ -341,7 +356,6 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="patchCoord">The patch location (x and z).</param>
|
||||
API_FUNCTION() void RemovePatch(API_PARAM(Ref) const Int2& patchCoord);
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -374,7 +388,7 @@ public:
|
||||
/// <param name="resultChunk">The raycast result hit chunk. Valid only if raycast hits anything.</param>
|
||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||
bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, TerrainChunk*& resultChunk, float maxDistance = MAX_float) const;
|
||||
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, API_PARAM(Out) TerrainChunk*& resultChunk, float maxDistance = MAX_float) const;
|
||||
|
||||
/// <summary>
|
||||
/// Performs a raycast against this terrain collision shape. Returns the hit chunk.
|
||||
|
||||
@@ -11,7 +11,14 @@
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
#include "Engine/Core/Math/OrientedBoundingBox.h"
|
||||
#include "Engine/Level/Scene/Scene.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Level/Prefabs/PrefabManager.h"
|
||||
#endif
|
||||
|
||||
TerrainChunk::TerrainChunk(const SpawnParams& params)
|
||||
: ScriptingObject(params)
|
||||
{
|
||||
}
|
||||
|
||||
void TerrainChunk::Init(TerrainPatch* patch, uint16 x, uint16 z)
|
||||
{
|
||||
@@ -21,7 +28,7 @@ void TerrainChunk::Init(TerrainPatch* patch, uint16 x, uint16 z)
|
||||
_z = z;
|
||||
_yOffset = 0;
|
||||
_yHeight = 1;
|
||||
_heightmapUVScaleBias = Float4(1.0f, 1.0f, _x, _z) * (1.0f / TerrainPatch::CHUNKS_COUNT_EDGE);
|
||||
_heightmapUVScaleBias = Float4(1.0f, 1.0f, _x, _z) * (1.0f / Terrain::ChunksCountEdge);
|
||||
_perInstanceRandom = (_patch->_terrain->_id.C ^ _x ^ _z) * (1.0f / (float)MAX_uint32);
|
||||
OverrideMaterial = nullptr;
|
||||
}
|
||||
@@ -51,8 +58,8 @@ bool TerrainChunk::PrepareDraw(const RenderContext& renderContext)
|
||||
|
||||
//lod = 0;
|
||||
//lod = 10;
|
||||
//lod = (_x + _z + TerrainPatch::CHUNKS_COUNT_EDGE * (_patch->_x + _patch->_z));
|
||||
//lod = (int32)Vector2::Distance(Vector2(2, 2), Vector2(_patch->_x, _patch->_z) * TerrainPatch::CHUNKS_COUNT_EDGE + Vector2(_x, _z));
|
||||
//lod = (_x + _z + Terrain::ChunksCountEdge * (_patch->_x + _patch->_z));
|
||||
//lod = (int32)Vector2::Distance(Vector2(2, 2), Vector2(_patch->_x, _patch->_z) * Terrain::ChunksCountEdge + Vector2(_x, _z));
|
||||
//lod = (int32)(Vector3::Distance(_bounds.GetCenter(), view.Position) / 10000.0f);
|
||||
}
|
||||
lod = Math::Clamp(lod, minStreamedLod, lodCount - 1);
|
||||
@@ -93,7 +100,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext) const
|
||||
drawCall.ObjectRadius = _sphere.Radius;
|
||||
drawCall.Terrain.Patch = _patch;
|
||||
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
|
||||
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
|
||||
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * Terrain::ChunksCountEdge + _x), (float)(_patch->_z * Terrain::ChunksCountEdge + _z));
|
||||
drawCall.Terrain.CurrentLOD = (float)lod;
|
||||
drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1);
|
||||
drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
|
||||
@@ -151,7 +158,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* materi
|
||||
drawCall.ObjectRadius = _sphere.Radius;
|
||||
drawCall.Terrain.Patch = _patch;
|
||||
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
|
||||
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
|
||||
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * Terrain::ChunksCountEdge + _x), (float)(_patch->_z * Terrain::ChunksCountEdge + _z));
|
||||
drawCall.Terrain.CurrentLOD = (float)lod;
|
||||
drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1);
|
||||
drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
|
||||
@@ -232,46 +239,46 @@ void TerrainChunk::CacheNeighbors()
|
||||
_neighbors[0] = this;
|
||||
if (_z > 0)
|
||||
{
|
||||
_neighbors[0] = &_patch->Chunks[(_z - 1) * TerrainPatch::CHUNKS_COUNT_EDGE + _x];
|
||||
_neighbors[0] = &_patch->Chunks[(_z - 1) * Terrain::ChunksCountEdge + _x];
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto patch = _patch->_terrain->GetPatch(_patch->_x, _patch->_z - 1);
|
||||
if (patch)
|
||||
_neighbors[0] = &patch->Chunks[(TerrainPatch::CHUNKS_COUNT_EDGE - 1) * TerrainPatch::CHUNKS_COUNT_EDGE + _x];
|
||||
_neighbors[0] = &patch->Chunks[(Terrain::ChunksCountEdge - 1) * Terrain::ChunksCountEdge + _x];
|
||||
}
|
||||
|
||||
// 1: left
|
||||
_neighbors[1] = this;
|
||||
if (_x > 0)
|
||||
{
|
||||
_neighbors[1] = &_patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE + (_x - 1)];
|
||||
_neighbors[1] = &_patch->Chunks[_z * Terrain::ChunksCountEdge + (_x - 1)];
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto patch = _patch->_terrain->GetPatch(_patch->_x - 1, _patch->_z);
|
||||
if (patch)
|
||||
_neighbors[1] = &patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE + (TerrainPatch::CHUNKS_COUNT_EDGE - 1)];
|
||||
_neighbors[1] = &patch->Chunks[_z * Terrain::ChunksCountEdge + (Terrain::ChunksCountEdge - 1)];
|
||||
}
|
||||
|
||||
// 2: right
|
||||
_neighbors[2] = this;
|
||||
if (_x < TerrainPatch::CHUNKS_COUNT_EDGE - 1)
|
||||
if (_x < Terrain::ChunksCountEdge - 1)
|
||||
{
|
||||
_neighbors[2] = &_patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE + (_x + 1)];
|
||||
_neighbors[2] = &_patch->Chunks[_z * Terrain::ChunksCountEdge + (_x + 1)];
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto patch = _patch->_terrain->GetPatch(_patch->_x + 1, _patch->_z);
|
||||
if (patch)
|
||||
_neighbors[2] = &patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE];
|
||||
_neighbors[2] = &patch->Chunks[_z * Terrain::ChunksCountEdge];
|
||||
}
|
||||
|
||||
// 3: top
|
||||
_neighbors[3] = this;
|
||||
if (_z < TerrainPatch::CHUNKS_COUNT_EDGE - 1)
|
||||
if (_z < Terrain::ChunksCountEdge - 1)
|
||||
{
|
||||
_neighbors[3] = &_patch->Chunks[(_z + 1) * TerrainPatch::CHUNKS_COUNT_EDGE + _x];
|
||||
_neighbors[3] = &_patch->Chunks[(_z + 1) * Terrain::ChunksCountEdge + _x];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -17,14 +17,14 @@ struct RenderContext;
|
||||
/// <summary>
|
||||
/// Represents a single terrain chunk.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API TerrainChunk : public ISerializable
|
||||
API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API TerrainChunk : public ScriptingObject, public ISerializable
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE(TerrainChunk);
|
||||
friend Terrain;
|
||||
friend TerrainPatch;
|
||||
friend TerrainChunk;
|
||||
|
||||
private:
|
||||
|
||||
TerrainPatch* _patch;
|
||||
uint16 _x, _z;
|
||||
Float4 _heightmapUVScaleBias;
|
||||
@@ -41,11 +41,10 @@ private:
|
||||
void Init(TerrainPatch* patch, uint16 x, uint16 z);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The material to override the terrain default one for this chunk.
|
||||
/// </summary>
|
||||
AssetReference<MaterialBase> OverrideMaterial;
|
||||
API_FIELD() AssetReference<MaterialBase> OverrideMaterial;
|
||||
|
||||
/// <summary>
|
||||
/// The baked lightmap entry info for this chunk.
|
||||
@@ -53,11 +52,10 @@ public:
|
||||
LightmapEntry Lightmap;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the x coordinate.
|
||||
/// </summary>
|
||||
FORCE_INLINE int32 GetX() const
|
||||
API_FUNCTION() FORCE_INLINE int32 GetX() const
|
||||
{
|
||||
return _x;
|
||||
}
|
||||
@@ -65,7 +63,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the z coordinate.
|
||||
/// </summary>
|
||||
FORCE_INLINE int32 GetZ() const
|
||||
API_FUNCTION() FORCE_INLINE int32 GetZ() const
|
||||
{
|
||||
return _z;
|
||||
}
|
||||
@@ -73,7 +71,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the patch.
|
||||
/// </summary>
|
||||
FORCE_INLINE TerrainPatch* GetPatch() const
|
||||
API_FUNCTION() FORCE_INLINE TerrainPatch* GetPatch() const
|
||||
{
|
||||
return _patch;
|
||||
}
|
||||
@@ -81,7 +79,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the chunk world bounds.
|
||||
/// </summary>
|
||||
FORCE_INLINE const BoundingBox& GetBounds() const
|
||||
API_FUNCTION() FORCE_INLINE const BoundingBox& GetBounds() const
|
||||
{
|
||||
return _bounds;
|
||||
}
|
||||
@@ -89,7 +87,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the chunk transformation (world to local).
|
||||
/// </summary>
|
||||
FORCE_INLINE const Transform& GetTransform() const
|
||||
API_FUNCTION() FORCE_INLINE const Transform& GetTransform() const
|
||||
{
|
||||
return _transform;
|
||||
}
|
||||
@@ -97,10 +95,9 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the scale (in XY) and bias (in ZW) applied to the vertex UVs to get the chunk coordinates.
|
||||
/// </summary>
|
||||
/// <param name="result">The result.</param>
|
||||
FORCE_INLINE void GetHeightmapUVScaleBias(Float4* result) const
|
||||
API_FUNCTION() FORCE_INLINE const Float4& GetHeightmapUVScaleBias() const
|
||||
{
|
||||
*result = _heightmapUVScaleBias;
|
||||
return _heightmapUVScaleBias;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -120,7 +117,6 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Prepares for drawing chunk. Cached LOD and material.
|
||||
/// </summary>
|
||||
@@ -140,7 +136,7 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="material">The material to use for rendering.</param>
|
||||
/// <param name="lodIndex">The LOD index.</param>
|
||||
void Draw(const RenderContext& renderContext, MaterialBase* material, int32 lodIndex = 0) const;
|
||||
API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, int32 lodIndex = 0) const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if there is an intersection between the terrain chunk and a point
|
||||
@@ -148,7 +144,7 @@ public:
|
||||
/// <param name="ray">The ray.</param>
|
||||
/// <param name="distance">The output distance.</param>
|
||||
/// <returns>True if chunk intersects with the ray, otherwise false.</returns>
|
||||
bool Intersects(const Ray& ray, Real& distance);
|
||||
API_FUNCTION() bool Intersects(const Ray& ray, API_PARAM(Out) Real& distance);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the cached bounds of the chunk.
|
||||
@@ -166,7 +162,6 @@ public:
|
||||
void CacheNeighbors();
|
||||
|
||||
public:
|
||||
|
||||
// [ISerializable]
|
||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||
|
||||
@@ -44,6 +44,11 @@ struct TerrainCollisionDataHeader
|
||||
float ScaleXZ;
|
||||
};
|
||||
|
||||
TerrainPatch::TerrainPatch(const SpawnParams& params)
|
||||
: ScriptingObject(params)
|
||||
{
|
||||
}
|
||||
|
||||
void TerrainPatch::Init(Terrain* terrain, int16 x, int16 z)
|
||||
{
|
||||
ScopeLock lock(_collisionLocker);
|
||||
@@ -54,13 +59,13 @@ void TerrainPatch::Init(Terrain* terrain, int16 x, int16 z)
|
||||
_physicsHeightField = nullptr;
|
||||
_x = x;
|
||||
_z = z;
|
||||
const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE;
|
||||
const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * Terrain::Terrain::ChunksCountEdge;
|
||||
_offset = Float3(_x * size, 0.0f, _z * size);
|
||||
_yOffset = 0.0f;
|
||||
_yHeight = 1.0f;
|
||||
for (int32 i = 0; i < CHUNKS_COUNT; i++)
|
||||
for (int32 i = 0; i < Terrain::ChunksCount; i++)
|
||||
{
|
||||
Chunks[i].Init(this, i % CHUNKS_COUNT_EDGE, i / CHUNKS_COUNT_EDGE);
|
||||
Chunks[i].Init(this, i % Terrain::Terrain::ChunksCountEdge, i / Terrain::Terrain::ChunksCountEdge);
|
||||
}
|
||||
Heightmap = nullptr;
|
||||
for (int32 i = 0; i < TERRAIN_MAX_SPLATMAPS_COUNT; i++)
|
||||
@@ -111,7 +116,7 @@ void TerrainPatch::UpdateBounds()
|
||||
PROFILE_CPU();
|
||||
Chunks[0].UpdateBounds();
|
||||
_bounds = Chunks[0]._bounds;
|
||||
for (int32 i = 1; i < CHUNKS_COUNT; i++)
|
||||
for (int32 i = 1; i < Terrain::ChunksCount; i++)
|
||||
{
|
||||
Chunks[i].UpdateBounds();
|
||||
BoundingBox::Merge(_bounds, Chunks[i]._bounds, _bounds);
|
||||
@@ -130,7 +135,7 @@ void TerrainPatch::UpdateTransform()
|
||||
}
|
||||
|
||||
// Update chunks cache
|
||||
for (int32 i = 0; i < CHUNKS_COUNT; i++)
|
||||
for (int32 i = 0; i < Terrain::ChunksCount; i++)
|
||||
{
|
||||
Chunks[i].UpdateTransform();
|
||||
}
|
||||
@@ -168,9 +173,9 @@ struct TerrainDataUpdateInfo
|
||||
{
|
||||
ChunkSize = patch->GetTerrain()->GetChunkSize();
|
||||
VertexCountEdge = ChunkSize + 1;
|
||||
HeightmapSize = ChunkSize * TerrainPatch::CHUNKS_COUNT_EDGE + 1;
|
||||
HeightmapSize = ChunkSize * Terrain::ChunksCountEdge + 1;
|
||||
HeightmapLength = HeightmapSize * HeightmapSize;
|
||||
TextureSize = VertexCountEdge * TerrainPatch::CHUNKS_COUNT_EDGE;
|
||||
TextureSize = VertexCountEdge * Terrain::ChunksCountEdge;
|
||||
}
|
||||
|
||||
bool UsePhysicalMaterials() const
|
||||
@@ -231,7 +236,7 @@ FORCE_INLINE bool ReadIsHole(const Color32& raw)
|
||||
return (raw.B + raw.A) >= (int32)(1.9f * MAX_uint8);
|
||||
}
|
||||
|
||||
void CalculateHeightmapRange(Terrain* terrain, TerrainDataUpdateInfo& info, const float* heightmap, float chunkOffsets[TerrainPatch::CHUNKS_COUNT], float chunkHeights[TerrainPatch::CHUNKS_COUNT])
|
||||
void CalculateHeightmapRange(Terrain* terrain, TerrainDataUpdateInfo& info, const float* heightmap, float chunkOffsets[Terrain::ChunksCount], float chunkHeights[Terrain::ChunksCount])
|
||||
{
|
||||
PROFILE_CPU_NAMED("Terrain.CalculateRange");
|
||||
|
||||
@@ -240,10 +245,10 @@ void CalculateHeightmapRange(Terrain* terrain, TerrainDataUpdateInfo& info, cons
|
||||
float minPatchHeight = MAX_float;
|
||||
float maxPatchHeight = MIN_float;
|
||||
|
||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
const int32 chunkX = (chunkIndex % TerrainPatch::CHUNKS_COUNT_EDGE) * info.ChunkSize;
|
||||
const int32 chunkZ = (chunkIndex / TerrainPatch::CHUNKS_COUNT_EDGE) * info.ChunkSize;
|
||||
const int32 chunkX = (chunkIndex % Terrain::ChunksCountEdge) * info.ChunkSize;
|
||||
const int32 chunkZ = (chunkIndex / Terrain::ChunksCountEdge) * info.ChunkSize;
|
||||
|
||||
float minHeight = MAX_float;
|
||||
float maxHeight = MIN_float;
|
||||
@@ -286,10 +291,10 @@ void UpdateHeightMap(const TerrainDataUpdateInfo& info, const float* heightmap,
|
||||
const auto heightmapPtr = heightmap;
|
||||
const auto ptr = (Color32*)data;
|
||||
|
||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
const int32 chunkX = (chunkIndex % TerrainPatch::CHUNKS_COUNT_EDGE);
|
||||
const int32 chunkZ = (chunkIndex / TerrainPatch::CHUNKS_COUNT_EDGE);
|
||||
const int32 chunkX = (chunkIndex % Terrain::ChunksCountEdge);
|
||||
const int32 chunkZ = (chunkIndex / Terrain::ChunksCountEdge);
|
||||
|
||||
const int32 chunkTextureX = chunkX * info.VertexCountEdge;
|
||||
const int32 chunkTextureZ = chunkZ * info.VertexCountEdge;
|
||||
@@ -328,10 +333,10 @@ void UpdateSplatMap(const TerrainDataUpdateInfo& info, const Color32* splatMap,
|
||||
|
||||
const auto splatPtr = splatMap;
|
||||
const auto ptr = (Color32*)data;
|
||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
const int32 chunkX = (chunkIndex % TerrainPatch::CHUNKS_COUNT_EDGE);
|
||||
const int32 chunkZ = (chunkIndex / TerrainPatch::CHUNKS_COUNT_EDGE);
|
||||
const int32 chunkX = (chunkIndex % Terrain::ChunksCountEdge);
|
||||
const int32 chunkZ = (chunkIndex / Terrain::ChunksCountEdge);
|
||||
|
||||
const int32 chunkTextureX = chunkX * info.VertexCountEdge;
|
||||
const int32 chunkTextureZ = chunkZ * info.VertexCountEdge;
|
||||
@@ -450,10 +455,10 @@ void UpdateNormalsAndHoles(const TerrainDataUpdateInfo& info, const float* heigh
|
||||
|
||||
// Write back to the data container
|
||||
const auto ptr = (Color32*)data;
|
||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
const int32 chunkX = (chunkIndex % TerrainPatch::CHUNKS_COUNT_EDGE);
|
||||
const int32 chunkZ = (chunkIndex / TerrainPatch::CHUNKS_COUNT_EDGE);
|
||||
const int32 chunkX = (chunkIndex % Terrain::ChunksCountEdge);
|
||||
const int32 chunkZ = (chunkIndex / Terrain::ChunksCountEdge);
|
||||
|
||||
const int32 chunkTextureX = chunkX * info.VertexCountEdge;
|
||||
const int32 chunkTextureZ = chunkZ * info.VertexCountEdge;
|
||||
@@ -543,9 +548,9 @@ void FixMips(const TerrainDataUpdateInfo& info, TextureBase::InitData* initData,
|
||||
const int32 textureSizeMipHigher = textureSizeMip << 1;
|
||||
|
||||
// Make heightmap values on left edge the same as the left edge of the chunk on the higher LOD
|
||||
for (int32 chunkX = 0; chunkX < TerrainPatch::CHUNKS_COUNT_EDGE; chunkX++)
|
||||
for (int32 chunkX = 0; chunkX < Terrain::ChunksCountEdge; chunkX++)
|
||||
{
|
||||
for (int32 chunkZ = 0; chunkZ < TerrainPatch::CHUNKS_COUNT_EDGE; chunkZ++)
|
||||
for (int32 chunkZ = 0; chunkZ < Terrain::ChunksCountEdge; chunkZ++)
|
||||
{
|
||||
const int32 chunkTextureX = chunkX * vertexCountEdgeMip;
|
||||
const int32 chunkTextureZ = chunkZ * vertexCountEdgeMip;
|
||||
@@ -558,11 +563,11 @@ void FixMips(const TerrainDataUpdateInfo& info, TextureBase::InitData* initData,
|
||||
int32 x = 0, xCount = vertexCountEdgeMip;
|
||||
if (chunkX == 0)
|
||||
x = 1;
|
||||
else if (chunkX == TerrainPatch::CHUNKS_COUNT_EDGE - 1)
|
||||
else if (chunkX == Terrain::ChunksCountEdge - 1)
|
||||
xCount--;
|
||||
if (chunkZ == 0)
|
||||
z = 1;
|
||||
else if (chunkZ == TerrainPatch::CHUNKS_COUNT_EDGE - 1)
|
||||
else if (chunkZ == Terrain::ChunksCountEdge - 1)
|
||||
zCount--;
|
||||
|
||||
for (; z < zCount; z++)
|
||||
@@ -638,7 +643,7 @@ bool CookCollision(TerrainDataUpdateInfo& info, TextureBase::InitData* initData,
|
||||
const int32 collisionLOD = Math::Clamp<int32>(collisionLod, 0, initData->Mips.Count() - 1);
|
||||
const int32 collisionLODInv = (int32)Math::Pow(2.0f, (float)collisionLOD);
|
||||
const int32 heightFieldChunkSize = ((info.ChunkSize + 1) >> collisionLOD) - 1;
|
||||
const int32 heightFieldSize = heightFieldChunkSize * TerrainPatch::CHUNKS_COUNT_EDGE + 1;
|
||||
const int32 heightFieldSize = heightFieldChunkSize * Terrain::ChunksCountEdge + 1;
|
||||
const int32 heightFieldLength = heightFieldSize * heightFieldSize;
|
||||
GET_TERRAIN_SCRATCH_BUFFER(heightFieldData, heightFieldLength, PhysicsBackend::HeightFieldSample);
|
||||
PhysicsBackend::HeightFieldSample sample;
|
||||
@@ -649,11 +654,11 @@ bool CookCollision(TerrainDataUpdateInfo& info, TextureBase::InitData* initData,
|
||||
const auto& mip = initData->Mips[collisionLOD];
|
||||
const int32 vertexCountEdgeMip = info.VertexCountEdge >> collisionLOD;
|
||||
const int32 textureSizeMip = info.TextureSize >> collisionLOD;
|
||||
for (int32 chunkX = 0; chunkX < TerrainPatch::CHUNKS_COUNT_EDGE; chunkX++)
|
||||
for (int32 chunkX = 0; chunkX < Terrain::ChunksCountEdge; chunkX++)
|
||||
{
|
||||
const int32 chunkTextureX = chunkX * vertexCountEdgeMip;
|
||||
const int32 chunkStartX = chunkX * heightFieldChunkSize;
|
||||
for (int32 chunkZ = 0; chunkZ < TerrainPatch::CHUNKS_COUNT_EDGE; chunkZ++)
|
||||
for (int32 chunkZ = 0; chunkZ < Terrain::ChunksCountEdge; chunkZ++)
|
||||
{
|
||||
const int32 chunkTextureZ = chunkZ * vertexCountEdgeMip;
|
||||
const int32 chunkStartZ = chunkZ * heightFieldChunkSize;
|
||||
@@ -709,7 +714,7 @@ bool ModifyCollision(TerrainDataUpdateInfo& info, TextureBase::InitData* initDat
|
||||
const int32 collisionLOD = Math::Clamp<int32>(collisionLod, 0, initData->Mips.Count() - 1);
|
||||
const int32 collisionLODInv = (int32)Math::Pow(2.0f, (float)collisionLOD);
|
||||
const int32 heightFieldChunkSize = ((info.ChunkSize + 1) >> collisionLOD) - 1;
|
||||
const int32 heightFieldSize = heightFieldChunkSize * TerrainPatch::CHUNKS_COUNT_EDGE + 1;
|
||||
const int32 heightFieldSize = heightFieldChunkSize * Terrain::ChunksCountEdge + 1;
|
||||
const Int2 samplesOffset(Vector2::Floor(modifiedOffsetRatio * (float)heightFieldSize));
|
||||
Int2 samplesSize(Vector2::Ceil(modifiedSizeRatio * (float)heightFieldSize));
|
||||
samplesSize.X = Math::Max(samplesSize.X, 1);
|
||||
@@ -729,14 +734,14 @@ bool ModifyCollision(TerrainDataUpdateInfo& info, TextureBase::InitData* initDat
|
||||
const auto& mip = initData->Mips[collisionLOD];
|
||||
const int32 vertexCountEdgeMip = info.VertexCountEdge >> collisionLOD;
|
||||
const int32 textureSizeMip = info.TextureSize >> collisionLOD;
|
||||
for (int32 chunkX = 0; chunkX < TerrainPatch::CHUNKS_COUNT_EDGE; chunkX++)
|
||||
for (int32 chunkX = 0; chunkX < Terrain::ChunksCountEdge; chunkX++)
|
||||
{
|
||||
const int32 chunkTextureX = chunkX * vertexCountEdgeMip;
|
||||
const int32 chunkStartX = chunkX * heightFieldChunkSize;
|
||||
if (chunkStartX >= samplesEnd.X || chunkStartX + vertexCountEdgeMip < samplesOffset.X)
|
||||
continue; // Skip unmodified chunks
|
||||
|
||||
for (int32 chunkZ = 0; chunkZ < TerrainPatch::CHUNKS_COUNT_EDGE; chunkZ++)
|
||||
for (int32 chunkZ = 0; chunkZ < Terrain::ChunksCountEdge; chunkZ++)
|
||||
{
|
||||
const int32 chunkTextureZ = chunkZ * vertexCountEdgeMip;
|
||||
const int32 chunkStartZ = chunkZ * heightFieldChunkSize;
|
||||
@@ -806,15 +811,15 @@ bool TerrainPatch::SetupHeightMap(int32 heightMapLength, const float* heightMap,
|
||||
const int32 lodCount = Math::Min<int32>(_terrain->_lodCount, MipLevelsCount(info.VertexCountEdge) - 2);
|
||||
|
||||
// Process heightmap to get per-patch height normalization values
|
||||
float chunkOffsets[CHUNKS_COUNT];
|
||||
float chunkHeights[CHUNKS_COUNT];
|
||||
float chunkOffsets[Terrain::ChunksCount];
|
||||
float chunkHeights[Terrain::ChunksCount];
|
||||
CalculateHeightmapRange(_terrain, info, heightMap, chunkOffsets, chunkHeights);
|
||||
|
||||
// Prepare
|
||||
#if USE_EDITOR
|
||||
const bool useVirtualStorage = Editor::IsPlayMode || forceUseVirtualStorage;
|
||||
#else
|
||||
const bool useVirtualStorage = true;
|
||||
const bool useVirtualStorage = true;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
String heightMapPath, heightFieldPath;
|
||||
@@ -910,11 +915,11 @@ bool TerrainPatch::SetupHeightMap(int32 heightMapLength, const float* heightMap,
|
||||
}
|
||||
}
|
||||
#else
|
||||
else
|
||||
{
|
||||
// Not supported
|
||||
CRASH;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not supported
|
||||
CRASH;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Prepare collision data destination container
|
||||
@@ -975,7 +980,7 @@ bool TerrainPatch::SetupHeightMap(int32 heightMapLength, const float* heightMap,
|
||||
// Update data
|
||||
_yOffset = info.PatchOffset;
|
||||
_yHeight = info.PatchHeight;
|
||||
for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
auto& chunk = Chunks[chunkIndex];
|
||||
chunk._yOffset = chunkOffsets[chunkIndex];
|
||||
@@ -1031,7 +1036,7 @@ bool TerrainPatch::SetupSplatMap(int32 index, int32 splatMapLength, const Color3
|
||||
#if USE_EDITOR
|
||||
const bool useVirtualStorage = Editor::IsPlayMode || forceUseVirtualStorage;
|
||||
#else
|
||||
const bool useVirtualStorage = true;
|
||||
const bool useVirtualStorage = true;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
String splatMapPath;
|
||||
@@ -1126,11 +1131,11 @@ bool TerrainPatch::SetupSplatMap(int32 index, int32 splatMapLength, const Color3
|
||||
}
|
||||
}
|
||||
#else
|
||||
else
|
||||
{
|
||||
// Not supported
|
||||
CRASH;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not supported
|
||||
CRASH;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TERRAIN_UPDATING
|
||||
@@ -1147,7 +1152,7 @@ bool TerrainPatch::SetupSplatMap(int32 index, int32 splatMapLength, const Color3
|
||||
bool TerrainPatch::InitializeHeightMap()
|
||||
{
|
||||
PROFILE_CPU_NAMED("Terrain.InitializeHeightMap");
|
||||
const auto heightmapSize = _terrain->GetChunkSize() * TerrainPatch::CHUNKS_COUNT_EDGE + 1;
|
||||
const auto heightmapSize = _terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
|
||||
Array<float> heightmap;
|
||||
heightmap.Resize(heightmapSize * heightmapSize);
|
||||
heightmap.SetAll(0.0f);
|
||||
@@ -1242,7 +1247,7 @@ void TerrainPatch::CacheHeightData()
|
||||
const float patchHeight = _yHeight;
|
||||
const auto heightmapPtr = _cachedHeightMap.Get();
|
||||
const auto holesMaskPtr = _cachedHolesMask.Get();
|
||||
for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
const int32 chunkTextureX = Chunks[chunkIndex]._x * info.VertexCountEdge;
|
||||
const int32 chunkTextureZ = Chunks[chunkIndex]._z * info.VertexCountEdge;
|
||||
@@ -1315,7 +1320,7 @@ void TerrainPatch::CacheSplatData()
|
||||
|
||||
// Extract splatmap data
|
||||
const auto splatMapPtr = static_cast<Color32*>(_cachedSplatMap[index].Get());
|
||||
for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
const int32 chunkTextureX = Chunks[chunkIndex]._x * info.VertexCountEdge;
|
||||
const int32 chunkTextureZ = Chunks[chunkIndex]._z * info.VertexCountEdge;
|
||||
@@ -1394,8 +1399,8 @@ bool TerrainPatch::ModifyHeightMap(const float* samples, const Int2& modifiedOff
|
||||
}
|
||||
|
||||
// Process heightmap to get per-patch height normalization values
|
||||
float chunkOffsets[CHUNKS_COUNT];
|
||||
float chunkHeights[CHUNKS_COUNT];
|
||||
float chunkOffsets[Terrain::ChunksCount];
|
||||
float chunkHeights[Terrain::ChunksCount];
|
||||
CalculateHeightmapRange(_terrain, info, heightMap, chunkOffsets, chunkHeights);
|
||||
// TODO: maybe calculate chunk ranges for only modified chunks
|
||||
const bool wasHeightRangeChanged = Math::NotNearEqual(_yOffset, info.PatchOffset) || Math::NotNearEqual(_yHeight, info.PatchHeight);
|
||||
@@ -1425,7 +1430,7 @@ bool TerrainPatch::ModifyHeightMap(const float* samples, const Int2& modifiedOff
|
||||
// Update all the stuff
|
||||
_yOffset = info.PatchOffset;
|
||||
_yHeight = info.PatchHeight;
|
||||
for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
auto& chunk = Chunks[chunkIndex];
|
||||
chunk._yOffset = chunkOffsets[chunkIndex];
|
||||
@@ -1631,7 +1636,7 @@ bool TerrainPatch::ModifySplatMap(int32 index, const Color32* samples, const Int
|
||||
#if USE_EDITOR
|
||||
const bool useVirtualStorage = Editor::IsPlayMode || Heightmap->IsVirtual();
|
||||
#else
|
||||
const bool useVirtualStorage = true;
|
||||
const bool useVirtualStorage = true;
|
||||
#endif
|
||||
|
||||
// Save the splatmap data to the asset
|
||||
@@ -1675,11 +1680,11 @@ bool TerrainPatch::ModifySplatMap(int32 index, const Color32* samples, const Int
|
||||
}
|
||||
}
|
||||
#else
|
||||
else
|
||||
{
|
||||
// Not supported
|
||||
CRASH;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not supported
|
||||
CRASH;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1987,7 +1992,7 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, floa
|
||||
// Find hit chunk
|
||||
resultChunk = nullptr;
|
||||
const auto hitPoint = origin + direction * hitDistance;
|
||||
for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
const auto box = Chunks[chunkIndex]._bounds;
|
||||
if (box.Minimum.X <= hitPoint.X && box.Maximum.X >= hitPoint.X &&
|
||||
@@ -2042,7 +2047,7 @@ void TerrainPatch::ClosestPoint(const Vector3& position, Vector3& result) const
|
||||
void TerrainPatch::UpdatePostManualDeserialization()
|
||||
{
|
||||
// Update data
|
||||
for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++)
|
||||
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||
{
|
||||
auto& chunk = Chunks[chunkIndex];
|
||||
chunk.UpdateTransform();
|
||||
@@ -2101,7 +2106,7 @@ void TerrainPatch::CreateCollision()
|
||||
|
||||
// Create shape
|
||||
JsonAsset* materials[8];
|
||||
for (int32 i = 0;i<8;i++)
|
||||
for (int32 i = 0; i < 8; i++)
|
||||
materials[i] = _terrain->GetPhysicalMaterials()[i];
|
||||
_physicsShape = PhysicsBackend::CreateShape(_terrain, shape, ToSpan(materials, 8), _terrain->IsActiveInHierarchy(), false);
|
||||
PhysicsBackend::SetShapeLocalPose(_physicsShape, Vector3(0, _yOffset * terrainTransform.Scale.Y, 0), Quaternion::Identity);
|
||||
@@ -2295,7 +2300,7 @@ const Array<Vector3>& TerrainPatch::GetCollisionTriangles()
|
||||
|
||||
#define GET_VERTEX(x, y) Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, row + (x), col + (y)) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))); Vector3::Transform(v##x##y, world, v##x##y)
|
||||
|
||||
const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE;
|
||||
const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * Terrain::Terrain::ChunksCountEdge;
|
||||
const Transform terrainTransform = _terrain->_transform;
|
||||
Transform localTransform(Vector3(_x * size, _yOffset, _z * size), Quaternion::Identity, Vector3(_collisionScaleXZ, _yHeight, _collisionScaleXZ));
|
||||
const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld();
|
||||
@@ -2344,7 +2349,7 @@ void TerrainPatch::GetCollisionTriangles(const BoundingSphere& bounds, Array<Vec
|
||||
|
||||
// Prepare
|
||||
const auto& triangles = GetCollisionTriangles();
|
||||
const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE;
|
||||
const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * Terrain::Terrain::ChunksCountEdge;
|
||||
Transform transform;
|
||||
transform.Translation = _offset + Vector3(0, _yOffset, 0);
|
||||
transform.Orientation = Quaternion::Identity;
|
||||
@@ -2450,7 +2455,7 @@ void TerrainPatch::ExtractCollisionGeometry(Array<Float3>& vertexBuffer, Array<i
|
||||
ScopeLock lock(Level::ScenesLock);
|
||||
if (_collisionVertices.IsEmpty())
|
||||
{
|
||||
const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE;
|
||||
const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * Terrain::Terrain::ChunksCountEdge;
|
||||
const Transform terrainTransform = _terrain->_transform;
|
||||
const Transform localTransform(Vector3(_x * size, _yOffset, _z * size), Quaternion::Identity, Float3(_collisionScaleXZ, _yHeight, _collisionScaleXZ));
|
||||
const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld();
|
||||
@@ -2512,7 +2517,7 @@ void TerrainPatch::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
|
||||
stream.JKEY("Chunks");
|
||||
stream.StartArray();
|
||||
for (int32 i = 0; i < CHUNKS_COUNT; i++)
|
||||
for (int32 i = 0; i < Terrain::Terrain::ChunksCount; i++)
|
||||
{
|
||||
stream.StartObject();
|
||||
Chunks[i].Serialize(stream, other ? &other->Chunks[i] : nullptr);
|
||||
@@ -2539,15 +2544,14 @@ void TerrainPatch::Deserialize(DeserializeStream& stream, ISerializeModifier* mo
|
||||
DESERIALIZE_MEMBER(Heightfield, _heightfield);
|
||||
|
||||
// Update offset (x or/and z may be modified)
|
||||
const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE;
|
||||
const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * Terrain::ChunksCountEdge;
|
||||
_offset = Vector3(_x * size, 0.0f, _z * size);
|
||||
|
||||
auto member = stream.FindMember("Chunks");
|
||||
if (member != stream.MemberEnd() && member->value.IsArray())
|
||||
{
|
||||
auto& chunksData = member->value;
|
||||
const auto chunksCount = Math::Min<int32>((int32)chunksData.Size(), CHUNKS_COUNT);
|
||||
|
||||
const auto chunksCount = Math::Min<int32>((int32)chunksData.Size(), Terrain::ChunksCount);
|
||||
for (int32 i = 0; i < chunksCount; i++)
|
||||
{
|
||||
Chunks[i].Deserialize(chunksData[i], modifier);
|
||||
|
||||
@@ -15,19 +15,13 @@ class TerrainMaterialShader;
|
||||
/// <summary>
|
||||
/// Represents single terrain patch made of 16 terrain chunks.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API TerrainPatch : public ISerializable
|
||||
API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API TerrainPatch : public ScriptingObject, public ISerializable
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE(TerrainPatch);
|
||||
friend Terrain;
|
||||
friend TerrainPatch;
|
||||
friend TerrainChunk;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
CHUNKS_COUNT = 16,
|
||||
CHUNKS_COUNT_EDGE = 4,
|
||||
};
|
||||
|
||||
private:
|
||||
Terrain* _terrain;
|
||||
int16 _x, _z;
|
||||
@@ -69,12 +63,12 @@ public:
|
||||
/// <summary>
|
||||
/// The chunks contained within the patch. Organized in 4x4 square.
|
||||
/// </summary>
|
||||
TerrainChunk Chunks[CHUNKS_COUNT];
|
||||
TerrainChunk Chunks[Terrain::ChunksCount];
|
||||
|
||||
/// <summary>
|
||||
/// The heightmap texture.
|
||||
/// </summary>
|
||||
AssetReference<Texture> Heightmap;
|
||||
API_FIELD() AssetReference<Texture> Heightmap;
|
||||
|
||||
/// <summary>
|
||||
/// The splatmap textures.
|
||||
@@ -85,7 +79,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the Y axis heightmap offset from terrain origin.
|
||||
/// </summary>
|
||||
FORCE_INLINE float GetOffsetY() const
|
||||
API_FUNCTION() FORCE_INLINE float GetOffsetY() const
|
||||
{
|
||||
return _yOffset;
|
||||
}
|
||||
@@ -93,7 +87,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the Y axis heightmap height.
|
||||
/// </summary>
|
||||
FORCE_INLINE float GetHeightY() const
|
||||
API_FUNCTION() FORCE_INLINE float GetHeightY() const
|
||||
{
|
||||
return _yHeight;
|
||||
}
|
||||
@@ -101,7 +95,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the x coordinate.
|
||||
/// </summary>
|
||||
FORCE_INLINE int32 GetX() const
|
||||
API_FUNCTION() FORCE_INLINE int32 GetX() const
|
||||
{
|
||||
return _x;
|
||||
}
|
||||
@@ -109,7 +103,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the z coordinate.
|
||||
/// </summary>
|
||||
FORCE_INLINE int32 GetZ() const
|
||||
API_FUNCTION() FORCE_INLINE int32 GetZ() const
|
||||
{
|
||||
return _z;
|
||||
}
|
||||
@@ -117,7 +111,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the terrain.
|
||||
/// </summary>
|
||||
FORCE_INLINE Terrain* GetTerrain() const
|
||||
API_FUNCTION() FORCE_INLINE Terrain* GetTerrain() const
|
||||
{
|
||||
return _terrain;
|
||||
}
|
||||
@@ -127,9 +121,9 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="index">The chunk zero-based index.</param>
|
||||
/// <returns>The chunk.</returns>
|
||||
TerrainChunk* GetChunk(int32 index)
|
||||
API_FUNCTION() TerrainChunk* GetChunk(int32 index)
|
||||
{
|
||||
if (index < 0 || index >= CHUNKS_COUNT)
|
||||
if (index < 0 || index >= Terrain::ChunksCount)
|
||||
return nullptr;
|
||||
return &Chunks[index];
|
||||
}
|
||||
@@ -139,9 +133,9 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="chunkCoord">The chunk location (x and z).</param>
|
||||
/// <returns>The chunk.</returns>
|
||||
TerrainChunk* GetChunk(const Int2& chunkCoord)
|
||||
API_FUNCTION() TerrainChunk* GetChunk(API_PARAM(Ref) const Int2& chunkCoord)
|
||||
{
|
||||
return GetChunk(chunkCoord.Y * CHUNKS_COUNT_EDGE + chunkCoord.X);
|
||||
return GetChunk(chunkCoord.Y * Terrain::ChunksCountEdge + chunkCoord.X);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -150,15 +144,38 @@ public:
|
||||
/// <param name="x">The chunk location x.</param>
|
||||
/// <param name="z">The chunk location z.</param>
|
||||
/// <returns>The chunk.</returns>
|
||||
TerrainChunk* GetChunk(int32 x, int32 z)
|
||||
API_FUNCTION() TerrainChunk* GetChunk(int32 x, int32 z)
|
||||
{
|
||||
return GetChunk(z * CHUNKS_COUNT_EDGE + x);
|
||||
return GetChunk(z * Terrain::ChunksCountEdge + x);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the splatmap assigned to this patch.
|
||||
/// </summary>
|
||||
/// <param name="index">The zero-based index of the splatmap.</param>
|
||||
/// <returns>The splatmap texture.</returns>
|
||||
API_FUNCTION() AssetReference<Texture> GetSplatmap(int32 index)
|
||||
{
|
||||
if (index < 0 || index >= TERRAIN_MAX_SPLATMAPS_COUNT)
|
||||
return nullptr;
|
||||
return Splatmap[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a splatmap to this patch.
|
||||
/// </summary>
|
||||
/// <param name="index">The zero-based index of the splatmap.</param>
|
||||
/// <param name="splatMap">Splatmap texture.</param>
|
||||
API_FUNCTION() void SetSplatmap(int32 index, const AssetReference<Texture>& splatMap)
|
||||
{
|
||||
if (index >= 0 && index < TERRAIN_MAX_SPLATMAPS_COUNT)
|
||||
Splatmap[index] = splatMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the patch world bounds.
|
||||
/// </summary>
|
||||
FORCE_INLINE const BoundingBox& GetBounds() const
|
||||
API_FUNCTION() FORCE_INLINE const BoundingBox& GetBounds() const
|
||||
{
|
||||
return _bounds;
|
||||
}
|
||||
@@ -184,7 +201,7 @@ public:
|
||||
/// Initializes the patch heightmap and collision to the default flat level.
|
||||
/// </summary>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
bool InitializeHeightMap();
|
||||
API_FUNCTION() bool InitializeHeightMap();
|
||||
|
||||
/// <summary>
|
||||
/// Setups the terrain patch using the specified heightmap data.
|
||||
@@ -194,7 +211,7 @@ public:
|
||||
/// <param name="holesMask">The holes mask (optional). Normalized to 0-1 range values with holes mask per-vertex. Must match the heightmap dimensions.</param>
|
||||
/// <param name="forceUseVirtualStorage">If set to <c>true</c> patch will use virtual storage by force. Otherwise it can use normal texture asset storage on drive (valid only during Editor). Runtime-created terrain can only use virtual storage (in RAM).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
bool SetupHeightMap(int32 heightMapLength, const float* heightMap, const byte* holesMask = nullptr, bool forceUseVirtualStorage = false);
|
||||
API_FUNCTION() bool SetupHeightMap(int32 heightMapLength, API_PARAM(Ref) const float* heightMap, API_PARAM(Ref) const byte* holesMask = nullptr, bool forceUseVirtualStorage = false);
|
||||
|
||||
/// <summary>
|
||||
/// Setups the terrain patch layer weights using the specified splatmaps data.
|
||||
@@ -204,7 +221,7 @@ public:
|
||||
/// <param name="splatMap">The splat map. Each array item contains 4 layer weights.</param>
|
||||
/// <param name="forceUseVirtualStorage">If set to <c>true</c> patch will use virtual storage by force. Otherwise it can use normal texture asset storage on drive (valid only during Editor). Runtime-created terrain can only use virtual storage (in RAM).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
bool SetupSplatMap(int32 index, int32 splatMapLength, const Color32* splatMap, bool forceUseVirtualStorage = false);
|
||||
API_FUNCTION() bool SetupSplatMap(int32 index, int32 splatMapLength, API_PARAM(Ref) const Color32* splatMap, bool forceUseVirtualStorage = false);
|
||||
#endif
|
||||
|
||||
#if TERRAIN_UPDATING
|
||||
@@ -212,40 +229,40 @@ public:
|
||||
/// Gets the raw pointer to the heightmap data.
|
||||
/// </summary>
|
||||
/// <returns>The heightmap data.</returns>
|
||||
float* GetHeightmapData();
|
||||
API_FUNCTION() float* GetHeightmapData();
|
||||
|
||||
/// <summary>
|
||||
/// Clears cache of the heightmap data.
|
||||
/// </summary>
|
||||
void ClearHeightmapCache();
|
||||
API_FUNCTION() void ClearHeightmapCache();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw pointer to the holes mask data.
|
||||
/// </summary>
|
||||
/// <returns>The holes mask data.</returns>
|
||||
byte* GetHolesMaskData();
|
||||
API_FUNCTION() byte* GetHolesMaskData();
|
||||
|
||||
/// <summary>
|
||||
/// Clears cache of the holes mask data.
|
||||
/// </summary>
|
||||
void ClearHolesMaskCache();
|
||||
API_FUNCTION() void ClearHolesMaskCache();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw pointer to the splat map data.
|
||||
/// </summary>
|
||||
/// <param name="index">The zero-based index of the splatmap texture.</param>
|
||||
/// <returns>The splat map data.</returns>
|
||||
Color32* GetSplatMapData(int32 index);
|
||||
API_FUNCTION() Color32* GetSplatMapData(int32 index);
|
||||
|
||||
/// <summary>
|
||||
/// Clears cache of the splat map data.
|
||||
/// </summary>
|
||||
void ClearSplatMapCache();
|
||||
API_FUNCTION() void ClearSplatMapCache();
|
||||
|
||||
/// <summary>
|
||||
/// Clears all caches.
|
||||
/// </summary>
|
||||
void ClearCache();
|
||||
API_FUNCTION() void ClearCache();
|
||||
|
||||
/// <summary>
|
||||
/// Modifies the terrain patch heightmap with the given samples.
|
||||
@@ -254,7 +271,7 @@ public:
|
||||
/// <param name="modifiedOffset">The offset from the first row and column of the heightmap data (offset destination x and z start position).</param>
|
||||
/// <param name="modifiedSize">The size of the heightmap to modify (x and z). Amount of samples in each direction.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
bool ModifyHeightMap(const float* samples, const Int2& modifiedOffset, const Int2& modifiedSize);
|
||||
API_FUNCTION() bool ModifyHeightMap(API_PARAM(Ref) const float* samples, API_PARAM(Ref) const Int2& modifiedOffset, API_PARAM(Ref) const Int2& modifiedSize);
|
||||
|
||||
/// <summary>
|
||||
/// Modifies the terrain patch holes mask with the given samples.
|
||||
@@ -263,7 +280,7 @@ public:
|
||||
/// <param name="modifiedOffset">The offset from the first row and column of the holes map data (offset destination x and z start position).</param>
|
||||
/// <param name="modifiedSize">The size of the holes map to modify (x and z). Amount of samples in each direction.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
bool ModifyHolesMask(const byte* samples, const Int2& modifiedOffset, const Int2& modifiedSize);
|
||||
API_FUNCTION() bool ModifyHolesMask(API_PARAM(Ref) const byte* samples, API_PARAM(Ref) const Int2& modifiedOffset, API_PARAM(Ref) const Int2& modifiedSize);
|
||||
|
||||
/// <summary>
|
||||
/// Modifies the terrain patch splat map (layers mask) with the given samples.
|
||||
@@ -273,7 +290,7 @@ public:
|
||||
/// <param name="modifiedOffset">The offset from the first row and column of the splat map data (offset destination x and z start position).</param>
|
||||
/// <param name="modifiedSize">The size of the splat map to modify (x and z). Amount of samples in each direction.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
bool ModifySplatMap(int32 index, const Color32* samples, const Int2& modifiedOffset, const Int2& modifiedSize);
|
||||
API_FUNCTION() bool ModifySplatMap(int32 index, API_PARAM(Ref) const Color32* samples, API_PARAM(Ref) const Int2& modifiedOffset, API_PARAM(Ref) const Int2& modifiedSize);
|
||||
|
||||
private:
|
||||
bool UpdateHeightData(struct TerrainDataUpdateInfo& info, const Int2& modifiedOffset, const Int2& modifiedSize, bool wasHeightRangeChanged, bool wasHeightChanged);
|
||||
@@ -293,7 +310,7 @@ public:
|
||||
/// <param name="resultHitDistance">The raycast result hit position distance from the ray origin. Valid only if raycast hits anything.</param>
|
||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||
bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance = MAX_float) const;
|
||||
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, float maxDistance = MAX_float) const;
|
||||
|
||||
/// <summary>
|
||||
/// Performs a raycast against this terrain collision shape.
|
||||
@@ -304,7 +321,7 @@ public:
|
||||
/// <param name="resultHitNormal">The raycast result hit position normal vector. Valid only if raycast hits anything.</param>
|
||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||
bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, Vector3& resultHitNormal, float maxDistance = MAX_float) const;
|
||||
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, API_PARAM(Out) Vector3& resultHitNormal, float maxDistance = MAX_float) const;
|
||||
|
||||
/// <summary>
|
||||
/// Performs a raycast against this terrain collision shape. Returns the hit chunk.
|
||||
@@ -315,7 +332,7 @@ public:
|
||||
/// <param name="resultChunk">The raycast result hit chunk. Valid only if raycast hits anything.</param>
|
||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||
bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, TerrainChunk*& resultChunk, float maxDistance = MAX_float) const;
|
||||
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, API_PARAM(Out) TerrainChunk*& resultChunk, float maxDistance = MAX_float) const;
|
||||
|
||||
/// <summary>
|
||||
/// Performs a raycast against terrain collision, returns results in a RaycastHit structure.
|
||||
@@ -325,14 +342,14 @@ public:
|
||||
/// <param name="hitInfo">The result hit information. Valid only when method returns true.</param>
|
||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||
bool RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance = MAX_float) const;
|
||||
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) RayCastHit& hitInfo, float maxDistance = MAX_float) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a point on the terrain collider that is closest to a given location. Can be used to find a hit location or position to apply explosion force or any other special effects.
|
||||
/// </summary>
|
||||
/// <param name="position">The position to find the closest point to it.</param>
|
||||
/// <param name="result">The result point on the collider that is closest to the specified location.</param>
|
||||
void ClosestPoint(const Vector3& position, Vector3& result) const;
|
||||
API_FUNCTION() void ClosestPoint(API_PARAM(Ref) const Vector3& position, API_PARAM(Out) Vector3& result) const;
|
||||
|
||||
#if USE_EDITOR
|
||||
/// <summary>
|
||||
@@ -354,7 +371,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="bounds">The world-space bounds to find terrain triangles that intersect with it.</param>
|
||||
/// <param name="result">The result triangles that intersect with the given bounds (in world-space).</param>
|
||||
void GetCollisionTriangles(const BoundingSphere& bounds, Array<Vector3>& result);
|
||||
void GetCollisionTriangles(API_PARAM(Ref) const BoundingSphere& bounds, API_PARAM(Out) Array<Vector3>& result);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -362,7 +379,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="vertexBuffer">The output vertex buffer.</param>
|
||||
/// <param name="indexBuffer">The output index buffer.</param>
|
||||
void ExtractCollisionGeometry(Array<Float3>& vertexBuffer, Array<int32>& indexBuffer);
|
||||
API_FUNCTION() void ExtractCollisionGeometry(API_PARAM(Out) Array<Float3>& vertexBuffer, API_PARAM(Out) Array<int32>& indexBuffer);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user