diff --git a/Assets/Textures/Skies/planets/AllSkyFree_Readme.txt b/Assets/Textures/Skies/planets/AllSkyFree_Readme.txt new file mode 100644 index 0000000..31a5299 --- /dev/null +++ b/Assets/Textures/Skies/planets/AllSkyFree_Readme.txt @@ -0,0 +1,60 @@ +Welcome to AllSky Free! + +This is a small sample edition of the full version of Allsky. +It contains a set of 10 skyboxes for use in your environments. +I hope you find them useful! + +You can Buy the full version of AllSky here : + +https://assetstore.unity.com/packages/2d/textures-materials/sky/allsky-200-sky-skybox-set-10109 + +The full version has 200 skies for Unity! Provided as 6 sided cubemaps sized from x1024 to x2048 per-side along with an equirectangular cubemap texture ranging from 4k to 16k in size. Each has an example lighting setup scene! + +Various styles: Day, Night, Cartoon, Fantasy, Hazy, Epic, Space, Sunless and Moonless! + +For lighting artists, environment artists and indie developers looking for a wide suite of skies to light their environments. + +Lighting from day to night: Twilight, sunset, multiple times of day, multiple times of night, skyglow. + +Many weather and cloud types: Clear, overcast, summery, stormy, autumnal, hazy, epic, foggy, cumulus. + + +TECHNICAL + + Texture format: Each sky is a 6 sided cubemap. Source PNG texture resolution per-side ranges from x1024 to x2048. Equirectangular images vary in size up to 16k textures. + + Skies are sorted by time of day or style in folders. + Each individual sky has a folder which contains the textures and a material with those textures assigned. + There is also a demo scene with example lighting and fog pass for reference. + + Each sky has its own 6 sided skybox material which you can set to your scene's current skybox. + Please consult the Unity documentation if you are unsure how to do this. + http://docs.unity3d.com/Manual/HOWTO-UseSkybox.html + + There is also an equirectangular material. Some users report that this is preferable in their use-case or build platform. + + The materials are mostly set as /mobile/skyboxes shaders - which should be fastest - but you can change them to the other skybox shaders that ship with Unity and set the required textures. Some add tint, exposure and rotation controls. + + The import resolution and type of compression used on the sky textures is entirely up to you. It should be set at a level which you feel utilises appropriate amounts of memory for your game amd platform, taking into account the amount of compression artifacts that you feel are acceptable. + +DEMO SCENE + + Each sky folder also has a demo scene. This shows a simple low-poly environment to demonstrate lighting and fog settings for that sky. + + It was lit in the Forward Lighting Rendering Path with Linear lighting Color Space. + For intended demo scene lighting values and fog to be visible you will need a project with those settings. + (Under Edit->Project Settings->Player) + If you have to change these settings it may be necessary to re-import the sky textures. + + The demo scene can benefit from increasing the Pixel light count in quality settings, and the Shadow Distance. + +WHO + + This asset pack is by Richard Whitelock. + A game developer, digital artist & photographer. + 15+ years in the games industry working in a variety of senior art roles on 20+ titles. + Particularly experienced in environment art, lighting & special FX. + Currently working on various indie game & personal projects. + + http://www.richardwhitelock.com + diff --git a/Assets/Textures/Skies/planets/back.png b/Assets/Textures/Skies/planets/back.png new file mode 100644 index 0000000..5230d4b Binary files /dev/null and b/Assets/Textures/Skies/planets/back.png differ diff --git a/Assets/Textures/Skies/planets/down.png b/Assets/Textures/Skies/planets/down.png new file mode 100644 index 0000000..3f16de5 Binary files /dev/null and b/Assets/Textures/Skies/planets/down.png differ diff --git a/Assets/Textures/Skies/planets/front.png b/Assets/Textures/Skies/planets/front.png new file mode 100644 index 0000000..16c9d85 Binary files /dev/null and b/Assets/Textures/Skies/planets/front.png differ diff --git a/Assets/Textures/Skies/planets/left.png b/Assets/Textures/Skies/planets/left.png new file mode 100644 index 0000000..39cd6e2 Binary files /dev/null and b/Assets/Textures/Skies/planets/left.png differ diff --git a/Assets/Textures/Skies/planets/right.png b/Assets/Textures/Skies/planets/right.png new file mode 100644 index 0000000..2e3e966 Binary files /dev/null and b/Assets/Textures/Skies/planets/right.png differ diff --git a/Assets/Textures/Skies/planets/up.png b/Assets/Textures/Skies/planets/up.png new file mode 100644 index 0000000..e9cd2c1 Binary files /dev/null and b/Assets/Textures/Skies/planets/up.png differ diff --git a/Assets/Textures/WithNormals/cobblestone.png b/Assets/Textures/WithNormals/cobblestone.png new file mode 100644 index 0000000..14f72ab Binary files /dev/null and b/Assets/Textures/WithNormals/cobblestone.png differ diff --git a/Assets/Textures/WithNormals/cobblestone_normals.png b/Assets/Textures/WithNormals/cobblestone_normals.png new file mode 100644 index 0000000..e58bde8 Binary files /dev/null and b/Assets/Textures/WithNormals/cobblestone_normals.png differ diff --git a/Assets/Textures/WithNormals/cobblestone_specular.png b/Assets/Textures/WithNormals/cobblestone_specular.png new file mode 100644 index 0000000..9d46404 Binary files /dev/null and b/Assets/Textures/WithNormals/cobblestone_specular.png differ diff --git a/Assets/Textures/WithNormals/cushion.png b/Assets/Textures/WithNormals/cushion.png new file mode 100644 index 0000000..8a789b1 Binary files /dev/null and b/Assets/Textures/WithNormals/cushion.png differ diff --git a/Assets/Textures/WithNormals/cushion_normals.png b/Assets/Textures/WithNormals/cushion_normals.png new file mode 100644 index 0000000..d8ca474 Binary files /dev/null and b/Assets/Textures/WithNormals/cushion_normals.png differ diff --git a/Assets/Textures/WithNormals/cushion_specular.png b/Assets/Textures/WithNormals/cushion_specular.png new file mode 100644 index 0000000..394d361 Binary files /dev/null and b/Assets/Textures/WithNormals/cushion_specular.png differ diff --git a/Assets/Textures/WithNormals/rock.png b/Assets/Textures/WithNormals/rock.png new file mode 100644 index 0000000..e8858a3 Binary files /dev/null and b/Assets/Textures/WithNormals/rock.png differ diff --git a/Assets/Textures/WithNormals/rock_normals.png b/Assets/Textures/WithNormals/rock_normals.png new file mode 100644 index 0000000..ee5a435 Binary files /dev/null and b/Assets/Textures/WithNormals/rock_normals.png differ diff --git a/Assets/Textures/WithNormals/rock_specular.png b/Assets/Textures/WithNormals/rock_specular.png new file mode 100644 index 0000000..a6bc227 Binary files /dev/null and b/Assets/Textures/WithNormals/rock_specular.png differ diff --git a/DX11Starter.vcxproj b/DX11Starter.vcxproj index 5d29ec5..c06c975 100644 --- a/DX11Starter.vcxproj +++ b/DX11Starter.vcxproj @@ -144,6 +144,7 @@ + @@ -156,6 +157,7 @@ + @@ -186,6 +188,18 @@ Pixel Pixel + + Pixel + Pixel + Pixel + Pixel + + + Vertex + Vertex + Vertex + Vertex + Vertex 5.0 @@ -309,6 +323,7 @@ + @@ -685,6 +700,220 @@ $(OutDir)/Assets/Textures/HQGame + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + $(OutDir)/Assets/Textures/WithNormals + + + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + + + false + true + false + true + false + true + false + true + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + $(OutDir)/Assets/Textures/Skies/planets + + diff --git a/DX11Starter.vcxproj.filters b/DX11Starter.vcxproj.filters index ba641ac..9ad1d9c 100644 --- a/DX11Starter.vcxproj.filters +++ b/DX11Starter.vcxproj.filters @@ -28,6 +28,15 @@ {347d5c70-73d2-4716-b28c-06526433d151} + + {7476640e-6b46-49e4-a478-c3ce10b2ddca} + + + {343d3538-c075-4c73-8ca8-f919b5ba231b} + + + {f0ccea00-427b-47f7-8fce-7110b649b668} + @@ -60,6 +69,9 @@ Source Files + + Source Files + @@ -95,6 +107,9 @@ Header Files + + Header Files + @@ -109,6 +124,12 @@ Shaders + + Shaders + + + Shaders + @@ -210,6 +231,51 @@ Assets\Textures\HQGame + + Assets\Textures\WithNormals + + + Assets\Textures\WithNormals + + + Assets\Textures\WithNormals + + + Assets\Textures\WithNormals + + + Assets\Textures\WithNormals + + + Assets\Textures\WithNormals + + + Assets\Textures\WithNormals + + + Assets\Textures\WithNormals + + + Assets\Textures\WithNormals + + + Assets\Textures\Skies\planets + + + Assets\Textures\Skies\planets + + + Assets\Textures\Skies\planets + + + Assets\Textures\Skies\planets + + + Assets\Textures\Skies\planets + + + Assets\Textures\Skies\planets + @@ -225,5 +291,8 @@ Shaders + + Shaders + \ No newline at end of file diff --git a/Defines.hlsli b/Defines.hlsli index e31b1ae..19e0c25 100644 --- a/Defines.hlsli +++ b/Defines.hlsli @@ -16,6 +16,7 @@ struct VertexToPixel float2 uv : TEXCOORD; float3 normal : NORMAL; float3 worldPosition : POSITION; + float3 tangent : TANGENT; }; // Struct representing a single vertex worth of data @@ -29,6 +30,7 @@ struct VertexShaderInput // v v v float3 localPosition : POSITION; float3 normal : NORMAL; + float3 tangent : TANGENT; float2 uv : TEXCOORD; }; diff --git a/Game.cpp b/Game.cpp index 1381f94..04b19dd 100644 --- a/Game.cpp +++ b/Game.cpp @@ -80,6 +80,8 @@ void Game::LoadShadersAndMaterials() materials = { std::make_shared(white, 0, vertexShader, pixelShader), std::make_shared(white, 0, vertexShader, pixelShader), + std::make_shared(white, 0, vertexShader, pixelShader), + std::make_shared(white, 0, vertexShader, pixelShader), }; } @@ -88,8 +90,6 @@ void Game::LoadShadersAndMaterials() // -------------------------------------------------------- void Game::LoadTextures() { - Microsoft::WRL::ComPtr sampler; - D3D11_SAMPLER_DESC sampDesc = {}; sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; @@ -99,15 +99,44 @@ void Game::LoadTextures() sampDesc.MaxLOD = D3D11_FLOAT32_MAX; device->CreateSamplerState(&sampDesc, sampler.GetAddressOf()); + demoCubemap = CreateCubemap( + device, + context, + L"Assets/Textures/Skies/planets/right.png", + L"Assets/Textures/Skies/planets/left.png", + L"Assets/Textures/Skies/planets/up.png", + L"Assets/Textures/Skies/planets/down.png", + L"Assets/Textures/Skies/planets/front.png", + L"Assets/Textures/Skies/planets/back.png" + ); + materials[0]->PushSampler("BasicSampler", sampler); + materials[0]->PushTexture(TEXTYPE_REFLECTION, demoCubemap); + materials[0]->hasReflectionMap = true; materials[0]->LoadTexture(L"Assets/Textures/HQGame/structure-endgame-deepfloor_albedo.png", TEXTYPE_ALBEDO, device.Get(), context.Get()); materials[0]->LoadTexture(L"Assets/Textures/HQGame/structure-endgame-deepfloor_specular.png", TEXTYPE_SPECULAR, device.Get(), context.Get()); materials[0]->LoadTexture(L"Assets/Textures/HQGame/structure-endgame-deepfloor_emissive.png", TEXTYPE_EMISSIVE, device.Get(), context.Get()); materials[1]->PushSampler("BasicSampler", sampler); - materials[1]->LoadTexture(L"Assets/Textures/HQGame/structure-endgame-floor_albedo.png", TEXTYPE_ALBEDO, device.Get(), context.Get()); - materials[1]->LoadTexture(L"Assets/Textures/HQGame/structure-endgame-floor_specular.png", TEXTYPE_SPECULAR, device.Get(), context.Get()); - materials[1]->LoadTexture(L"Assets/Textures/HQGame/structure-endgame-floor_emissive.png", TEXTYPE_EMISSIVE, device.Get(), context.Get()); + materials[1]->PushTexture(TEXTYPE_REFLECTION, demoCubemap); + materials[1]->hasReflectionMap = true; + materials[1]->LoadTexture(L"Assets/Textures/WithNormals/cobblestone.png", TEXTYPE_ALBEDO, device.Get(), context.Get()); + materials[1]->LoadTexture(L"Assets/Textures/WithNormals/cobblestone_specular.png", TEXTYPE_SPECULAR, device.Get(), context.Get()); + materials[1]->LoadTexture(L"Assets/Textures/WithNormals/cobblestone_normals.png", TEXTYPE_NORMAL, device.Get(), context.Get()); + + materials[2]->PushSampler("BasicSampler", sampler); + materials[2]->PushTexture(TEXTYPE_REFLECTION, demoCubemap); + materials[2]->hasReflectionMap = true; + materials[2]->LoadTexture(L"Assets/Textures/WithNormals/rock.png", TEXTYPE_ALBEDO, device.Get(), context.Get()); + materials[2]->LoadTexture(L"Assets/Textures/WithNormals/rock_specular.png", TEXTYPE_SPECULAR, device.Get(), context.Get()); + materials[2]->LoadTexture(L"Assets/Textures/WithNormals/rock_normals.png", TEXTYPE_NORMAL, device.Get(), context.Get()); + + materials[3]->PushSampler("BasicSampler", sampler); + materials[3]->PushTexture(TEXTYPE_REFLECTION, demoCubemap); + materials[3]->hasReflectionMap = true; + materials[3]->LoadTexture(L"Assets/Textures/WithNormals/cushion.png", TEXTYPE_ALBEDO, device.Get(), context.Get()); + materials[3]->LoadTexture(L"Assets/Textures/WithNormals/cushion_specular.png", TEXTYPE_SPECULAR, device.Get(), context.Get()); + materials[3]->LoadTexture(L"Assets/Textures/WithNormals/cushion_normals.png", TEXTYPE_NORMAL, device.Get(), context.Get()); } // -------------------------------------------------------- @@ -118,12 +147,13 @@ void Game::LoadLighting() ambient = XMFLOAT3(0.1f, 0.1f, 0.15f); lights = { - Light::Directional(XMFLOAT3(1, 0.5f, 0.5f), XMFLOAT3(1, 1, 1), 0.5f), - Light::Directional(XMFLOAT3(-0.25f, -1, 0.75f), XMFLOAT3(1, 1, 1), 0.5f), - Light::Directional(XMFLOAT3(-1, 1, -0.5f), XMFLOAT3(1, 1, 1), 0.5f), + Light::Directional(XMFLOAT3(1, 0.5f, 0.5f), XMFLOAT3(1, 1, 1), 0.75f), + Light::Directional(XMFLOAT3(-0.25f, -1, 0.75f), XMFLOAT3(1, 1, 1), 0.75f), + Light::Directional(XMFLOAT3(-1, 1, -0.5f), XMFLOAT3(1, 1, 1), 0.75f), Light::Point(XMFLOAT3(-1.5f, 0, 0), XMFLOAT3(1, 1, 1), 0.5f, 10), Light::Point(XMFLOAT3(1.5f, 0, 0), XMFLOAT3(1, 1, 1), 0.25f, 10), Light::Point(XMFLOAT3(0, 2, 0), XMFLOAT3(1, 0, 0), 0.25f, 10), + Light::Point(XMFLOAT3(-27.5f, 0, 0), XMFLOAT3(1, 1, 0.5f), 5, 20), }; } @@ -157,20 +187,31 @@ void Game::CreateBasicGeometry() }; entities = { - std::make_shared(materials[0], shapes[0]), - std::make_shared(materials[0], shapes[1]), - std::make_shared(materials[0], shapes[2]), - std::make_shared(materials[0], shapes[3]), + std::make_shared(materials[1], shapes[0]), + std::make_shared(materials[2], shapes[1]), + std::make_shared(materials[3], shapes[2]), + std::make_shared(materials[2], shapes[3]), std::make_shared(materials[1], shapes[4]), - std::make_shared(materials[1], shapes[5]), - std::make_shared(materials[1], shapes[6]), + std::make_shared(materials[0], shapes[5]), + std::make_shared(materials[0], shapes[6]), }; + entities[6]->GetMaterial()->SetEmitAmount(0.75f); + for (int i = 0; i < entities.size(); ++i) { entities[i]->GetTransform()->SetPosition((-(int)(entities.size() / 2) + i) * 5, 0, 0); - entities[i]->GetMaterial()->SetEmitAmount((entities.size() - i) * 0.25f); + entities[i]->GetMaterial()->SetRoughness(0.60f); } + + skybox = std::make_shared( + shapes[0], + std::make_shared(device, context, GetFullPathTo_Wide(L"SkyboxVertexShader.cso").c_str()), + std::make_shared(device, context, GetFullPathTo_Wide(L"SkyboxPixelShader.cso").c_str()), + demoCubemap, + sampler, + device + ); } @@ -226,6 +267,8 @@ void Game::Draw(float deltaTime, float totalTime) entity->Draw(camera, ambient, lights); } + skybox->Draw(context, camera); + // Present the back buffer to the user // - Puts the final frame we're drawing into the window so the user can see it // - Do this exactly ONCE PER FRAME (always at the very end of the frame) @@ -234,4 +277,113 @@ void Game::Draw(float deltaTime, float totalTime) // Due to the usage of a more sophisticated swap chain, // the render target must be re-bound after every call to Present() context->OMSetRenderTargets(1, backBufferRTV.GetAddressOf(), depthStencilView.Get()); -} \ No newline at end of file +} + +// -------------------------------------------------------- +// Loads six individual textures (the six faces of a cube map), then +// creates a blank cube map and copies each of the six textures to +// another face. Afterwards, creates a shader resource view for +// the cube map and cleans up all of the temporary resources. +// -------------------------------------------------------- +Microsoft::WRL::ComPtr Game::CreateCubemap( + Microsoft::WRL::ComPtr device, + Microsoft::WRL::ComPtr context, + const wchar_t* right, + const wchar_t* left, + const wchar_t* up, + const wchar_t* down, + const wchar_t* front, + const wchar_t* back) +{ + +// -------------------------------------------------------- +// Author: Chris Cascioli +// Purpose: Creates a cube map on the GPU from 6 individual textures +// +// - You are allowed to directly copy/paste this into your code base +// for assignments, given that you clearly cite that this is not +// code of your own design. +// +// - Note: This code assumes you’re putting the function in Game.cpp, +// you’ve included WICTextureLoader.h and you have an ID3D11Device +// ComPtr called “device”. Make any adjustments necessary for +// your own implementation. +// -------------------------------------------------------- + + // Load the 6 textures into an array. + // - We need references to the TEXTURES, not the SHADER RESOURCE VIEWS! + // - Specifically NOT generating mipmaps, as we usually don't need them for the sky! + // - Order matters here! +X, -X, +Y, -Y, +Z, -Z + ID3D11Texture2D* textures[6] = {}; + CreateWICTextureFromFile(device.Get(), right, (ID3D11Resource**)&textures[0], 0); + CreateWICTextureFromFile(device.Get(), left, (ID3D11Resource**)&textures[1], 0); + CreateWICTextureFromFile(device.Get(), up, (ID3D11Resource**)&textures[2], 0); + CreateWICTextureFromFile(device.Get(), down, (ID3D11Resource**)&textures[3], 0); + CreateWICTextureFromFile(device.Get(), front, (ID3D11Resource**)&textures[4], 0); + CreateWICTextureFromFile(device.Get(), back, (ID3D11Resource**)&textures[5], 0); + + // We'll assume all of the textures are the same color format and resolution, + // so get the description of the first shader resource view + D3D11_TEXTURE2D_DESC faceDesc = {}; + textures[0]->GetDesc(&faceDesc); + + // Describe the resource for the cube map, which is simply + // a "texture 2d array". This is a special GPU resource format, + // NOT just a C++ array of textures!!! + D3D11_TEXTURE2D_DESC cubeDesc = {}; + cubeDesc.ArraySize = 6; // Cube map! + cubeDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; // We'll be using as a texture in a shader + cubeDesc.CPUAccessFlags = 0; // No read back + cubeDesc.Format = faceDesc.Format; // Match the loaded texture's color format + cubeDesc.Width = faceDesc.Width; // Match the size + cubeDesc.Height = faceDesc.Height; // Match the size + cubeDesc.MipLevels = 1; // Only need 1 + cubeDesc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; // A CUBE MAP, not 6 separate textures + cubeDesc.Usage = D3D11_USAGE_DEFAULT; // Standard usage + cubeDesc.SampleDesc.Count = 1; + cubeDesc.SampleDesc.Quality = 0; + + // Create the actual texture resource + ID3D11Texture2D* cubeMapTexture = 0; + device->CreateTexture2D(&cubeDesc, 0, &cubeMapTexture); + + // Loop through the individual face textures and copy them, + // one at a time, to the cube map texure + for (int i = 0; i < 6; i++) + { + // Calculate the subresource position to copy into + unsigned int subresource = D3D11CalcSubresource( + 0, // Which mip (zero, since there's only one) + i, // Which array element? + 1); // How many mip levels are in the texture? + + // Copy from one resource (texture) to another + context->CopySubresourceRegion( + cubeMapTexture, // Destination resource + subresource, // Dest subresource index (one of the array elements) + 0, 0, 0, // XYZ location of copy + textures[i], // Source resource + 0, // Source subresource index (we're assuming there's only one) + 0); // Source subresource "box" of data to copy (zero means the whole thing) + } + + // At this point, all of the faces have been copied into the + // cube map texture, so we can describe a shader resource view for it + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.Format = cubeDesc.Format; // Same format as texture + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; // Treat this as a cube! + srvDesc.TextureCube.MipLevels = 1; // Only need access to 1 mip + srvDesc.TextureCube.MostDetailedMip = 0; // Index of the first mip we want to see + + // Make the SRV + Microsoft::WRL::ComPtr cubeSRV; + device->CreateShaderResourceView(cubeMapTexture, &srvDesc, cubeSRV.GetAddressOf()); + + // Now that we're done, clean up the stuff we don't need anymore + cubeMapTexture->Release(); // Done with this particular reference (the SRV has another) + for (int i = 0; i < 6; i++) + textures[i]->Release(); + + // Send back the SRV, which is what we need for our shaders + return cubeSRV; +} diff --git a/Game.h b/Game.h index f62f3f3..ceed40c 100644 --- a/Game.h +++ b/Game.h @@ -7,6 +7,7 @@ #include "SimpleShader.h" #include "Material.h" #include "Lights.h" +#include "Sky.h" #include #include // Used for ComPtr - a smart pointer for COM objects #include @@ -19,10 +20,20 @@ public: Game(HINSTANCE hInstance); ~Game(); - void Init(); - void OnResize(); - void Update(float deltaTime, float totalTime); - void Draw(float deltaTime, float totalTime); + void Init(); + void OnResize(); + void Update(float deltaTime, float totalTime); + void Draw(float deltaTime, float totalTime); + + static Microsoft::WRL::ComPtr CreateCubemap( + Microsoft::WRL::ComPtr _device, + Microsoft::WRL::ComPtr _context, + const wchar_t* _right, + const wchar_t* _left, + const wchar_t* _up, + const wchar_t* _down, + const wchar_t* _front, + const wchar_t* _back); private: // Should we use vsync to limit the frame rate? @@ -48,6 +59,10 @@ private: // A7 Lights std::vector lights; DirectX::XMFLOAT3 ambient; + // A9 Normalmaps & Cubemaps + std::shared_ptr skybox; + Microsoft::WRL::ComPtr sampler; + Microsoft::WRL::ComPtr demoCubemap; Microsoft::WRL::ComPtr constantBufferVS; }; diff --git a/Helpers.hlsli b/Helpers.hlsli index f674ce4..4e9a634 100644 --- a/Helpers.hlsli +++ b/Helpers.hlsli @@ -1,6 +1,9 @@ #ifndef __SHADER_HELPERS__ #define __SHADER_HELPERS__ +// from environment map demo +static const float F0_NON_METAL = 0.04f; + // gets view vector, needed once per shader float3 getView(float3 cameraPosition, float3 pixelWorldPosition) { @@ -44,4 +47,11 @@ float getAttenuation(float3 pointPosition, float3 worldPosition, float3 range) return attn * attn; } +// from environment map demo +// gets fresnel (Schlick approx.): f0 + (1-f0)(1 - (n dot v))^5 +float getFresnel(float3 normal, float3 view, float specularValue) +{ + return specularValue + (1 - specularValue) * pow(1 - saturate(dot(normal, view)), 5); +} + #endif diff --git a/Lights.hlsli b/Lights.hlsli index 3fd4973..633e801 100644 --- a/Lights.hlsli +++ b/Lights.hlsli @@ -22,4 +22,35 @@ struct Light float3 Padding; }; +// Gets the specular value for any light +float calculateSpecular(float3 normal, float3 direction, float3 view, float roughness, float diffuse) +{ + return getSpecular( + view, + getReflection(direction, normal), + getSpecularExponent(roughness, MAX_SPECULAR_EXPONENT) + ) * any(diffuse); +} + +// Gets the RGB value of a pixel with a directional light +float3 calculateDirectionalLight(Light light, float3 normal, float3 view, float roughness, float3 surfaceColor, float specularValue) +{ + float3 lightDirection = normalize(light.Direction); + float diffuse = getDiffuse(normal, -lightDirection); + float specular = calculateSpecular(normal, lightDirection, view, roughness, diffuse) * specularValue; + + return (diffuse * surfaceColor + specular) * light.Intensity * light.Color; +} + +// Gets the RGB value of a pixel with a point light +float3 calculatePointLight(Light light, float3 normal, float3 view, float3 worldPosition, float roughness, float3 surfaceColor, float specularValue) +{ + float3 lightDirection = normalize(light.Position - worldPosition); + float attenuation = getAttenuation(light.Position, worldPosition, light.Range); + float diffuse = getDiffuse(normal, lightDirection); + float specular = calculateSpecular(normal, lightDirection, view, roughness, diffuse) * specularValue; + + return (diffuse * surfaceColor + specular) * attenuation * light.Intensity * light.Color; +} + #endif diff --git a/Material.cpp b/Material.cpp index dc99ff6..9ca9fbd 100644 --- a/Material.cpp +++ b/Material.cpp @@ -13,6 +13,10 @@ Material::Material( uvOffset = DirectX::XMFLOAT2(0, 0); uvScale = DirectX::XMFLOAT2(1, 1); emitAmount = 0; + hasEmissiveMap = false; + hasSpecularMap = false; + hasNormalMap = false; + hasReflectionMap = false; } Material::~Material() @@ -36,6 +40,10 @@ void Material::Activate(Transform* _transform, std::shared_ptr _camera, pixelShader->SetFloat("emitAmount", GetEmitAmount()); pixelShader->SetFloat3("tint", GetTint()); pixelShader->SetFloat("lightCount", (int)_lights.size()); + pixelShader->SetInt("hasEmissiveMap", (int)hasEmissiveMap); + pixelShader->SetInt("hasSpecularMap", (int)hasSpecularMap); + pixelShader->SetInt("hasNormalMap", (int)hasNormalMap); + pixelShader->SetInt("hasReflectionMap", (int)hasReflectionMap); pixelShader->SetData("lights", &_lights[0], sizeof(Light) * (int)_lights.size()); pixelShader->CopyAllBufferData(); pixelShader->SetShader(); @@ -136,6 +144,11 @@ void Material::LoadTexture(const wchar_t* _path, const char* _type, ID3D11Device Microsoft::WRL::ComPtr shaderResourceView; DirectX::CreateWICTextureFromFile(_device, _context, DXCore::GetFullPathTo_Wide(_path).c_str(), 0, shaderResourceView.GetAddressOf()); PushTexture(_type, shaderResourceView); + + if (_type == TEXTYPE_EMISSIVE) hasEmissiveMap = true; + else if (_type == TEXTYPE_SPECULAR) hasSpecularMap = true; + else if (_type == TEXTYPE_NORMAL) hasNormalMap = true; + else if (_type == TEXTYPE_REFLECTION) hasReflectionMap = true; } void Material::PushSampler(std::string _name, Microsoft::WRL::ComPtr _sampler) diff --git a/Material.h b/Material.h index cdbd90b..3375880 100644 --- a/Material.h +++ b/Material.h @@ -13,6 +13,7 @@ constexpr auto TEXTYPE_ALBEDO = "Albedo"; constexpr auto TEXTYPE_NORMAL = "Normal"; constexpr auto TEXTYPE_EMISSIVE = "Emissive"; constexpr auto TEXTYPE_SPECULAR = "Specular"; +constexpr auto TEXTYPE_REFLECTION = "Reflection"; class Material { @@ -50,6 +51,10 @@ public: void PushSampler(std::string _name, Microsoft::WRL::ComPtr _sampler); void PushTexture(std::string _name, Microsoft::WRL::ComPtr _texture); + bool hasEmissiveMap; + bool hasSpecularMap; + bool hasNormalMap; + bool hasReflectionMap; private: DirectX::XMFLOAT3 tint; float roughness; diff --git a/Mesh.cpp b/Mesh.cpp index f1a0bbd..78e5fa1 100644 --- a/Mesh.cpp +++ b/Mesh.cpp @@ -230,9 +230,100 @@ Mesh::Mesh(const char* _file, Microsoft::WRL::ComPtr _device, Micr // sophisticated model loading library like TinyOBJLoader or AssImp (yes, that's its name) /// END OBJLOADER /// + CalculateTangents(&verts[0], verts.size(), &indices[0], indices.size()); CreateMesh(&verts[0], verts.size(), &indices[0], indices.size(), _device, _context); } +// -------------------------------------------------------- +// Author: Chris Cascioli +// Purpose: Calculates the tangents of the vertices in a mesh +// +// - You are allowed to directly copy/paste this into your code base +// for assignments, given that you clearly cite that this is not +// code of your own design. +// +// - Code originally adapted from: http://www.terathon.com/code/tangent.html +// - Updated version now found here: http://foundationsofgameenginedev.com/FGED2-sample.pdf +// - See listing 7.4 in section 7.5 (page 9 of the PDF) +// +// - Note: For this code to work, your Vertex format must +// contain an XMFLOAT3 called Tangent +// +// - Be sure to call this BEFORE creating your D3D vertex/index buffers +// -------------------------------------------------------- +void Mesh::CalculateTangents(Vertex* verts, int numVerts, unsigned int* indices, int numIndices) +{ + // Reset tangents + for (int i = 0; i < numVerts; i++) + { + verts[i].Tangent = XMFLOAT3(0, 0, 0); + } + + // Calculate tangents one whole triangle at a time + for (int i = 0; i < numIndices;) + { + // Grab indices and vertices of first triangle + unsigned int i1 = indices[i++]; + unsigned int i2 = indices[i++]; + unsigned int i3 = indices[i++]; + Vertex* v1 = &verts[i1]; + Vertex* v2 = &verts[i2]; + Vertex* v3 = &verts[i3]; + + // Calculate vectors relative to triangle positions + float x1 = v2->Position.x - v1->Position.x; + float y1 = v2->Position.y - v1->Position.y; + float z1 = v2->Position.z - v1->Position.z; + + float x2 = v3->Position.x - v1->Position.x; + float y2 = v3->Position.y - v1->Position.y; + float z2 = v3->Position.z - v1->Position.z; + + // Do the same for vectors relative to triangle uv's + float s1 = v2->UV.x - v1->UV.x; + float t1 = v2->UV.y - v1->UV.y; + + float s2 = v3->UV.x - v1->UV.x; + float t2 = v3->UV.y - v1->UV.y; + + // Create vectors for tangent calculation + float r = 1.0f / (s1 * t2 - s2 * t1); + + float tx = (t2 * x1 - t1 * x2) * r; + float ty = (t2 * y1 - t1 * y2) * r; + float tz = (t2 * z1 - t1 * z2) * r; + + // Adjust tangents of each vert of the triangle + v1->Tangent.x += tx; + v1->Tangent.y += ty; + v1->Tangent.z += tz; + + v2->Tangent.x += tx; + v2->Tangent.y += ty; + v2->Tangent.z += tz; + + v3->Tangent.x += tx; + v3->Tangent.y += ty; + v3->Tangent.z += tz; + } + + // Ensure all of the tangents are orthogonal to the normals + for (int i = 0; i < numVerts; i++) + { + // Grab the two vectors + XMVECTOR normal = XMLoadFloat3(&verts[i].Normal); + XMVECTOR tangent = XMLoadFloat3(&verts[i].Tangent); + + // Use Gram-Schmidt orthonormalize to ensure + // the normal and tangent are exactly 90 degrees apart + tangent = XMVector3Normalize( + tangent - normal * XMVector3Dot(normal, tangent)); + + // Store the tangent + XMStoreFloat3(&verts[i].Tangent, tangent); + } +} + void Mesh::CreateMesh(Vertex* _vertices, int _vertexCount, unsigned int* _indices, int _indexCount, Microsoft::WRL::ComPtr _device, Microsoft::WRL::ComPtr _context) { // Create the VERTEX BUFFER description diff --git a/Mesh.h b/Mesh.h index ad90b4d..c912c4a 100644 --- a/Mesh.h +++ b/Mesh.h @@ -31,6 +31,11 @@ private: Microsoft::WRL::ComPtr deviceContext; int countIndex; + void CalculateTangents( + Vertex* _verts, + int _numVerts, + unsigned int* _indices, + int _numIndices); void CreateMesh( Vertex* _vertices, int _vertexCount, diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index a7c90d2..7c986d6 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -18,58 +18,45 @@ cbuffer ExternalData : register(b0) float3 tint; float lightCount; + int hasEmissiveMap; + int hasSpecularMap; + int hasNormalMap; + int hasReflectionMap; + Light lights[MAX_LIGHTS]; } Texture2D Albedo : register(t0); Texture2D Specular : register(t1); Texture2D Emissive : register(t2); +Texture2D Normal : register(t3); +TextureCube Reflection : register(t4); SamplerState BasicSampler : register(s0); -// Gets the specular value for any light -float calculateSpecular(float3 normal, float3 direction, float3 view, float roughness) -{ - return getSpecular( - view, - getReflection(direction, normal), - getSpecularExponent(roughness, MAX_SPECULAR_EXPONENT) - ); -} - -// Gets the RGB value of a pixel with a directional light -float3 calculateDirectionalLight(Light light, float3 normal, float3 view, float roughness, float3 surfaceColor, float specularValue) -{ - float3 lightDirection = normalize(light.Direction); - float diffuse = getDiffuse(normal, -lightDirection); - float specular = calculateSpecular(normal, lightDirection, view, roughness) * specularValue; - - return (diffuse * surfaceColor + specular) * light.Intensity * light.Color; -} - -// Gets the RGB value of a pixel with a point light -float3 calculatePointLight(Light light, float3 normal, float3 view, float3 worldPosition, float roughness, float3 surfaceColor, float specularValue) -{ - float3 lightDirection = normalize(light.Position - worldPosition); - float attenuation = getAttenuation(light.Position, worldPosition, light.Range); - float diffuse = getDiffuse(normal, lightDirection); - float specular = calculateSpecular(normal, lightDirection, view, roughness) * specularValue; - - return (diffuse * surfaceColor + specular) * attenuation * light.Intensity * light.Color; -} - // shader entry point float4 main(VertexToPixel input) : SV_TARGET { // ensure input normals are normalized input.normal = normalize(input.normal); + input.tangent = normalize(input.tangent); + if (hasNormalMap > 0) + { + float3 unpackedNormal = Normal.Sample(BasicSampler, input.uv).rgb * 2 - 1; + float3 T = normalize(input.tangent - input.normal * dot(input.tangent, input.normal)); + float3 B = cross(T, input.normal); + float3x3 TBN = float3x3(T, B, input.normal); + input.normal = mul(unpackedNormal, TBN); + } input.uv = input.uv * scale + offset; // view only needs calculated once, so pre-calculate here and pass it to lights float3 view = getView(cameraPosition, input.worldPosition); float4 albedo = Albedo.Sample(BasicSampler, input.uv).rgba; - float specular = Specular.Sample(BasicSampler, input.uv).r; - float3 emit = Emissive.Sample(BasicSampler, input.uv).rgb; + float specular = 1; + if (hasSpecularMap > 0) specular = Specular.Sample(BasicSampler, input.uv).r; + float3 emit = float3(1, 1, 1); + if (hasEmissiveMap > 0) emit = Emissive.Sample(BasicSampler, input.uv).rgb; float3 surface = albedo.rgb * tint; float3 light = ambient * surface; @@ -87,5 +74,14 @@ float4 main(VertexToPixel input) : SV_TARGET } } - return float4(light + (emit * emitAmount), albedo.a); + float3 final = float3(light + (emit * emitAmount)); + + if (hasReflectionMap > 0) + { + float3 reflVec = getReflection(view, input.normal); + float3 reflCol = Reflection.Sample(BasicSampler, reflVec).rgba; + final = lerp(final, reflCol, getFresnel(input.normal, view, F0_NON_METAL)); + } + + return float4(final, albedo.a); } diff --git a/Sky.cpp b/Sky.cpp new file mode 100644 index 0000000..8a54ed2 --- /dev/null +++ b/Sky.cpp @@ -0,0 +1,51 @@ +#include "Sky.h" + +Sky::Sky( + std::shared_ptr _mesh, + std::shared_ptr _vertexShader, + std::shared_ptr _pixelShader, + Microsoft::WRL::ComPtr _cubemap, + Microsoft::WRL::ComPtr _sampler, + Microsoft::WRL::ComPtr _device) +{ + mesh = _mesh; + cubemap = _cubemap; + sampler = _sampler; + vertexShader = _vertexShader; + pixelShader = _pixelShader; + + D3D11_RASTERIZER_DESC rDesc = {}; + rDesc.FillMode = D3D11_FILL_SOLID; + rDesc.CullMode = D3D11_CULL_FRONT; + _device->CreateRasterizerState(&rDesc, rasterizerState.GetAddressOf()); + + D3D11_DEPTH_STENCIL_DESC dDesc = {}; + dDesc.DepthEnable = true; + dDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + _device->CreateDepthStencilState(&dDesc, depthState.GetAddressOf()); +} + +Sky::~Sky() +{ +} + +void Sky::Draw(Microsoft::WRL::ComPtr _context, std::shared_ptr _camera) +{ + _context->RSSetState(rasterizerState.Get()); + _context->OMSetDepthStencilState(depthState.Get(), 0); + + vertexShader->SetMatrix4x4("view", _camera->GetViewMatrix()); + vertexShader->SetMatrix4x4("projection", _camera->GetProjectionMatrix()); + vertexShader->CopyAllBufferData(); + vertexShader->SetShader(); + + pixelShader->SetShaderResourceView("SkyTexture", cubemap.Get()); + pixelShader->SetSamplerState("Sampler", sampler.Get()); + pixelShader->CopyAllBufferData(); + pixelShader->SetShader(); + + mesh->Draw(); + + _context->RSSetState(0); + _context->OMSetDepthStencilState(0, 0); +} diff --git a/Sky.h b/Sky.h new file mode 100644 index 0000000..b0bb454 --- /dev/null +++ b/Sky.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include "Mesh.h" +#include "SimpleShader.h" +#include "Camera.h" + +class Sky +{ +public: + Sky( + std::shared_ptr _mesh, + std::shared_ptr _vertexShader, + std::shared_ptr _pixelShader, + Microsoft::WRL::ComPtr _cubemap, + Microsoft::WRL::ComPtr _sampler, + Microsoft::WRL::ComPtr _device); + ~Sky(); + + void Draw( + Microsoft::WRL::ComPtr _context, + std::shared_ptr _camera); + +private: + Microsoft::WRL::ComPtr sampler; + Microsoft::WRL::ComPtr depthState; + Microsoft::WRL::ComPtr rasterizerState; + Microsoft::WRL::ComPtr cubemap; + std::shared_ptr mesh; + std::shared_ptr vertexShader; + std::shared_ptr pixelShader; +}; diff --git a/SkyboxDefines.hlsli b/SkyboxDefines.hlsli new file mode 100644 index 0000000..f70fc71 --- /dev/null +++ b/SkyboxDefines.hlsli @@ -0,0 +1,20 @@ +#ifndef __SKYBOX_DEFINES__ +#define __SKYBOX_DEFINES__ + +struct SkyboxVertexToPixel +{ + float4 screenPosition : SV_POSITION; + float3 sampleDir : DIRECTION; +}; + +// Struct representing a single vertex worth of data +// - This should match Vertex.h +struct SkyboxVertexShaderInput +{ + float3 localPosition : POSITION; + float3 normal : NORMAL; + float3 tangent : TANGENT; + float2 uv : TEXCOORD; +}; + +#endif diff --git a/SkyboxPixelShader.hlsl b/SkyboxPixelShader.hlsl new file mode 100644 index 0000000..cf63c2a --- /dev/null +++ b/SkyboxPixelShader.hlsl @@ -0,0 +1,9 @@ +#include "SkyboxDefines.hlsli" + +TextureCube SkyTexture : register(t0); +SamplerState Sampler : register(s0); + +float4 main(SkyboxVertexToPixel input) : SV_TARGET +{ + return SkyTexture.Sample(Sampler, input.sampleDir); +} diff --git a/SkyboxVertexShader.hlsl b/SkyboxVertexShader.hlsl new file mode 100644 index 0000000..0b822ec --- /dev/null +++ b/SkyboxVertexShader.hlsl @@ -0,0 +1,25 @@ +#include "SkyboxDefines.hlsli" + +cbuffer ExternalData : register(b0) +{ + matrix view; + matrix projection; +} + +matrix RemoveTranslation(matrix m) +{ + m._14 = 0; + m._24 = 0; + m._34 = 0; + return m; +} + +SkyboxVertexToPixel main(SkyboxVertexShaderInput input) +{ + SkyboxVertexToPixel output; + matrix worldViewProjection = mul(projection, RemoveTranslation(view)); + output.screenPosition = mul(worldViewProjection, float4(input.localPosition, 1.0f)); + output.screenPosition.z = output.screenPosition.w; + output.sampleDir = input.localPosition; + return output; +} diff --git a/Vertex.h b/Vertex.h index fe94c18..eef37ea 100644 --- a/Vertex.h +++ b/Vertex.h @@ -11,5 +11,6 @@ struct Vertex { DirectX::XMFLOAT3 Position; DirectX::XMFLOAT3 Normal; + DirectX::XMFLOAT3 Tangent; DirectX::XMFLOAT2 UV; }; \ No newline at end of file diff --git a/VertexShader.hlsl b/VertexShader.hlsl index 85973ee..30950f7 100644 --- a/VertexShader.hlsl +++ b/VertexShader.hlsl @@ -40,6 +40,7 @@ VertexToPixel main( VertexShaderInput input ) // Pass normal and world position throuh output.normal = normalize(mul((float3x3)worldInvTranspose, input.normal)); + output.tangent = normalize(mul((float3x3)worldInvTranspose, input.tangent)); output.worldPosition = mul(world, float4(input.localPosition, 1)).xyz; // Whatever we return will make its way through the pipeline to the