Added better perlin terrain generation
Added function to scatter models onto the terrain
This commit is contained in:
+26
-26
@@ -15,7 +15,7 @@ void Graphics2::CreateSceneGraph()
|
||||
|
||||
GetCamera()->SetCameraPosition(0.0f, 550.0f, -80.0f);
|
||||
SceneGraphPointer sceneGraph = GetSceneGraph();
|
||||
|
||||
|
||||
// This is where you add nodes to the scene graph
|
||||
//shared_ptr<TexturedCubeNode> cube = make_shared<TexturedCubeNode>(L"Body", L"Textures\\woodbox.bmp");
|
||||
//cube->SetWorldTransform(XMMatrixScaling(5.0f, 8.0f, 2.5f) * XMMatrixTranslation(0, 23.0f, 0));
|
||||
@@ -28,7 +28,7 @@ void Graphics2::CreateSceneGraph()
|
||||
sceneGraph->Add(skyDome);
|
||||
|
||||
//shared_ptr<HeightMapTerrainNode> terrainNode = make_shared<HeightMapTerrainNode>(L"MainTerrain", L"Textures\\Example_HeightMap.raw", L"RandomWords");
|
||||
shared_ptr<PerlinTerrainNode> terrainNode = make_shared<PerlinTerrainNode>(L"MainTerrain", L"LovelyCat", 10.0f, 20.0f, 1.0f, 1);
|
||||
shared_ptr<PerlinTerrainNode> terrainNode = make_shared<PerlinTerrainNode>(L"MainTerrain", L"LovelyCat", 10.0f);
|
||||
terrainNode->SetAmbientLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetAmbientLight());
|
||||
terrainNode->SetDirectionalLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightDirection(), DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightColor());
|
||||
terrainNode->SetWaterColor(XMFLOAT4(SharedMethods::RGBValueToIntensity(0x84), SharedMethods::RGBValueToIntensity(0xC1), SharedMethods::RGBValueToIntensity(0xF9), 1.0f));
|
||||
@@ -36,26 +36,6 @@ void Graphics2::CreateSceneGraph()
|
||||
//terrainNode->SetWaterColor(XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f));
|
||||
sceneGraph->Add(terrainNode);
|
||||
|
||||
shared_ptr<SceneGraph> treeGroupA = make_shared<SceneGraph>(L"TreeGroupA");
|
||||
|
||||
shared_ptr<MeshNode> treeNode1 = make_shared<MeshNode>(L"Tree1", L"Models\\Tree\\Tree1.3ds");
|
||||
treeNode1->SetWorldTransform(XMMatrixScaling(0.005f, 0.01f, 0.005f) * XMMatrixRotationAxis(XMVectorSet(1.0f, 0.0f, 1.0f, 0.0f), 0.1f * XM_PI) * XMMatrixTranslation(0.0f, 320.0f, 250.0f));
|
||||
treeGroupA->Add(treeNode1);
|
||||
|
||||
shared_ptr<MeshNode> treeNode2 = make_shared<MeshNode>(L"Tree2", L"Models\\Tree\\Tree1.3ds");
|
||||
treeNode2->SetWorldTransform(XMMatrixScaling(0.002f, 0.002f, 0.002f) * XMMatrixTranslation(-150.0f, 380.0f, 150.0f));
|
||||
treeGroupA->Add(treeNode2);
|
||||
|
||||
shared_ptr<MeshNode> treeNode3 = make_shared<MeshNode>(L"Tree3", L"Models\\Tree\\Tree1.3ds");
|
||||
treeNode3->SetWorldTransform(XMMatrixScaling(0.005f, 0.005f, 0.005f) * XMMatrixRotationAxis(XMVectorSet(1.0f, 0.0f, 1.0f, 0.0f), -0.1f * XM_PI) * XMMatrixTranslation(100.0f, 290.0f, 350.0f));
|
||||
treeGroupA->Add(treeNode3);
|
||||
|
||||
shared_ptr<MeshNode> treeNode4 = make_shared<MeshNode>(L"Tree4", L"Models\\Tree\\Tree1.3ds");
|
||||
treeNode4->SetWorldTransform(XMMatrixScaling(0.005f, 0.01f, 0.005f) * XMMatrixRotationAxis(XMVectorSet(1.0f, 0.0f, 1.0f, 0.0f), 0.1f * XM_PI) * XMMatrixTranslation(0.0f, 320.0f, 250.0f));
|
||||
treeGroupA->Add(treeNode4);
|
||||
|
||||
sceneGraph->Add(treeGroupA);
|
||||
|
||||
shared_ptr<ControlledSplitMeshNode> plane1Node = make_shared<ControlledSplitMeshNode>(L"Plane1", L"Models\\Plane\\Bonanza.3DS");
|
||||
plane1Node->SetStartOrientation(XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), XM_PI) * XMMatrixRotationAxis(XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f), 0.5f * XM_PI));
|
||||
plane1Node->SetNodePosition(0.0f, 550.0f, -50.0f);
|
||||
@@ -74,9 +54,30 @@ void Graphics2::CreateSceneGraph()
|
||||
|
||||
void Graphics2::UpdateSceneGraph()
|
||||
{
|
||||
GetCurrentControlInputs();
|
||||
|
||||
SceneGraphPointer sceneGraph = GetSceneGraph();
|
||||
shared_ptr<TerrainNode> mainTerrain = dynamic_pointer_cast<TerrainNode>(sceneGraph->Find(L"MainTerrain"));
|
||||
|
||||
if (!_initDone && mainTerrain != nullptr)
|
||||
{
|
||||
vector<TerrainPopNode> rngSpawnList;
|
||||
|
||||
TerrainPopNode treeModelA = TerrainPopNode();
|
||||
treeModelA.modelName = L"Models\\Tree\\Tree2.fbx";
|
||||
treeModelA.nodeBaseName = L"treeA";
|
||||
treeModelA.scaleFactor = 1.0f;
|
||||
|
||||
rngSpawnList.push_back(treeModelA);
|
||||
|
||||
shared_ptr<SceneGraph> treeGroupA = make_shared<SceneGraph>(L"TreeGroupA");
|
||||
|
||||
mainTerrain->PopulateTerrain(treeGroupA, rngSpawnList, 10, 10, 400.0f, 550.0f, 0.9f, 1.0f);
|
||||
treeGroupA->Initialise();
|
||||
sceneGraph->Add(treeGroupA);
|
||||
|
||||
_initDone = true;
|
||||
}
|
||||
|
||||
GetCurrentControlInputs();
|
||||
XMVECTOR startCameraPos = GetCamera()->GetCameraPosition();
|
||||
|
||||
if (_currentPlayerObject != nullptr)
|
||||
@@ -189,8 +190,7 @@ void Graphics2::UpdateSceneGraph()
|
||||
}
|
||||
|
||||
// Check the camera and our terrain boundaries
|
||||
XMVECTOR currentCameraPos = GetCamera()->GetCameraPosition();
|
||||
shared_ptr<TerrainNode> mainTerrain = dynamic_pointer_cast<TerrainNode>(sceneGraph->Find(L"MainTerrain"));
|
||||
XMVECTOR currentCameraPos = GetCamera()->GetCameraPosition();
|
||||
GetCamera()->Update();
|
||||
if (mainTerrain != nullptr)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,8 @@ public:
|
||||
void UpdateSceneGraph();
|
||||
|
||||
private:
|
||||
bool _initDone = false;
|
||||
|
||||
bool _boosting = false;
|
||||
float _boostMultiplier = 1;
|
||||
float _boostMin = 1;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
newmtl mat_0-default-grey.jpg
|
||||
Ka 0.000000 0.000000 0.000000
|
||||
Kd 0.698039 0.698039 0.698039
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
Ns 9.84916
|
||||
map_Kd default-grey.jpg
|
||||
|
||||
newmtl mat_1-boat_fishing02.jpg
|
||||
Ka 0.000000 0.000000 0.000000
|
||||
Kd 0.698039 0.698039 0.698039
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
Ns 9.84916
|
||||
map_Kd boat_fishing02.jpg
|
||||
|
||||
newmtl mat_2-default-grey.jpg
|
||||
Ka 0.000000 0.000000 0.000000
|
||||
Kd 0.698039 0.698039 0.698039
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
Ns 9.84916
|
||||
map_Kd default-grey.jpg
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 134 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 111 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,11 +1,8 @@
|
||||
#include "PerlinTerrainNode.h"
|
||||
|
||||
PerlinTerrainNode::PerlinTerrainNode(wstring name, wstring seed, float offsetX, float offsetY, float chunkSize, int layers, int widthX, int widthZ, float waterHeight, int cellSizeX, int cellSizeZ) : TerrainNode(name, seed, waterHeight, widthX, widthZ, cellSizeX, cellSizeZ)
|
||||
PerlinTerrainNode::PerlinTerrainNode(wstring name, wstring seed, float chunkSize, int widthX, int widthZ, float waterHeight, int cellSizeX, int cellSizeZ) : TerrainNode(name, seed, waterHeight, widthX, widthZ, cellSizeX, cellSizeZ)
|
||||
{
|
||||
_offsetX = offsetX;
|
||||
_offsetY = offsetY;
|
||||
_chunkSize = chunkSize;
|
||||
_layers = layers;
|
||||
|
||||
GeneratePerlinValues();
|
||||
if (!GeneratePerlinHeights())
|
||||
@@ -14,44 +11,64 @@ PerlinTerrainNode::PerlinTerrainNode(wstring name, wstring seed, float offsetX,
|
||||
}
|
||||
}
|
||||
|
||||
void PerlinTerrainNode::GeneratePerlinValues()
|
||||
{
|
||||
std::seed_seq seedGenerator(_seedString.begin(), _seedString.end());
|
||||
std::mt19937 generator;
|
||||
generator.seed(seedGenerator);
|
||||
std::uniform_int_distribution<> dist(0, 511);
|
||||
char bufferChar;
|
||||
int newPosition;
|
||||
|
||||
_p.clear();
|
||||
copy(_staticP.begin(), _staticP.end(), back_inserter(_p));
|
||||
|
||||
for (int i = 0; i < 512; i++)
|
||||
{
|
||||
newPosition = dist(generator);
|
||||
bufferChar = _p[i];
|
||||
_p[i] = _p[newPosition];
|
||||
_p[newPosition] = bufferChar;
|
||||
}
|
||||
}
|
||||
|
||||
// Method for filling the height values array for the terrain generation
|
||||
bool PerlinTerrainNode::GeneratePerlinHeights()
|
||||
{
|
||||
for (int z = 0; z < _gridRows; z++)
|
||||
{
|
||||
float mapZ = ((float)z / (float)_gridRows) + 0.5f;
|
||||
float mapZ = ((float)z / (float)_gridRows);
|
||||
|
||||
for (int x = 0; x < _gridCols; x++)
|
||||
{
|
||||
float mapX = ((float)x / (float)_gridCols) + 0.5f;
|
||||
float mapX = ((float)x / (float)_gridCols);
|
||||
|
||||
float currentHeightValue = GetPerlinValueAt(_offsetX + mapX, _offsetY + mapZ, 8, 0.85f) - 0.25f;
|
||||
//float currentHeightValue = GetPerlinValueAt(mapX, mapZ, 8, 0.85f) - 0.25f;
|
||||
float currentHeightValue = 0.0f;
|
||||
|
||||
int octaves = 12;
|
||||
float currentOctaveValue = 1.0f;
|
||||
float stepOff = 1.0f;
|
||||
float stepTotal = 0.0f;
|
||||
// n covers the persistance, frequency and
|
||||
for (int n = 1; n <= octaves; n++)
|
||||
{
|
||||
currentHeightValue += stepOff * GetNoiseValueAt(((float)x * currentOctaveValue) / ((float)_gridCols / _chunkSize), ((float)z * currentOctaveValue) / ((float)_gridRows / _chunkSize));
|
||||
currentOctaveValue *= 2;
|
||||
stepTotal += stepOff;
|
||||
stepOff *= 0.5f;
|
||||
|
||||
}
|
||||
|
||||
//currentHeightValue = currentHeightValue / stepTotal; // *(currentHeightValue * 2.0f);
|
||||
//currentHeightValue = currentHeightValue - floor(currentHeightValue);
|
||||
_heightValues.push_back(currentHeightValue);
|
||||
_heightValues.push_back((currentHeightValue + 1.0f) * 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method for generating the permutation array needed for perlin noise
|
||||
void PerlinTerrainNode::GeneratePerlinValues()
|
||||
{
|
||||
// Set the permutation array length
|
||||
p.resize(256);
|
||||
|
||||
// Fill the permutation array with 0 to 255
|
||||
iota(p.begin(), p.end(), 0);
|
||||
|
||||
default_random_engine engine(_seedHash);
|
||||
|
||||
// Shuffle the array values using the seed value given
|
||||
shuffle(p.begin(), p.end(), engine);
|
||||
|
||||
// Duplicate the permutation results so our array is 512
|
||||
p.insert(p.end(), p.begin(), p.end());
|
||||
}
|
||||
|
||||
float PerlinTerrainNode::Fade(float t)
|
||||
{
|
||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||
@@ -59,77 +76,56 @@ float PerlinTerrainNode::Fade(float t)
|
||||
|
||||
float PerlinTerrainNode::Grad(int hash, float x, float y)
|
||||
{
|
||||
// Fast Grad switch check converted from a java implimentation of perlin noise
|
||||
switch (hash & 0xF)
|
||||
int h = hash & 7;
|
||||
float u = y;
|
||||
float v = x;
|
||||
if (h < 4)
|
||||
{
|
||||
case 0x0: return x;
|
||||
case 0x1: return x + y;
|
||||
case 0x2: return y;
|
||||
case 0x3: return -x + y;
|
||||
case 0x4: return -x;
|
||||
case 0x5: return -x - y;
|
||||
case 0x6: return -y;
|
||||
case 0x7: return x - y;
|
||||
case 0x8: return x;
|
||||
case 0x9: return x + y;
|
||||
case 0xA: return y;
|
||||
case 0xB: return -x + y;
|
||||
case 0xC: return -x;
|
||||
case 0xD: return -x - y;
|
||||
case 0xE: return -y;
|
||||
case 0xF: return x - y;
|
||||
|
||||
default: return 0; // Never occurs
|
||||
u = x;
|
||||
v = y;
|
||||
}
|
||||
}
|
||||
|
||||
// Method to calculate the perlin value at x/y with the given octaves and persistance values, also normalised
|
||||
float PerlinTerrainNode::GetPerlinValueAt(float x, float y, int octaves, float persistance)
|
||||
{
|
||||
float total = 0.0f;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float maxValue = 0.0f;
|
||||
|
||||
for (int i = 0; i < octaves; i++)
|
||||
|
||||
float outA = u;
|
||||
if ((h & 1))
|
||||
{
|
||||
total += (GetNoiseValueAt(x * frequency, y * frequency) * amplitude);
|
||||
maxValue += amplitude;
|
||||
|
||||
amplitude *= persistance;
|
||||
frequency *= 2;
|
||||
outA = -u;
|
||||
}
|
||||
|
||||
return total / maxValue;
|
||||
float outB = 2.0f * v;
|
||||
if ((h & 2))
|
||||
{
|
||||
outB = -2.0f * v;
|
||||
}
|
||||
|
||||
return outA + outB;
|
||||
}
|
||||
|
||||
// Method to get the perlin noise value at x/y
|
||||
float PerlinTerrainNode::GetNoiseValueAt(float x, float y)
|
||||
{
|
||||
int x0 = (int)x & 255;
|
||||
int y0 = (int)y & 255;
|
||||
int ix0 = (int)floor(x);
|
||||
int iy0 = (int)floor(y);
|
||||
|
||||
int x1 = x0 + 1;
|
||||
int y1 = y0 + 1;
|
||||
float fx0 = x - (float)ix0;
|
||||
float fy0 = y - (float)iy0;
|
||||
float fx1 = fx0 - 1.0f;
|
||||
float fy1 = fy0 - 1.0f;
|
||||
|
||||
int ix1 = (ix0 + 1) & 0xff;
|
||||
int iy1 = (iy0 + 1) & 0xff;
|
||||
ix0 = ix0 & 0xff;
|
||||
iy0 = iy0 & 0xff;
|
||||
|
||||
float dx = x - (float)x0;
|
||||
float dy = y - (float)y0;
|
||||
float t = Fade(fy0);
|
||||
float s = Fade(fx0);
|
||||
|
||||
float u = Fade(dx);
|
||||
float v = Fade(dy);
|
||||
float nx0 = Grad(_p[ix0 + _p[iy0]], fx0, fy0);
|
||||
float nx1 = Grad(_p[ix0 + _p[iy1]], fx0, fy1);
|
||||
float n0 = SharedMethods::Lerp<float>(nx0, nx1, t);
|
||||
|
||||
int aa = p[p[x0] + y0];
|
||||
int ab = p[p[x0] + y1];
|
||||
int ba = p[p[x1] + y0];
|
||||
int bb = p[p[x1] + y1];
|
||||
nx0 = Grad(_p[ix1 + _p[iy0]], fx1, fy0);
|
||||
nx1 = Grad(_p[ix1 + _p[iy1]], fx1, fy1);
|
||||
float n1 = SharedMethods::Lerp<float>(nx0, nx1, t);
|
||||
|
||||
float na0 = Grad(aa, dx, dy);
|
||||
float na1 = Grad(ba, dx - 1.0f, dy);
|
||||
float nal = SharedMethods::Lerp(na0, na1, u);
|
||||
|
||||
float nb0 = Grad(ab, dx, dy - 1.0f);
|
||||
float nb1 = Grad(bb, dx - 1.0f, dy - 1.0f);
|
||||
float nbl = SharedMethods::Lerp(nb0, nb1, u);
|
||||
|
||||
return (SharedMethods::Lerp(nal, nbl, v) + 1.0f) / 2.0f;
|
||||
return 0.507f * SharedMethods::Lerp(n0, n1, s);
|
||||
}
|
||||
@@ -9,21 +9,48 @@
|
||||
class PerlinTerrainNode : public TerrainNode
|
||||
{
|
||||
public:
|
||||
PerlinTerrainNode(wstring name, wstring seed, float offsetX, float offsetY, float chunkSize, int layers, int widthX = 1023, int widthZ = 1023, float waterHeight = 150.0f, int cellSizeX = 10, int cellSizeZ = 10);
|
||||
PerlinTerrainNode(wstring name, wstring seed, float chunkSize, int widthX = 1023, int widthZ = 1023, float waterHeight = 300.0f, int cellSizeX = 10, int cellSizeZ = 10);
|
||||
|
||||
private:
|
||||
vector<int> p;
|
||||
float _offsetX;
|
||||
float _offsetY;
|
||||
// the static perlin permutation array, we could calculate a random one but apparently you can run into sequencing issues and this just seems like the best solution
|
||||
vector<unsigned char> _staticP = { 151,160,137,91,90,15,
|
||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
|
||||
151,160,137,91,90,15,
|
||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
|
||||
};
|
||||
|
||||
vector<unsigned char> _p;
|
||||
|
||||
float _chunkSize;
|
||||
int _layers;
|
||||
|
||||
float Fade(float t);
|
||||
float Grad(int hash, float x, float y);
|
||||
|
||||
void GeneratePerlinValues();
|
||||
bool GeneratePerlinHeights();
|
||||
float GetPerlinValueAt(float x, float y, int octaves, float persistance);
|
||||
float GetNoiseValueAt(float x, float y);
|
||||
void GeneratePerlinValues();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "DirectXCore.h"
|
||||
#include <string>
|
||||
|
||||
struct CBUFFER
|
||||
{
|
||||
@@ -16,6 +17,13 @@ struct CBUFFER
|
||||
float padding[2];
|
||||
};
|
||||
|
||||
struct TerrainPopNode
|
||||
{
|
||||
std::wstring nodeBaseName;
|
||||
std::wstring modelName;
|
||||
float scaleFactor;
|
||||
};
|
||||
|
||||
namespace SharedMethods
|
||||
{
|
||||
XMMATRIX RotateFromPoint(const float x, const float y, const float z, const XMMATRIX rotationMatrix);
|
||||
|
||||
@@ -498,6 +498,52 @@ void TerrainNode::LoadTerrainTextures()
|
||||
));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
for (int x = 0; x < _gridCols; x += xStep)
|
||||
{
|
||||
int currentIndex = ((z * _gridCols) + x) * 4;
|
||||
|
||||
float totalHeights = 0.0f;
|
||||
float totalSlope = 0.0f;
|
||||
for (int si = 0; si < 4; si++)
|
||||
{
|
||||
totalHeights += _terrainVerts[currentIndex + si].Position.y;
|
||||
totalSlope += _terrainVerts[currentIndex + si].Normal.y;
|
||||
}
|
||||
|
||||
float heightValue = totalHeights / 4.0f;
|
||||
|
||||
if (heightValue >= heightLower && heightValue <= heightUpper)
|
||||
{
|
||||
float avgSlope = totalSlope / 4.0f;
|
||||
|
||||
if (avgSlope >= slopeLower && avgSlope <= slopeUpper)
|
||||
{
|
||||
int nodeIndex = 0;
|
||||
if (nodesForPop.size() > 1)
|
||||
{
|
||||
nodeIndex = rand() % nodesForPop.size();
|
||||
}
|
||||
|
||||
float scale = (rand() % 100 * 0.01f) * nodesForPop[nodeIndex].scaleFactor;
|
||||
|
||||
float xPos = x * _cellSizeX + _terrainStartX;
|
||||
float yPos = heightValue - 1.0f;
|
||||
float zPos = (-z + 1) * _cellSizeZ + _terrainStartZ;
|
||||
|
||||
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(XMMatrixScaling(scale, scale, scale) * XMMatrixTranslation(xPos, yPos, zPos));
|
||||
currentSceneGraph->Add(newNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainNode::GenerateBlendMap()
|
||||
{
|
||||
RGBA snowTops = RGBA{ 0u, 0u, 0u, 255u };
|
||||
@@ -507,7 +553,13 @@ void TerrainNode::GenerateBlendMap()
|
||||
|
||||
vector<RGBA> colorSteps = {darkDirt, lightDirt, grassLand, grassLand, grassLand, snowTops};
|
||||
|
||||
ColorGradient terrainBlendGradient = ColorGradient(80.0f, 620.0f, colorSteps);
|
||||
float waterOffset = _waterHeight - 50.0f;
|
||||
if (waterOffset < 0.0f)
|
||||
{
|
||||
waterOffset = 0.0f;
|
||||
}
|
||||
|
||||
ColorGradient terrainBlendGradient = ColorGradient(waterOffset, 820.0f, colorSteps);
|
||||
|
||||
// Note that _numberOfRows and _numberOfColumns need to be setup
|
||||
// to the number of rows and columns in your grid in order for this
|
||||
@@ -538,24 +590,30 @@ void TerrainNode::GenerateBlendMap()
|
||||
int currentIndex = ((i * _gridCols) + j) * 4;
|
||||
|
||||
float totalHeights = 0.0f;
|
||||
float biggestSlope = 0.0f;
|
||||
float totalSlope = 0.0f;
|
||||
|
||||
for (int si = 0; si < 4; si++)
|
||||
{
|
||||
totalHeights += _terrainVerts[currentIndex + si].Position.y;
|
||||
if (_terrainVerts[currentIndex + si].Normal.y > biggestSlope)
|
||||
{
|
||||
biggestSlope = _terrainVerts[currentIndex + si].Normal.y;
|
||||
}
|
||||
totalHeights += _terrainVerts[currentIndex + si].Position.y;
|
||||
totalSlope += _terrainVerts[currentIndex + si].Normal.y;
|
||||
}
|
||||
|
||||
|
||||
float avgHeight = totalHeights / 4.0f;
|
||||
float avgSlope = totalSlope / 4.0f;
|
||||
|
||||
RGBA currentBlend = terrainBlendGradient.GetRGBAValue(avgHeight);
|
||||
r = (BYTE)currentBlend.red;
|
||||
g = (BYTE)currentBlend.green;
|
||||
b = (BYTE)currentBlend.blue;
|
||||
a = (BYTE)currentBlend.alpha;
|
||||
a = (BYTE)currentBlend.alpha;
|
||||
// Override the G channel if we are cliff height and slope angle
|
||||
if (avgHeight > 500.0f)
|
||||
{
|
||||
if (avgSlope < 0.6f)
|
||||
{
|
||||
g = (BYTE)SharedMethods::Clamp<int>(avgHeight - 450.0f, 0, 150);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD mapValue = (a << 24) + (b << 16) + (g << 8) + r;
|
||||
*blendMapPtr++ = mapValue;
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include "WICTextureLoader.h"
|
||||
#include "SharedMethods.h"
|
||||
#include "SceneNode.h"
|
||||
|
||||
#include "SceneGraph.h"
|
||||
#include "MeshNode.h"
|
||||
#include "SplitMeshNode.h"
|
||||
|
||||
typedef struct TerrainVertex
|
||||
{
|
||||
@@ -49,6 +51,8 @@ public:
|
||||
void Render(void);
|
||||
void virtual Shutdown(void);
|
||||
|
||||
void PopulateTerrain(SceneGraphPointer currentSceneGraph, vector<TerrainPopNode>& nodesForPop, int xStep, int zStep, float heightLower, float heightUpper, float slopeLower, float slopeUpper);
|
||||
|
||||
float GetHeightAtPoint(float x, float z, bool waterCollide = false);
|
||||
bool CheckXBoundary(float x);
|
||||
bool CheckZBoundary(float z);
|
||||
|
||||
Reference in New Issue
Block a user