#include "SubMeshRenderer.h" void SubMeshRenderer::SetSubMesh(shared_ptr subMesh) { _subMesh = subMesh; } void SubMeshRenderer::SetWorldTransformation(FXMMATRIX worldTransformation) { XMStoreFloat4x4(&_worldTransformation, worldTransformation); } void SubMeshRenderer::SetAmbientLight(XMFLOAT4 ambientLight) { _ambientLight = ambientLight; } void SubMeshRenderer::SetDirectionalLight(FXMVECTOR lightVector, XMFLOAT4 lightColour) { _directionalLightColour = lightColour; XMStoreFloat4(&_directionalLightVector, lightVector); } void SubMeshRenderer::SetCameraPosition(XMFLOAT4 cameraPosition) { _cameraPosition = cameraPosition; } bool SubMeshRenderer::Initialise() { _device = DirectXFramework::GetDXFramework()->GetDevice(); _deviceContext = DirectXFramework::GetDXFramework()->GetDeviceContext(); BuildShaders(); BuildVertexLayout(); BuildConstantBuffer(); BuildBlendState(); BuildRendererState(); return true; } void SubMeshRenderer::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; // 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; _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); shared_ptr 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(_subMesh->GetIndexCount()), 0, 0); // Turn back face culling back on in case another renderer // relies on it _deviceContext->RSSetState(_defaultRasteriserState.Get()); } void SubMeshRenderer::Shutdown(void) { } void SubMeshRenderer::BuildShaders() { DWORD shaderCompileFlags = 0; #if defined( _DEBUG ) shaderCompileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #endif ComPtr 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 SubMeshRenderer::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 SubMeshRenderer::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 SubMeshRenderer::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 SubMeshRenderer::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())); }