1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
#pragma once
#include "Configuration/UnityConfigure.h"
#if ENABLE_TERRAIN
#include "Runtime/Math/Vector3.h"
#include "Runtime/Geometry/AABB.h"
#include "Runtime/Utilities/Utility.h"
#include "Runtime/Dynamics/Collider.h"
#include "Runtime/Utilities/LinkedList.h"
#include "Runtime/Dynamics/PhysicMaterial.h"
class Mesh;
class NxHeightField;
class NxHeightFieldDesc;
struct SubMesh;
class TerrainData;
class TerrainCollider;
class TerrainRenderer;
class VBO;
enum
{
kDirectionLeft = 0, kDirectionRight = 1, kDirectionUp = 2, kDirectionDown = 3,
kDirectionLeftUp = 0, kDirectionRightUp = 1, kDirectionLeftDown = 2, kDirectionRightDown = 3,
};
enum
{
kDirectionLeftFlag = (1<<kDirectionLeft),
kDirectionRightFlag = (1<<kDirectionRight),
kDirectionUpFlag = (1<<kDirectionUp),
kDirectionDownFlag = (1<<kDirectionDown),
kDirectionDirectNeighbourMask = (kDirectionLeftFlag|kDirectionRightFlag|kDirectionUpFlag|kDirectionDownFlag),
};
//made this value constant. It is not currently being modified anyways, and this way,
//cached triangles strips can be used across several terrains.
//Must be an odd number.
#define kPatchSize 17
class Heightmap
{
public:
enum { kMaxHeight = 32766 };
DECLARE_SERIALIZE(Heightmap)
Heightmap (TerrainData* owner);
virtual ~Heightmap ();
int GetWidth () const { return m_Width; }
int GetHeight () const { return m_Height; }
int GetMipLevels () const { return m_Levels; }
const Vector3f& GetScale () const { return m_Scale; }
Vector3f GetSize () const;
void SetSize (const Vector3f& size);
virtual void AwakeFromLoad(AwakeFromLoadMode mode){}
/// After editing is complete we need to recompute the error for the modified patches
/// We also update the min&max height of each patch
void RecomputeInvalidPatches (UNITY_TEMP_VECTOR(int)& recomputedPatches);
float GetMaximumHeightError (int x, int y, int level) const;
/// The scaled interpolated height at the normalized coordinate x, y [0...1]
/// Out of bounds x and y will be clamped
float GetInterpolatedHeight (float x, float y) const;
/// Interpolates 4 height values just like GetInterpolated height
/// Used for optimized heightmap lookups when you know the corners.
// Corners are laid out like this
/// 0 1
/// 2 3
static float Bilerp (const float* corners, float u, float v);
/// The scaled height at height map pixel x, y.
/// Out of bounds x and y will be clamped
float GetHeight (int x, int y) const;
SInt16 GetRawHeight(int sampleIndex) const { return m_Heights[sampleIndex]; }
float GetHeightRespectingNeighbors (int x, int y, const TerrainRenderer *renderer) const;
float GetSteepness (float x, float y) const;
Vector3f GetInterpolatedNormal (float x, float y) const;
void GetHeights (int xBase, int yBase, int width, int height, float* heights) const;
void SetHeights (int xBase, int yBase, int width, int height, const float* heights, bool delay);
int GetAdjustedSize (int size) const;
void SetResolution (int resolution);
int GetResolution () const { return m_Width; }
int GetTotalPatchCount () const { return GetPatchIndex(0, 0, m_Levels) + 1; }
int GetMaterialIndex () const;
void GetPatchData (int xPatch, int yPatch, int mipLevel, float* heights) const;
void UpdatePatchIndices (Mesh& mesh, int xPatch, int yPatch, int level, int edgeMask);
void UpdatePatchMesh (Mesh& mesh, int xPatch, int yPatch, int mipLevel, int edgeMask, TerrainRenderer *renderer);
void UpdatePatchIndices (VBO& vbo, SubMesh& subMesh, int xPatch, int yPatch, int level, int edgeMask);
void UpdatePatchMesh (VBO& vbo, SubMesh& subMesh, int xPatch, int yPatch, int mipLevel, int edgeMask, TerrainRenderer *renderer);
AABB GetBounds (int xPatch, int yPatch, int mipLevel) const;
NxHeightField* GetNxHeightField ();
typedef List< ListNode<TerrainCollider> > TerrainColliderList;
TerrainColliderList& GetTerrainColliders () { return m_TerrainColliders; }
///@TODO: THIS IS STILL INCORRECT
Vector3f CalculateNormalSobel (int x, int y) const;
Vector3f CalculateNormalSobelRespectingNeighbors (int x, int y, const TerrainRenderer *renderer) const;
AABB GetBounds () const;
void AwakeFromLoad ();
#if ENABLE_PHYSICS
PPtr<PhysicMaterial> GetPhysicMaterial() const { return m_DefaultPhysicMaterial; }
void SetPhysicMaterial(PPtr<PhysicMaterial> mat);
#endif
private:
TerrainData* m_TerrainData;
/// Raw heightmap
std::vector<SInt16> m_Heights;
// Precomputed error of every patch
std::vector<float> m_PrecomputedError;
// Precomputed min&max value of each terrain patch
std::vector<float> m_MinMaxPatchHeights;
TerrainColliderList m_TerrainColliders;
int m_Width;
int m_Height;
int m_Levels;
Vector3f m_Scale;
int GetPatchCountX (int level) const { return 1 << (m_Levels - level); }
int GetPatchCountY (int level) const { return 1 << (m_Levels - level); }
inline float GetPatchHeight (float* data, int x, int y) const
{
return data[y + x * kPatchSize];
}
/// Calculates the index of the patch given it's level and x, y index
int GetPatchIndex (int x, int y, int level) const;
float InterpolatePatchHeight (float* data, float fx, float fy) const;
float ComputeMaximumHeightError (int xPatch, int yPatch, int level) const;
void RecalculateMinMaxHeight (int xPatch, int yPatch, int mipLevel);
// Precompute error only on a part of the heightmap
// if forceHighestLod is enabled we simply set the error to infinity
// This casues the heightmap to be rendered at full res (Used while editing)
void PrecomputeError (int minX, int minY, int width, int height, bool forceHighestLod);
#if ENABLE_PHYSICS
PPtr<PhysicMaterial> m_DefaultPhysicMaterial;
NxHeightField* m_NxHeightField;
void CleanupNx ();
void CreateNx ();
void UpdateNx ();
void BuildDesc (NxHeightFieldDesc& desc);
void RecreateShapes ();
#endif
};
template<class TransferFunc>
void Heightmap::Transfer (TransferFunc& transfer)
{
TRANSFER(m_Heights);
transfer.Align();
TRANSFER(m_PrecomputedError);
TRANSFER(m_MinMaxPatchHeights);
#if ENABLE_PHYSICS
TRANSFER(m_DefaultPhysicMaterial);
#endif
TRANSFER(m_Width);
TRANSFER(m_Height);
TRANSFER(m_Levels);
TRANSFER(m_Scale);
}
#endif // ENABLE_TERRAIN
|