Files
directx-plane-game/Graphics2/MeshRenderer.cpp
iDunnoDev 7a57c73ac3 Added the camera class
Added the DDS Texture Loading for future use
Added the gamepad class for future use
Added first child method to the scenegraph
Added RGB to intensity and lerp methods to the shared methods class
Added the terrain node class with normals
Fixed issue with submeshnode not passing the world transform to the actual meshes
2022-04-18 22:33:15 +01:00

235 lines
9.0 KiB
C++

#include "MeshRenderer.h"
#include "DirectXFramework.h"
void MeshRenderer::SetMesh(shared_ptr<Mesh> mesh)
{
_mesh = mesh;
}
void MeshRenderer::SetWorldTransformation(FXMMATRIX worldTransformation)
{
XMStoreFloat4x4(&_worldTransformation, worldTransformation);
}
void MeshRenderer::SetAmbientLight(XMFLOAT4 ambientLight)
{
_ambientLight = ambientLight;
}
void MeshRenderer::SetDirectionalLight(FXMVECTOR lightVector, XMFLOAT4 lightColour)
{
_directionalLightColour = lightColour;
XMStoreFloat4(&_directionalLightVector, lightVector);
}
void MeshRenderer::SetCameraPosition(XMFLOAT4 cameraPosition)
{
_cameraPosition = cameraPosition;
}
bool MeshRenderer::Initialise()
{
_device = DirectXFramework::GetDXFramework()->GetDevice();
_deviceContext = DirectXFramework::GetDXFramework()->GetDeviceContext();
BuildShaders();
BuildVertexLayout();
BuildConstantBuffer();
BuildBlendState();
BuildRendererState();
return true;
}
void MeshRenderer::RenderNode(shared_ptr<Node> node, bool renderTransparent)
{
unsigned int subMeshCount = (unsigned int)node->GetMeshCount();
// Loop through all submeshes in the mesh, rendering them
for (unsigned int i = 0; i < subMeshCount; i++)
{
unsigned int meshIndex = node->GetMesh(i);
shared_ptr<SubMesh> subMesh = _mesh->GetSubMesh(meshIndex);
shared_ptr<Material> material = subMesh->GetMaterial();
float opacity = material->GetOpacity();
if ((renderTransparent && opacity < 1.0f) ||
(!renderTransparent && opacity == 1.0f))
{
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);
}
}
// Render the children
unsigned int childrenCount = (unsigned int)node->GetChildrenCount();
// Loop through all submeshes in the mesh, rendering them
for (unsigned int i = 0; i < childrenCount; i++)
{
RenderNode(node->GetChild(i), renderTransparent);
}
}
void MeshRenderer::Render()
{
// Turn off back face culling while we render a mesh.
// We do this since ASSIMP does not appear to be setting the
// TWOSIDED property on materials correctly. Without turning off
// 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;
// Reset the CBUFFER since its now a class member.
_cBuffer = CBUFFER();
_cBuffer.completeTransformation = completeTransformation;
_cBuffer.worldTransformation = XMLoadFloat4x4(&_worldTransformation);
_cBuffer.ambientColor = _ambientLight;
_cBuffer.lightVector = XMVector4Normalize(XMLoadFloat4(&_directionalLightVector));
_cBuffer.lightColor = _directionalLightColour;
_cBuffer.cameraPosition = _cameraPosition;
_deviceContext->VSSetShader(_vertexShader.Get(), 0, 0);
_deviceContext->PSSetShader(_pixelShader.Get(), 0, 0);
_deviceContext->IASetInputLayout(_layout.Get());
// Set the blend state correctly to handle opacity
float blendFactors[] = { 0.0f, 0.0f, 0.0f, 0.0f };
_deviceContext->OMSetBlendState(_transparentBlendState.Get(), blendFactors, 0xffffffff);
// We do two passes through the nodes. The first time we render nodes
// that are not transparent (i.e. their opacity == 1.0f).
RenderNode(_mesh->GetRootNode(), 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.
RenderNode(_mesh->GetRootNode(), true);
// Turn back face culling back on in case another renderer
// relies on it
_deviceContext->RSSetState(_defaultRasteriserState.Get());
}
void MeshRenderer::Shutdown(void)
{
}
void MeshRenderer::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"TexturedShaders.hlsl",
nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
"VShader", "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"TexturedShaders.hlsl",
nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
"PShader", "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 MeshRenderer::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 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT , D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT , D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
ThrowIfFailed(_device->CreateInputLayout(vertexDesc, ARRAYSIZE(vertexDesc), _vertexShaderByteCode->GetBufferPointer(), _vertexShaderByteCode->GetBufferSize(), _layout.GetAddressOf()));
}
void MeshRenderer::BuildConstantBuffer()
{
D3D11_BUFFER_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.ByteWidth = sizeof(CBUFFER);
bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
ThrowIfFailed(_device->CreateBuffer(&bufferDesc, NULL, _constantBuffer.GetAddressOf()));
}
void MeshRenderer::BuildBlendState()
{
D3D11_BLEND_DESC transparentDesc = { 0 };
transparentDesc.AlphaToCoverageEnable = false;
transparentDesc.IndependentBlendEnable = false;
transparentDesc.RenderTarget[0].BlendEnable = true;
transparentDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
transparentDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
transparentDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
transparentDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
transparentDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
transparentDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
transparentDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
ThrowIfFailed(_device->CreateBlendState(&transparentDesc, _transparentBlendState.GetAddressOf()));
}
void MeshRenderer::BuildRendererState()
{
// Set default and no cull 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()));
}