Added Comments

Added ability to hold shift and skip the terrain generation when loading
Added ability for the perlin terrain to save a raw image of the terrain to use as a cache
This commit is contained in:
iDunnoDev
2022-06-13 16:41:25 +01:00
committed by iDunnoDev
parent 51afdeecbd
commit 616f68bf8b
40 changed files with 468 additions and 51 deletions

View File

@ -4,9 +4,11 @@
TerrainNode::TerrainNode(wstring name, wstring seed, float waterHeight, int widthX, int widthZ, int cellSizeX, int cellSizeZ) : SceneNode(name)
{
// Get the seed string and hash it
_seedString = seed;
_seedHash = std::hash<wstring>{}(_seedString);
_seedHash = (unsigned int)std::hash<wstring>{}(_seedString);
// Set the random seed number
srand(_seedHash);
_widthX = widthX;
@ -83,9 +85,9 @@ void TerrainNode::GenerateTerrainData()
float bv = 1.0f / (float)(_gridRows - 1u);
int currentVertexCount = 0;
for (int z = 0; z < _gridRows; z++)
for (int z = 0; z < (int)_gridRows; z++)
{
for (int x = 0; x < _gridCols; x++)
for (int x = 0; x < (int)_gridCols; x++)
{
int currentIndex = (z * _gridCols) + x;
int offsetIndexX = 1;
@ -165,9 +167,9 @@ void TerrainNode::GenerateTerrainData()
void TerrainNode::GenerateTerrainNormals()
{
int currentNormalIndex = 0;
for (int z = 0; z < _gridRows; z++)
for (int z = 0; z < (int)_gridRows; z++)
{
for (int x = 0; x < _gridCols; x++)
for (int x = 0; x < (int)_gridCols; x++)
{
XMVECTOR v1 = XMVectorSet(_terrainVerts[currentNormalIndex + 1].Position.x - _terrainVerts[currentNormalIndex].Position.x,
_terrainVerts[currentNormalIndex + 1].Position.y - _terrainVerts[currentNormalIndex].Position.y,
@ -185,6 +187,7 @@ void TerrainNode::GenerateTerrainNormals()
XMStoreFloat3(&_terrainVerts[currentNormalIndex + 2].Normal, XMVectorAdd(XMLoadFloat3(&_terrainVerts[currentNormalIndex + 2].Normal), polygonNormal));
XMStoreFloat3(&_terrainVerts[currentNormalIndex + 3].Normal, XMVectorAdd(XMLoadFloat3(&_terrainVerts[currentNormalIndex + 3].Normal), polygonNormal));
// Process all the connected normals
AddNormalToVertex(z - 1, x - 1, 3, polygonNormal);
AddNormalToVertex(z - 1, x, 2, polygonNormal);
AddNormalToVertex(z - 1, x, 3, polygonNormal);
@ -218,6 +221,7 @@ void TerrainNode::AddNormalToVertex(int row, int col, int vertexIndex, XMVECTOR
int finalIndex = vertexIndex + ((rowIndexOffset + colIndexOffset) * 4);
// Check if the index is not around the edges
if (row >= 0 && row < (int)_gridRows && col >= 0 && col < (int)_gridCols)
{
XMStoreFloat3(&_terrainVerts[finalIndex].Normal, XMVectorAdd(XMLoadFloat3(&_terrainVerts[finalIndex].Normal), normal));
@ -498,13 +502,15 @@ void TerrainNode::LoadTerrainTextures()
));
}
// Method for populating the terrain with random clutter described in the structs
void TerrainNode::PopulateTerrain(SceneGraphPointer currentSceneGraph, vector<TerrainPopNode>& nodesForPop, int xStep, int zStep, float heightLower, float heightUpper, float slopeLower, float slopeUpper)
{
for (int z = 0; z < _gridRows; z += zStep)
// Step through the z and x with the given spacing
for (int z = 0; z < (int)_gridRows; z += zStep)
{
for (int x = 0; x < _gridCols; x += xStep)
for (int x = 0; x < (int)_gridCols; x += xStep)
{
int currentIndex = ((z * _gridCols) + x) * 4;
int currentIndex = ((z * (int)_gridCols) + x) * 4;
float totalHeights = 0.0f;
float totalSlope = 0.0f;
@ -516,12 +522,15 @@ void TerrainNode::PopulateTerrain(SceneGraphPointer currentSceneGraph, vector<Te
float heightValue = totalHeights / 4.0f;
// If the height value is within the given range
if (heightValue >= heightLower && heightValue <= heightUpper)
{
float avgSlope = totalSlope / 4.0f;
// If the slope value is within the given range
if (avgSlope >= slopeLower && avgSlope <= slopeUpper)
{
// The Height level and slope values are in range, create a mesh node with the provided details
int nodeIndex = 0;
if (nodesForPop.size() > 1)
{
@ -529,12 +538,13 @@ void TerrainNode::PopulateTerrain(SceneGraphPointer currentSceneGraph, vector<Te
}
float scale = (rand() % 100 * 0.01f) * nodesForPop[nodeIndex].scaleFactor;
float yRotation = rand() % 360;
float yRotation = (float)(rand() % 360);
float xPos = x * _cellSizeX + _terrainStartX;
float yPos = heightValue;
float zPos = (-z + 1) * _cellSizeZ + _terrainStartZ;
// Made a unique name to stop conflicts
wstring nodeName = L"_" + to_wstring(z) + L"_" + to_wstring(x);
shared_ptr<MeshNode> newNode = make_shared<MeshNode>(nodesForPop[nodeIndex].nodeBaseName + nodeName, nodesForPop[nodeIndex].modelName);
newNode->SetWorldTransform(XMMatrixRotationAxis(XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f), yRotation * XM_PI / 180.0f) * XMMatrixScaling(scale, scale, scale) * XMMatrixTranslation(xPos, yPos, zPos));
@ -547,11 +557,13 @@ void TerrainNode::PopulateTerrain(SceneGraphPointer currentSceneGraph, vector<Te
void TerrainNode::GenerateBlendMap()
{
// Set up the color gradients for each type of texture
RGBA snowTops = RGBA{ 0u, 0u, 0u, 255u };
RGBA grassLand = RGBA{ 0u, 0u, 0u, 0u };
RGBA lightDirt = RGBA{ 50u, 0u, 255u, 0u };
RGBA darkDirt = RGBA{ 255u, 50u, 50u, 0u };
// Create a vector of these gradients, multiple grass because i want it to cover more area, i need to come up with a better way if i have time
vector<RGBA> colorSteps = {darkDirt, lightDirt, grassLand, grassLand, grassLand, snowTops};
float waterOffset = _waterHeight - 50.0f;
@ -560,6 +572,7 @@ void TerrainNode::GenerateBlendMap()
waterOffset = 0.0f;
}
// Set up the gradient
ColorGradient terrainBlendGradient = ColorGradient(waterOffset, 820.0f, colorSteps);
// Note that _numberOfRows and _numberOfColumns need to be setup
@ -593,6 +606,7 @@ void TerrainNode::GenerateBlendMap()
float totalHeights = 0.0f;
float totalSlope = 0.0f;
// Calculate the average height and slope values
for (int si = 0; si < 4; si++)
{
totalHeights += _terrainVerts[currentIndex + si].Position.y;
@ -602,6 +616,7 @@ void TerrainNode::GenerateBlendMap()
float avgHeight = totalHeights / 4.0f;
float avgSlope = totalSlope / 4.0f;
// Get the RGB value from the gradient at the given height value
RGBA currentBlend = terrainBlendGradient.GetRGBAValue(avgHeight);
r = (BYTE)currentBlend.red;
g = (BYTE)currentBlend.green;
@ -612,7 +627,7 @@ void TerrainNode::GenerateBlendMap()
{
if (avgSlope < 0.6f)
{
g = (BYTE)SharedMethods::Clamp<int>(avgHeight - 450.0f, 0, 150);
g = (BYTE)SharedMethods::Clamp<int>((int)(avgHeight - 450.0f), 0, 150);
}
}
@ -667,13 +682,14 @@ void TerrainNode::BuildExtraMaps()
));
}
// Method for getting the height value at a given point, can also check if we are colliding with water or not
float TerrainNode::GetHeightAtPoint(float x, float z, bool waterCollide)
{
int cellX = (int)((x - _terrainStartX) / _cellSizeX);
int cellZ = (int)((_terrainStartZ - z) / _cellSizeZ);
int currentIndex = (cellZ * _gridCols * 4) + (cellX * 4);
float dx = x - _terrainVerts[currentIndex].Position.x;
float dz = z - _terrainVerts[currentIndex].Position.z;
@ -695,6 +711,7 @@ float TerrainNode::GetHeightAtPoint(float x, float z, bool waterCollide)
XMFLOAT4 normal;
XMStoreFloat4(&normal, XMVector3Normalize(XMVector3Cross(v1, v2)));
// Get the normal value for the vert we landed on
float result = _terrainVerts[currentIndex].Position.y + (normal.x * dx + normal.z * dz) / -normal.y;
if (waterCollide)
{
@ -707,6 +724,7 @@ float TerrainNode::GetHeightAtPoint(float x, float z, bool waterCollide)
return result;
}
// Method for checking if we are within the X Boundary
bool TerrainNode::CheckXBoundary(float x)
{
if (!(x > _terrainStartX && x < _terrainEndX))
@ -717,6 +735,7 @@ bool TerrainNode::CheckXBoundary(float x)
return true;
}
// Method for checking if we are withing the Z Boundary
bool TerrainNode::CheckZBoundary(float z)
{
if (!(z < _terrainStartZ && z > _terrainEndZ))