Added follow cam

Added "Controlled" mesh classes
Added Global Lighting Class
Added Gamepad controls
Split terrain nodes into Height and Perlin classes
Fixed Splitmesh node stuff
This commit is contained in:
iDunnoDev
2022-05-09 17:50:22 +01:00
committed by iDunnoDev
parent bc906064e5
commit f6bba67897
58 changed files with 1743 additions and 351 deletions

View File

@ -1,17 +1,16 @@
#include "Camera.h"
XMVECTOR defaultForward = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
XMVECTOR defaultRight = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f);
XMVECTOR defaultUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
Camera::Camera()
{
_nodeFollowed = nullptr;
_cameraPosition = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
_moveLeftRight = 0.0f;
_moveForwardBack = 0.0f;
_cameraYaw = 0.0f;
_cameraPitch = 0.0f;
_cameraRoll = 0.0f;
_followPositionOnly = false;
_followOffset = XMFLOAT3(0.0f, 0.0f, 0.0f);
}
Camera::~Camera()
@ -83,14 +82,28 @@ XMVECTOR Camera::GetCameraPosition(void)
return XMLoadFloat4(&_cameraPosition);
}
XMFLOAT4 Camera::GetRawCameraPosition(void)
{
return _cameraPosition;
}
void Camera::SetCameraPosition(float x, float y, float z)
{
_cameraPosition = XMFLOAT4(x, y, z, 0.0f);
SetCameraPosition(XMFLOAT4(x, y, z, 0.0f));
}
void Camera::SetCameraPosition(XMVECTOR vectorIn)
{
XMFLOAT4 floatIn;
XMStoreFloat4(&floatIn, vectorIn);
SetCameraPosition(floatIn);
}
void Camera::SetCameraPosition(XMFLOAT4 floatIn)
{
_cameraPosition = floatIn;
}
void Camera::SetFollowNode(shared_ptr<ObjectNode> nodeFollowed, XMFLOAT3 followOffset, bool positionOnly)
{
_nodeFollowed = nodeFollowed;
_followOffset = followOffset;
_followPositionOnly = positionOnly;
}
void Camera::Update(void)
@ -101,31 +114,84 @@ void Camera::Update(void)
XMVECTOR cameraForward;
XMVECTOR cameraUp;
// Yaw (rotation around the Y axis) will have an impact on the forward and right vectors
XMMATRIX cameraRotationYaw = XMMatrixRotationAxis(defaultUp, _cameraYaw);
cameraRight = XMVector3TransformCoord(defaultRight, cameraRotationYaw);
cameraForward = XMVector3TransformCoord(defaultForward, cameraRotationYaw);
XMVECTOR defaultForward = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
XMVECTOR defaultRight = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f);
XMVECTOR defaultUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
// Pitch (rotation around the X axis) impact the up and forward vectors
XMMATRIX cameraRotationPitch = XMMatrixRotationAxis(cameraRight, _cameraPitch);
cameraUp = XMVector3TransformCoord(defaultUp, cameraRotationPitch);
cameraForward = XMVector3TransformCoord(cameraForward, cameraRotationPitch);
if (_nodeFollowed == nullptr)
{
// Yaw (rotation around the Y axis) will have an impact on the forward and right vectors
XMMATRIX cameraRotationYaw = XMMatrixRotationAxis(defaultUp, _cameraYaw);
cameraRight = XMVector3TransformCoord(defaultRight, cameraRotationYaw);
cameraForward = XMVector3TransformCoord(defaultForward, cameraRotationYaw);
// Roll (rotation around the Z axis) will impact the Up and Right vectors
XMMATRIX cameraRotationRoll = XMMatrixRotationAxis(cameraForward, _cameraRoll);
cameraUp = XMVector3TransformCoord(cameraUp, cameraRotationRoll);
cameraRight = XMVector3TransformCoord(cameraRight, cameraRotationRoll);
// Pitch (rotation around the X axis) impact the up and forward vectors
XMMATRIX cameraRotationPitch = XMMatrixRotationAxis(cameraRight, _cameraPitch);
cameraUp = XMVector3TransformCoord(defaultUp, cameraRotationPitch);
cameraForward = XMVector3TransformCoord(cameraForward, cameraRotationPitch);
// Adjust the camera position by the appropriate amount forward/back and left/right
cameraPosition = XMLoadFloat4(&_cameraPosition) + _moveLeftRight * cameraRight + _moveForwardBack * cameraForward;
XMStoreFloat4(&_cameraPosition, cameraPosition);
// Roll (rotation around the Z axis) will impact the Up and Right vectors
XMMATRIX cameraRotationRoll = XMMatrixRotationAxis(cameraForward, _cameraRoll);
cameraUp = XMVector3TransformCoord(cameraUp, cameraRotationRoll);
cameraRight = XMVector3TransformCoord(cameraRight, cameraRotationRoll);
// Reset the amount we are moving
_moveLeftRight = 0.0f;
_moveForwardBack = 0.0f;
// Adjust the camera position by the appropriate amount forward/back and left/right
cameraPosition = XMLoadFloat4(&_cameraPosition) + _moveLeftRight * cameraRight + _moveForwardBack * cameraForward;
XMStoreFloat4(&_cameraPosition, cameraPosition);
// Calculate a vector that tells us the direction the camera is looking in
cameraTarget = cameraPosition + XMVector3Normalize(cameraForward);
// Reset the amount we are moving
_moveLeftRight = 0.0f;
_moveForwardBack = 0.0f;
// Calculate a vector that tells us the direction the camera is looking in
cameraTarget = cameraPosition + XMVector3Normalize(cameraForward);
}
else
{
if (_followPositionOnly)
{
_cameraYaw = 0.0f;
_cameraPitch = 0.0f;
_cameraRoll = 0.0f;
}
else
{
_cameraYaw = XMConvertToRadians(_nodeFollowed->GetYaw());
_cameraPitch = XMConvertToRadians(_nodeFollowed->GetPitch());
_cameraRoll = XMConvertToRadians(_nodeFollowed->GetRoll());
}
// Yaw (rotation around the Y axis) will have an impact on the forward and right vectors
XMMATRIX cameraRotationYaw = XMMatrixRotationAxis(defaultUp, _cameraYaw);
cameraRight = XMVector3TransformCoord(defaultRight, cameraRotationYaw);
cameraForward = XMVector3TransformCoord(defaultForward, cameraRotationYaw);
// Pitch (rotation around the X axis) impact the up and forward vectors
XMMATRIX cameraRotationPitch = XMMatrixRotationAxis(cameraRight, _cameraPitch);
cameraUp = XMVector3TransformCoord(defaultUp, cameraRotationPitch);
cameraForward = XMVector3TransformCoord(cameraForward, cameraRotationPitch);
// Roll (rotation around the Z axis) will impact the Up and Right vectors
XMMATRIX cameraRotationRoll = XMMatrixRotationAxis(cameraForward, _cameraRoll);
cameraUp = XMVector3TransformCoord(cameraUp, cameraRotationRoll);
cameraRight = XMVector3TransformCoord(cameraRight, cameraRotationRoll);
XMFLOAT4 nodePosition;
XMStoreFloat4(&nodePosition, _nodeFollowed->GetNodePosition());
if (_followPositionOnly)
{
cameraPosition = XMVectorSet(nodePosition.x + _followOffset.x, nodePosition.y + _followOffset.y, nodePosition.z + _followOffset.z, 1.0f);
cameraTarget = cameraPosition + XMVector3Normalize(cameraForward);
}
else
{
XMVECTOR offset = XMVectorSet(_followOffset.x, _followOffset.y, _followOffset.z, 1.0f);
cameraPosition = _nodeFollowed->GetNodePosition() + offset;
cameraTarget = XMLoadFloat4(&nodePosition) + XMVector3Normalize(cameraForward);
}
// Set the camera position
XMStoreFloat4(&_cameraPosition, cameraPosition);
}
// and calculate our view matrix
XMStoreFloat4x4(&_viewMatrix, XMMatrixLookAtLH(cameraPosition, cameraTarget, cameraUp));

View File

@ -1,6 +1,8 @@
#pragma once
#include "core.h"
#include "DirectXCore.h"
#include "SharedMethods.h"
#include "ObjectNode.h"
class Camera
{
@ -11,7 +13,8 @@ public:
void Update();
XMMATRIX GetViewMatrix();
XMVECTOR GetCameraPosition();
XMFLOAT4 GetRawCameraPosition();
void SetCameraPosition(XMVECTOR vectorIn);
void SetCameraPosition(XMFLOAT4 floatIn);
void SetCameraPosition(float x, float y, float z);
void SetPitch(float pitch);
void SetTotalPitch(float pitch);
@ -24,6 +27,7 @@ public:
float GetRoll() const;
void SetLeftRight(float leftRight);
void SetForwardBack(float forwardBack);
void SetFollowNode(shared_ptr<ObjectNode> nodeFollowed, XMFLOAT3 followOffset, bool positionOnly);
private:
XMFLOAT4 _cameraPosition;
@ -37,5 +41,8 @@ private:
float _cameraPitch;
float _cameraRoll;
shared_ptr<ObjectNode> _nodeFollowed;
XMFLOAT3 _followOffset;
bool _followPositionOnly;
};

View File

