#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 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())); }