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

@ -184,8 +184,10 @@ void Camera::Update(void)
cameraTarget = cameraPosition + XMVector3Normalize(cameraForward); cameraTarget = cameraPosition + XMVector3Normalize(cameraForward);
} }
else else
{ {
// Trying some rotation so that the camera actually follows the model instead of staying in place
XMVECTOR offset = XMVectorSet(_followOffset.x, _followOffset.y, _followOffset.z, 1.0f); XMVECTOR offset = XMVectorSet(_followOffset.x, _followOffset.y, _followOffset.z, 1.0f);
// The pitch and roll rotations really mess it up and i dont have time to look into it, the simple turn follow is good enough for now
XMMATRIX offsetRotationMatrix = XMMatrixRotationAxis(defaultUp, _cameraYaw); // *XMMatrixRotationAxis(defaultForward, _cameraPitch); XMMATRIX offsetRotationMatrix = XMMatrixRotationAxis(defaultUp, _cameraYaw); // *XMMatrixRotationAxis(defaultForward, _cameraPitch);
cameraPosition = _nodeFollowed->GetNodePosition() + XMVector3TransformCoord(offset, offsetRotationMatrix); cameraPosition = _nodeFollowed->GetNodePosition() + XMVector3TransformCoord(offset, offsetRotationMatrix);

View File

@ -27,6 +27,8 @@ public:
float GetRoll() const; float GetRoll() const;
void SetLeftRight(float leftRight); void SetLeftRight(float leftRight);
void SetForwardBack(float forwardBack); void SetForwardBack(float forwardBack);
// Method for setting which object node is being followed
void SetFollowNode(shared_ptr<ObjectNode> nodeFollowed, XMFLOAT3 followOffset, bool positionOnly); void SetFollowNode(shared_ptr<ObjectNode> nodeFollowed, XMFLOAT3 followOffset, bool positionOnly);
private: private:
@ -38,6 +40,7 @@ private:
float _moveForwardBack; float _moveForwardBack;
float _cameraYaw; float _cameraYaw;
// Camera yaw previous to help with the rotation, remove later
float _cameraYawPrev; float _cameraYawPrev;
float _cameraPitch; float _cameraPitch;
float _cameraRoll; float _cameraRoll;

View File

@ -6,6 +6,7 @@ ControlledMeshNode::ControlledMeshNode(wstring name, wstring modelName) : MeshNo
void ControlledMeshNode::Update(FXMMATRIX& currentWorldTransformation) void ControlledMeshNode::Update(FXMMATRIX& currentWorldTransformation)
{ {
// Run the update for both parent node classes
MeshNode::Update(currentWorldTransformation); MeshNode::Update(currentWorldTransformation);
ObjectNode::Update(_worldTransformation); ObjectNode::Update(_worldTransformation);
} }

View File

@ -2,6 +2,7 @@
#include "ObjectNode.h" #include "ObjectNode.h"
#include "MeshNode.h" #include "MeshNode.h"
// Class for handing the moveable mesh nodes, inherits from both the mesh and object nodes, the object node contains what is needed for pitch, yaw and forward back movement
class ControlledMeshNode : public MeshNode, public ObjectNode class ControlledMeshNode : public MeshNode, public ObjectNode
{ {
public: public:

View File

@ -6,6 +6,7 @@ ControlledSplitMeshNode::ControlledSplitMeshNode(wstring name, wstring modelName
void ControlledSplitMeshNode::Update(FXMMATRIX& currentWorldTransformation) void ControlledSplitMeshNode::Update(FXMMATRIX& currentWorldTransformation)
{ {
// Run the update for both parent node classes
ObjectNode::Update(_worldTransformation); ObjectNode::Update(_worldTransformation);
SceneGraph::Update(currentWorldTransformation); SceneGraph::Update(currentWorldTransformation);
} }

View File

@ -4,6 +4,7 @@
#include "ObjectNode.h" #include "ObjectNode.h"
#include "SubMeshNode.h" #include "SubMeshNode.h"
// Class for handing the moveable split mesh nodes, inherits from both the mesh and object nodes, the object node contains what is needed for pitch, yaw and forward back movement
class ControlledSplitMeshNode : public SplitMeshNode, public ObjectNode class ControlledSplitMeshNode : public SplitMeshNode, public ObjectNode
{ {
public: public:

View File

@ -11,6 +11,7 @@ GamePadController::~GamePadController(void)
{ {
} }
// Method for processing the current inputs, i added params for the current inputs vector and a bool to set the boosting varaible
void GamePadController::ProcessGameController(set<ControlInputs>& currentInputs, bool &boostHit) void GamePadController::ProcessGameController(set<ControlInputs>& currentInputs, bool &boostHit)
{ {
DWORD magnitudeSquared; DWORD magnitudeSquared;

View File

@ -5,6 +5,7 @@
#include <XInput.h> #include <XInput.h>
#pragma comment(lib, "XInput.lib") #pragma comment(lib, "XInput.lib")
// Emum class for helping with the select of which controller inputs to use
enum class ControlInputs { Forward, Back, TurnLeft, TurnRight, StrafeLeft, StrafeRight, Up, Down, Fire1, Fire2 }; enum class ControlInputs { Forward, Back, TurnLeft, TurnRight, StrafeLeft, StrafeRight, Up, Down, Fire1, Fire2 };
class GamePadController class GamePadController

View File

@ -2,6 +2,7 @@
GlobalLighting::GlobalLighting() GlobalLighting::GlobalLighting()
{ {
// Set the default lighting to 0
_ambientLight = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f); _ambientLight = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
_directionalLightVector = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); _directionalLightVector = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
_directionalLightColor = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f); _directionalLightColor = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "DirectXCore.h" #include "DirectXCore.h"
// Class for holding the global lighting settings, this saves having to go through every node to change these values
class GlobalLighting class GlobalLighting
{ {
public: public:

View File

@ -4,6 +4,7 @@ Graphics2 app;
void Graphics2::CreateSceneGraph() void Graphics2::CreateSceneGraph()
{ {
// Reset our variables for movement
_boostMultiplier = _boostMin; _boostMultiplier = _boostMin;
_flySpeed = 1; _flySpeed = 1;
_turnSpeed = 1; _turnSpeed = 1;
@ -13,7 +14,16 @@ void Graphics2::CreateSceneGraph()
_currentPlayerObject = nullptr; _currentPlayerObject = nullptr;
// Check if the shift and ctrl keys are held to disable the clutter
if (GetAsyncKeyState(VK_SHIFT) && GetAsyncKeyState(VK_CONTROL))
{
_noClutter = true;
}
// Set the default camera position
GetCamera()->SetCameraPosition(0.0f, 550.0f, -80.0f); GetCamera()->SetCameraPosition(0.0f, 550.0f, -80.0f);
// Get the main scene graph
SceneGraphPointer sceneGraph = GetSceneGraph(); SceneGraphPointer sceneGraph = GetSceneGraph();
// This is where you add nodes to the scene graph // This is where you add nodes to the scene graph
@ -21,29 +31,40 @@ void Graphics2::CreateSceneGraph()
//cube->SetWorldTransform(XMMatrixScaling(5.0f, 8.0f, 2.5f) * XMMatrixTranslation(0, 23.0f, 0)); XMMatrixScaling(50.0f, 800.0f, 50.0f) * XMMatrixTranslation(-65.0f, 350.0f, -65.0f) //cube->SetWorldTransform(XMMatrixScaling(5.0f, 8.0f, 2.5f) * XMMatrixTranslation(0, 23.0f, 0)); XMMatrixScaling(50.0f, 800.0f, 50.0f) * XMMatrixTranslation(-65.0f, 350.0f, -65.0f)
//sceneGraph->Add(cube); //sceneGraph->Add(cube);
// Set some global lighting variables for the ambient and directional lights, if i get time look into other lighting?
DirectXFramework::GetDXFramework()->GetGlobalLighting()->SetAmbientLight(XMFLOAT4(0.7f, 0.7f, 0.7f, 1.0f)); DirectXFramework::GetDXFramework()->GetGlobalLighting()->SetAmbientLight(XMFLOAT4(0.7f, 0.7f, 0.7f, 1.0f));
DirectXFramework::GetDXFramework()->GetGlobalLighting()->SetDirectionalLight(XMVectorSet(0.5f, -1.0f, -1.0f, 0.0f), XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f)); DirectXFramework::GetDXFramework()->GetGlobalLighting()->SetDirectionalLight(XMVectorSet(0.5f, -1.0f, -1.0f, 0.0f), XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f));
shared_ptr<SkyNode> skyDome = make_shared<SkyNode>(L"SkyDome", L"Textures\\SkyWater.dds", 180.0f); // Add the skybox node
shared_ptr<SkyNode> skyDome = make_shared<SkyNode>(L"SkyDome", L"Textures\\SkyWater.dds", 360.0f);
sceneGraph->Add(skyDome); sceneGraph->Add(skyDome);
// Set the terrain node, we can use the heightmap or perlin noise nodes
//shared_ptr<HeightMapTerrainNode> terrainNode = make_shared<HeightMapTerrainNode>(L"MainTerrain", L"Textures\\Example_HeightMap.raw", L"RandomWords"); //shared_ptr<HeightMapTerrainNode> terrainNode = make_shared<HeightMapTerrainNode>(L"MainTerrain", L"Textures\\Example_HeightMap.raw", L"RandomWords");
//My height maps do not load with the given function, i have no idea what format its in then...
//shared_ptr<HeightMapTerrainNode> terrainNode = make_shared<HeightMapTerrainNode>(L"MainTerrain", L"TerrainCache\\cache_LovelyCat_10_000000.raw", L"RandomWords");
shared_ptr<PerlinTerrainNode> terrainNode = make_shared<PerlinTerrainNode>(L"MainTerrain", L"LovelyCat", 10.0f); shared_ptr<PerlinTerrainNode> terrainNode = make_shared<PerlinTerrainNode>(L"MainTerrain", L"LovelyCat", 10.0f);
terrainNode->SetAmbientLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetAmbientLight()); terrainNode->SetAmbientLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetAmbientLight());
terrainNode->SetDirectionalLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightDirection(), DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightColor()); terrainNode->SetDirectionalLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightDirection(), DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightColor());
// Set the water color for tinting here
terrainNode->SetWaterColor(XMFLOAT4(SharedMethods::RGBValueToIntensity(0x84), SharedMethods::RGBValueToIntensity(0xC1), SharedMethods::RGBValueToIntensity(0xF9), 1.0f)); terrainNode->SetWaterColor(XMFLOAT4(SharedMethods::RGBValueToIntensity(0x84), SharedMethods::RGBValueToIntensity(0xC1), SharedMethods::RGBValueToIntensity(0xF9), 1.0f));
//terrainNode->SetWaterColor(XMFLOAT4(1.0f, 0.0f, 0.8f, 1.0f)); // Rivers of blood mode
//terrainNode->SetWaterColor(XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f)); //terrainNode->SetWaterColor(XMFLOAT4(SharedMethods::RGBValueToIntensity(0x66), 0.0f, 0.0f, 1.0f));
sceneGraph->Add(terrainNode); sceneGraph->Add(terrainNode);
// Add the controlled plane model
shared_ptr<ControlledSplitMeshNode> plane1Node = make_shared<ControlledSplitMeshNode>(L"Plane1", L"Models\\Plane\\Bonanza.3DS"); 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->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); plane1Node->SetNodePosition(0.0f, 550.0f, -50.0f);
sceneGraph->Add(plane1Node); sceneGraph->Add(plane1Node);
// Add the boat scene graph so i can scale and position the model
shared_ptr<SceneGraph> boatGraph = make_shared<SceneGraph>(L"boatGraph"); shared_ptr<SceneGraph> boatGraph = make_shared<SceneGraph>(L"boatGraph");
boatGraph->SetWorldTransform(XMMatrixScaling(0.1f, 0.1f, 0.1f) * XMMatrixTranslation(-1880.0f, 290.0f, 610.0f)); boatGraph->SetWorldTransform(XMMatrixScaling(0.1f, 0.1f, 0.1f) * XMMatrixTranslation(-1880.0f, 290.0f, 610.0f));
// Added the moveable boat model
shared_ptr<ControlledMeshNode> boat1Node = make_shared<ControlledMeshNode>(L"Boat1", L"Models\\Boat\\Boat.FBX"); shared_ptr<ControlledMeshNode> boat1Node = make_shared<ControlledMeshNode>(L"Boat1", L"Models\\Boat\\Boat.FBX");
boat1Node->SetStartOrientation(XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), (90.0f * XM_PI) / 180.0f) * XMMatrixRotationAxis(XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f), (90.0f * XM_PI) / 180.0f)); boat1Node->SetStartOrientation(XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), (90.0f * XM_PI) / 180.0f) * XMMatrixRotationAxis(XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f), (90.0f * XM_PI) / 180.0f));
boat1Node->SetNodePosition(0.0f, 0.0f, 0.0f); boat1Node->SetNodePosition(0.0f, 0.0f, 0.0f);
@ -51,9 +72,11 @@ void Graphics2::CreateSceneGraph()
sceneGraph->Add(boatGraph); sceneGraph->Add(boatGraph);
// Set the current player object to the plane and turn on follow mode
_currentPlayerObject = plane1Node; _currentPlayerObject = plane1Node;
GetCamera()->SetFollowNode(plane1Node, XMFLOAT3(0.0f, 40.0f, -100.0f), false); GetCamera()->SetFollowNode(plane1Node, XMFLOAT3(0.0f, 40.0f, -100.0f), false);
// Set the background color although i assume this will be deprecated when the skybox is added
SetBackgroundColour(XMFLOAT4(0.29f, 0.38f, 0.72f, 1.0f)); SetBackgroundColour(XMFLOAT4(0.29f, 0.38f, 0.72f, 1.0f));
//SetBackgroundColour(XMFLOAT4(SharedMethods::RGBValueToIntensity(0x89), 0, 1, 1)); //SetBackgroundColour(XMFLOAT4(SharedMethods::RGBValueToIntensity(0x89), 0, 1, 1));
@ -62,18 +85,23 @@ void Graphics2::CreateSceneGraph()
_currentPropRotation = 0; _currentPropRotation = 0;
} }
// Method for generating the random clutter on the terrain
void Graphics2::GenerateClutter() void Graphics2::GenerateClutter()
{ {
SceneGraphPointer sceneGraph = GetSceneGraph(); SceneGraphPointer sceneGraph = GetSceneGraph();
// Get the current terrain node so that we can access its methods
shared_ptr<TerrainNode> mainTerrain = dynamic_pointer_cast<TerrainNode>(sceneGraph->Find(L"MainTerrain")); shared_ptr<TerrainNode> mainTerrain = dynamic_pointer_cast<TerrainNode>(sceneGraph->Find(L"MainTerrain"));
// Check if the terrain is actually loaded before trying to access it.
if (!_initDone && mainTerrain != nullptr) if (!_initDone && mainTerrain != nullptr)
{ {
// Create the spawn object lists
vector<TerrainPopNode> rngSpawnList; vector<TerrainPopNode> rngSpawnList;
vector<TerrainPopNode> rngBushSpawnList; vector<TerrainPopNode> rngBushSpawnList;
vector<TerrainPopNode> rngSnowSpawnList; vector<TerrainPopNode> rngSnowSpawnList;
vector<TerrainPopNode> rngDirtSpawnList; vector<TerrainPopNode> rngDirtSpawnList;
// Trees
TerrainPopNode treeModelA = TerrainPopNode(); TerrainPopNode treeModelA = TerrainPopNode();
treeModelA.modelName = L"Models\\Tree\\Tree1.fbx"; treeModelA.modelName = L"Models\\Tree\\Tree1.fbx";
treeModelA.nodeBaseName = L"treeA"; treeModelA.nodeBaseName = L"treeA";
@ -89,10 +117,13 @@ void Graphics2::GenerateClutter()
shared_ptr<SceneGraph> treeGroupA = make_shared<SceneGraph>(L"TreeGroupA"); shared_ptr<SceneGraph> treeGroupA = make_shared<SceneGraph>(L"TreeGroupA");
// Populate the terrain and add the child scene graph to the main scenegraph
mainTerrain->PopulateTerrain(treeGroupA, rngSpawnList, 20, 20, 500.0f, 650.0f, 0.9f, 1.0f); mainTerrain->PopulateTerrain(treeGroupA, rngSpawnList, 20, 20, 500.0f, 650.0f, 0.9f, 1.0f);
// Initialise the newly created models
treeGroupA->Initialise(); treeGroupA->Initialise();
sceneGraph->Add(treeGroupA); sceneGraph->Add(treeGroupA);
// Bushes
TerrainPopNode bushModelA = TerrainPopNode(); TerrainPopNode bushModelA = TerrainPopNode();
bushModelA.modelName = L"Models\\Tree\\Bush1.fbx"; bushModelA.modelName = L"Models\\Tree\\Bush1.fbx";
bushModelA.nodeBaseName = L"bushA"; bushModelA.nodeBaseName = L"bushA";
@ -130,6 +161,7 @@ void Graphics2::GenerateClutter()
bushGroupA->Initialise(); bushGroupA->Initialise();
sceneGraph->Add(bushGroupA); sceneGraph->Add(bushGroupA);
// The Snow trees
TerrainPopNode treeModelSA = TerrainPopNode(); TerrainPopNode treeModelSA = TerrainPopNode();
treeModelSA.modelName = L"Models\\Tree\\Tree3.fbx"; treeModelSA.modelName = L"Models\\Tree\\Tree3.fbx";
treeModelSA.nodeBaseName = L"treeSA"; treeModelSA.nodeBaseName = L"treeSA";
@ -143,6 +175,7 @@ void Graphics2::GenerateClutter()
treeGroupSA->Initialise(); treeGroupSA->Initialise();
sceneGraph->Add(treeGroupSA); sceneGraph->Add(treeGroupSA);
// The Rocks and desert tree
TerrainPopNode treeModelDA = TerrainPopNode(); TerrainPopNode treeModelDA = TerrainPopNode();
treeModelDA.modelName = L"Models\\Tree\\Tree4.fbx"; treeModelDA.modelName = L"Models\\Tree\\Tree4.fbx";
treeModelDA.nodeBaseName = L"treeDA"; treeModelDA.nodeBaseName = L"treeDA";
@ -181,16 +214,21 @@ void Graphics2::GenerateClutter()
void Graphics2::UpdateSceneGraph() void Graphics2::UpdateSceneGraph()
{ {
SceneGraphPointer sceneGraph = GetSceneGraph(); SceneGraphPointer sceneGraph = GetSceneGraph();
shared_ptr<TerrainNode> mainTerrain = dynamic_pointer_cast<TerrainNode>(sceneGraph->Find(L"MainTerrain")); shared_ptr<TerrainNode> mainTerrain = dynamic_pointer_cast<TerrainNode>(sceneGraph->Find(L"MainTerrain"));
if (!_initDone && mainTerrain != nullptr) // Check if the main terrain exists and runs the generate clutter method, we have to run it in the update because
// the terrain hasnt actually been generated til now, and we need the heights and normals so we can check if something can fit in a place
if (!_initDone && mainTerrain != nullptr && !_noClutter)
{ {
//GenerateClutter(); GenerateClutter();
} }
// This block gets the current inputs from either the keyboard of the gamepad, gamepad is a little iffy since the pitch is kind of wanky
GetCurrentControlInputs(); GetCurrentControlInputs();
XMVECTOR startCameraPos = GetCamera()->GetCameraPosition(); XMVECTOR startCameraPos = GetCamera()->GetCameraPosition();
// If the current player object is set, then always move forward
if (_currentPlayerObject != nullptr) if (_currentPlayerObject != nullptr)
{ {
_currentPlayerObject->SetForwardBack(_flySpeed * _boostMultiplier); _currentPlayerObject->SetForwardBack(_flySpeed * _boostMultiplier);
@ -278,9 +316,11 @@ void Graphics2::UpdateSceneGraph()
} }
} }
// Fetch the plane and boat nodes so that we can move them
shared_ptr<ControlledSplitMeshNode> plane1 = dynamic_pointer_cast<ControlledSplitMeshNode>(sceneGraph->Find(L"Plane1")); shared_ptr<ControlledSplitMeshNode> plane1 = dynamic_pointer_cast<ControlledSplitMeshNode>(sceneGraph->Find(L"Plane1"));
shared_ptr<ControlledMeshNode> boat1 = dynamic_pointer_cast<ControlledMeshNode>(sceneGraph->Find(L"Boat1")); shared_ptr<ControlledMeshNode> boat1 = dynamic_pointer_cast<ControlledMeshNode>(sceneGraph->Find(L"Boat1"));
// Move the plane
if (plane1 != nullptr) if (plane1 != nullptr)
{ {
//plane1->SetWorldTransform(SharedMethods::RotateFromPoint(-60.0f, 0, 0, XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), _currentRotation * XM_PI / 180.0f))); //plane1->SetWorldTransform(SharedMethods::RotateFromPoint(-60.0f, 0, 0, XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), _currentRotation * XM_PI / 180.0f)));
@ -288,15 +328,19 @@ void Graphics2::UpdateSceneGraph()
//sceneGraph->Find(L"Plane1")->GetFirstChild()->GetFirstChild()->SetWorldTransform(XMMatrixRotationAxis(XMVectorSet(0.0f, -1.0f, -1.0f, 0.0f), _currentSideRotation * XM_PI / 180.0f)); //sceneGraph->Find(L"Plane1")->GetFirstChild()->GetFirstChild()->SetWorldTransform(XMMatrixRotationAxis(XMVectorSet(0.0f, -1.0f, -1.0f, 0.0f), _currentSideRotation * XM_PI / 180.0f));
//sceneGraph->Find(L"Plane1")->Update((SharedMethods::RotateFromPoint(30.0f, -20.0f, 0, XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), _currentSideRotation * XM_PI / 180.0f))) * XMMatrixRotationAxis(XMVectorSet(0.0f, -1.0f, 0.0f, 0.0f), _currentRotation * XM_PI / 180.0f)); //sceneGraph->Find(L"Plane1")->Update((SharedMethods::RotateFromPoint(30.0f, -20.0f, 0, XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), _currentSideRotation * XM_PI / 180.0f))) * XMMatrixRotationAxis(XMVectorSet(0.0f, -1.0f, 0.0f, 0.0f), _currentRotation * XM_PI / 180.0f));
// Spin the planes propeller, it goes faster if you are boosting
plane1->Find(L"airscrew")->SetWorldTransform(SharedMethods::RotateFromPoint(0.0f, 15.471f, 14.5f, XMMatrixRotationAxis(XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f), _currentPropRotation * XM_PI / 180.0f))); plane1->Find(L"airscrew")->SetWorldTransform(SharedMethods::RotateFromPoint(0.0f, 15.471f, 14.5f, XMMatrixRotationAxis(XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f), _currentPropRotation * XM_PI / 180.0f)));
} }
// Move the boat
if (boat1 != nullptr) if (boat1 != nullptr)
{ {
boat1->SetForwardBack(-3.0f); boat1->SetForwardBack(-3.0f);
boat1->SetYaw(-0.2f); boat1->SetYaw(-0.2f);
} }
// Reset the rotation numbers when theyve done a full rotation so they just just increase forever
if (_currentRotation == 360) if (_currentRotation == 360)
{ {
_currentRotation = 0; _currentRotation = 0;
@ -320,6 +364,7 @@ void Graphics2::UpdateSceneGraph()
GetCamera()->Update(); GetCamera()->Update();
if (mainTerrain != nullptr) if (mainTerrain != nullptr)
{ {
// If a boundary is hit then move the object back
bool boundaryHit = false; bool boundaryHit = false;
XMFLOAT4 cameraOffset = XMFLOAT4(XMVectorGetX(startCameraPos), XMVectorGetY(startCameraPos), XMVectorGetZ(startCameraPos), 0.0f); XMFLOAT4 cameraOffset = XMFLOAT4(XMVectorGetX(startCameraPos), XMVectorGetY(startCameraPos), XMVectorGetZ(startCameraPos), 0.0f);
@ -372,6 +417,7 @@ void Graphics2::UpdateSceneGraph()
ResetCurrentControlInputs(); ResetCurrentControlInputs();
} }
// Method for getting the current frames inputs
void Graphics2::GetCurrentControlInputs() void Graphics2::GetCurrentControlInputs()
{ {
// Check if the window has focus before accepting any keypresses // Check if the window has focus before accepting any keypresses
@ -393,25 +439,25 @@ void Graphics2::GetCurrentControlInputs()
} }
// Forward // Forward
if (GetAsyncKeyState(0x57)) if (GetAsyncKeyState(0x57) || GetAsyncKeyState(VK_UP))
{ {
_currentInputs.insert(ControlInputs::Forward); _currentInputs.insert(ControlInputs::Forward);
} }
// Back // Back
if (GetAsyncKeyState(0x53)) if (GetAsyncKeyState(0x53) || GetAsyncKeyState(VK_DOWN))
{ {
_currentInputs.insert(ControlInputs::Back); _currentInputs.insert(ControlInputs::Back);
} }
// Turn Left // Turn Left
if (GetAsyncKeyState(0x41)) if (GetAsyncKeyState(0x41) || GetAsyncKeyState(VK_LEFT))
{ {
_currentInputs.insert(ControlInputs::TurnLeft); _currentInputs.insert(ControlInputs::TurnLeft);
} }
// Turn Right // Turn Right
if (GetAsyncKeyState(0x44)) if (GetAsyncKeyState(0x44) || GetAsyncKeyState(VK_RIGHT))
{ {
_currentInputs.insert(ControlInputs::TurnRight); _currentInputs.insert(ControlInputs::TurnRight);
} }
@ -442,6 +488,7 @@ void Graphics2::GetCurrentControlInputs()
} }
} }
// Method for clearing the current inputs ready for the next frame
void Graphics2::ResetCurrentControlInputs() void Graphics2::ResetCurrentControlInputs()
{ {
_currentInputs.clear(); _currentInputs.clear();

View File

@ -28,9 +28,9 @@ private:
float _boostStep = 0.5f; float _boostStep = 0.5f;
float _boostMax = 5.0f; float _boostMax = 5.0f;
float _flySpeed; float _flySpeed = 0.0f;
float _turnSpeed; float _turnSpeed = 0.0f;
int _invertPitch; int _invertPitch = 0;
float _currentRotation = 0.0f; float _currentRotation = 0.0f;
float _currentSideRotation = 0.0f; float _currentSideRotation = 0.0f;
@ -43,6 +43,8 @@ private:
shared_ptr<ObjectNode> _currentPlayerObject; shared_ptr<ObjectNode> _currentPlayerObject;
bool _noClutter = false;
void GetCurrentControlInputs(); void GetCurrentControlInputs();
void ResetCurrentControlInputs(); void ResetCurrentControlInputs();
void GenerateClutter(); void GenerateClutter();

View File

@ -5,6 +5,7 @@
HeightMapTerrainNode::HeightMapTerrainNode(wstring name, wstring heightMap, wstring seed, float waterHeight, int widthX, int widthZ, int cellSizeX, int cellSizeZ) : TerrainNode(name, seed, waterHeight, widthX, widthZ, cellSizeX, cellSizeZ) HeightMapTerrainNode::HeightMapTerrainNode(wstring name, wstring heightMap, wstring seed, float waterHeight, int widthX, int widthZ, int cellSizeX, int cellSizeZ) : TerrainNode(name, seed, waterHeight, widthX, widthZ, cellSizeX, cellSizeZ)
{ {
_heightMap = heightMap; _heightMap = heightMap;
// Try to load the height map otherwise fail and set the error bool
if (!LoadHeightMap(_heightMap)) if (!LoadHeightMap(_heightMap))
{ {
_initError = true; _initError = true;

View File

@ -3,6 +3,7 @@
#include "SharedMethods.h" #include "SharedMethods.h"
#include "TerrainNode.h" #include "TerrainNode.h"
// Height map terrain node, contains the methods needed to generate a terrain node with the given weird height map
class HeightMapTerrainNode : public TerrainNode class HeightMapTerrainNode : public TerrainNode
{ {
public: public:

View File

@ -1,6 +1,9 @@
#pragma once #pragma once
#include "DirectXCore.h" #include "DirectXCore.h"
// The object node contains all of the methods and variables needed to move a node using pitch, yaw, roll, and the directions
// It should be inherited by another node so that it doesnt interupt with the normal rendering functions and saves us having to
// duplicate code for every time, it also allows the child classes to be accessed by the ObjectNode type when needed
class ObjectNode class ObjectNode
{ {
public: public:

View File

@ -2,17 +2,29 @@
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) 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)
{ {
// Set the chink size
_chunkSize = chunkSize; _chunkSize = chunkSize;
GeneratePerlinValues(); // Check if a cache image exists and load it if so
if (!GeneratePerlinHeights()) if (!ReadCache())
{ {
_initError = true; // No Cache image existed so generate the perlin noise map
GeneratePerlinValues();
if (!GeneratePerlinHeights())
{
_initError = true;
}
else
{
// The generation was successful, save it to the cache
CacheOutput();
}
} }
} }
void PerlinTerrainNode::GeneratePerlinValues() void PerlinTerrainNode::GeneratePerlinValues()
{ {
// Setup the RNG
std::seed_seq seedGenerator(_seedString.begin(), _seedString.end()); std::seed_seq seedGenerator(_seedString.begin(), _seedString.end());
std::mt19937 generator; std::mt19937 generator;
generator.seed(seedGenerator); generator.seed(seedGenerator);
@ -20,9 +32,12 @@ void PerlinTerrainNode::GeneratePerlinValues()
char bufferChar; char bufferChar;
int newPosition; int newPosition;
// Clear the permutation array so we can reinsert a new copy
_p.clear(); _p.clear();
copy(_staticP.begin(), _staticP.end(), back_inserter(_p)); copy(_staticP.begin(), _staticP.end(), back_inserter(_p));
// Loop through and alternate the numbers so they are in a random position, this will not create any new numbers so we should always have what we started with
// just in a different order
for (int i = 0; i < 512; i++) for (int i = 0; i < 512; i++)
{ {
newPosition = dist(generator); newPosition = dist(generator);
@ -32,20 +47,83 @@ void PerlinTerrainNode::GeneratePerlinValues()
} }
} }
bool PerlinTerrainNode::ReadCache()
{
ifstream cachedImage;
string stringSeed = string(_seedString.begin(), _seedString.end());
string chunkSizeString = to_string(_chunkSize);
replace(chunkSizeString.begin(), chunkSizeString.end(), '.', '_');
cachedImage.open("TerrainCache\\cache_" + stringSeed + "_" + chunkSizeString + ".raw", std::ios_base::binary);
// Couldnt open the cache, either doesnt exist or some issue opening the file, a new one should be generated
if (!cachedImage)
{
return false;
}
// Load the files bytes into a vector we can foreach loop
vector<char> fileBytes((istreambuf_iterator<char>(cachedImage)), (istreambuf_iterator<char>()));
for (BYTE currentByte : fileBytes)
{
// Change the number back into a float value, some precision is lost because of this but i cant notice it really
float heightValue = currentByte / 255.0f;
_heightValues.push_back(heightValue);
}
cachedImage.close();
return true;
}
void PerlinTerrainNode::CacheOutput()
{
// Create a unique string name for the seed and cluster size given
string stringSeed = string(_seedString.begin(), _seedString.end());
string chunkSizeString = to_string(_chunkSize);
replace(chunkSizeString.begin(), chunkSizeString.end(), '.', '_');
ofstream output("TerrainCache\\cache_" + stringSeed + "_" + chunkSizeString + ".raw", std::ios_base::binary);
// Loop through the height values array
int current = 0;
for (float value : _heightValues)
{
// Force the value to be within 255, we lose some precision from this conversion but to generate an image it has to be this way
BYTE currentByte = (int)(255 * value) & 0xff;
// Write the value to the file buffer
output << currentByte;
// Constantly flush the buffer so that we dont have it waiting in memory for too long
if (current >= 100)
{
output.flush();
current = 0;
}
else
{
current++;
}
}
// Close the file
output.close();
}
// Method for filling the height values array for the terrain generation // Method for filling the height values array for the terrain generation
bool PerlinTerrainNode::GeneratePerlinHeights() bool PerlinTerrainNode::GeneratePerlinHeights()
{ {
for (int z = 0; z < _gridRows; z++) for (int z = 0; z < (int)_gridRows; z++)
{ {
float mapZ = ((float)z / (float)_gridRows); float mapZ = ((float)z / (float)_gridRows);
for (int x = 0; x < _gridCols; x++) for (int x = 0; x < (int)_gridCols; x++)
{ {
float mapX = ((float)x / (float)_gridCols); float mapX = ((float)x / (float)_gridCols);
//float currentHeightValue = GetPerlinValueAt(mapX, mapZ, 8, 0.85f) - 0.25f; //float currentHeightValue = GetPerlinValueAt(mapX, mapZ, 8, 0.85f) - 0.25f;
float currentHeightValue = 0.0f; float currentHeightValue = 0.0f;
// Octaves adds "noise" to the final outcome, 12 is really the max before it tanks the system for little effect
int octaves = 12; int octaves = 12;
float currentOctaveValue = 1.0f; float currentOctaveValue = 1.0f;
float stepOff = 1.0f; float stepOff = 1.0f;
@ -53,6 +131,7 @@ bool PerlinTerrainNode::GeneratePerlinHeights()
// n covers the persistance, frequency and // n covers the persistance, frequency and
for (int n = 1; n <= octaves; n++) for (int n = 1; n <= octaves; n++)
{ {
// Generate a noise at the given position
currentHeightValue += stepOff * GetNoiseValueAt(((float)x * currentOctaveValue) / ((float)_gridCols / _chunkSize), ((float)z * currentOctaveValue) / ((float)_gridRows / _chunkSize)); currentHeightValue += stepOff * GetNoiseValueAt(((float)x * currentOctaveValue) / ((float)_gridCols / _chunkSize), ((float)z * currentOctaveValue) / ((float)_gridRows / _chunkSize));
currentOctaveValue *= 2; currentOctaveValue *= 2;
stepTotal += stepOff; stepTotal += stepOff;
@ -62,6 +141,7 @@ bool PerlinTerrainNode::GeneratePerlinHeights()
//currentHeightValue = currentHeightValue / stepTotal; // *(currentHeightValue * 2.0f); //currentHeightValue = currentHeightValue / stepTotal; // *(currentHeightValue * 2.0f);
//currentHeightValue = currentHeightValue - floor(currentHeightValue); //currentHeightValue = currentHeightValue - floor(currentHeightValue);
// Normalise the result to a number between 0 and 1, since most like to generate numbers between -1 and 1, we just have to add 1 and half the value
_heightValues.push_back((currentHeightValue + 1.0f) * 0.5f); _heightValues.push_back((currentHeightValue + 1.0f) * 0.5f);
} }
} }
@ -76,6 +156,7 @@ float PerlinTerrainNode::Fade(float t)
float PerlinTerrainNode::Grad(int hash, float x, float y) float PerlinTerrainNode::Grad(int hash, float x, float y)
{ {
// To be honest this is something i dont really understand, it shifts bits around to see which direction we need to multiply in
int h = hash & 7; int h = hash & 7;
float u = y; float u = y;
float v = x; float v = x;

View File

@ -3,9 +3,11 @@
#include <vector> #include <vector>
#include <numeric> #include <numeric>
#include <random> #include <random>
#include <fstream>
#include "SharedMethods.h" #include "SharedMethods.h"
#include "TerrainNode.h" #include "TerrainNode.h"
// Class for generating a terrain using a perlin noise algorithm, this now caches the result too so it only has to run on the initial time its loaded.
class PerlinTerrainNode : public TerrainNode class PerlinTerrainNode : public TerrainNode
{ {
public: public:
@ -41,11 +43,20 @@ private:
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
}; };
// Vector to hold the actual randomised perlin noise permutation array
vector<unsigned char> _p; vector<unsigned char> _p;
// The chunk size lets us control how large a noise spot should be, lower numbers will make things flatter, larger numbers will make things spikey
float _chunkSize; float _chunkSize;
// Methods for Caching the output to a raw image format, and reading it back in the next time its loaded
bool ReadCache();
void CacheOutput();
// Methods for fading a number, used for the noise calculation
float Fade(float t); float Fade(float t);
// Method for generating a perlin gradient.
float Grad(int hash, float x, float y); float Grad(int hash, float x, float y);
void GeneratePerlinValues(); void GeneratePerlinValues();

View File

@ -71,6 +71,7 @@ SceneNodePointer SceneGraph::Find(wstring name)
for (SceneNodePointer& currentSceneGraphPtr : _children) for (SceneNodePointer& currentSceneGraphPtr : _children)
{ {
foundValue = currentSceneGraphPtr->Find(name); foundValue = currentSceneGraphPtr->Find(name);
// Keep going til we find a value, then break the loop all the way down
if (foundValue != nullptr) if (foundValue != nullptr)
{ {
break; break;

View File

@ -17,10 +17,15 @@ public:
void Add(SceneNodePointer node); void Add(SceneNodePointer node);
void Remove(SceneNodePointer node); void Remove(SceneNodePointer node);
SceneNodePointer Find(wstring name); SceneNodePointer Find(wstring name);
// Placeholder methods for possibly going up the graph to find the Root and Parent nodes
SceneNodePointer GetRootNode(); SceneNodePointer GetRootNode();
SceneNodePointer GetParent(); SceneNodePointer GetParent();
// Returns a scenegraphs first child element, useful if you dont know the names but know the structure
SceneNodePointer GetFirstChild(); SceneNodePointer GetFirstChild();
// Method for returning a pointer to the child list, needed for the split mesh renderer mainly
list<SceneNodePointer>& GetChildren(); list<SceneNodePointer>& GetChildren();
protected: protected:

View File

@ -6,13 +6,13 @@ XMMATRIX SharedMethods::RotateFromPoint(const float x, const float y, const floa
return XMMatrixTranslation(x, y, z) * rotationMatrix * XMMatrixTranslation(-x, -y, -z); return XMMatrixTranslation(x, y, z) * rotationMatrix * XMMatrixTranslation(-x, -y, -z);
} }
// Method so i can use normal RGB values and hopefully hex values too since im use to those // Function so i can use normal RGB values and hopefully hex values too since im use to those
float SharedMethods::RGBValueToIntensity(const int value) float SharedMethods::RGBValueToIntensity(const int value)
{ {
return (float)value / 255.0f; return (float)value / 255.0f;
} }
// Method to generate a random intensity rating between 2 floats // Function to generate a random intensity rating between 2 floats
float SharedMethods::GenerateRandomIntensity(const float min, const float max) float SharedMethods::GenerateRandomIntensity(const float min, const float max)
{ {
float randNo = (float)rand() / (float)RAND_MAX; float randNo = (float)rand() / (float)RAND_MAX;
@ -22,7 +22,7 @@ float SharedMethods::GenerateRandomIntensity(const float min, const float max)
return (float)roundedNo * 0.01f; return (float)roundedNo * 0.01f;
} }
// Method for genering random UV's, maybe get rid of this in future // Function for genering random UV's, maybe get rid of this in future
float SharedMethods::GenerateRandomUV(const float min, const float max) float SharedMethods::GenerateRandomUV(const float min, const float max)
{ {
return SharedMethods::Clamp<float>((float)(rand() % (int)(max * 100.0f)) * 0.01f, (float)min, (float)max); return SharedMethods::Clamp<float>((float)(rand() % (int)(max * 100.0f)) * 0.01f, (float)min, (float)max);

View File

@ -2,6 +2,7 @@
#include "DirectXCore.h" #include "DirectXCore.h"
#include <string> #include <string>
// The generic CBuffer used in most of the nodes
struct CBUFFER struct CBUFFER
{ {
XMMATRIX completeTransformation; XMMATRIX completeTransformation;
@ -18,6 +19,7 @@ struct CBUFFER
float padding[1]; float padding[1];
}; };
// Struct to hold the terrain populate methods variables
struct TerrainPopNode struct TerrainPopNode
{ {
std::wstring nodeBaseName; std::wstring nodeBaseName;
@ -25,12 +27,16 @@ struct TerrainPopNode
float scaleFactor; float scaleFactor;
}; };
// The Shared methods namespace should be used for functions that are used in many places to stop duplicate code and keep things consolidated
namespace SharedMethods namespace SharedMethods
{ {
// Function for creating a rotation matrix that should be around a specific point
XMMATRIX RotateFromPoint(const float x, const float y, const float z, const XMMATRIX rotationMatrix); XMMATRIX RotateFromPoint(const float x, const float y, const float z, const XMMATRIX rotationMatrix);
// Function for converting a 255 style RGB value to its normalised intensity value
float RGBValueToIntensity(const int value); float RGBValueToIntensity(const int value);
// Template function for clamping a number between 2 values, the template allows this to be used for any numeric type
template <typename T = float> T Clamp(const T value, const T min, const T max) template <typename T = float> T Clamp(const T value, const T min, const T max)
{ {
if (value < min) if (value < min)
@ -47,12 +53,13 @@ namespace SharedMethods
} }
} }
// Methods for lerping values // Template function for lerping values
template <typename T = float> float Lerp(const T a, const T b, const float p) template <typename T = float> float Lerp(const T a, const T b, const float p)
{ {
return (float)a + p * ((float)b - (float)a); return (float)a + p * ((float)b - (float)a);
} }
// Template function for doing a cubic interpolate, i think this is unused currently but i did play around with the idea
template <typename T = float> float CubicInterpolate(const T n0, const T n1, const T n2, const T n3, const float a) template <typename T = float> float CubicInterpolate(const T n0, const T n1, const T n2, const T n3, const float a)
{ {
float p = ((float)n3 - (float)n2) - ((float)n0 - (float)n1); float p = ((float)n3 - (float)n2) - ((float)n0 - (float)n1);
@ -63,7 +70,10 @@ namespace SharedMethods
return p * a * a * a + q * a * a + r * a + s; return p * a * a * a + q * a * a + r * a + s;
} }
// Function for generating a random float value
float GenerateRandomIntensity(const float min, const float max); float GenerateRandomIntensity(const float min, const float max);
// Function for generating random UV values
float GenerateRandomUV(const float min, const float max); float GenerateRandomUV(const float min, const float max);
}; };

View File

@ -13,6 +13,7 @@ bool SplitMeshNode::Initialise()
} }
else else
{ {
// Loop the meshes sub meshes to generate the scene graph tree
Add(AddMeshNode(_mesh->GetRootNode())); Add(AddMeshNode(_mesh->GetRootNode()));
} }
@ -40,6 +41,7 @@ void SplitMeshNode::Render(void)
void SplitMeshNode::Shutdown(void) void SplitMeshNode::Shutdown(void)
{ {
// Release the mesh from the resource manager
_resourceManager->ReleaseMesh(_modelName); _resourceManager->ReleaseMesh(_modelName);
SceneGraph::Shutdown(); SceneGraph::Shutdown();
} }

View File

@ -4,6 +4,7 @@
#include "SubMeshRenderer.h" #include "SubMeshRenderer.h"
#include "SubMeshNode.h" #include "SubMeshNode.h"
// Class for creating a scenegraph centric split mesh node, that allows for transformation of any of the sub meshes
class SplitMeshNode : public SceneGraph class SplitMeshNode : public SceneGraph
{ {
public: public:

View File

@ -2,6 +2,7 @@
#include "DirectXFramework.h" #include "DirectXFramework.h"
#include "SceneNode.h" #include "SceneNode.h"
// Class for holding the details of the sub meshes of a split node class
class SubMeshNode : public SceneNode class SubMeshNode : public SceneNode
{ {
public: public:

View File

@ -2,6 +2,7 @@
void SubMeshRenderer::SetRootChildren(list<SceneNodePointer>& rootChildren) void SubMeshRenderer::SetRootChildren(list<SceneNodePointer>& rootChildren)
{ {
// Sets the root children since the actual sub mesh root could have multiple children...
_rootGraph = &rootChildren; _rootGraph = &rootChildren;
} }
@ -35,8 +36,10 @@ bool SubMeshRenderer::Initialise()
void SubMeshRenderer::RenderChild(SceneNodePointer node, bool renderTransparent) void SubMeshRenderer::RenderChild(SceneNodePointer node, bool renderTransparent)
{ {
// Check if the current node is a sub mesh
shared_ptr<SubMeshNode> currentMeshNode = dynamic_pointer_cast<SubMeshNode>(node); shared_ptr<SubMeshNode> currentMeshNode = dynamic_pointer_cast<SubMeshNode>(node);
// If the current node is a submesh, render it
if (currentMeshNode != nullptr) if (currentMeshNode != nullptr)
{ {
XMMATRIX projectionTransformation = DirectXFramework::GetDXFramework()->GetProjectionTransformation(); XMMATRIX projectionTransformation = DirectXFramework::GetDXFramework()->GetProjectionTransformation();
@ -82,6 +85,7 @@ void SubMeshRenderer::RenderChild(SceneNodePointer node, bool renderTransparent)
} }
} }
// If the current node is not a sub mesh its most likely a scene graph, if so loop the children of it
shared_ptr<SceneGraph> currentGraphNode = dynamic_pointer_cast<SceneGraph>(node); shared_ptr<SceneGraph> currentGraphNode = dynamic_pointer_cast<SceneGraph>(node);
if (currentGraphNode != nullptr) if (currentGraphNode != nullptr)
@ -118,6 +122,9 @@ void SubMeshRenderer::Render()
float blendFactors[] = { 0.0f, 0.0f, 0.0f, 0.0f }; float blendFactors[] = { 0.0f, 0.0f, 0.0f, 0.0f };
_deviceContext->OMSetBlendState(_transparentBlendState.Get(), blendFactors, 0xffffffff); _deviceContext->OMSetBlendState(_transparentBlendState.Get(), blendFactors, 0xffffffff);
// IT REALLY NEEDS TO DO BOTH TO RENDER SOMEWHAT CORRECTLY
// This should solve that now
// We do two passes through the nodes. The first time we render nodes // We do two passes through the nodes. The first time we render nodes
// that are not transparent (i.e. their opacity == 1.0f). // that are not transparent (i.e. their opacity == 1.0f).
for (SceneNodePointer& child : *_rootGraph) for (SceneNodePointer& child : *_rootGraph)

View File

@ -5,6 +5,7 @@
#include "Renderer.h" #include "Renderer.h"
#include "Mesh.h" #include "Mesh.h"
// Class for rendering a sub mesh since its different to a normal mesh render
class SubMeshRenderer : public Renderer class SubMeshRenderer : public Renderer
{ {
public: public:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -4,9 +4,11 @@
TerrainNode::TerrainNode(wstring name, wstring seed, float waterHeight, int widthX, int widthZ, int cellSizeX, int cellSizeZ) : SceneNode(name) 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; _seedString = seed;
_seedHash = std::hash<wstring>{}(_seedString); _seedHash = (unsigned int)std::hash<wstring>{}(_seedString);
// Set the random seed number
srand(_seedHash); srand(_seedHash);
_widthX = widthX; _widthX = widthX;
@ -83,9 +85,9 @@ void TerrainNode::GenerateTerrainData()
float bv = 1.0f / (float)(_gridRows - 1u); float bv = 1.0f / (float)(_gridRows - 1u);
int currentVertexCount = 0; 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 currentIndex = (z * _gridCols) + x;
int offsetIndexX = 1; int offsetIndexX = 1;
@ -165,9 +167,9 @@ void TerrainNode::GenerateTerrainData()
void TerrainNode::GenerateTerrainNormals() void TerrainNode::GenerateTerrainNormals()
{ {
int currentNormalIndex = 0; 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, XMVECTOR v1 = XMVectorSet(_terrainVerts[currentNormalIndex + 1].Position.x - _terrainVerts[currentNormalIndex].Position.x,
_terrainVerts[currentNormalIndex + 1].Position.y - _terrainVerts[currentNormalIndex].Position.y, _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 + 2].Normal, XMVectorAdd(XMLoadFloat3(&_terrainVerts[currentNormalIndex + 2].Normal), polygonNormal));
XMStoreFloat3(&_terrainVerts[currentNormalIndex + 3].Normal, XMVectorAdd(XMLoadFloat3(&_terrainVerts[currentNormalIndex + 3].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 - 1, 3, polygonNormal);
AddNormalToVertex(z - 1, x, 2, polygonNormal); AddNormalToVertex(z - 1, x, 2, polygonNormal);
AddNormalToVertex(z - 1, x, 3, 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); 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) if (row >= 0 && row < (int)_gridRows && col >= 0 && col < (int)_gridCols)
{ {
XMStoreFloat3(&_terrainVerts[finalIndex].Normal, XMVectorAdd(XMLoadFloat3(&_terrainVerts[finalIndex].Normal), normal)); 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) 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 totalHeights = 0.0f;
float totalSlope = 0.0f; float totalSlope = 0.0f;
@ -516,12 +522,15 @@ void TerrainNode::PopulateTerrain(SceneGraphPointer currentSceneGraph, vector<Te
float heightValue = totalHeights / 4.0f; float heightValue = totalHeights / 4.0f;
// If the height value is within the given range
if (heightValue >= heightLower && heightValue <= heightUpper) if (heightValue >= heightLower && heightValue <= heightUpper)
{ {
float avgSlope = totalSlope / 4.0f; float avgSlope = totalSlope / 4.0f;
// If the slope value is within the given range
if (avgSlope >= slopeLower && avgSlope <= slopeUpper) 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; int nodeIndex = 0;
if (nodesForPop.size() > 1) 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 scale = (rand() % 100 * 0.01f) * nodesForPop[nodeIndex].scaleFactor;
float yRotation = rand() % 360; float yRotation = (float)(rand() % 360);
float xPos = x * _cellSizeX + _terrainStartX; float xPos = x * _cellSizeX + _terrainStartX;
float yPos = heightValue; float yPos = heightValue;
float zPos = (-z + 1) * _cellSizeZ + _terrainStartZ; float zPos = (-z + 1) * _cellSizeZ + _terrainStartZ;
// Made a unique name to stop conflicts
wstring nodeName = L"_" + to_wstring(z) + L"_" + to_wstring(x); wstring nodeName = L"_" + to_wstring(z) + L"_" + to_wstring(x);
shared_ptr<MeshNode> newNode = make_shared<MeshNode>(nodesForPop[nodeIndex].nodeBaseName + nodeName, nodesForPop[nodeIndex].modelName); 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)); 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() void TerrainNode::GenerateBlendMap()
{ {
// Set up the color gradients for each type of texture
RGBA snowTops = RGBA{ 0u, 0u, 0u, 255u }; RGBA snowTops = RGBA{ 0u, 0u, 0u, 255u };
RGBA grassLand = RGBA{ 0u, 0u, 0u, 0u }; RGBA grassLand = RGBA{ 0u, 0u, 0u, 0u };
RGBA lightDirt = RGBA{ 50u, 0u, 255u, 0u }; RGBA lightDirt = RGBA{ 50u, 0u, 255u, 0u };
RGBA darkDirt = RGBA{ 255u, 50u, 50u, 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}; vector<RGBA> colorSteps = {darkDirt, lightDirt, grassLand, grassLand, grassLand, snowTops};
float waterOffset = _waterHeight - 50.0f; float waterOffset = _waterHeight - 50.0f;
@ -560,6 +572,7 @@ void TerrainNode::GenerateBlendMap()
waterOffset = 0.0f; waterOffset = 0.0f;
} }
// Set up the gradient
ColorGradient terrainBlendGradient = ColorGradient(waterOffset, 820.0f, colorSteps); ColorGradient terrainBlendGradient = ColorGradient(waterOffset, 820.0f, colorSteps);
// Note that _numberOfRows and _numberOfColumns need to be setup // Note that _numberOfRows and _numberOfColumns need to be setup
@ -593,6 +606,7 @@ void TerrainNode::GenerateBlendMap()
float totalHeights = 0.0f; float totalHeights = 0.0f;
float totalSlope = 0.0f; float totalSlope = 0.0f;
// Calculate the average height and slope values
for (int si = 0; si < 4; si++) for (int si = 0; si < 4; si++)
{ {
totalHeights += _terrainVerts[currentIndex + si].Position.y; totalHeights += _terrainVerts[currentIndex + si].Position.y;
@ -602,6 +616,7 @@ void TerrainNode::GenerateBlendMap()
float avgHeight = totalHeights / 4.0f; float avgHeight = totalHeights / 4.0f;
float avgSlope = totalSlope / 4.0f; float avgSlope = totalSlope / 4.0f;
// Get the RGB value from the gradient at the given height value
RGBA currentBlend = terrainBlendGradient.GetRGBAValue(avgHeight); RGBA currentBlend = terrainBlendGradient.GetRGBAValue(avgHeight);
r = (BYTE)currentBlend.red; r = (BYTE)currentBlend.red;
g = (BYTE)currentBlend.green; g = (BYTE)currentBlend.green;
@ -612,7 +627,7 @@ void TerrainNode::GenerateBlendMap()
{ {
if (avgSlope < 0.6f) 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) float TerrainNode::GetHeightAtPoint(float x, float z, bool waterCollide)
{ {
int cellX = (int)((x - _terrainStartX) / _cellSizeX); int cellX = (int)((x - _terrainStartX) / _cellSizeX);
int cellZ = (int)((_terrainStartZ - z) / _cellSizeZ); int cellZ = (int)((_terrainStartZ - z) / _cellSizeZ);
int currentIndex = (cellZ * _gridCols * 4) + (cellX * 4); int currentIndex = (cellZ * _gridCols * 4) + (cellX * 4);
float dx = x - _terrainVerts[currentIndex].Position.x; float dx = x - _terrainVerts[currentIndex].Position.x;
float dz = z - _terrainVerts[currentIndex].Position.z; float dz = z - _terrainVerts[currentIndex].Position.z;
@ -695,6 +711,7 @@ float TerrainNode::GetHeightAtPoint(float x, float z, bool waterCollide)
XMFLOAT4 normal; XMFLOAT4 normal;
XMStoreFloat4(&normal, XMVector3Normalize(XMVector3Cross(v1, v2))); 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; float result = _terrainVerts[currentIndex].Position.y + (normal.x * dx + normal.z * dz) / -normal.y;
if (waterCollide) if (waterCollide)
{ {
@ -707,6 +724,7 @@ float TerrainNode::GetHeightAtPoint(float x, float z, bool waterCollide)
return result; return result;
} }
// Method for checking if we are within the X Boundary
bool TerrainNode::CheckXBoundary(float x) bool TerrainNode::CheckXBoundary(float x)
{ {
if (!(x > _terrainStartX && x < _terrainEndX)) if (!(x > _terrainStartX && x < _terrainEndX))
@ -717,6 +735,7 @@ bool TerrainNode::CheckXBoundary(float x)
return true; return true;
} }
// Method for checking if we are withing the Z Boundary
bool TerrainNode::CheckZBoundary(float z) bool TerrainNode::CheckZBoundary(float z)
{ {
if (!(z < _terrainStartZ && z > _terrainEndZ)) if (!(z < _terrainStartZ && z > _terrainEndZ))

View File

@ -12,6 +12,7 @@
#include "MeshNode.h" #include "MeshNode.h"
#include "SplitMeshNode.h" #include "SplitMeshNode.h"
// Struct for holding the terrain vertex data
typedef struct TerrainVertex typedef struct TerrainVertex
{ {
XMFLOAT3 Position; XMFLOAT3 Position;
@ -20,6 +21,8 @@ typedef struct TerrainVertex
XMFLOAT2 BlendMapTexCoord; XMFLOAT2 BlendMapTexCoord;
} TerrainVertex; } TerrainVertex;
// Custom CBuffer for the terrain that can hold the water values, THE BYTE TOTAL FOR THIS MUST HAVE A FACTOR OF 16!!
// a float is 4 bytes, so we techically dont need to pad with the array at the bottom but i left it in to remind myself
struct TCBUFFER struct TCBUFFER
{ {
XMMATRIX completeTransformation; XMMATRIX completeTransformation;
@ -38,6 +41,7 @@ struct TCBUFFER
float padding[4]; float padding[4];
}; };
// Class for processing the data of a terrain, one of the child classes should be passing the values to here to process as this class does not generate any actual values.
class TerrainNode : public SceneNode class TerrainNode : public SceneNode
{ {
public: public:
@ -51,13 +55,16 @@ public:
void Render(void); void Render(void);
void virtual Shutdown(void); void virtual Shutdown(void);
// Method for randomly placing models onto the terrain with the given commands
void PopulateTerrain(SceneGraphPointer currentSceneGraph, vector<TerrainPopNode>& nodesForPop, int xStep, int zStep, float heightLower, float heightUpper, float slopeLower, float slopeUpper); void PopulateTerrain(SceneGraphPointer currentSceneGraph, vector<TerrainPopNode>& nodesForPop, int xStep, int zStep, float heightLower, float heightUpper, float slopeLower, float slopeUpper);
// Methods for checking if you are in the bounds
float GetHeightAtPoint(float x, float z, bool waterCollide = false); float GetHeightAtPoint(float x, float z, bool waterCollide = false);
bool CheckXBoundary(float x); bool CheckXBoundary(float x);
bool CheckZBoundary(float z); bool CheckZBoundary(float z);
protected: protected:
// Bool so we can set this if the children have an error processing the data and we wont run
bool _initError = false; bool _initError = false;
int _widthX; int _widthX;
@ -80,6 +87,7 @@ protected:
float _terrainEndX; float _terrainEndX;
float _terrainEndZ; float _terrainEndZ;
// Vars for dealing with the random number seed
wstring _seedString; wstring _seedString;
unsigned int _seedHash; unsigned int _seedHash;
@ -111,7 +119,9 @@ protected:
ComPtr<ID3D11RasterizerState> _defaultRasteriserState; ComPtr<ID3D11RasterizerState> _defaultRasteriserState;
ComPtr<ID3D11RasterizerState> _wireframeRasteriserState; ComPtr<ID3D11RasterizerState> _wireframeRasteriserState;
// Pointer for the snow texture since i could not load it with the other textures, i think its because of mixed formats
ComPtr<ID3D11ShaderResourceView> _snowTest; ComPtr<ID3D11ShaderResourceView> _snowTest;
ComPtr<ID3D11ShaderResourceView> _waterNormalMap; ComPtr<ID3D11ShaderResourceView> _waterNormalMap;
XMFLOAT4 _waterColor; XMFLOAT4 _waterColor;
@ -126,9 +136,13 @@ protected:
void LoadTerrainTextures(); void LoadTerrainTextures();
void GenerateBlendMap(); void GenerateBlendMap();
// Method to get a height value at the given index
float GetHeightValueAt(int index); float GetHeightValueAt(int index);
// Method for adding the normals to each vertex, easier to manage this way
void AddNormalToVertex(int row, int col, int vertexIndex, XMVECTOR normal); void AddNormalToVertex(int row, int col, int vertexIndex, XMVECTOR normal);
// Method for loading the extra image maps we had, but now just for the water normals
void BuildExtraMaps(); void BuildExtraMaps();
}; };

View File

@ -22,6 +22,8 @@ cbuffer ConstantBuffer
Texture2D BlendMap : register(t0); Texture2D BlendMap : register(t0);
Texture2DArray TexturesArray : register(t1); Texture2DArray TexturesArray : register(t1);
// Textures for the water normals and the snow
Texture2D WaterNormalMap : register(t2); Texture2D WaterNormalMap : register(t2);
Texture2D snowTest : register(t3); Texture2D snowTest : register(t3);
@ -51,6 +53,7 @@ struct PixelShaderInput
float2 BlendMapTexCoord : TEXCOORD1; float2 BlendMapTexCoord : TEXCOORD1;
}; };
// Function for rotating a UV around a point
float2 UVRotate(float2 uvCoord, float2 pivotPoint, float rotation) float2 UVRotate(float2 uvCoord, float2 pivotPoint, float rotation)
{ {
float2x2 rotateMatrix = float2x2(float2(sin(rotation), -cos(rotation)), float2(cos(rotation), sin(rotation))); float2x2 rotateMatrix = float2x2(float2(sin(rotation), -cos(rotation)), float2(cos(rotation), sin(rotation)));
@ -63,31 +66,35 @@ float2 UVRotate(float2 uvCoord, float2 pivotPoint, float rotation)
} }
// Typical HLSL hasing function for psuedo random number generation
float4 hash4(float2 v)
{
float4 p = mul(float4x2(127.1f, 311.7f, 269.5f, 183.3f, 113.5f, 271.9f, 246.1f, 124.6f), v);
return frac(sin(p) * 43758.5453123);
}
PixelShaderInput VShader(VertexShaderInput vin) PixelShaderInput VShader(VertexShaderInput vin)
{ {
PixelShaderInput output; PixelShaderInput output;
float3 position = vin.Position; float3 position = vin.Position;
output.PositionOG = output.PositionWS = mul(worldTransformation, float4(position, 1.0f)); output.PositionOG = output.PositionWS = mul(worldTransformation, float4(position, 1.0f));
output.TexCoord = vin.TexCoord; output.TexCoord = vin.TexCoord;
// Check if the y pos is lower than the water point, and set the position to it minus a tiny offset because the textures were clipping and causing a weird effect // Check if the y pos is lower than the water point
if (position.y < waterHeight) if (position.y < waterHeight)
{ {
position.y = waterHeight; // Change up the flat water height with some psuedo RNG height generation
float4 yOffset = hash4(float2(-position.y, position.y));
// the offset should return as a value between 0 and 1, i change this to be a value between -1 and 1, then add some height modifier so you can actually see the difference
position.y = waterHeight + (((yOffset.y * 2.0f) - 1.0f) * 3.0f);
} }
output.Position = mul(completeTransformation, float4(position, 1.0f)); output.Position = mul(completeTransformation, float4(position, 1.0f));
output.PositionWS = mul(worldTransformation, float4(position, 1.0f)); //output.PositionWS = mul(worldTransformation, float4(position, 1.0f));
output.NormalWS = float4(mul((float3x3)worldTransformation, vin.Normal), 1.0f); output.NormalWS = float4(mul((float3x3)worldTransformation, vin.Normal), 1.0f);
output.BlendMapTexCoord = vin.BlendMapTexCoord; output.BlendMapTexCoord = vin.BlendMapTexCoord;
return output; return output;
} }
float4 hash4(float2 v)
{
float4 p = mul(float4x2(127.1, 311.7, 269.5, 183.3, 113.5, 271.9, 246.1, 124.6), v);
return frac(sin(p) * 43758.5453123);
}
float4 PShader(PixelShaderInput input) : SV_TARGET float4 PShader(PixelShaderInput input) : SV_TARGET
{ {
float4 directionToCamera = normalize(input.PositionWS - cameraPosition); float4 directionToCamera = normalize(input.PositionWS - cameraPosition);
@ -95,14 +102,13 @@ float4 PShader(PixelShaderInput input) : SV_TARGET
float surfaceShininess = shininess; float surfaceShininess = shininess;
float4 adjustedNormal = normalize(input.NormalWS); float4 adjustedNormal = normalize(input.NormalWS);
float currentHeightPer = (waterHeight - input.PositionOG.y) / waterHeight;
if (input.PositionOG.y < waterHeight) if (input.PositionOG.y < waterHeight)
{ {
// Sample the normal from the water normal map and calculate it with the worldtransform // Sample the normal from the water normal map and calculate it with the worldtransform
float3 n0 = 2.0f * (float3)WaterNormalMap.Sample(ss, input.TexCoord) - 1.0f; float4 n0 = WaterNormalMap.Sample(ss, input.TexCoord);
float4 n2 = float4(mul((float3x3)worldTransformation, n0), 1.0f); float4 n1 = float4((n0.xyz * 2.0f) - 1.0f, 1.0f);
adjustedNormal = normalize(n2); //float4 n2 = float4(mul((float3x3)worldTransformation, n0), 1.0f);
adjustedNormal = n1; // normalize(n2);
surfaceShininess = waterShininess; surfaceShininess = waterShininess;
} }
@ -122,9 +128,7 @@ float4 PShader(PixelShaderInput input) : SV_TARGET
float4 color; float4 color;
// Randomly rotate the UV coordinates using the noise map // Randomly rotate the UV coordinates using the noise map
float2 scaleCenter = float2(0.5f, 0.5f); float2 scaleCenter = float2(0.5f, 0.5f);
// The noise map is greyscale so we only need to check 1 channel since they should all be the same value
float2 scaledUV = frac(UVRotate(input.TexCoord, scaleCenter, input.BlendMapTexCoord.x)); // (input.TexCoord - scaleCenter) * currentScale + scaleCenter; float2 scaledUV = frac(UVRotate(input.TexCoord, scaleCenter, input.BlendMapTexCoord.x)); // (input.TexCoord - scaleCenter) * currentScale + scaleCenter;
float2 xChange = ddx(scaledUV); float2 xChange = ddx(scaledUV);
@ -145,6 +149,7 @@ float4 PShader(PixelShaderInput input) : SV_TARGET
float4 c2 = TexturesArray.SampleGrad(ss, float3(scaledUV, 2.0f), xChange, yChange); float4 c2 = TexturesArray.SampleGrad(ss, float3(scaledUV, 2.0f), xChange, yChange);
float4 c3 = TexturesArray.SampleGrad(ss, float3(scaledUV, 3.0f), xChange, yChange); float4 c3 = TexturesArray.SampleGrad(ss, float3(scaledUV, 3.0f), xChange, yChange);
//float4 c4 = TexturesArray.SampleGrad(ss, float3(scaledUV, 4.0f), xChange, yChange); //float4 c4 = TexturesArray.SampleGrad(ss, float3(scaledUV, 4.0f), xChange, yChange);
// Using the single snow texture because of the snow dds loading glitch
float4 c4 = snowTest.SampleGrad(ss, float2(scaledUV), xChange, yChange); float4 c4 = snowTest.SampleGrad(ss, float2(scaledUV), xChange, yChange);
// Sample the blend map. // Sample the blend map.
@ -157,7 +162,7 @@ float4 PShader(PixelShaderInput input) : SV_TARGET
color = lerp(color, c3, t.b); color = lerp(color, c3, t.b);
color = lerp(color, c4, t.a); color = lerp(color, c4, t.a);
// Combine all components // Combine all components, and check if this is water
if (input.PositionOG.y < waterHeight) if (input.PositionOG.y < waterHeight)
{ {
// Tint the water // Tint the water

View File

@ -64,6 +64,7 @@ float4 PShader(PixelShaderInput input) : SV_TARGET
// Combine all components // Combine all components
float4 color; float4 color;
// Check if the texture is valid before trying to sample it, some meshes use materials to color them and dont export an image texture file even though the color value is stored with the vertex // Check if the texture is valid before trying to sample it, some meshes use materials to color them and dont export an image texture file even though the color value is stored with the vertex
// This might be totally my end because ive seen others be able to load the plane with all the correct textures???
if (validTexture == 1) if (validTexture == 1)
{ {
color = saturate((ambientLight + diffuse + specular) * Texture.Sample(ss, input.TexCoord)); color = saturate((ambientLight + diffuse + specular) * Texture.Sample(ss, input.TexCoord));

Binary file not shown.