@ -15,6 +15,7 @@ ColorGradient::~ColorGradient()
// Get the RGBA value at the give point
RGBA ColorGradient::GetRGBAValue(float inputValue)
{
// Check if we are at the start or end, return those values if so
if (inputValue <= _minValue)
{
return _colorSteps.front();
@ -24,10 +25,12 @@ RGBA ColorGradient::GetRGBAValue(float inputValue)
return _colorSteps.back();
}
// Get the point which the input value is at between the entire range
float range = _maxValue - _minValue;
float value = inputValue - _minValue;
float steps = range / (float)(_colorSteps.size() - 1);
// Which gradient step are we in
int colorStepInside = (int)(value / steps);
float normalisedValue = (value - (colorStepInside * steps)) / steps;
@ -38,6 +41,7 @@ RGBA ColorGradient::GetRGBAValue(float inputValue)
// Method for interpolating the color between each step
RGBA ColorGradient::Interpolate(RGBA a, RGBA b, float pointValue)
{
// Check if we are at the start or end, return those values if so
if (pointValue <= 0.0f)
{
return a;
@ -47,10 +51,13 @@ RGBA ColorGradient::Interpolate(RGBA a, RGBA b, float pointValue)
return b;
}
unsigned int currentRed = (unsigned int)((1.0f - pointValue) * a.red + pointValue * b.red);
unsigned int currentGreen = (unsigned int)((1.0f - pointValue) * a.green + pointValue * b.green);
unsigned int currentBlue = (unsigned int)((1.0f - pointValue) * a.blue + pointValue * b.blue);
unsigned int currentAlpha = (unsigned int)((1.0f - pointValue) * a.alpha + pointValue * b.alpha);
//pointValue = SharedMethods::Clamp<float>(pointValue * 1.5f, 0.0f, 1.0f);
// Lerp the color values for each channel between the steps
unsigned int currentRed = (unsigned int)SharedMethods::Lerp<unsigned int>(a.red, b.red, pointValue);
unsigned int currentGreen = (unsigned int)SharedMethods::Lerp<unsigned int>(a.green, b.green, pointValue);
unsigned int currentBlue = (unsigned int)SharedMethods::Lerp<unsigned int>(a.blue, b.blue, pointValue);
unsigned int currentAlpha = (unsigned int)SharedMethods::Lerp<unsigned int>(a.alpha, b.alpha, pointValue);
return RGBA{ currentRed, currentGreen, currentBlue, currentAlpha };
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <vector>
#include "SharedMethods.h"
using namespace std;

View File

@ -0,0 +1,24 @@
#include "ControlledMeshNode.h"
ControlledMeshNode::ControlledMeshNode(wstring name, wstring modelName) : MeshNode(name, modelName), ObjectNode()
{
}
void ControlledMeshNode::Update(FXMMATRIX& currentWorldTransformation)
{
ObjectNode::Update(_worldTransformation);
}
bool ControlledMeshNode::Initialise(void)
{
if (!MeshNode::Initialise())
{
return false;
}
return true;
}
XMMATRIX ControlledMeshNode::GetWorldTransformation() const
{
return XMLoadFloat4x4(&_combinedWorldTransformation);
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "ObjectNode.h"
#include "MeshNode.h"
class ControlledMeshNode : public MeshNode, public ObjectNode
{
public:
ControlledMeshNode(wstring name, wstring modelName);
void Update(FXMMATRIX& currentWorldTransformation);
bool Initialise(void);
XMMATRIX GetWorldTransformation() const;
private:
};

View File

@ -0,0 +1,25 @@
#include "ControlledSplitMeshNode.h"
ControlledSplitMeshNode::ControlledSplitMeshNode(wstring name, wstring modelName) : SplitMeshNode(name, modelName), ObjectNode()
{
}
void ControlledSplitMeshNode::Update(FXMMATRIX& currentWorldTransformation)
{
ObjectNode::Update(_worldTransformation);
SceneGraph::Update(currentWorldTransformation);
}
bool ControlledSplitMeshNode::Initialise(void)
{
if (!SplitMeshNode::Initialise())
{
return false;
}
return true;
}
XMMATRIX ControlledSplitMeshNode::GetWorldTransformation() const
{
return XMLoadFloat4x4(&_combinedWorldTransformation);
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "DirectXFramework.h"
#include "SplitMeshNode.h"
#include "ObjectNode.h"
#include "SubMeshNode.h"
class ControlledSplitMeshNode : public SplitMeshNode, public ObjectNode
{
public:
ControlledSplitMeshNode(wstring name, wstring modelName);
void Update(FXMMATRIX& currentWorldTransformation);
bool Initialise(void);
XMMATRIX GetWorldTransformation() const;
private:
};

View File

@ -67,6 +67,7 @@ bool DirectXFramework::Initialise()
_resourceManager = make_shared<ResourceManager>();
_sceneGraph = make_shared<SceneGraph>();
_camera = make_shared<Camera>();
_globalLighting = make_shared<GlobalLighting>();
CreateSceneGraph();
return _sceneGraph->Initialise();

View File

@ -5,6 +5,7 @@
#include "ResourceManager.h"
#include "SceneGraph.h"
#include "Camera.h"
#include "GlobalLighting.h"
class DirectXFramework : public Framework
{
@ -34,6 +35,7 @@ public:
void SetBackgroundColour(XMFLOAT4 backgroundColour);
inline shared_ptr<Camera> GetCamera() { return _camera; }
inline shared_ptr<GlobalLighting> GetGlobalLighting() { return _globalLighting; }
private:
ComPtr<ID3D11Device> _device;
@ -60,5 +62,6 @@ private:
shared_ptr<ResourceManager> _resourceManager;
shared_ptr<Camera> _camera;
shared_ptr<GlobalLighting> _globalLighting;
};

View File

@ -11,7 +11,7 @@ GamePadController::~GamePadController(void)
{
}
void GamePadController::ProcessGameController()
void GamePadController::ProcessGameController(set<ControlInputs>& currentInputs, bool &boostHit)
{
DWORD magnitudeSquared;
@ -40,11 +40,29 @@ void GamePadController::ProcessGameController()
// check if the controller is inside a circular dead zone. We do it this way to avoid having to
// take the square root of the magnitude above.
if (magnitudeSquared <= _leftThumbDeadZoneSquared)
{
{
thumbLX = 0;
thumbLY = 0;
}
if (thumbLY > 0)
{
currentInputs.insert(ControlInputs::Forward);
}
else if (thumbLY < 0)
{
currentInputs.insert(ControlInputs::Back);
}
if (thumbLX > 0)
{
currentInputs.insert(ControlInputs::StrafeRight);
}
else if (thumbLX < 0)
{
currentInputs.insert(ControlInputs::StrafeLeft);
}
// Deal with the right thumb stick
SHORT thumbRX = _controllerState.Gamepad.sThumbRX;
SHORT thumbRY = _controllerState.Gamepad.sThumbRY;
@ -59,36 +77,64 @@ void GamePadController::ProcessGameController()
thumbRY = 0;
}
if (thumbRY > 0)
{
currentInputs.insert(ControlInputs::Up);
}
else if (thumbRY < 0)
{
currentInputs.insert(ControlInputs::Down);
}
if (thumbRX > 0)
{
currentInputs.insert(ControlInputs::TurnRight);
}
else if (thumbRX < 0)
{
currentInputs.insert(ControlInputs::TurnLeft);
}
// Check left and right triggers
BYTE leftTrigger = _controllerState.Gamepad.bLeftTrigger;
if (leftTrigger <= XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
{
{
leftTrigger = 0;
}
if (leftTrigger > 0)
{
boostHit = true;
}
BYTE rightTrigger = _controllerState.Gamepad.bRightTrigger;
if (rightTrigger <= XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
{
{
rightTrigger = 0;
}
if (rightTrigger)
{
currentInputs.insert(ControlInputs::Fire2);
}
// Test the different digital buttons
WORD buttons = _controllerState.Gamepad.wButtons;
if (buttons & XINPUT_GAMEPAD_DPAD_UP)
{
// Directional pad up pressed
currentInputs.insert(ControlInputs::Forward);
}
if (buttons & XINPUT_GAMEPAD_DPAD_DOWN)
{
// Directional pad down pressed
currentInputs.insert(ControlInputs::Back);
}
if (buttons & XINPUT_GAMEPAD_DPAD_LEFT)
{
// Directional pad left pressed
currentInputs.insert(ControlInputs::TurnLeft);
}
if (buttons & XINPUT_GAMEPAD_DPAD_RIGHT)
{
// Directional pad right pressed
currentInputs.insert(ControlInputs::TurnRight);
}
// Other button mask values that can be used are:

View File

@ -1,15 +1,18 @@
#pragma once
#include <set>
#include "Core.h"
#include "DirectXCore.h"
#include <XInput.h>
#pragma comment(lib, "XInput.lib")
enum class ControlInputs { Forward, Back, TurnLeft, TurnRight, StrafeLeft, StrafeRight, Up, Down, Fire1, Fire2 };
class GamePadController
{
public:
GamePadController();
~GamePadController();
void ProcessGameController();
void ProcessGameController(set<ControlInputs>& currentInputs, bool &boostHit);
private:
XINPUT_STATE _controllerState;

View File

@ -0,0 +1,38 @@
#include "GlobalLighting.h"
GlobalLighting::GlobalLighting()
{
_ambientLight = XMFLOAT4(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);
}
GlobalLighting::~GlobalLighting()
{
}
void GlobalLighting::SetAmbientLight(XMFLOAT4 ambientLight)
{
_ambientLight = ambientLight;
}
XMFLOAT4 GlobalLighting::GetAmbientLight() const
{
return _ambientLight;
}
void GlobalLighting::SetDirectionalLight(FXMVECTOR direction, XMFLOAT4 lightColor)
{
_directionalLightVector = direction;
_directionalLightColor = lightColor;
}
XMVECTOR GlobalLighting::GetDirectionalLightDirection() const
{
return _directionalLightVector;
}
XMFLOAT4 GlobalLighting::GetDirectionalLightColor() const
{
return _directionalLightColor;
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "DirectXCore.h"
class GlobalLighting
{
public:
GlobalLighting();
~GlobalLighting();
void SetAmbientLight(XMFLOAT4 ambientLight);
XMFLOAT4 GetAmbientLight() const;
void SetDirectionalLight(FXMVECTOR direction, XMFLOAT4 lightColor);
XMVECTOR GetDirectionalLightDirection() const;
XMFLOAT4 GetDirectionalLightColor() const;
private:
XMFLOAT4 _ambientLight;
XMVECTOR _directionalLightVector;
XMFLOAT4 _directionalLightColor;
};

View File

@ -4,32 +4,65 @@ Graphics2 app;
void Graphics2::CreateSceneGraph()
{
_boostMultiplier = 1;
_boostMultiplier = _boostMin;
_flySpeed = 1;
_turnSpeed = 1;
_invertPitch = -1;
GetCamera()->SetCameraPosition(0.0f, 550.0f, -80.0f);
_currentController = GamePadController();
_currentPlayerObject = nullptr;
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));
//sceneGraph->Add(cube);
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));
shared_ptr<SkyNode> skyDome = make_shared<SkyNode>(L"SkyDome", L"Textures\\SkyWater.dds", 30.0f);
sceneGraph->Add(skyDome);
shared_ptr<TerrainNode> terrainNode = make_shared<TerrainNode>(L"MainTerrain", L"Textures\\Example_HeightMap.raw", L"lovelycat");
terrainNode->SetAmbientLight(XMFLOAT4(0.7f, 0.7f, 0.7f, 1.0f));
terrainNode->SetDirectionalLight(XMVectorSet(0.5f, -1.0f, -1.0f, 0.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f));
terrainNode->SetWaterColor(XMFLOAT4(SharedMethods::RGBValueToIntensity(0xA4), SharedMethods::RGBValueToIntensity(0xC1), SharedMethods::RGBValueToIntensity(0xF9), 1.0f));
//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);
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));
//terrainNode->SetWaterColor(XMFLOAT4(1.0f, 0.0f, 0.8f, 1.0f));
//terrainNode->SetWaterColor(XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f));
sceneGraph->Add(terrainNode);
shared_ptr<SplitMeshNode> node = make_shared<SplitMeshNode>(L"Plane1", L"Models\\Plane\\Bonanza.3DS");
//shared_ptr<MeshNode> node = make_shared<MeshNode>(L"Plane1", L"Models\\Plane\\Bonanza.3DS");
node->SetWorldTransform(XMMatrixTranslation(-30.0f, 520.0f, 0));
sceneGraph->Add(node);
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);
sceneGraph->Add(plane1Node);
//_currentPlayerObject = plane1Node;
//GetCamera()->SetFollowNode(plane1Node, XMFLOAT3(0.0f, 30.0f, -80.0f), false);
SetBackgroundColour(XMFLOAT4(0.29f, 0.38f, 0.72f, 1.0f));
//SetBackgroundColour(XMFLOAT4(SharedMethods::RGBValueToIntensity(0x89), 0, 1, 1));
@ -44,47 +77,103 @@ void Graphics2::UpdateSceneGraph()
GetCurrentControlInputs();
SceneGraphPointer sceneGraph = GetSceneGraph();
XMVECTOR startCameraPos = GetCamera()->GetCameraPosition();
if (_currentPlayerObject != nullptr)
{
_currentPlayerObject->SetForwardBack(_flySpeed * _boostMultiplier);
}
for (ControlInputs currentControl : _currentInputs)
{
switch (currentControl)
{
case ControlInputs::Forward:
GetCamera()->SetForwardBack(_flySpeed * _boostMultiplier);
if (_currentPlayerObject == nullptr)
{
GetCamera()->SetForwardBack(_flySpeed * _boostMultiplier);
}
break;
case ControlInputs::Back:
GetCamera()->SetForwardBack(-_flySpeed * _boostMultiplier);
if (_currentPlayerObject == nullptr)
{
GetCamera()->SetForwardBack(-_flySpeed * _boostMultiplier);
}
break;
case ControlInputs::StrafeLeft:
GetCamera()->SetLeftRight(-_flySpeed * _boostMultiplier);
if (_currentPlayerObject != nullptr)
{
_currentPlayerObject->SetLeftRight(-_flySpeed * _boostMultiplier);
}
else
{
GetCamera()->SetLeftRight(-_flySpeed * _boostMultiplier);
}
break;
case ControlInputs::StrafeRight:
GetCamera()->SetLeftRight(_flySpeed * _boostMultiplier);
if (_currentPlayerObject != nullptr)
{
_currentPlayerObject->SetLeftRight(_flySpeed * _boostMultiplier);
}
else
{
GetCamera()->SetLeftRight(_flySpeed * _boostMultiplier);
}
break;
case ControlInputs::TurnLeft:
GetCamera()->SetYaw(-_turnSpeed);
if (_currentPlayerObject != nullptr)
{
_currentPlayerObject->SetYaw(-_turnSpeed);
}
else
{
GetCamera()->SetYaw(-_turnSpeed);
}
break;
case ControlInputs::TurnRight:
GetCamera()->SetYaw(_turnSpeed);
if (_currentPlayerObject != nullptr)
{
_currentPlayerObject->SetYaw(_turnSpeed);
}
else
{
GetCamera()->SetYaw(_turnSpeed);
}
break;
case ControlInputs::Up:
GetCamera()->SetPitch(_turnSpeed * _invertPitch);
if (_currentPlayerObject != nullptr)
{
_currentPlayerObject->SetPitch(_turnSpeed * _invertPitch);
}
else
{
GetCamera()->SetPitch(_turnSpeed * _invertPitch);
}
break;
case ControlInputs::Down:
GetCamera()->SetPitch(-_turnSpeed * _invertPitch);
if (_currentPlayerObject != nullptr)
{
_currentPlayerObject->SetPitch(-_turnSpeed * _invertPitch);
}
else
{
GetCamera()->SetPitch(-_turnSpeed * _invertPitch);
}
break;
}
}
SceneNodePointer plane1 = sceneGraph->Find(L"Plane1");
shared_ptr<ControlledSplitMeshNode> plane1 = dynamic_pointer_cast<ControlledSplitMeshNode>(sceneGraph->Find(L"Plane1"));
plane1->GetFirstChild()->SetWorldTransform(SharedMethods::RotateFromPoint(-60.0f, 0, 0, XMMatrixRotationAxis(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), _currentRotation * XM_PI / 180.0f)));
plane1 ->GetFirstChild()->AddToWorldTransform(XMMatrixRotationAxis(XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f), 90.0f * 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));
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->AddToWorldTransform(XMMatrixRotationAxis(XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f), 90.0f * 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));
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)));
//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));
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)));
}
if (_currentRotation == 360)
{
@ -99,6 +188,61 @@ void Graphics2::UpdateSceneGraph()
_currentPropRotation += 100;
}
// Check the camera and our terrain boundaries
XMVECTOR currentCameraPos = GetCamera()->GetCameraPosition();
shared_ptr<TerrainNode> mainTerrain = dynamic_pointer_cast<TerrainNode>(sceneGraph->Find(L"MainTerrain"));
GetCamera()->Update();
if (mainTerrain != nullptr)
{
bool boundaryHit = false;
XMFLOAT4 cameraOffset = XMFLOAT4(XMVectorGetX(startCameraPos), XMVectorGetY(startCameraPos), XMVectorGetZ(startCameraPos), 0.0f);
if (XMVectorGetY(currentCameraPos) < mainTerrain->GetHeightAtPoint(XMVectorGetX(currentCameraPos), XMVectorGetZ(currentCameraPos), true) + 4.0f)
{
cameraOffset.y = cameraOffset.y + 4.0f;
boundaryHit = true;
}
float currentCameraXPos = XMVectorGetX(currentCameraPos);
float xOffset = 150.0f;
if (currentCameraXPos > 0)
{
xOffset = -xOffset;
}
float currentCameraZPos = XMVectorGetZ(currentCameraPos);
float zOffset = 150.0f;
if (currentCameraZPos > 0)
{
zOffset = -zOffset;
}
if (!mainTerrain->CheckXBoundary(currentCameraXPos + -xOffset))
{
cameraOffset.x = cameraOffset.x + xOffset;
boundaryHit = true;
}
if (!mainTerrain->CheckZBoundary(currentCameraZPos + -zOffset))
{
cameraOffset.z = cameraOffset.z + zOffset;
boundaryHit = true;
}
if (boundaryHit)
{
if (_currentPlayerObject != nullptr)
{
_currentPlayerObject->SetNodePosition(cameraOffset);
}
else
{
GetCamera()->SetCameraPosition(cameraOffset);
}
}
}
// Reset the control array ready for the next frames input
ResetCurrentControlInputs();
}
@ -107,61 +251,67 @@ void Graphics2::GetCurrentControlInputs()
// Check if the window has focus before accepting any keypresses
if (GetForegroundWindow() == Framework::GetHWnd())
{
if (GetAsyncKeyState(VK_SHIFT))
// Check if any connected controllers have inputs
bool boostHit = false;
_currentController.ProcessGameController(_currentInputs, boostHit);
if (GetAsyncKeyState(VK_SHIFT) || boostHit)
{
_boostMultiplier = 2;
_currentInputs.insert(ControlInputs::Fire1);
_boostMultiplier = SharedMethods::Clamp<float>(_boostMultiplier + _boostStep, 1, _boostMax);
}
else
{
_boostMultiplier = 1;
_boostMultiplier = SharedMethods::Clamp<float>(_boostMultiplier - _boostStep, 1, _boostMax);
}
// Forward
if (GetAsyncKeyState(0x57))
{
_currentInputs.push_back(ControlInputs::Forward);
_currentInputs.insert(ControlInputs::Forward);
}
// Back
if (GetAsyncKeyState(0x53))
{
_currentInputs.push_back(ControlInputs::Back);
_currentInputs.insert(ControlInputs::Back);
}
// Turn Left
if (GetAsyncKeyState(0x41))
{
_currentInputs.push_back(ControlInputs::TurnLeft);
_currentInputs.insert(ControlInputs::TurnLeft);
}
// Turn Right
if (GetAsyncKeyState(0x44))
{
_currentInputs.push_back(ControlInputs::TurnRight);
_currentInputs.insert(ControlInputs::TurnRight);
}
// Strafe Left
if (GetAsyncKeyState(0x51))
{
_currentInputs.push_back(ControlInputs::StrafeLeft);
_currentInputs.insert(ControlInputs::StrafeLeft);
}
// Strafe Right
if (GetAsyncKeyState(0x45))
{
_currentInputs.push_back(ControlInputs::StrafeRight);
_currentInputs.insert(ControlInputs::StrafeRight);
}
// "Jump"
if (GetAsyncKeyState(VK_SPACE))
{
_currentInputs.push_back(ControlInputs::Up);
_currentInputs.insert(ControlInputs::Up);
}
// "Crouch"
if (GetAsyncKeyState(VK_CONTROL))
{
_currentInputs.push_back(ControlInputs::Down);
_currentInputs.insert(ControlInputs::Down);
}
}
}

View File

@ -1,13 +1,16 @@
#pragma once
#include "DirectXFramework.h"
#include "SharedMethods.h"
#include "GamePadController.h"
#include "TexturedCubeNode.h"
#include "MeshNode.h"
#include "SplitMeshNode.h"
#include "TerrainNode.h"
#include "ControlledSplitMeshNode.h"
#include "HeightMapTerrainNode.h"
#include "PerlinTerrainNode.h"
#include "SkyNode.h"
#include <ctime>
enum class ControlInputs {Forward, Back, TurnLeft, TurnRight, StrafeLeft, StrafeRight, Up, Down, Fire1, Fire2};
#include <set>
class Graphics2 : public DirectXFramework
{
@ -16,19 +19,26 @@ public:
void UpdateSceneGraph();
private:
bool _boosting;
float _boostMultiplier;
bool _boosting = false;
float _boostMultiplier = 1;
float _boostMin = 1;
float _boostStep = 0.5f;
float _boostMax = 5.0f;
float _flySpeed;
float _turnSpeed;
int _invertPitch;
float _currentRotation = 0.0f;
float _currentSideRotation = 0.0f;
float _currentPropRotation = 0.0f;
vector<ControlInputs> _currentInputs;
GamePadController _currentController;
// Changed from a vector to a set because sets only allow for unique values and thats all i want
set<ControlInputs> _currentInputs;
shared_ptr<ObjectNode> _currentPlayerObject;
void GetCurrentControlInputs();
void ResetCurrentControlInputs();

View File

@ -82,6 +82,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..\Assimp\include;$(IncludePath);</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@ -128,7 +129,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
@ -146,18 +147,22 @@
<ItemGroup>
<ClInclude Include="Camera.h" />
<ClInclude Include="ColorGradient.h" />
<ClInclude Include="ControlledMeshNode.h" />
<ClInclude Include="ControlledSplitMeshNode.h" />
<ClInclude Include="Core.h" />
<ClInclude Include="DDSTextureLoader.h" />
<ClInclude Include="DirectXCore.h" />
<ClInclude Include="Framework.h" />
<ClInclude Include="DirectXFramework.h" />
<ClInclude Include="GamePadController.h" />
<ClInclude Include="GlobalLighting.h" />
<ClInclude Include="Graphics2.h" />
<ClInclude Include="HeightMapTerrainNode.h" />
<ClInclude Include="HelperFunctions.h" />
<ClInclude Include="Mesh.h" />
<ClInclude Include="MeshNode.h" />
<ClInclude Include="MeshRenderer.h" />
<ClInclude Include="ObjectNode.h" />
<ClInclude Include="PerlinTerrainNode.h" />
<ClInclude Include="Renderer.h" />
<ClInclude Include="resource.h" />
@ -165,6 +170,7 @@
<ClInclude Include="SceneGraph.h" />
<ClInclude Include="SceneNode.h" />
<ClInclude Include="SharedMethods.h" />
<ClInclude Include="SkyNode.h" />
<ClInclude Include="SplitMeshNode.h" />
<ClInclude Include="SubMeshNode.h" />
<ClInclude Include="SubMeshRenderer.h" />
@ -188,19 +194,24 @@
<ItemGroup>
<ClCompile Include="Camera.cpp" />
<ClCompile Include="ColorGradient.cpp" />
<ClCompile Include="ControlledMeshNode.cpp" />
<ClCompile Include="ControlledSplitMeshNode.cpp" />
<ClCompile Include="DDSTextureLoader.cpp" />
<ClCompile Include="Framework.cpp" />
<ClCompile Include="DirectXFramework.cpp" />
<ClCompile Include="GamePadController.cpp" />
<ClCompile Include="GlobalLighting.cpp" />
<ClCompile Include="Graphics2.cpp" />
<ClCompile Include="HeightMapTerrainNode.cpp" />
<ClCompile Include="Mesh.cpp" />
<ClCompile Include="MeshNode.cpp" />
<ClCompile Include="MeshRenderer.cpp" />
<ClCompile Include="ObjectNode.cpp" />
<ClCompile Include="PerlinTerrainNode.cpp" />
<ClCompile Include="ResourceManager.cpp" />
<ClCompile Include="SceneGraph.cpp" />
<ClCompile Include="SharedMethods.cpp" />
<ClCompile Include="SkyNode.cpp" />
<ClCompile Include="SplitMeshNode.cpp" />
<ClCompile Include="SubMeshNode.cpp" />
<ClCompile Include="SubMeshRenderer.cpp" />
@ -232,6 +243,11 @@
<FileType>Document</FileType>
</Text>
</ItemGroup>
<ItemGroup>
<Text Include="SkyShader.hlsl">
<FileType>Document</FileType>
</Text>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -102,6 +102,21 @@
<ClInclude Include="HeightMapTerrainNode.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SkyNode.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ControlledSplitMeshNode.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ObjectNode.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ControlledMeshNode.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GlobalLighting.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Graphics2.rc">
@ -195,6 +210,21 @@
<ClCompile Include="HeightMapTerrainNode.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SkyNode.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ControlledSplitMeshNode.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ObjectNode.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ControlledMeshNode.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GlobalLighting.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="shader.hlsl">
@ -209,6 +239,9 @@
<Text Include="TerrainShadersNoBlend.hlsl">
<Filter>Shaders</Filter>
</Text>
<Text Include="SkyShader.hlsl">
<Filter>Shaders</Filter>
</Text>
</ItemGroup>
<ItemGroup>
<None Include="assimp-vc140-mt.dll" />

View File

@ -0,0 +1,36 @@
#include "HeightMapTerrainNode.h"
#define WORLD_HEIGHT 1024
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;
if (!LoadHeightMap(_heightMap))
{
_initError = true;
}
}
bool HeightMapTerrainNode::LoadHeightMap(wstring heightMapFilename)
{
unsigned int mapSize = _gridCols * _gridRows;
USHORT* rawFileValues = new USHORT[mapSize];
std::ifstream inputHeightMap;
inputHeightMap.open(heightMapFilename.c_str(), std::ios_base::binary);
if (!inputHeightMap)
{
return false;
}
inputHeightMap.read((char*)rawFileValues, mapSize * 2);
inputHeightMap.close();
// Normalise BYTE values to the range 0.0f - 1.0f;
for (unsigned int i = 0; i < mapSize; i++)
{
_heightValues.push_back((float)rawFileValues[i] / 65536);
}
delete[] rawFileValues;
return true;
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "DirectXFramework.h"
#include "SharedMethods.h"
#include "TerrainNode.h"
class HeightMapTerrainNode : public TerrainNode
{
public:
HeightMapTerrainNode(wstring name, wstring heightMap, wstring seed, float waterHeight = 150.0f, int widthX = 1023, int widthZ = 1023, int cellSizeX = 10, int cellSizeZ = 10);
private:
wstring _heightMap;
bool LoadHeightMap(wstring heightMapFilename);
};

View File

@ -21,9 +21,8 @@ void MeshNode::Render()
{
_renderer->SetMesh(_mesh);
_renderer->SetWorldTransformation(XMLoadFloat4x4(&_combinedWorldTransformation));
_renderer->SetCameraPosition(DirectXFramework::GetDXFramework()->GetCamera()->GetRawCameraPosition());
_renderer->SetAmbientLight(XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f));
_renderer->SetDirectionalLight(XMVectorSet(0.0f, -1.0f, 1.0f, 0.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f));
_renderer->SetAmbientLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetAmbientLight());
_renderer->SetDirectionalLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightDirection(), DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightColor());
_renderer->Render();
}

View File

@ -101,7 +101,7 @@ void MeshRenderer::Render()
_cBuffer.ambientColor = _ambientLight;
_cBuffer.lightVector = XMVector4Normalize(XMLoadFloat4(&_directionalLightVector));
_cBuffer.lightColor = _directionalLightColour;
_cBuffer.cameraPosition = _cameraPosition;
XMStoreFloat4(&_cBuffer.cameraPosition, DirectXFramework::GetDXFramework()->GetCamera()->GetCameraPosition());
_deviceContext->VSSetShader(_vertexShader.Get(), 0, 0);
_deviceContext->PSSetShader(_pixelShader.Get(), 0, 0);

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

132
Graphics2/ObjectNode.cpp Normal file
View File

@ -0,0 +1,132 @@
#include "ObjectNode.h"
ObjectNode::ObjectNode()
{
_nodeRootPosition = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
_moveLeftRight = 0.0f;
_moveForwardBack = 0.0f;
_nodeYaw = 0.0f;
_nodePitch = 0.0f;
_nodeRoll = 0.0f;
XMStoreFloat4x4(&_originalOrientation, XMMatrixIdentity());
}
void ObjectNode::Update(XMFLOAT4X4& currentWorldTransform)
{
XMVECTOR nodePosition;
XMVECTOR nodeRight;
XMVECTOR nodeForward;
XMVECTOR nodeUp;
XMVECTOR defaultForward = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
XMVECTOR defaultRight = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f);
XMVECTOR defaultUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
// Yaw (rotation around the Y axis) will have an impact on the forward and right vectors
XMMATRIX nodeRotationYaw = XMMatrixRotationAxis(defaultUp, _nodeYaw);
nodeRight = XMVector3TransformCoord(defaultRight, nodeRotationYaw);
nodeForward = XMVector3TransformCoord(defaultForward, nodeRotationYaw);
// Pitch (rotation around the X axis) impact the up and forward vectors
XMMATRIX nodeRotationPitch = XMMatrixRotationAxis(nodeRight, _nodePitch);
nodeUp = XMVector3TransformCoord(defaultUp, nodeRotationPitch);
nodeForward = XMVector3TransformCoord(nodeForward, nodeRotationPitch);
// Roll (rotation around the Z axis) will impact the Up and Right vectors
XMMATRIX nodeRotationRoll = XMMatrixRotationAxis(nodeForward, _nodeRoll);
nodeUp = XMVector3TransformCoord(nodeUp, nodeRotationRoll);
nodeRight = XMVector3TransformCoord(nodeRight, nodeRotationRoll);
// Adjust the node position by the appropriate amount forward/back and left/right
nodePosition = XMLoadFloat4(&_nodeRootPosition) + _moveLeftRight * nodeRight + _moveForwardBack * nodeForward;
XMStoreFloat4(&_nodeRootPosition, nodePosition);
// Reset the amount we are moving
_moveLeftRight = 0.0f;
_moveForwardBack = 0.0f;
XMMATRIX worldTransformation = XMLoadFloat4x4(&_originalOrientation) * nodeRotationYaw * nodeRotationPitch * nodeRotationRoll * XMMatrixTranslation(_nodeRootPosition.x, _nodeRootPosition.y, _nodeRootPosition.z);
XMStoreFloat4x4(&currentWorldTransform, worldTransformation);
}
void ObjectNode::SetPitch(float pitch)
{
_nodePitch += XMConvertToRadians(pitch);
}
void ObjectNode::SetTotalPitch(float pitch)
{
_nodePitch = XMConvertToRadians(pitch);
}
float ObjectNode::GetPitch() const
{
return XMConvertToDegrees(_nodePitch);
}
void ObjectNode::SetYaw(float yaw)
{
_nodeYaw += XMConvertToRadians(yaw);
}
void ObjectNode::SetTotalYaw(float yaw)
{
_nodeYaw = XMConvertToRadians(yaw);
}
float ObjectNode::GetYaw() const
{
return XMConvertToDegrees(_nodeYaw);
}
void ObjectNode::SetRoll(float roll)
{
_nodeRoll += XMConvertToRadians(roll);
}
void ObjectNode::SetTotalRoll(float roll)
{
_nodeRoll = XMConvertToRadians(roll);
}
float ObjectNode::GetRoll() const
{
return XMConvertToDegrees(_nodeRoll);
}
void ObjectNode::SetLeftRight(float leftRight)
{
_moveLeftRight = leftRight;
}
void ObjectNode::SetForwardBack(float forwardBack)
{
_moveForwardBack = forwardBack;
}
XMVECTOR ObjectNode::GetNodePosition(void)
{
return XMLoadFloat4(&_nodeRootPosition);
}
void ObjectNode::SetNodePosition(float x, float y, float z)
{
SetNodePosition(XMFLOAT4(x, y, z, 0.0f));
}
void ObjectNode::SetNodePosition(XMVECTOR vectorIn)
{
XMFLOAT4 floatIn;
XMStoreFloat4(&floatIn, vectorIn);
SetNodePosition(floatIn);
}
void ObjectNode::SetNodePosition(XMFLOAT4 floatIn)
{
_nodeRootPosition = floatIn;
}
void ObjectNode::SetStartOrientation(FXMMATRIX originalOrientation)
{
XMStoreFloat4x4(&_originalOrientation, originalOrientation);
}

40
Graphics2/ObjectNode.h Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include "DirectXCore.h"
class ObjectNode
{
public:
ObjectNode();
void Update(XMFLOAT4X4& currentWorldTransform);
XMVECTOR GetNodePosition();
void SetNodePosition(XMVECTOR vectorIn);
void SetNodePosition(XMFLOAT4 floatIn);
void SetNodePosition(float x, float y, float z);
void SetPitch(float pitch);
void SetTotalPitch(float pitch);
float GetPitch() const;
void SetYaw(float yaw);
void SetTotalYaw(float yaw);
float GetYaw() const;
void SetRoll(float roll);
void SetTotalRoll(float roll);
float GetRoll() const;
void SetLeftRight(float leftRight);
void SetForwardBack(float forwardBack);
void SetStartOrientation(FXMMATRIX originalOrientation);
protected:
XMFLOAT4 _nodeRootPosition;
float _moveLeftRight;
float _moveForwardBack;
float _nodeYaw;
float _nodePitch;
float _nodeRoll;
XMFLOAT4X4 _originalOrientation;
};

View File

@ -0,0 +1,135 @@
#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)
{
_offsetX = offsetX;
_offsetY = offsetY;
_chunkSize = chunkSize;
_layers = layers;
GeneratePerlinValues();
if (!GeneratePerlinHeights())
{
_initError = true;
}
}
// 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;
for (int x = 0; x < _gridCols; x++)
{
float mapX = ((float)x / (float)_gridCols) + 0.5f;
float currentHeightValue = GetPerlinValueAt(_offsetX + mapX, _offsetY + mapZ, 8, 0.85f) - 0.25f;
//currentHeightValue = currentHeightValue - floor(currentHeightValue);
_heightValues.push_back(currentHeightValue);
}
}
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);
}
float PerlinTerrainNode::Grad(int hash, float x, float y)
{
// Fast Grad switch check converted from a java implimentation of perlin noise
switch (hash & 0xF)
{
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
}
}
// 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++)
{
total += (GetNoiseValueAt(x * frequency, y * frequency) * amplitude);
maxValue += amplitude;
amplitude *= persistance;
frequency *= 2;
}
return total / maxValue;
}
// 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 x1 = x0 + 1;
int y1 = y0 + 1;
float dx = x - (float)x0;
float dy = y - (float)y0;
float u = Fade(dx);
float v = Fade(dy);
int aa = p[p[x0] + y0];
int ab = p[p[x0] + y1];
int ba = p[p[x1] + y0];
int bb = p[p[x1] + y1];
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;
}

View File

@ -0,0 +1,29 @@
#pragma once
#include "DirectXFramework.h"
#include <vector>
#include <numeric>
#include <random>
#include "SharedMethods.h"
#include "TerrainNode.h"
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);
private:
vector<int> p;
float _offsetX;
float _offsetY;
float _chunkSize;
int _layers;
float Fade(float t);
float Grad(int hash, float x, float y);
bool GeneratePerlinHeights();
float GetPerlinValueAt(float x, float y, int octaves, float persistance);
float GetNoiseValueAt(float x, float y);
void GeneratePerlinValues();
};

View File

@ -87,4 +87,9 @@ SceneNodePointer SceneGraph::GetFirstChild()
firstChild = _children.front();
}
return firstChild;
}
list<SceneNodePointer>& SceneGraph::GetChildren()
{
return _children;
}

View File

@ -21,7 +21,9 @@ public:
SceneNodePointer GetParent();
SceneNodePointer GetFirstChild();
private:
list<SceneNodePointer>& GetChildren();
protected:
// Here you need to add whatever collection you are going to
// use to store the children of this scene graph
list<SceneNodePointer> _children;

View File

@ -1,28 +1,19 @@
#include "SharedMethods.h"
XMMATRIX SharedMethods::RotateFromPoint(float x, float y, float z, XMMATRIX rotationMatrix)
XMMATRIX SharedMethods::RotateFromPoint(const float x, const float y, const float z, const XMMATRIX rotationMatrix)
{
// Translates a matrix to a point, rotates and then returns back to where it was
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
float SharedMethods::RGBValueToIntensity(int value)
float SharedMethods::RGBValueToIntensity(const int value)
{
return (float)value / 255.0f;
}
float SharedMethods::Lerp(int a, int b, int p)
{
return Lerp((float)a, (float)b, (float)p);
}
float SharedMethods::Lerp(float a, float b, float p)
{
return a + p * (b - a);
}
float SharedMethods::GenerateRandomIntensity(float min, float max)
// Method to generate a random intensity rating between 2 floats
float SharedMethods::GenerateRandomIntensity(const float min, const float max)
{
float randNo = (float)rand() / (float)RAND_MAX;
float rangeDiff = max - min;
@ -31,19 +22,8 @@ float SharedMethods::GenerateRandomIntensity(float min, float max)
return (float)roundedNo * 0.01f;
}
float SharedMethods::GenerateRandomUV(int min, int max)
{
int randNo = rand() % ((max - min) + 1) + min;
float finalNo;
if (randNo < max)
{
int randMan = rand() % 90;
finalNo = (float)(randNo * 0.1f) + (randMan * 0.01f);
}
else
{
finalNo = (float)randNo * 0.1f;
}
return finalNo;
// Method for genering random UV's, maybe get rid of this in future
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);
}

View File

@ -1,5 +1,5 @@
#pragma once
#include "DirectXFramework.h"
#include "DirectXCore.h"
struct CBUFFER
{
@ -16,33 +16,45 @@ struct CBUFFER
float padding[2];
};
struct TCBUFFER
{
XMMATRIX completeTransformation;
XMMATRIX worldTransformation;
XMFLOAT4 cameraPosition;
XMVECTOR lightVector;
XMFLOAT4 lightColor;
XMFLOAT4 ambientColor;
XMFLOAT4 diffuseCoefficient;
XMFLOAT4 specularCoefficient;
float shininess;
float opacity;
float waterHeight;
float waterShininess;
XMFLOAT4 waterColor;
float padding[4];
};
namespace SharedMethods
{
XMMATRIX RotateFromPoint(float x, float y, float z, XMMATRIX rotationMatrix);
XMMATRIX RotateFromPoint(const float x, const float y, const float z, const XMMATRIX rotationMatrix);
float RGBValueToIntensity(int value);
float Lerp(int a, int b, int p);
float Lerp(float a, float b, float p);
float RGBValueToIntensity(const int value);
template <typename T = float> T Clamp(const T value, const T min, const T max)
{
if (value < min)
{
return min;
}
else if (value > max)
{
return max;
}
else
{
return value;
}
}
float GenerateRandomIntensity(float min, float max);
float GenerateRandomUV(int min, int max);
// Methods for lerping values
template <typename T = float> float Lerp(const T a, const T b, const float p)
{
return (float)a + p * ((float)b - (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 q = ((float)n0 - (float)n1) - p;
float r = (float)n2 - (float)n0;
float s = (float)n1;
return p * a * a * a + q * a * a + r * a + s;
}
float GenerateRandomIntensity(const float min, const float max);
float GenerateRandomUV(const float min, const float max);
};

291
Graphics2/SkyNode.cpp Normal file
View File

@ -0,0 +1,291 @@
#include "SkyNode.h"
SkyNode::SkyNode(wstring name, wstring skyCubeTextureName, float skyRadius) : SceneNode(name)
{
_skyCubeTextureName = skyCubeTextureName;
_skyRadius = skyRadius;
}
SkyNode::~SkyNode()
{
}
bool SkyNode::Initialise()
{
_device = DirectXFramework::GetDXFramework()->GetDevice();
_deviceContext = DirectXFramework::GetDXFramework()->GetDeviceContext();
if (_device.Get() == nullptr || _deviceContext.Get() == nullptr)
{
return false;
}
CreateSphere(_skyRadius, 180);
GenerateBuffers();
BuildShaders();
BuildVertexLayout();
BuildConstantBuffer();
BuildRendererStates();
BuildDepthStencilState();
LoadSkyboxTexture();
return true;
}
void SkyNode::CreateSphere(float radius, size_t tessellation)
{
_skyDomeVerts.clear();
_indices.clear();
size_t verticalSegments = tessellation;
size_t horizontalSegments = tessellation * 2;
// Create rings of vertices at progressively higher latitudes.
for (size_t i = 0; i <= verticalSegments; i++)
{
float v = 1 - (float)i / verticalSegments;
float latitude = (i * XM_PI / verticalSegments) - XM_PIDIV2;
float dy, dxz;
XMScalarSinCos(&dy, &dxz, latitude);
// Create a single ring of vertices at this latitude.
for (size_t j = 0; j <= horizontalSegments; j++)
{
float u = (float)j / horizontalSegments;
float longitude = j * XM_2PI / horizontalSegments;
float dx, dz;
XMScalarSinCos(&dx, &dz, longitude);
dx *= dxz;
dz *= dxz;
SkyVertex vertex;
vertex.Position.x = dx * radius;
vertex.Position.y = dy * radius;
vertex.Position.z = dz * radius;
_skyDomeVerts.push_back(vertex);
}
}
// Fill the index buffer with triangles joining each pair of latitude rings.
size_t stride = horizontalSegments + 1;
for (size_t i = 0; i < verticalSegments; i++)
{
for (size_t j = 0; j <= horizontalSegments; j++)
{
size_t nextI = i + 1;
size_t nextJ = (j + 1) % stride;
_indices.push_back((UINT)(i * stride + j));
_indices.push_back((UINT)(nextI * stride + j));
_indices.push_back((UINT)(i * stride + nextJ));
_indices.push_back((UINT)(i * stride + nextJ));
_indices.push_back((UINT)(nextI * stride + j));
_indices.push_back((UINT)(nextI * stride + nextJ));
}
}
_vertexCount = (unsigned int)_skyDomeVerts.size();
_indicesCount = (unsigned int)_indices.size();
}
void SkyNode::GenerateBuffers()
{
// Setup the structure that specifies how big the vertex
// buffer should be
D3D11_BUFFER_DESC vertexBufferDescriptor;
vertexBufferDescriptor.Usage = D3D11_USAGE_IMMUTABLE;
vertexBufferDescriptor.ByteWidth = sizeof(SkyVertex) * _vertexCount;
vertexBufferDescriptor.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDescriptor.CPUAccessFlags = 0;
vertexBufferDescriptor.MiscFlags = 0;
vertexBufferDescriptor.StructureByteStride = 0;
// Now set up a structure that tells DirectX where to get the
// data for the vertices from
D3D11_SUBRESOURCE_DATA vertexInitialisationData;
vertexInitialisationData.pSysMem = &_skyDomeVerts[0];
// and create the vertex buffer
ThrowIfFailed(_device->CreateBuffer(&vertexBufferDescriptor, &vertexInitialisationData, _vertexBuffer.GetAddressOf()));
// Setup the structure that specifies how big the index
// buffer should be
D3D11_BUFFER_DESC indexBufferDescriptor;
indexBufferDescriptor.Usage = D3D11_USAGE_IMMUTABLE;
indexBufferDescriptor.ByteWidth = sizeof(UINT) * _indicesCount;
indexBufferDescriptor.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDescriptor.CPUAccessFlags = 0;
indexBufferDescriptor.MiscFlags = 0;
indexBufferDescriptor.StructureByteStride = 0;
// Now set up a structure that tells DirectX where to get the
// data for the indices from
D3D11_SUBRESOURCE_DATA indexInitialisationData;
indexInitialisationData.pSysMem = &_indices[0];
// and create the index buffer
ThrowIfFailed(_device->CreateBuffer(&indexBufferDescriptor, &indexInitialisationData, _indexBuffer.GetAddressOf()));
}
void SkyNode::Render()
{
XMMATRIX projectionTransformation = DirectXFramework::GetDXFramework()->GetProjectionTransformation();
XMMATRIX viewTransformation = DirectXFramework::GetDXFramework()->GetCamera()->GetViewMatrix();
XMFLOAT4 cameraPosition;
XMStoreFloat4(&cameraPosition, DirectXFramework::GetDXFramework()->GetCamera()->GetCameraPosition());
XMMATRIX skyWorldTransformation = XMMatrixTranslation(cameraPosition.x, cameraPosition.y, cameraPosition.z);
XMMATRIX completeTransformation = skyWorldTransformation * viewTransformation * projectionTransformation;
// Draw the first cube
SCBUFFER cBuffer;
cBuffer.completeTransformation = completeTransformation;
_deviceContext->PSSetShaderResources(0, 1, _skyCubeTexture.GetAddressOf());
_deviceContext->VSSetShader(_vertexShader.Get(), 0, 0);
_deviceContext->PSSetShader(_pixelShader.Get(), 0, 0);
_deviceContext->IASetInputLayout(_layout.Get());
UINT stride = sizeof(SkyVertex);
UINT offset = 0;
_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer.GetAddressOf(), &stride, &offset);
_deviceContext->IASetIndexBuffer(_indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
// Update the constant buffer
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
_deviceContext->UpdateSubresource(_constantBuffer.Get(), 0, 0, &cBuffer, 0, 0);
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
_deviceContext->RSSetState(_noCullRasteriserState.Get());
_deviceContext->OMSetDepthStencilState(_stencilState.Get(), 1);
_deviceContext->DrawIndexed(_indicesCount, 0, 0);
_deviceContext->OMSetDepthStencilState(nullptr, 1);
_deviceContext->RSSetState(_defaultRasteriserState.Get());
}
void SkyNode::Shutdown(void)
{
}
void SkyNode::BuildShaders()
{
DWORD shaderCompileFlags = 0;
#if defined( _DEBUG )
shaderCompileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#endif
ComPtr<ID3DBlob> compilationMessages = nullptr;
//Compile vertex shader
HRESULT hr = D3DCompileFromFile(L"SkyShader.hlsl",
nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
"VS", "vs_5_0",
shaderCompileFlags, 0,
_vertexShaderByteCode.GetAddressOf(),
compilationMessages.GetAddressOf());
if (compilationMessages.Get() != nullptr)
{
// If there were any compilation messages, display them
MessageBoxA(0, (char*)compilationMessages->GetBufferPointer(), 0, 0);
}
// Even if there are no compiler messages, check to make sure there were no other errors.
ThrowIfFailed(hr);
ThrowIfFailed(_device->CreateVertexShader(_vertexShaderByteCode->GetBufferPointer(), _vertexShaderByteCode->GetBufferSize(), NULL, _vertexShader.GetAddressOf()));
// Compile pixel shader
hr = D3DCompileFromFile(L"SkyShader.hlsl",
nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
"PS", "ps_5_0",
shaderCompileFlags, 0,
_pixelShaderByteCode.GetAddressOf(),
compilationMessages.GetAddressOf());
if (compilationMessages.Get() != nullptr)
{
// If there were any compilation messages, display them
MessageBoxA(0, (char*)compilationMessages->GetBufferPointer(), 0, 0);
}
ThrowIfFailed(hr);
ThrowIfFailed(_device->CreatePixelShader(_pixelShaderByteCode->GetBufferPointer(), _pixelShaderByteCode->GetBufferSize(), NULL, _pixelShader.GetAddressOf()));
}
void SkyNode::BuildVertexLayout()
{
// Create the vertex input layout. This tells DirectX the format
// of each of the vertices we are sending to it.
D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
ThrowIfFailed(_device->CreateInputLayout(vertexDesc, ARRAYSIZE(vertexDesc), _vertexShaderByteCode->GetBufferPointer(), _vertexShaderByteCode->GetBufferSize(), _layout.GetAddressOf()));
}
void SkyNode::BuildConstantBuffer()
{
D3D11_BUFFER_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.ByteWidth = sizeof(SCBUFFER);
bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
ThrowIfFailed(_device->CreateBuffer(&bufferDesc, NULL, _constantBuffer.GetAddressOf()));
}
void SkyNode::LoadSkyboxTexture()
{
ThrowIfFailed(CreateDDSTextureFromFile(_device.Get(),
_skyCubeTextureName.c_str(),
nullptr,
_skyCubeTexture.GetAddressOf()
));
}
void SkyNode::BuildRendererStates()
{
// Set default and wireframe rasteriser states
D3D11_RASTERIZER_DESC rasteriserDesc;
rasteriserDesc.FillMode = D3D11_FILL_SOLID;
rasteriserDesc.CullMode = D3D11_CULL_BACK;
rasteriserDesc.FrontCounterClockwise = false;
rasteriserDesc.DepthBias = 0;
rasteriserDesc.SlopeScaledDepthBias = 0.0f;
rasteriserDesc.DepthBiasClamp = 0.0f;
rasteriserDesc.DepthClipEnable = true;
rasteriserDesc.ScissorEnable = false;
rasteriserDesc.MultisampleEnable = false;
rasteriserDesc.AntialiasedLineEnable = false;
ThrowIfFailed(_device->CreateRasterizerState(&rasteriserDesc, _defaultRasteriserState.GetAddressOf()));
rasteriserDesc.CullMode = D3D11_CULL_NONE;
ThrowIfFailed(_device->CreateRasterizerState(&rasteriserDesc, _noCullRasteriserState.GetAddressOf()));
}
void SkyNode::BuildDepthStencilState()
{
D3D11_DEPTH_STENCIL_DESC stencilDesc;
stencilDesc.DepthEnable = true;
stencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
stencilDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
stencilDesc.StencilEnable = false;
stencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
stencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
stencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
stencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
stencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
stencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
stencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
stencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
stencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
stencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
ThrowIfFailed(_device->CreateDepthStencilState(&stencilDesc, _stencilState.GetAddressOf()));
}

67
Graphics2/SkyNode.h Normal file
View File

@ -0,0 +1,67 @@
#pragma once
#include "DirectXFramework.h"
#include "DDSTextureLoader.h"
#include "SharedMethods.h"
#include "SceneNode.h"
typedef struct SkyVertex
{
XMFLOAT3 Position;
} SkyVertex;
struct SCBUFFER
{
XMMATRIX completeTransformation;
};
class SkyNode : public SceneNode
{
public:
SkyNode(wstring name, wstring skyCubeTextureName, float skyRadius);
~SkyNode();
bool Initialise(void);
void Render(void);
void Shutdown(void);
private:
float _skyRadius;
UINT _indicesCount;
UINT _vertexCount;
vector<SkyVertex> _skyDomeVerts;
vector<int> _indices;
ComPtr<ID3D11Device> _device;
ComPtr<ID3D11DeviceContext> _deviceContext;
ComPtr<ID3D11Buffer> _vertexBuffer;
ComPtr<ID3D11Buffer> _indexBuffer;
ComPtr<ID3DBlob> _vertexShaderByteCode = nullptr;
ComPtr<ID3DBlob> _pixelShaderByteCode = nullptr;
ComPtr<ID3D11VertexShader> _vertexShader;
ComPtr<ID3D11PixelShader> _pixelShader;
ComPtr<ID3D11InputLayout> _layout;
ComPtr<ID3D11Buffer> _constantBuffer;
ComPtr<ID3D11RasterizerState> _defaultRasteriserState;
ComPtr<ID3D11RasterizerState> _noCullRasteriserState;
ComPtr<ID3D11DepthStencilState> _stencilState;
ComPtr<ID3D11ShaderResourceView> _skyCubeTexture;
wstring _skyCubeTextureName;
void CreateSphere(float radius, size_t tessellation);
void GenerateBuffers();
void BuildShaders();
void BuildVertexLayout();
void BuildConstantBuffer();
void BuildRendererStates();
void BuildDepthStencilState();
void LoadSkyboxTexture();
};

36
Graphics2/SkyShader.hlsl Normal file
View File

@ -0,0 +1,36 @@
cbuffer ConstantBuffer
{
float4x4 completeTransformation;
};
TextureCube cubeMap;
SamplerState samTriLinearSam;
struct VertexIn
{
float3 Position : POSITION;
};
struct VertexOut
{
float4 Position : SV_POSITION;
float3 TexCoord : TEXCOORD;
};
VertexOut VS(VertexIn vin)
{
VertexOut vout;
// Set z = w so that z/w = 1 (i.e., skydome always on far plane).
vout.Position = mul(float4(vin.Position, 1.0f), completeTransformation).xyww;
vout.TexCoord = vin.Position;
return vout;
}
float4 PS(VertexOut pin) : SV_Target
{
return cubeMap.Sample(samTriLinearSam, pin.TexCoord);
}

View File

@ -5,6 +5,7 @@ bool SplitMeshNode::Initialise()
bool currentStatus = true;
_resourceManager = DirectXFramework::GetDXFramework()->GetResourceManager();
_renderer = dynamic_pointer_cast<SubMeshRenderer>(_resourceManager->GetRenderer(L"SMR"));
_mesh = _resourceManager->GetMesh(_modelName);
if (_mesh == nullptr)
{
@ -20,9 +21,29 @@ bool SplitMeshNode::Initialise()
currentStatus = SceneGraph::Initialise();
}
if (currentStatus)
{
currentStatus = _renderer->Initialise();
}
return currentStatus;
}
void SplitMeshNode::Render(void)
{
_renderer->SetRootChildren(GetChildren());
_renderer->SetWorldTransformation(XMLoadFloat4x4(&_combinedWorldTransformation));
_renderer->SetAmbientLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetAmbientLight());
_renderer->SetDirectionalLight(DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightDirection(), DirectXFramework::GetDXFramework()->GetGlobalLighting()->GetDirectionalLightColor());
_renderer->Render();
}
void SplitMeshNode::Shutdown(void)
{
_resourceManager->ReleaseMesh(_modelName);
SceneGraph::Shutdown();
}
SceneNodePointer SplitMeshNode::AddMeshNode(shared_ptr<Node> node)
{
unsigned int subMeshCount = (unsigned int)node->GetMeshCount();
@ -41,7 +62,14 @@ SceneNodePointer SplitMeshNode::AddMeshNode(shared_ptr<Node> node)
{
unsigned int meshIndex = node->GetMesh(i);
shared_ptr<SubMesh> subMesh = _mesh->GetSubMesh(meshIndex);
shared_ptr<SubMeshNode> subNode = make_shared<SubMeshNode>(node->GetName() + L"_" + to_wstring(i), subMesh);
shared_ptr<Material> material = subMesh->GetMaterial();
float opacity = material->GetOpacity();
bool transparent = false;
if (opacity < 1.0f)
{
transparent = true;
}
shared_ptr<SubMeshNode> subNode = make_shared<SubMeshNode>(node->GetName() + L"_" + to_wstring(i), subMesh, transparent);
currentNodeGraph->Add(subNode);
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "DirectXFramework.h"
#include "SceneGraph.h"
#include "SubMeshRenderer.h"
#include "SubMeshNode.h"
class SplitMeshNode : public SceneGraph
@ -8,6 +9,8 @@ class SplitMeshNode : public SceneGraph
public:
SplitMeshNode(wstring name, wstring modelName) : SceneGraph(name) { _modelName = modelName; }
bool Initialise(void);
void Render(void);
void Shutdown(void);
SceneNodePointer AddMeshNode(shared_ptr<Node> node);
private:

View File

@ -1,26 +1,33 @@
#include "SubMeshNode.h"
bool SubMeshNode::Initialise()
{
_resourceManager = DirectXFramework::GetDXFramework()->GetResourceManager();
_renderer = dynamic_pointer_cast<SubMeshRenderer>(_resourceManager->GetRenderer(L"SMR"));
{
if (_subMesh == nullptr)
{
return false;
}
return _renderer->Initialise();
return true;
}
void SubMeshNode::Shutdown()
{
{
}
void SubMeshNode::Render()
{
_renderer->SetSubMesh(_subMesh);
_renderer->SetWorldTransformation(XMLoadFloat4x4(&_combinedWorldTransformation));
_renderer->SetCameraPosition(DirectXFramework::GetDXFramework()->GetCamera()->GetRawCameraPosition());
_renderer->SetAmbientLight(XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f));
_renderer->SetDirectionalLight(XMVectorSet(0.0f, -1.0f, 1.0f, 0.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f));
_renderer->Render();
{
}
bool SubMeshNode::IsTransparent() const
{
return _transparent;
}
shared_ptr<SubMesh> SubMeshNode::GetSubMesh() const
{
return _subMesh;
}
XMFLOAT4X4 SubMeshNode::GetCurrentTransform() const
{
return _combinedWorldTransformation;
}

View File

@ -1,21 +1,23 @@
#pragma once
#include "DirectXFramework.h"
#include "SceneNode.h"
#include "SubMeshRenderer.h"
class SubMeshNode : public SceneNode
{
public:
SubMeshNode(wstring name, shared_ptr<SubMesh> subMesh) : SceneNode(name) { _subMesh = subMesh; }
SubMeshNode(wstring name, shared_ptr<SubMesh> subMesh, bool transparent = false) : SceneNode(name) { _subMesh = subMesh; _transparent = transparent; }
bool Initialise();
void Render();
void Shutdown();
private:
shared_ptr<SubMeshRenderer> _renderer;
shared_ptr<ResourceManager> _resourceManager;
bool IsTransparent() const;
shared_ptr<SubMesh> GetSubMesh() const;
XMFLOAT4X4 GetCurrentTransform() const;
private:
shared_ptr<SubMesh> _subMesh;
bool _transparent;
};

View File

@ -1,8 +1,8 @@
#include "SubMeshRenderer.h"
void SubMeshRenderer::SetSubMesh(shared_ptr<SubMesh> subMesh)
void SubMeshRenderer::SetRootChildren(list<SceneNodePointer>& rootChildren)
{
_subMesh = subMesh;
_rootGraph = &rootChildren;
}
void SubMeshRenderer::SetWorldTransformation(FXMMATRIX worldTransformation)
@ -21,11 +21,6 @@ void SubMeshRenderer::SetDirectionalLight(FXMVECTOR lightVector, XMFLOAT4 lightC
XMStoreFloat4(&_directionalLightVector, lightVector);
}
void SubMeshRenderer::SetCameraPosition(XMFLOAT4 cameraPosition)
{
_cameraPosition = cameraPosition;
}
bool SubMeshRenderer::Initialise()
{
_device = DirectXFramework::GetDXFramework()->GetDevice();
@ -38,6 +33,60 @@ bool SubMeshRenderer::Initialise()
return true;
}
void SubMeshRenderer::RenderChild(SceneNodePointer node, bool renderTransparent)
{
shared_ptr<SubMeshNode> currentMeshNode = dynamic_pointer_cast<SubMeshNode>(node);
if (currentMeshNode != nullptr)
{
XMMATRIX projectionTransformation = DirectXFramework::GetDXFramework()->GetProjectionTransformation();
XMMATRIX viewTransformation = DirectXFramework::GetDXFramework()->GetCamera()->GetViewMatrix();
XMMATRIX completeTransformation = XMLoadFloat4x4(&currentMeshNode->GetCurrentTransform()) * viewTransformation * projectionTransformation;
shared_ptr<SubMesh> subMesh = currentMeshNode->GetSubMesh();
shared_ptr<Material> material = subMesh->GetMaterial();
float opacity = material->GetOpacity();
if ((renderTransparent && opacity < 1.0f) ||
(!renderTransparent && opacity == 1.0f))
{
_cBuffer.completeTransformation = completeTransformation;
_cBuffer.worldTransformation = XMLoadFloat4x4(&currentMeshNode->GetCurrentTransform());
UINT stride = sizeof(VERTEX);
UINT offset = 0;
_vertexBuffer = subMesh->GetVertexBuffer();
_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer.GetAddressOf(), &stride, &offset);
_indexBuffer = subMesh->GetIndexBuffer();
_deviceContext->IASetIndexBuffer(_indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
_cBuffer.diffuseCoefficient = material->GetDiffuseColour();
_cBuffer.specularCoefficient = material->GetSpecularColour();
_cBuffer.shininess = material->GetShininess();
_cBuffer.opacity = opacity;
// Update the constant buffer
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
_deviceContext->UpdateSubresource(_constantBuffer.Get(), 0, 0, &_cBuffer, 0, 0);
_texture = material->GetTexture();
_deviceContext->PSSetShaderResources(0, 1, _texture.GetAddressOf());
_deviceContext->PSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
_deviceContext->DrawIndexed(static_cast<UINT>(subMesh->GetIndexCount()), 0, 0);
}
}
shared_ptr<SceneGraph> currentGraphNode = dynamic_pointer_cast<SceneGraph>(node);
if (currentGraphNode != nullptr)
{
// Render the children
// Loop through all submeshes in the mesh, rendering them
for (SceneNodePointer& child : currentGraphNode->GetChildren())
{
RenderChild(child, renderTransparent);
}
}
}
void SubMeshRenderer::Render()
{
// Turn off back face culling while we render a mesh.
@ -46,20 +95,12 @@ void SubMeshRenderer::Render()
// back face culling, some materials do not render correctly.
_deviceContext->RSSetState(_noCullRasteriserState.Get());
XMMATRIX projectionTransformation = DirectXFramework::GetDXFramework()->GetProjectionTransformation();
XMMATRIX viewTransformation = DirectXFramework::GetDXFramework()->GetCamera()->GetViewMatrix();
XMMATRIX completeTransformation = XMLoadFloat4x4(&_worldTransformation) * viewTransformation * projectionTransformation;
// Draw the first cube
CBUFFER cBuffer;
cBuffer.completeTransformation = completeTransformation;
cBuffer.worldTransformation = XMLoadFloat4x4(&_worldTransformation);
cBuffer.ambientColor = _ambientLight;
cBuffer.lightVector = XMVector4Normalize(XMLoadFloat4(&_directionalLightVector));
cBuffer.lightColor = _directionalLightColour;
cBuffer.cameraPosition = _cameraPosition;
// Reset the CBUFFER since its now a class member.
_cBuffer = CBUFFER();
_cBuffer.ambientColor = _ambientLight;
_cBuffer.lightVector = XMVector4Normalize(XMLoadFloat4(&_directionalLightVector));
_cBuffer.lightColor = _directionalLightColour;
XMStoreFloat4(&_cBuffer.cameraPosition, DirectXFramework::GetDXFramework()->GetCamera()->GetCameraPosition());
_deviceContext->VSSetShader(_vertexShader.Get(), 0, 0);
_deviceContext->PSSetShader(_pixelShader.Get(), 0, 0);
@ -69,27 +110,20 @@ void SubMeshRenderer::Render()
float blendFactors[] = { 0.0f, 0.0f, 0.0f, 0.0f };
_deviceContext->OMSetBlendState(_transparentBlendState.Get(), blendFactors, 0xffffffff);
shared_ptr<Material> material = _subMesh->GetMaterial();
float opacity = material->GetOpacity();
UINT stride = sizeof(VERTEX);
UINT offset = 0;
_vertexBuffer = _subMesh->GetVertexBuffer();
_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer.GetAddressOf(), &stride, &offset);
_indexBuffer = _subMesh->GetIndexBuffer();
_deviceContext->IASetIndexBuffer(_indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
cBuffer.diffuseCoefficient = material->GetDiffuseColour();
cBuffer.specularCoefficient = material->GetSpecularColour();
cBuffer.shininess = material->GetShininess();
cBuffer.opacity = opacity;
// Update the constant buffer
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
_deviceContext->UpdateSubresource(_constantBuffer.Get(), 0, 0, &cBuffer, 0, 0);
_texture = material->GetTexture();
_deviceContext->PSSetShaderResources(0, 1, _texture.GetAddressOf());
_deviceContext->PSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
_deviceContext->DrawIndexed(static_cast<UINT>(_subMesh->GetIndexCount()), 0, 0);
// We do two passes through the nodes. The first time we render nodes
// that are not transparent (i.e. their opacity == 1.0f).
for (SceneNodePointer& child : *_rootGraph)
{
RenderChild(child, false);
}
// Now we render any transparent nodes
// We have to do this since blending always blends the submesh with
// whatever is in the render target. If we render a transparent node
// first, it will be opaque.
for (SceneNodePointer& child : *_rootGraph)
{
RenderChild(child, true);
}
// Turn back face culling back on in case another renderer
// relies on it
@ -202,3 +236,4 @@ void SubMeshRenderer::BuildRendererState()
rasteriserDesc.CullMode = D3D11_CULL_NONE;
ThrowIfFailed(_device->CreateRasterizerState(&rasteriserDesc, _noCullRasteriserState.GetAddressOf()));
}

View File

@ -1,22 +1,24 @@
#pragma once
#include "SharedMethods.h"
#include "DirectXFramework.h"
#include "SubMeshNode.h"
#include "Renderer.h"
#include "Mesh.h"
class SubMeshRenderer : public Renderer
{
public:
void SetSubMesh(shared_ptr<SubMesh> subMesh);
public:
void SetRootChildren(list<SceneNodePointer>& rootChildren);
void SetWorldTransformation(FXMMATRIX worldTransformation);
void SetAmbientLight(XMFLOAT4 ambientLight);
void SetDirectionalLight(FXMVECTOR lightVector, XMFLOAT4 lightColour);
void SetCameraPosition(XMFLOAT4 cameraPosition);
bool Initialise();
bool Initialise();
void Render();
void Shutdown(void);
private:
list<SceneNodePointer>* _rootGraph;
shared_ptr<SubMesh> _subMesh;
XMFLOAT4X4 _worldTransformation;
XMFLOAT4 _ambientLight;
@ -44,10 +46,14 @@ private:
ComPtr<ID3D11RasterizerState> _defaultRasteriserState;
ComPtr<ID3D11RasterizerState> _noCullRasteriserState;
CBUFFER _cBuffer;
void BuildShaders();
void BuildVertexLayout();
void BuildConstantBuffer();
void BuildBlendState();
void BuildRendererState();
void RenderChild(SceneNodePointer node, bool renderTransparent);
};

View File

@ -2,9 +2,8 @@
#define WORLD_HEIGHT 1024
TerrainNode::TerrainNode(wstring name, wstring heightMap, wstring seed, float waterHeight, wstring waterNormalMap, int widthX, int widthZ, int cellSizeX, int cellSizeZ) : SceneNode(name)
{
_heightMap = heightMap;
TerrainNode::TerrainNode(wstring name, wstring seed, float waterHeight, int widthX, int widthZ, int cellSizeX, int cellSizeZ) : SceneNode(name)
{
_seedString = seed;
_seedHash = std::hash<wstring>{}(_seedString);
@ -20,11 +19,10 @@ TerrainNode::TerrainNode(wstring name, wstring heightMap, wstring seed, float wa
_cellSizeZ = cellSizeZ;
_waterHeight = waterHeight;
_waterNormalMapName = waterNormalMap;
_polygonsCount = (_gridCols * _gridRows) * 2;
_vertexCount = _polygonsCount * 2;
_indiciesCount = _polygonsCount * 3;
_indicesCount = _polygonsCount * 3;
}
void TerrainNode::SetAmbientLight(XMFLOAT4 ambientLight)
@ -43,38 +41,18 @@ void TerrainNode::SetDirectionalLight(FXMVECTOR lightVector, XMFLOAT4 lightColor
XMStoreFloat4(&_directionalLightVector, lightVector);
}
void TerrainNode::SetCameraPosition(XMFLOAT4 cameraPosition)
{
_cameraPosition = cameraPosition;
}
bool TerrainNode::Initialise()
{
_device = DirectXFramework::GetDXFramework()->GetDevice();
_deviceContext = DirectXFramework::GetDXFramework()->GetDeviceContext();
if (_device.Get() == nullptr || _deviceContext.Get() == nullptr)
if (_device.Get() == nullptr || _deviceContext.Get() == nullptr || _initError)
{
return false;
}
if (_heightMap.length() > 0)
{
if (LoadHeightMap(_heightMap))
{
_usedHeightMap = true;
}
else
{
_usedHeightMap = false;
}
}
else
{
_usedHeightMap = false;
}
GenerateTerrainData();
GenerateTerrainNormals();
LoadTerrainTextures();
GenerateBlendMap();
BuildExtraMaps();
@ -89,7 +67,7 @@ bool TerrainNode::Initialise()
}
void TerrainNode::GenerateTerrainData()
{
{
float totalWidth = (float)(_gridCols * _cellSizeX);
float totalDepth = (float)(_gridRows * _cellSizeZ);
@ -121,16 +99,16 @@ void TerrainNode::GenerateTerrainData()
offsetIndexZ = 0;
}
float rUA = 0.0f;
float rVA = rUA; // 0.0f;
float rUB = 1.0f;
float rVB = rUB;
// Generate pairs of random UV's
float rUA = SharedMethods::GenerateRandomUV(0.0f, 0.25f);
float rVA = SharedMethods::GenerateRandomUV(0.0f, 0.25f); //rUA; // 0.0f;
float rUB = SharedMethods::GenerateRandomUV(0.75f, 1.0f);
float rVB = SharedMethods::GenerateRandomUV(0.75f, 1.0f); //rUB;
/*int tumbleAmount = rand() % 10;
// Rotate the UV's around a bit to add some more variance
int tumbleAmount = rand() % 10;
float prevUV = 0.0f;
bool firstTumble = true;
for (int ti = 0; ti < tumbleAmount; ti++)
{
prevUV = rVB;
@ -138,11 +116,11 @@ void TerrainNode::GenerateTerrainData()
rUB = rVA;
rVA = rUA;
rUA = prevUV;
}*/
}
// TL
TerrainVertex vertex{};
vertex.Position = XMFLOAT3(x * _cellSizeX + centerWidth, GetHeightMapValueAt(currentIndex), (-z + 1) * _cellSizeZ + centerDepth);
vertex.Position = XMFLOAT3(x * _cellSizeX + centerWidth, GetHeightValueAt(currentIndex), (-z + 1) * _cellSizeZ + centerDepth);
vertex.Normal = XMFLOAT3(0.0f, 0.0f, 0.0f);
vertex.TexCoord = XMFLOAT2(rUA, rVA);
vertex.BlendMapTexCoord = XMFLOAT2((bu * x), (bv * z));
@ -150,7 +128,7 @@ void TerrainNode::GenerateTerrainData()
// TR
vertex = TerrainVertex();
vertex.Position = XMFLOAT3((x + 1) * _cellSizeX + centerWidth, GetHeightMapValueAt(currentIndex + offsetIndexX), (-z + 1) * _cellSizeZ + centerDepth);
vertex.Position = XMFLOAT3((x + 1) * _cellSizeX + centerWidth, GetHeightValueAt(currentIndex + offsetIndexX), (-z + 1) * _cellSizeZ + centerDepth);
vertex.Normal = XMFLOAT3(0.0f, 0.0f, 0.0f);
vertex.TexCoord = XMFLOAT2(rUB, rVA);
vertex.BlendMapTexCoord = XMFLOAT2((bu * (x + 1)), (bv * z));
@ -158,7 +136,7 @@ void TerrainNode::GenerateTerrainData()
// BL
vertex = TerrainVertex();
vertex.Position = XMFLOAT3(x * _cellSizeX + centerWidth, GetHeightMapValueAt(currentIndex + offsetIndexZ), -z * _cellSizeZ + centerDepth);
vertex.Position = XMFLOAT3(x * _cellSizeX + centerWidth, GetHeightValueAt(currentIndex + offsetIndexZ), -z * _cellSizeZ + centerDepth);
vertex.Normal = XMFLOAT3(0.0f, 0.0f, 0.0f);
vertex.TexCoord = XMFLOAT2(rUA, rVB);
vertex.BlendMapTexCoord = XMFLOAT2((bu * x), (bv * (z + 1)));
@ -166,7 +144,7 @@ void TerrainNode::GenerateTerrainData()
// BR
vertex = TerrainVertex();
vertex.Position = XMFLOAT3((x + 1) * _cellSizeX + centerWidth, GetHeightMapValueAt(currentIndex + offsetIndexZ + offsetIndexX), -z * _cellSizeZ + centerDepth);
vertex.Position = XMFLOAT3((x + 1) * _cellSizeX + centerWidth, GetHeightValueAt(currentIndex + offsetIndexZ + offsetIndexX), -z * _cellSizeZ + centerDepth);
vertex.Normal = XMFLOAT3(0.0f, 0.0f, 0.0f);
vertex.TexCoord = XMFLOAT2(rUB, rVB);
vertex.BlendMapTexCoord = XMFLOAT2((bu * (x + 1)), (bv * (z + 1)));
@ -182,7 +160,10 @@ void TerrainNode::GenerateTerrainData()
currentVertexCount += 4;
}
}
}
void TerrainNode::GenerateTerrainNormals()
{
int currentNormalIndex = 0;
for (int z = 0; z < _gridRows; z++)
{
@ -243,6 +224,13 @@ void TerrainNode::AddNormalToVertex(int row, int col, int vertexIndex, XMVECTOR
}
}
float TerrainNode::GetHeightValueAt(int index)
{
float result = _heightValues[index] * WORLD_HEIGHT; // +(rand() % 10);
return result;
}
void TerrainNode::GenerateBuffers()
{
// Setup the structure that specifies how big the vertex
@ -267,7 +255,7 @@ void TerrainNode::GenerateBuffers()
// buffer should be
D3D11_BUFFER_DESC indexBufferDescriptor;
indexBufferDescriptor.Usage = D3D11_USAGE_IMMUTABLE;
indexBufferDescriptor.ByteWidth = sizeof(UINT) * _indiciesCount;
indexBufferDescriptor.ByteWidth = sizeof(UINT) * _indicesCount;
indexBufferDescriptor.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDescriptor.CPUAccessFlags = 0;
indexBufferDescriptor.MiscFlags = 0;
@ -302,13 +290,13 @@ void TerrainNode::Render()
XMStoreFloat4(&cBuffer.cameraPosition, DirectXFramework::GetDXFramework()->GetCamera()->GetCameraPosition());
cBuffer.waterHeight = _waterHeight;
cBuffer.waterShininess = 15.0f;
cBuffer.waterShininess = 10.0f;
cBuffer.waterColor = _waterColor;
_deviceContext->PSSetShaderResources(0, 1, _blendMapResourceView.GetAddressOf());
_deviceContext->PSSetShaderResources(1, 1, _texturesResourceView.GetAddressOf());
_deviceContext->PSSetShaderResources(2, 1, _waterNormalMap.GetAddressOf());
_deviceContext->PSSetShaderResources(3, 1, _rngNoiseMap.GetAddressOf());
_deviceContext->PSSetShaderResources(3, 1, _snowTest.GetAddressOf());
_deviceContext->VSSetShader(_vertexShader.Get(), 0, 0);
_deviceContext->PSSetShader(_pixelShader.Get(), 0, 0);
@ -320,7 +308,7 @@ void TerrainNode::Render()
_deviceContext->IASetIndexBuffer(_indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
cBuffer.diffuseCoefficient = XMFLOAT4(0.8f, 0.8f, 0.8f, 1.0f);
cBuffer.specularCoefficient = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
cBuffer.shininess = 10.0f;
cBuffer.shininess = 5.0f;
cBuffer.opacity = 1.0f;
// Update the constant buffer
@ -330,7 +318,7 @@ void TerrainNode::Render()
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
//_deviceContext->RSSetState(_wireframeRasteriserState.Get());
_deviceContext->DrawIndexed(_indiciesCount, 0, 0);
_deviceContext->DrawIndexed(_indicesCount, 0, 0);
}
void TerrainNode::Shutdown(void)
@ -425,41 +413,6 @@ void TerrainNode::BuildRendererStates()
ThrowIfFailed(_device->CreateRasterizerState(&rasteriserDesc, _wireframeRasteriserState.GetAddressOf()));
}
bool TerrainNode::LoadHeightMap(wstring heightMapFilename)
{
unsigned int mapSize = _gridCols * _gridRows;
USHORT* rawFileValues = new USHORT[mapSize];
std::ifstream inputHeightMap;
inputHeightMap.open(heightMapFilename.c_str(), std::ios_base::binary);
if (!inputHeightMap)
{
return false;
}
inputHeightMap.read((char*)rawFileValues, mapSize * 2);
inputHeightMap.close();
// Normalise BYTE values to the range 0.0f - 1.0f;
for (unsigned int i = 0; i < mapSize; i++)
{
_heightValues.push_back((float)rawFileValues[i] / 65536);
}
delete[] rawFileValues;
return true;
}
float TerrainNode::GetHeightMapValueAt(int index)
{
float result = 0;
if (_usedHeightMap)
{
result = _heightValues[index] * WORLD_HEIGHT; // +(rand() % 10);
}
return result;
}
void TerrainNode::LoadTerrainTextures()
{
// Change the paths below as appropriate for your use
@ -535,18 +488,26 @@ void TerrainNode::LoadTerrainTextures()
viewDescription.Texture2DArray.ArraySize = 5;
ThrowIfFailed(_device->CreateShaderResourceView(textureArray.Get(), &viewDescription, _texturesResourceView.GetAddressOf()));
// Cheeky load in the snow hack to solve that weird issue
wstring snowTestName = L"Textures\\snow.dds";
ThrowIfFailed(CreateDDSTextureFromFile(_device.Get(),
snowTestName.c_str(),
nullptr,
_snowTest.GetAddressOf()
));
}
void TerrainNode::GenerateBlendMap()
{
RGBA snowTops = RGBA{ 0u, 0u, 0u, 255u };
RGBA grassLand = RGBA{ 0u, 0u, 50u, 0u };
RGBA grassLand = RGBA{ 0u, 0u, 0u, 0u };
RGBA lightDirt = RGBA{ 50u, 0u, 255u, 0u };
RGBA darkDirt = RGBA{ 255u, 0u, 0u, 0u };
RGBA darkDirt = RGBA{ 255u, 50u, 50u, 0u };
vector<RGBA> colorSteps = {darkDirt, lightDirt, grassLand, grassLand, grassLand, snowTops};
ColorGradient terrainBlendGradient = ColorGradient(30.0f, 650.0f, colorSteps);
ColorGradient terrainBlendGradient = ColorGradient(80.0f, 620.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
@ -563,7 +524,10 @@ void TerrainNode::GenerateBlendMap()
{
for (DWORD j = 0; j < _gridCols; j++)
{
r = 0u;
g = 0u;
b = 0u;
a = 0u;
// Calculate the appropriate blend colour for the
// current location in the blend map. This has been
// left as an exercise for you. You need to calculate
@ -588,10 +552,10 @@ void TerrainNode::GenerateBlendMap()
float avgHeight = totalHeights / 4.0f;
RGBA currentBlend = terrainBlendGradient.GetRGBAValue(avgHeight);
r = currentBlend.red;
g = currentBlend.green;
b = currentBlend.blue;
a = currentBlend.alpha;
r = (BYTE)currentBlend.red;
g = (BYTE)currentBlend.green;
b = (BYTE)currentBlend.blue;
a = (BYTE)currentBlend.alpha;
DWORD mapValue = (a << 24) + (b << 16) + (g << 8) + r;
*blendMapPtr++ = mapValue;
@ -635,17 +599,71 @@ void TerrainNode::BuildExtraMaps()
// Initialise method (and make the corresponding call to
// CoUninitialize in the Shutdown method). Otherwise,
// the following call will throw an exception
wstring waterNormalMapName = L"Textures\\waterNormals.bmp";
ThrowIfFailed(CreateWICTextureFromFile(_device.Get(),
_deviceContext.Get(),
_waterNormalMapName.c_str(),
waterNormalMapName.c_str(),
nullptr,
_waterNormalMap.GetAddressOf()
));
}
ThrowIfFailed(CreateWICTextureFromFile(_device.Get(),
_deviceContext.Get(),
L"Textures\\noiseMap.png",
nullptr,
_rngNoiseMap.GetAddressOf()
));
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;
int currentNormalIndex = ((cellZ * _gridCols) + cellX) * 6;
if (dx < dz)
{
currentNormalIndex += 3;
}
XMVECTOR v1 = XMVectorSet(_terrainVerts[_indices[currentNormalIndex + 1]].Position.x - _terrainVerts[_indices[currentNormalIndex]].Position.x,
_terrainVerts[_indices[currentNormalIndex + 1]].Position.y - _terrainVerts[_indices[currentNormalIndex]].Position.y,
_terrainVerts[_indices[currentNormalIndex + 1]].Position.z - _terrainVerts[_indices[currentNormalIndex]].Position.z,
0.0f);
XMVECTOR v2 = XMVectorSet(_terrainVerts[_indices[currentNormalIndex + 2]].Position.x - _terrainVerts[_indices[currentNormalIndex]].Position.x,
_terrainVerts[_indices[currentNormalIndex + 2]].Position.y - _terrainVerts[_indices[currentNormalIndex]].Position.y,
_terrainVerts[_indices[currentNormalIndex + 2]].Position.z - _terrainVerts[_indices[currentNormalIndex]].Position.z,
0.0f);
XMFLOAT4 normal;
XMStoreFloat4(&normal, XMVector3Normalize(XMVector3Cross(v1, v2)));
float result = _terrainVerts[currentIndex].Position.y + (normal.x * dx + normal.z * dz) / -normal.y;
if (waterCollide)
{
if (result <= _waterHeight)
{
result = _waterHeight;
}
}
return result;
}
bool TerrainNode::CheckXBoundary(float x)
{
if (!(x > _terrainStartX && x < _terrainEndX))
{
return false;
}
return true;
}
bool TerrainNode::CheckZBoundary(float z)
{
if (!(z < _terrainStartZ && z > _terrainEndZ))
{
return false;
}
return true;
}

View File

@ -2,6 +2,7 @@
#include "DirectXFramework.h"
#include <fstream>
#include <vector>
#include <ctime>
#include "ColorGradient.h"
#include "DDSTextureLoader.h"
#include "WICTextureLoader.h"
@ -17,21 +18,44 @@ typedef struct TerrainVertex
XMFLOAT2 BlendMapTexCoord;
} TerrainVertex;
struct TCBUFFER
{
XMMATRIX completeTransformation;
XMMATRIX worldTransformation;
XMFLOAT4 cameraPosition;
XMVECTOR lightVector;
XMFLOAT4 lightColor;
XMFLOAT4 ambientColor;
XMFLOAT4 diffuseCoefficient;
XMFLOAT4 specularCoefficient;
float shininess;
float opacity;
float waterHeight;
float waterShininess;
XMFLOAT4 waterColor;
float padding[4];
};
class TerrainNode : public SceneNode
{
public:
TerrainNode(wstring name, wstring heightMap, wstring seed, float waterHeight = 150.0f, wstring waterNormalMap = L"Textures\\waterNormals.bmp", int widthX = 1023, int widthZ = 1023, int cellSizeX = 10, int cellSizeZ = 10);
TerrainNode(wstring name, wstring seed, float waterHeight = 150.0f, int widthX = 1023, int widthZ = 1023, int cellSizeX = 10, int cellSizeZ = 10);
void SetAmbientLight(XMFLOAT4 ambientLight);
void SetWaterColor(XMFLOAT4 waterColor);
void SetDirectionalLight(FXMVECTOR lightVector, XMFLOAT4 lightColor);
void SetCameraPosition(XMFLOAT4 cameraPosition);
bool Initialise(void);
bool virtual Initialise(void);
void Render(void);
void Shutdown(void);
void virtual Shutdown(void);
float GetHeightAtPoint(float x, float z, bool waterCollide = false);
bool CheckXBoundary(float x);
bool CheckZBoundary(float z);
protected:
bool _initError = false;
private:
int _widthX;
int _widthZ;
@ -41,25 +65,22 @@ private:
int _cellSizeX;
int _cellSizeZ;
bool _usedHeightMap;
float _waterHeight;
UINT _polygonsCount;
UINT _indiciesCount;
UINT _indicesCount;
UINT _vertexCount;
float _terrainStartX;
float _terrainStartZ;
float _terrainEndX;
float _terrainEndZ;
wstring _heightMap;
wstring _seedString;
unsigned int _seedHash;
vector<TerrainVertex> _terrainVerts;
vector<int> _indices;
vector<int> _indices;
vector<float> _heightValues;
XMFLOAT4 _ambientLight;
@ -86,12 +107,12 @@ private:
ComPtr<ID3D11RasterizerState> _defaultRasteriserState;
ComPtr<ID3D11RasterizerState> _wireframeRasteriserState;
ComPtr<ID3D11ShaderResourceView> _rngNoiseMap;
ComPtr<ID3D11ShaderResourceView> _snowTest;
ComPtr<ID3D11ShaderResourceView> _waterNormalMap;
wstring _waterNormalMapName;
XMFLOAT4 _waterColor;
void GenerateTerrainData();
void virtual GenerateTerrainData();
void GenerateTerrainNormals();
void GenerateBuffers();
void BuildShaders();
void BuildVertexLayout();
@ -101,8 +122,7 @@ private:
void LoadTerrainTextures();
void GenerateBlendMap();
bool LoadHeightMap(wstring heightMapFilename);
float GetHeightMapValueAt(int index);
float GetHeightValueAt(int index);
void AddNormalToVertex(int row, int col, int vertexIndex, XMVECTOR normal);
void BuildExtraMaps();

View File

@ -11,16 +11,19 @@ cbuffer ConstantBuffer
float shininess; // The shininess factor
float opacity; // The opacity (transparency) of the material. 0 = fully transparent, 1 = fully opaque
// Vars to deal with the water, also padding because the cbuffer needs to be a multiple of 16
float waterHeight;
float waterShininess;
float4 waterColor;
// Padded with a float array, floats being 4 bytes each, the above just hits the multiple of 16 but added extra incase this was the issue, will remove later most likely
float padding[4];
}
Texture2D BlendMap : register(t0);
Texture2DArray TexturesArray : register(t1);
Texture2D WaterNormalMap : register(t2);
Texture2D rngNoiseMap : register(t3);
Texture2D snowTest : register(t3);
SamplerState ss
{
@ -42,6 +45,7 @@ struct PixelShaderInput
{
float4 Position : SV_POSITION;
float4 PositionWS: TEXCOORD2;
float4 PositionOG: TEXCOORD4;
float4 NormalWS : TEXCOORD3;
float2 TexCoord : TEXCOORD0;
float2 BlendMapTexCoord : TEXCOORD1;
@ -63,14 +67,17 @@ PixelShaderInput VShader(VertexShaderInput vin)
{
PixelShaderInput output;
float3 position = vin.Position;
output.PositionOG = output.PositionWS = mul(worldTransformation, float4(position, 1.0f));
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
if (position.y < waterHeight)
{
position.y = waterHeight - 0.01f;
position.y = waterHeight;
}
output.Position = mul(completeTransformation, float4(position, 1.0f));
output.PositionWS = mul(worldTransformation, float4(position, 1.0f));
output.NormalWS = float4(mul((float3x3)worldTransformation, vin.Normal), 1.0f);
output.TexCoord = vin.TexCoord;
output.BlendMapTexCoord = vin.BlendMapTexCoord;
return output;
}
@ -87,11 +94,15 @@ float4 PShader(PixelShaderInput input) : SV_TARGET
float4 directionToLight = normalize(-lightVector);
float surfaceShininess = shininess;
float4 adjustedNormal = normalize(input.NormalWS);
if (input.PositionWS.y < waterHeight)
float currentHeightPer = (waterHeight - input.PositionOG.y) / waterHeight;
if (input.PositionOG.y < waterHeight)
{
float3 n0 = (float3)WaterNormalMap.Sample(ss, input.TexCoord);
// 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 n2 = float4(mul((float3x3)worldTransformation, n0), 1.0f);
adjustedNormal = n2;
adjustedNormal = normalize(n2);
surfaceShininess = waterShininess;
}
@ -110,11 +121,11 @@ float4 PShader(PixelShaderInput input) : SV_TARGET
float4 ambientLight = ambientColor * diffuseCoefficient;
float4 color;
float4 randSamp = rngNoiseMap.Sample(ss, input.BlendMapTexCoord);
// Randomly rotate the UV coordinates using the noise map
float2 scaleCenter = float2(0.5f, 0.5f);
float currentScale = randSamp.r;
float2 scaledUV = frac(UVRotate(input.TexCoord, scaleCenter, currentScale)); // (input.TexCoord - scaleCenter) * currentScale + scaleCenter;
// 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 xChange = ddx(scaledUV);
float2 yChange = ddy(scaledUV);
@ -133,7 +144,8 @@ float4 PShader(PixelShaderInput input) : SV_TARGET
float4 c1 = TexturesArray.SampleGrad(ss, float3(scaledUV, 1.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 c4 = TexturesArray.SampleGrad(ss, float3(scaledUV, 4.0f), xChange, yChange);
//float4 c4 = TexturesArray.SampleGrad(ss, float3(scaledUV, 4.0f), xChange, yChange);
float4 c4 = snowTest.SampleGrad(ss, float2(scaledUV), xChange, yChange);
// Sample the blend map.
float4 t = BlendMap.Sample(ss, input.BlendMapTexCoord);
@ -146,9 +158,10 @@ float4 PShader(PixelShaderInput input) : SV_TARGET
color = lerp(color, c4, t.a);
// Combine all components
if (input.PositionWS.y < waterHeight)
if (input.PositionOG.y < waterHeight)
{
color = color * waterColor;
// Tint the water
color = saturate(color) * waterColor;
}
color = (ambientLight + diffuse) * color;
color = saturate(color + specular);

View File

@ -7,15 +7,6 @@ struct Vertex
XMFLOAT2 TextureCoordinate;
};
struct CBUFFER
{
XMMATRIX CompleteTransformation;
XMMATRIX WorldTransformation;
XMVECTOR LightVector;
XMFLOAT4 LightColour;
XMFLOAT4 AmbientColour;
};
bool TexturedCubeNode::Initialise()
{
_device = DirectXFramework::GetDXFramework()->GetDevice();
@ -45,11 +36,11 @@ void TexturedCubeNode::Render()
// Draw the first cube
CBUFFER cBuffer;
cBuffer.CompleteTransformation = completeTransformation;
cBuffer.WorldTransformation = XMLoadFloat4x4(&_combinedWorldTransformation);
cBuffer.AmbientColour = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f);
cBuffer.LightVector = XMVector4Normalize(XMVectorSet(0.0f, 1.0f, 1.0f, 0.0f));
cBuffer.LightColour = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
cBuffer.completeTransformation = completeTransformation;
cBuffer.worldTransformation = XMLoadFloat4x4(&_combinedWorldTransformation);
cBuffer.ambientColor = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f);
cBuffer.lightVector = XMVector4Normalize(XMVectorSet(0.0f, 1.0f, 1.0f, 0.0f));
cBuffer.lightColor = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
// Update the constant buffer
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
@ -170,7 +161,7 @@ void TexturedCubeNode::BuildShaders()
ComPtr<ID3DBlob> compilationMessages = nullptr;
//Compile vertex shader
HRESULT hr = D3DCompileFromFile(L"shader.hlsl",
HRESULT hr = D3DCompileFromFile(L"TexturedShaders.hlsl",
nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
"VS", "vs_5_0",
shaderCompileFlags, 0,
@ -188,7 +179,7 @@ void TexturedCubeNode::BuildShaders()
_deviceContext->VSSetShader(_vertexShader.Get(), 0, 0);
// Compile pixel shader
hr = D3DCompileFromFile(L"shader.hlsl",
hr = D3DCompileFromFile(L"TexturedShaders.hlsl",
nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
"PS", "ps_5_0",
shaderCompileFlags, 0,

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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB