├── TestViewer ├── Assets │ ├── StoreLogo.png │ ├── SplashScreen.scale-200.png │ ├── LockScreenLogo.scale-200.png │ ├── Square44x44Logo.scale-200.png │ ├── Wide310x150Logo.scale-200.png │ ├── Square150x150Logo.scale-200.png │ └── Square44x44Logo.targetsize-24_altform-unplated.png ├── TestViewer_TemporaryKey.pfx ├── App.xaml ├── MainPage.xaml.cs ├── MainPage.xaml ├── Properties │ ├── Default.rd.xml │ └── AssemblyInfo.cs ├── Package.appxmanifest ├── App.xaml.cs └── TestViewer.csproj ├── SceneLoader ├── SceneLoaderComponent.def ├── NugetPackager │ ├── SceneLoaderComponent.props │ ├── SceneLoaderComponent.targets │ └── SceneLoaderComponent.nuspec ├── readme.md ├── pch.cpp ├── SceneLoaderComponent.idl ├── packages.config ├── GLTFVisitor_Skin.cpp ├── UtilForIntermingledNamespaces.h ├── GLTFVisitor_Camera.cpp ├── GLTFVisitor_Sampler.cpp ├── GLTFVisitor_Texture.cpp ├── GLTFVisitor_Mesh.cpp ├── GLTFVisitor_Material.cpp ├── SceneLoader.h ├── Bounds3D.h ├── SceneLoader.vcxproj.filters ├── pch.h ├── GLTFVisitor_Node.cpp ├── UtilForIntermingledNamespaces.cpp ├── SceneResourceSet.h ├── GLTFVisitor.h ├── GLTFVisitor.cpp ├── SceneLoader.cpp ├── Bounds3D.cpp ├── GLTFVisitor_MeshPrimitive.cpp ├── GLTFVisitor_Image.cpp ├── SceneResourceSet.cpp └── SceneLoader.vcxproj ├── version.json ├── Experimental └── CameraComponent │ ├── ModelViewer.xaml │ ├── Projection.cs │ ├── Animatable.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── Camera.cs │ ├── OrthographicProjection.cs │ ├── ModelViewer.xaml.cs │ ├── PerspectiveProjection.cs │ ├── CameraComponent.csproj │ ├── FirstPersonCamera.cs │ ├── OrbitalCamera.cs │ └── Viewport.cs ├── LICENSE.md ├── settings.xamlstyler ├── README.md ├── azure-pipelines.yml ├── SceneLoader.sln └── .gitignore /TestViewer/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/HEAD/TestViewer/Assets/StoreLogo.png -------------------------------------------------------------------------------- /TestViewer/TestViewer_TemporaryKey.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/HEAD/TestViewer/TestViewer_TemporaryKey.pfx -------------------------------------------------------------------------------- /TestViewer/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/HEAD/TestViewer/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /TestViewer/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/HEAD/TestViewer/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /TestViewer/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/HEAD/TestViewer/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /TestViewer/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/HEAD/TestViewer/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /TestViewer/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/HEAD/TestViewer/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /SceneLoader/SceneLoaderComponent.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE 3 | DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE 4 | -------------------------------------------------------------------------------- /SceneLoader/NugetPackager/SceneLoaderComponent.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /TestViewer/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/HEAD/TestViewer/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /SceneLoader/readme.md: -------------------------------------------------------------------------------- 1 | Steps to run locally: 2 | 3 | 1. Clone the repo 4 | 2. Install Windows SDK 18362 5 | 3. cd ..\build 6 | 4. Run ./build.bat 7 | 8 | Outputs: 9 | The project create a nuget package located in ..\bin\nupkg -------------------------------------------------------------------------------- /SceneLoader/pch.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | -------------------------------------------------------------------------------- /TestViewer/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SceneLoader/SceneLoaderComponent.idl: -------------------------------------------------------------------------------- 1 | namespace SceneLoaderComponent 2 | { 3 | [default_interface] 4 | runtimeclass SceneLoader 5 | { 6 | SceneLoader(); 7 | Windows.UI.Composition.Scenes.SceneNode Load(Windows.Storage.Streams.IBuffer buffer, Windows.UI.Composition.Compositor compositor); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /SceneLoader/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-build.{height}", 3 | "publicReleaseRefSpec": [ 4 | "^refs/heads/master$", // we release out of master 5 | "^refs/heads/dev$", // we release out of dev 6 | "^refs/heads/rel/\\d+\\.\\d+\\.\\d+" // we also release branches starting with rel/N.N.N 7 | ], 8 | "nugetPackageVersion":{ 9 | "semVer": 2 10 | }, 11 | "cloudBuild": { 12 | "buildNumber": { 13 | "enabled": false 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Skin.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | using namespace winrt; 12 | 13 | namespace SceneLoader 14 | { 15 | // Skin 16 | void GLTFVisitor::operator()(const Skin& /*skin*/, VisitState /*alreadyVisited*/, const VisitDefaultAction&) 17 | { 18 | } 19 | 20 | 21 | 22 | } -------------------------------------------------------------------------------- /SceneLoader/UtilForIntermingledNamespaces.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | namespace SceneLoader { 8 | winrt::Windows::Foundation::MemoryBuffer CopyArrayOfBytesToMemoryBuffer(BYTE* data, size_t byteLength); 9 | 10 | std::pair GetDataPointerFromMemoryBuffer(winrt::Windows::Foundation::IMemoryBufferReference); 11 | 12 | winrt::hstring GetHSTRINGFromStdString(const std::string& s); 13 | } -------------------------------------------------------------------------------- /Experimental/CameraComponent/ModelViewer.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /TestViewer/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using Windows.UI.Xaml.Controls; 6 | 7 | namespace TestViewer 8 | { 9 | /// 10 | /// A page that generates a gltf image using the SceneLoaderComponent. 11 | /// 12 | public sealed partial class MainPage : Page 13 | { 14 | public MainPage() 15 | { 16 | this.InitializeComponent(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Camera.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | namespace winrt { 12 | using namespace Windows::UI::Composition; 13 | using namespace Windows::UI::Composition::Scenes; 14 | } 15 | using namespace winrt; 16 | 17 | namespace SceneLoader 18 | { 19 | // Camera 20 | void GLTFVisitor::operator()(const Camera& /*camera*/, VisitState /*alreadyVisited*/, const VisitDefaultAction&) 21 | { 22 | } 23 | } -------------------------------------------------------------------------------- /SceneLoader/NugetPackager/SceneLoaderComponent.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | $(MSBuildThisFileDirectory)$(Platform)\SceneLoaderComponent.winmd 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Sampler.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | using namespace winrt; 12 | 13 | namespace SceneLoader 14 | { 15 | void GLTFVisitor::operator()(const Sampler& sampler, VisitState state, const VisitDefaultAction&) 16 | { 17 | if (state == VisitState::New) 18 | { 19 | if (!m_resourceSet->GetGLTFSamplerById(sampler.id, nullptr)) 20 | { 21 | m_resourceSet->StoreGLTFSamplerById(sampler.id, sampler); 22 | } 23 | else 24 | { 25 | Microsoft::glTF::Sampler storedSampler; 26 | 27 | m_resourceSet->GetGLTFSamplerById(sampler.id, &storedSampler); 28 | 29 | assert(storedSampler == sampler); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Texture.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | using namespace winrt; 12 | 13 | namespace SceneLoader 14 | { 15 | void GLTFVisitor::operator()(const Texture& texture, TextureType /*textureType*/, VisitState state, const VisitDefaultAction&) 16 | { 17 | if (state == VisitState::New) 18 | { 19 | if (!m_resourceSet->GetGLTFTextureById(texture.id, nullptr)) 20 | { 21 | m_resourceSet->StoreGLTFTextureById(texture.id, texture); 22 | } 23 | else 24 | { 25 | Microsoft::glTF::Texture storedTexture; 26 | 27 | m_resourceSet->GetGLTFTextureById(texture.id, &storedTexture); 28 | 29 | assert(storedTexture == texture); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Mesh.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | namespace winrt { 12 | using namespace Windows::UI::Composition::Scenes; 13 | } 14 | using namespace winrt; 15 | using namespace std; 16 | 17 | namespace SceneLoader 18 | { 19 | // Mesh 20 | void GLTFVisitor::operator()(const Mesh& mesh, VisitState state) 21 | { 22 | if (state == VisitState::New) 23 | { 24 | wstring meshID{ mesh.id.begin(), mesh.id.end() }; 25 | 26 | // We'll have a new SceneNode for each GLTF Mesh and another for each GLTF MeshComponent. 27 | auto sceneNodeForTheGLTFMesh = SceneNode::Create(m_compositor); 28 | sceneNodeForTheGLTFMesh.Comment(meshID); 29 | 30 | m_latestSceneNode.Children().Append(sceneNodeForTheGLTFMesh); 31 | 32 | m_latestSceneNode = sceneNodeForTheGLTFMesh; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Windows Community Toolkit 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | 5 | All rights reserved. 6 | 7 | # MIT License (MIT) 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Material.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | namespace winrt { 12 | using namespace Windows::UI::Composition::Scenes; 13 | } 14 | using namespace winrt; 15 | 16 | namespace SceneLoader 17 | { 18 | // Material 19 | void GLTFVisitor::operator()(const Material& material, VisitState /*alreadyVisited*/, const VisitDefaultAction&) 20 | { 21 | auto curMaterial = m_resourceSet->EnsureMaterialById(material.id); 22 | 23 | if (!m_resourceSet->GetGLTFMaterialById(material.id, nullptr)) 24 | { 25 | m_resourceSet->StoreGLTFMaterialById(material.id, material); 26 | } 27 | else 28 | { 29 | Microsoft::glTF::Material storedMaterial; 30 | 31 | m_resourceSet->GetGLTFMaterialById(material.id, &storedMaterial); 32 | 33 | assert(storedMaterial == material); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /TestViewer/MainPage.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/Projection.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Numerics; 6 | 7 | namespace CameraComponent 8 | { 9 | /// 10 | /// An interface that defines properties and functions that a Projection object must implement. 11 | /// 12 | public interface Projection : Animatable 13 | { 14 | /// 15 | /// Distance from the camera to the near plane. 16 | /// 17 | float Near { get; set; } 18 | 19 | /// 20 | /// Distance from the camera to the far plane. 21 | /// 22 | float Far { get; set; } 23 | 24 | /// 25 | /// Returns the matrix created by the near and far planes and other properties of the projection. 26 | /// 27 | /// A Matrix4x4 created from the specific type of projection's properties. 28 | Matrix4x4 GetProjectionMatrix(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /TestViewer/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /TestViewer/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Reflection; 6 | using System.Runtime.CompilerServices; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [assembly: AssemblyTitle("TestViewer")] 13 | [assembly: AssemblyDescription("")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("")] 16 | [assembly: AssemblyProduct("TestViewer")] 17 | [assembly: AssemblyCopyright("Copyright © 2019")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Version information for an assembly consists of the following four values: 22 | // 23 | // Major Version 24 | // Minor Version 25 | // Build Number 26 | // Revision 27 | // 28 | // You can specify all the values or you can default the Build and Revision Numbers 29 | // by using the '*' as shown below: 30 | // [assembly: AssemblyVersion("1.0.*")] 31 | [assembly: AssemblyVersion("1.0.0.0")] 32 | [assembly: AssemblyFileVersion("1.0.0.0")] 33 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /Experimental/CameraComponent/Animatable.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using Windows.UI.Composition; 6 | 7 | namespace CameraComponent 8 | { 9 | /// 10 | /// An interface that defines functions non-Composition objects can implement to become animatable. 11 | /// 12 | public interface Animatable 13 | { 14 | /// 15 | /// Returns an object's set of animatable properties. 16 | /// 17 | CompositionPropertySet GetPropertySet(); 18 | 19 | /// 20 | /// Starts a given animation on the specified property. 21 | /// 22 | /// The name of the property to be animated. 23 | /// The animation being applied. 24 | void StartAnimation(string propertyName, CompositionAnimation animation); 25 | 26 | /// 27 | /// Stops any animations on the specified property. 28 | /// 29 | /// The name of the property whose animations we are stopping. 30 | void StopAnimation(string propertyName); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /SceneLoader/SceneLoader.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | #include "SceneLoader.g.h" 8 | 9 | namespace winrt::SceneLoaderComponent::implementation 10 | { 11 | struct SceneLoader : SceneLoaderT 12 | { 13 | SceneLoader() = default; 14 | 15 | winrt::Windows::UI::Composition::Scenes::SceneNode Load(winrt::Windows::Storage::Streams::IBuffer buffer, winrt::Windows::UI::Composition::Compositor compositor); 16 | 17 | private: 18 | void ParseGLTF( 19 | BYTE * data, 20 | UINT32 capacity, 21 | winrt::Windows::UI::Composition::Compositor& compositor, 22 | winrt::Windows::UI::Composition::Scenes::SceneNode& rootNode); 23 | void DoIt( 24 | Microsoft::glTF::Document & gltfDoc, 25 | std::shared_ptr resourceReader, 26 | winrt::Windows::UI::Composition::Compositor& compositor, 27 | winrt::Windows::UI::Composition::Scenes::SceneNode& rootNode); 28 | }; 29 | } 30 | 31 | namespace winrt::SceneLoaderComponent::factory_implementation 32 | { 33 | struct SceneLoader : SceneLoaderT 34 | { 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Reflection; 6 | using System.Runtime.CompilerServices; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [assembly: AssemblyTitle("CameraComponent")] 13 | [assembly: AssemblyDescription("")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("")] 16 | [assembly: AssemblyProduct("CameraComponent")] 17 | [assembly: AssemblyCopyright("Copyright © 2019")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Version information for an assembly consists of the following four values: 22 | // 23 | // Major Version 24 | // Minor Version 25 | // Build Number 26 | // Revision 27 | // 28 | // You can specify all the values or you can default the Build and Revision Numbers 29 | // by using the '*' as shown below: 30 | // [assembly: AssemblyVersion("1.0.*")] 31 | [assembly: AssemblyVersion("1.0.0.0")] 32 | [assembly: AssemblyFileVersion("1.0.0.0")] 33 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /Experimental/CameraComponent/Camera.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Numerics; 6 | 7 | namespace CameraComponent 8 | { 9 | /// 10 | /// An interface that defines properties and functions that a Camera object must implement. 11 | /// 12 | public interface Camera : Animatable 13 | { 14 | /// 15 | /// A reference to a class that implements the Projection interace. 16 | /// 17 | Projection Projection { get; set; } 18 | 19 | /// 20 | /// Returns the matrix created using the Camera's position and rotation in world space. 21 | /// 22 | /// /// A Matrix4x4 that is the product of the matrices representing the camera's translation and rotation. 23 | Matrix4x4 GetViewMatrix(); 24 | 25 | /// 26 | /// Returns the matrix created using the Camera's view matrix and the Camera's Projection's matrix. 27 | /// 28 | /// A Matrix4x4 that is the the product of the matrices representing the camera's transformations in world space and 29 | /// the matrix created by the Camera's Projection property. 30 | Matrix4x4 GetModelViewProjectionMatrix(); 31 | } 32 | } -------------------------------------------------------------------------------- /SceneLoader/NugetPackager/SceneLoaderComponent.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SceneLoaderComponent 5 | $version$ 6 | developer 7 | developer 8 | https://github.com/windows-toolkit/SceneLoader 9 | false 10 | Parses a GLTF file and produces a WUC SceneNode. 11 | 12 | Copyright 2019 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /SceneLoader/Bounds3D.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | namespace SceneLoader { 8 | 9 | class Bounds3D 10 | { 11 | public: 12 | Bounds3D(winrt::Windows::UI::Composition::Scenes::SceneBoundingBox sceneBounds); 13 | 14 | Bounds3D(winrt::Windows::Foundation::Numerics::float3 _min = winrt::Windows::Foundation::Numerics::float3(FLT_MAX, FLT_MAX, FLT_MAX), 15 | winrt::Windows::Foundation::Numerics::float3 _max = winrt::Windows::Foundation::Numerics::float3(FLT_MIN, FLT_MIN, FLT_MIN)); 16 | 17 | static Bounds3D Union(const Bounds3D &lBounds, const Bounds3D &rBounds); 18 | static Bounds3D Transform(const Bounds3D &srcBounds, const winrt::Windows::Foundation::Numerics::float4x4 &transform); 19 | 20 | winrt::Windows::Foundation::Numerics::float3 Min() const; 21 | 22 | winrt::Windows::Foundation::Numerics::float3 Max() const; 23 | 24 | private: 25 | winrt::Windows::Foundation::Numerics::float3 m_min; 26 | winrt::Windows::Foundation::Numerics::float3 m_max; 27 | }; 28 | 29 | Bounds3D ComputeTreeBounds(winrt::Windows::UI::Composition::Scenes::SceneNode root, 30 | winrt::Windows::Foundation::Numerics::float4x4 parentTransform); 31 | 32 | void DecomposeMatrix( 33 | const std::array matrix, 34 | winrt::Windows::Foundation::Numerics::float3* pOutScale, 35 | winrt::Windows::Foundation::Numerics::quaternion* pOutRotation, 36 | winrt::Windows::Foundation::Numerics::float3* pOutTranslation 37 | ); 38 | } -------------------------------------------------------------------------------- /TestViewer/Package.appxmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | TestViewer 18 | developer 19 | Assets\StoreLogo.png 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /SceneLoader/SceneLoader.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 670a1d9e-70b7-4796-adc5-1817c10d6040 6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /settings.xamlstyler: -------------------------------------------------------------------------------- 1 | { 2 | "AttributesTolerance": 1, 3 | "KeepFirstAttributeOnSameLine": true, 4 | "MaxAttributeCharatersPerLine": 0, 5 | "MaxAttributesPerLine": 1, 6 | "NewlineExemptionElements": "RadialGradientBrush, GradientStop, LinearGradientBrush, ScaleTransfom, SkewTransform, RotateTransform, TranslateTransform, Trigger, Condition, Setter", 7 | "SeparateByGroups": false, 8 | "AttributeIndentation": 0, 9 | "AttributeIndentationStyle": 1, 10 | "RemoveDesignTimeReferences": false, 11 | "EnableAttributeReordering": true, 12 | "AttributeOrderingRuleGroups": [ 13 | "x:Class", 14 | "xmlns, xmlns:x", 15 | "xmlns:*", 16 | "x:Key, Key, x:Name, Name, x:Uid, Uid, Title", 17 | "Grid.Row, Grid.RowSpan, Grid.Column, Grid.ColumnSpan, Canvas.Left, Canvas.Top, Canvas.Right, Canvas.Bottom", 18 | "Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight", 19 | "Margin, Padding, HorizontalAlignment, VerticalAlignment, HorizontalContentAlignment, VerticalContentAlignment, Panel.ZIndex", 20 | "*:*, *", 21 | "PageSource, PageIndex, Offset, Color, TargetName, Property, Value, StartPoint, EndPoint", 22 | "mc:Ignorable, d:IsDataSource, d:LayoutOverrides, d:IsStaticText", 23 | "Storyboard.*, From, To, Duration" 24 | ], 25 | "FirstLineAttributes": "", 26 | "OrderAttributesByName": true, 27 | "PutEndingBracketOnNewLine": false, 28 | "RemoveEndingTagOfEmptyElement": true, 29 | "SpaceBeforeClosingSlash": true, 30 | "RootElementLineBreakRule": 0, 31 | "ReorderVSM": 2, 32 | "ReorderGridChildren": false, 33 | "ReorderCanvasChildren": false, 34 | "ReorderSetters": 0, 35 | "FormatMarkupExtension": true, 36 | "NoNewLineMarkupExtensions": "x:Bind, Binding", 37 | "ThicknessSeparator": 2, 38 | "ThicknessAttributes": "Margin, Padding, BorderThickness, ThumbnailClipMargin", 39 | "FormatOnSave": true, 40 | "CommentPadding": 2, 41 | "IndentSize": 4 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SceneLoader for Windows UI 2 | 3 | SceneLoader is a library for generating [Windows.UI.Composition.Scenes](https://docs.microsoft.com/uwp/api/windows.ui.composition.scenes) scene graphs from 3D file formats such as [glTF](https://www.khronos.org/gltf/). This project aims to simplify the design-to-code workflow for rendering 3D assets in your Windows applications. 4 | 5 | SceneLoader currently produces a [SceneNode](https://docs.microsoft.com/uwp/api/windows.ui.composition.scenes.scenenode), allowing you to programmatically construct your own [Visual](https://docs.microsoft.com/uwp/api/windows.ui.composition.scenes.scenevisual) tree. A [proposed companion Microsoft.UI.Xaml control](https://github.com/microsoft/microsoft-ui-xaml/issues/686) is expected to enable 3D assets to be loaded from markup without requiring explicit management of the Visual tree. 6 | 7 | ## Supported SDKs 8 | * May 2019 Update (18362) 9 | 10 | ## Getting Started 11 | * [Documentation](https://docs.microsoft.com/uwp/api/windows.ui.composition.scenes) 12 | * [Code Sample](https://github.com/windows-toolkit/SceneLoader/blob/master/TestViewer/MainPage.xaml.cs) 13 | 14 | ## Build Status 15 | | Target | Branch | Status | Recommended NuGet package | 16 | | ------ | ------ | ------ | ------ | 17 | | 0.0.1 | master | [![Build Status](https://dev.azure.com/dotnet/WindowsCommunityToolkit/_apis/build/status/windows-toolkit.SceneLoader?branchName=master)](https://dev.azure.com/dotnet/WindowsCommunityToolkit/_build/latest?definitionId=80&branchName=master) | ? | 18 | 19 | ## Feedback and Requests 20 | Please use [GitHub Issues](https://github.com/windows-toolkit/SceneLoader/issues) for bug reports and feature requests. 21 | 22 | ## Principles 23 | This project has adopted the code of conduct defined by the [Contributor Covenant](http://contributor-covenant.org/) 24 | to clarify expected behavior in our community. 25 | For more information see the [.NET Foundation Code of Conduct](http://dotnetfoundation.org/code-of-conduct). 26 | 27 | ## .NET Foundation 28 | This project is supported by the [.NET Foundation](http://dotnetfoundation.org). 29 | 30 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Control which branches get CI triggers (defaults to all branches if this parameter is not set) 2 | trigger: 3 | - master 4 | - rel/* 5 | 6 | # Specify the target branches for pull request builds 7 | pr: 8 | - master 9 | - rel/* 10 | 11 | # Microsoft-hosted agent pool for Visual Studio 2017 on Windows Server 2016 12 | pool: 13 | vmImage: vs2017-win2016 14 | 15 | # variables: 16 | # BuildConfiguration: SceneLoader 17 | 18 | steps: 19 | # Setup Environment Variables 20 | - task: BatchScript@1 21 | inputs: 22 | filename: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\Common7\\Tools\\VsDevCmd.bat" 23 | arguments: -no_logo 24 | modifyEnvironment: true 25 | displayName: Setup Environment Variables 26 | 27 | # Install Nuget Tool Installer 28 | - task: NuGetToolInstaller@0 29 | displayName: Use NuGet 4.7.0 30 | inputs: 31 | versionSpec: 4.7.0 32 | 33 | # Install NBGV Tool 34 | - task: DotNetCoreCLI@2 35 | inputs: 36 | command: custom 37 | custom: tool 38 | arguments: install --tool-path . nbgv 39 | displayName: Install NBGV tool 40 | 41 | # Set cloud build variables 42 | - script: nbgv cloud 43 | displayName: Set Version 44 | 45 | # Install Windows SDK 18362 (minimum compatible sdk) 46 | - powershell: .\build\Install-WindowsSdkISO.ps1 18362 47 | displayName: Insider SDK 48 | 49 | # Run cake build 50 | - powershell: .\build.ps1 -target=PackageNuget 51 | displayName: Build 52 | workingDirectory: .\build 53 | 54 | # Sign Nuget package 55 | - task: PowerShell@2 56 | displayName: Authenticode Sign Packages 57 | inputs: 58 | filePath: build/Sign-Package.ps1 59 | env: 60 | SignClientUser: $(SignClientUser) 61 | SignClientSecret: $(SignClientSecret) 62 | ArtifactDirectory: bin\nupkg 63 | condition: and(succeeded(), not(eq(variables['build.reason'], 'PullRequest')), not(eq(variables['SignClientSecret'], '')), not(eq(variables['SignClientUser'], ''))) 64 | 65 | # Publish nuget package 66 | - task: PublishBuildArtifacts@1 67 | displayName: Publish Package Artifacts 68 | inputs: 69 | pathToPublish: .\bin\nupkg 70 | artifactType: container 71 | artifactName: Packages -------------------------------------------------------------------------------- /SceneLoader/pch.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | 8 | // rapidjson (a dependency of GLTF SDK) uses iterators in a way 9 | // that is deprecated on C++17. We can't got back to C++14 because 10 | // C++/WinRT requires C++17. The following line shuts off 11 | // the C++17 warning about the deprecated way of using iterators. 12 | #define _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING 13 | 14 | // std 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | // GLTF SDK 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | // Windows 43 | #include 44 | #include 45 | #include 46 | 47 | // C++/WinRT 48 | #include "winrt/Windows.ApplicationModel.Core.h" 49 | #include "winrt/Windows.Graphics.DirectX.h" 50 | #include "winrt/Windows.UI.Core.h" 51 | #include "winrt/Windows.UI.Composition.h" 52 | #include "winrt/Windows.UI.Composition.Scenes.h" 53 | #include "winrt/Windows.UI.Input.h" 54 | #include "winrt/Windows.UI.Xaml.h" 55 | #include "winrt/Windows.UI.Xaml.Controls.h" 56 | #include "winrt/Windows.Storage.Pickers.h" 57 | #include "winrt/Windows.Storage.Streams.h" 58 | #include "winrt/Windows.Foundation.h" 59 | #include "winrt/Windows.Foundation.Collections.h" 60 | #include "winrt/Windows.Foundation.Numerics.h" 61 | #include "winrt/Windows.Graphics.DirectX.Direct3D11.h" 62 | 63 | 64 | // FIXME: WinRT ABI headers should be moved to UtilForIntermingledNamespaces.h/cpp 65 | #include -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Node.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | #include "UtilForIntermingledNamespaces.h" 9 | #include "Bounds3D.h" 10 | 11 | using namespace Microsoft::glTF; 12 | 13 | namespace winrt { 14 | using namespace Windows::UI::Composition::Scenes; 15 | using namespace Windows::Foundation::Numerics; 16 | } 17 | using namespace winrt; 18 | 19 | using namespace std; 20 | 21 | namespace SceneLoader 22 | { 23 | // Node 24 | void GLTFVisitor::operator()(const Node& node, const Node* nodeParent) 25 | { 26 | wstring nodeID{ node.id.begin(), node.id.end() }; 27 | 28 | auto sceneNode = SceneNode::Create(m_compositor); 29 | sceneNode.Comment(nodeID); 30 | 31 | m_latestSceneNode = sceneNode; 32 | m_sceneNodeMap.Insert(GetHSTRINGFromStdString(node.id), sceneNode); 33 | 34 | if (!nodeParent) 35 | { 36 | m_rootSceneNode.Children().Append(sceneNode); 37 | } 38 | else 39 | { 40 | m_sceneNodeMap.Lookup(GetHSTRINGFromStdString(nodeParent->id)).Children().Append(sceneNode); 41 | } 42 | 43 | switch (node.GetTransformationType()) 44 | { 45 | case TRANSFORMATION_MATRIX: 46 | float3 scale; 47 | quaternion rotation; 48 | float3 translation; 49 | 50 | DecomposeMatrix( 51 | node.matrix.values, 52 | &scale, 53 | &rotation, 54 | &translation); 55 | 56 | sceneNode.Transform().Scale(scale); 57 | sceneNode.Transform().Translation(translation); 58 | sceneNode.Transform().Orientation(rotation); 59 | break; 60 | 61 | case TRANSFORMATION_TRS: 62 | sceneNode.Transform().Scale({ node.scale.x, node.scale.y, node.scale.z }); 63 | sceneNode.Transform().Orientation({ node.rotation.x, node.rotation.y, node.rotation.z, node.rotation.w }); 64 | sceneNode.Transform().Translation({ node.translation.x, node.translation.y, node.translation.z }); 65 | break; 66 | 67 | case TRANSFORMATION_IDENTITY: 68 | default: 69 | // Move along. Nothing to see here. 70 | break; 71 | } 72 | } 73 | } // SceneLoader 74 | -------------------------------------------------------------------------------- /SceneLoader/UtilForIntermingledNamespaces.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "UtilForIntermingledNamespaces.h" 8 | 9 | // WinRT 10 | #include 11 | 12 | // This class doesn't use any "using namespace XXX" because it mixes C++/WinRT 13 | // objects with WinRT ABI Objects (::Windows::Foundation::IMemoryBufferByteAccess). 14 | // The reason for that is that C++/WinRT doesn't expose ::Windows::Foundation::IMemoryBufferByteAccess 15 | // that is being declared into MemoryBuffer.h. 16 | // https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/interop-winrt-abi 17 | 18 | namespace SceneLoader 19 | { 20 | winrt::Windows::Foundation::MemoryBuffer 21 | CopyArrayOfBytesToMemoryBuffer(BYTE* data, size_t byteLength) 22 | { 23 | winrt::Windows::Foundation::MemoryBuffer mb{ winrt::Windows::Foundation::MemoryBuffer(static_cast(byteLength)) }; // FIXME: Check bounds sizeof(size_t) > sizeof(UINT32) on x64 24 | winrt::Windows::Foundation::IMemoryBufferReference mbr = mb.CreateReference(); 25 | winrt::com_ptr const mba{ mbr.as() }; 26 | 27 | { 28 | BYTE* bytes = nullptr; 29 | UINT32 capacity; 30 | mba->GetBuffer(&bytes, &capacity); 31 | for (UINT32 i = 0; i < capacity; ++i) 32 | { 33 | bytes[i] = data[i]; 34 | } 35 | } 36 | 37 | return mb; 38 | } 39 | 40 | // std::span is only available in C++20 :( 41 | std::pair 42 | GetDataPointerFromMemoryBuffer(winrt::Windows::Foundation::IMemoryBufferReference memoryBufferReference) 43 | { 44 | auto memoryBufferByteAccess = memoryBufferReference.as(); 45 | 46 | BYTE* data; 47 | UINT32 capacity; 48 | 49 | memoryBufferByteAccess->GetBuffer(&data, &capacity); 50 | 51 | return std::make_pair(data, capacity); 52 | } 53 | 54 | winrt::hstring 55 | GetHSTRINGFromStdString(const std::string& s) 56 | { 57 | size_t keyLenght = s.length() + 1; 58 | auto wcstring = std::make_unique(keyLenght); 59 | size_t convertedChars = 0; 60 | mbstowcs_s(&convertedChars, wcstring.get(), keyLenght, s.c_str(), _TRUNCATE); 61 | 62 | return wcstring.get(); 63 | } 64 | 65 | } // namespace SceneLoader 66 | -------------------------------------------------------------------------------- /SceneLoader/SceneResourceSet.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | namespace SceneLoader 8 | { 9 | class SceneResourceSet 10 | { 11 | public: 12 | SceneResourceSet(winrt::Windows::UI::Composition::Compositor compositor); 13 | 14 | winrt::Windows::UI::Composition::Scenes::SceneMetallicRoughnessMaterial EnsureMaterialById(const std::string id); 15 | 16 | void StoreGLTFSamplerById(const std::string id, Microsoft::glTF::Sampler sampler); 17 | bool GetGLTFSamplerById(const std::string id, Microsoft::glTF::Sampler* pSampler); 18 | 19 | void StoreGLTFMaterialById(const std::string id, Microsoft::glTF::Material material); 20 | bool GetGLTFMaterialById(const std::string id, Microsoft::glTF::Material* pMaterial); 21 | 22 | void StoreGLTFTextureById(const std::string id, Microsoft::glTF::Texture texture); 23 | bool GetGLTFTextureById(const std::string id, Microsoft::glTF::Texture* pTexture); 24 | 25 | void CreateSceneMaterialObjects(); 26 | 27 | void SetSceneSampler(winrt::Windows::UI::Composition::Scenes::SceneSurfaceMaterialInput materialInput, Microsoft::glTF::Sampler sampler); 28 | 29 | winrt::Windows::UI::Composition::Scenes::SceneSurfaceMaterialInput GetMaterialInputFromTextureId(const std::string textureId); 30 | 31 | winrt::Windows::UI::Composition::CompositionMipmapSurface EnsureMipMapSurfaceId( 32 | const std::string id, 33 | winrt::Windows::Graphics::SizeInt32 size, 34 | winrt::Windows::Graphics::DirectX::DirectXPixelFormat pixelFormat, 35 | winrt::Windows::Graphics::DirectX::DirectXAlphaMode alphaMode, 36 | winrt::Windows::UI::Composition::ICompositionGraphicsDevice3 graphicsDevice); 37 | 38 | winrt::Windows::UI::Composition::CompositionMipmapSurface LookupMipMapSurfaceId(const std::string id); 39 | 40 | void SetLatestMeshRendererComponent(winrt::Windows::UI::Composition::Scenes::SceneMeshRendererComponent& meshRendererComponent); 41 | 42 | static void UnimplementedFeatureFound(); 43 | 44 | private: 45 | winrt::Windows::UI::Composition::Compositor m_compositor; 46 | 47 | // Only keeps track of the equivalent Mipmap from the DOM into the Scenes API. 48 | winrt::Windows::Foundation::Collections::IMap m_sceneSurfaceMaterialInputMap{ nullptr }; 49 | 50 | // Only keeps track of the equivalent Mipmap from the DOM into the Scenes API. 51 | winrt::Windows::Foundation::Collections::IMap m_sceneMipMapSurfaceMap{ nullptr }; 52 | 53 | // Only keeps track of the equivalent Materials from the DOM into the Scenes API. 54 | winrt::Windows::Foundation::Collections::IMap m_sceneMaterialMap{ nullptr }; 55 | 56 | // Only keeps track of the equivalent Materials from the DOM into the Scenes API. 57 | std::map m_gltfSamplerMap; 58 | std::map m_gltfMaterialMap; 59 | std::map m_gltfTextureMap; 60 | 61 | winrt::Windows::UI::Composition::Scenes::SceneMeshRendererComponent m_latestMeshRendererComponent{ nullptr }; 62 | 63 | static bool s_assertOnUnimplementedFeature; 64 | }; 65 | } // SceneLoader -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | #include "SceneResourceSet.h" 8 | 9 | namespace SceneLoader 10 | { 11 | struct GLTFVisitor 12 | { 13 | GLTFVisitor(winrt::Windows::UI::Composition::Compositor compositor, 14 | winrt::Windows::UI::Composition::Scenes::SceneNode rootSceneNode, 15 | std::shared_ptr resourceSet, 16 | std::shared_ptr gltfResourceReader, 17 | Microsoft::glTF::Document& gltfDocument, 18 | Microsoft::glTF::Scene& gltfScene); 19 | 20 | // Node 21 | void operator()(const Microsoft::glTF::Node& node, const Microsoft::glTF::Node* nodeParent); 22 | 23 | // Mesh 24 | void operator()(const Microsoft::glTF::Mesh& mesh, Microsoft::glTF::VisitState alreadyVisited); 25 | 26 | // MeshPrimitive 27 | void operator()(const Microsoft::glTF::MeshPrimitive&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 28 | 29 | // Material 30 | void operator()(const Microsoft::glTF::Material&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 31 | 32 | // Texture 33 | void operator()(const Microsoft::glTF::Texture&, Microsoft::glTF::TextureType, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 34 | 35 | // Image 36 | void operator()(const Microsoft::glTF::Image&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 37 | 38 | // Sampler 39 | void operator()(const Microsoft::glTF::Sampler&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 40 | 41 | // Skin 42 | void operator()(const Microsoft::glTF::Skin&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 43 | 44 | // Camera 45 | void operator()(const Microsoft::glTF::Camera&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 46 | 47 | HRESULT EnsureGraphicsDevice(); 48 | 49 | 50 | winrt::Windows::UI::Composition::CompositionMipmapSurface EnsureMipMapSurfaceId( 51 | const std::string id, 52 | winrt::Windows::Graphics::SizeInt32 size, 53 | winrt::Windows::Graphics::DirectX::DirectXPixelFormat pixelFormat, 54 | winrt::Windows::Graphics::DirectX::DirectXAlphaMode alphaMode); 55 | 56 | private: 57 | winrt::Windows::UI::Composition::Compositor m_compositor{ nullptr }; 58 | 59 | winrt::com_ptr m_graphicsDevice{ nullptr }; 60 | 61 | // The SceneNode connected to the SceneVisual 62 | winrt::Windows::UI::Composition::Scenes::SceneNode m_rootSceneNode{ nullptr }; 63 | 64 | // Only keeps track of the equivalent SceneNodes from the DOM into the Scenes API. 65 | winrt::Windows::Foundation::Collections::IMap m_sceneNodeMap{ nullptr }; 66 | 67 | // It keeps the equivalent SceneNodes from the DOM and the ones needed for adapting Mesh and MeshPrimitives into the Scenes API. 68 | winrt::Windows::UI::Composition::Scenes::SceneNode m_latestSceneNode{ nullptr }; 69 | 70 | Microsoft::glTF::Document& m_gltfDocument; 71 | 72 | Microsoft::glTF::Scene& m_gltfScene; 73 | 74 | std::shared_ptr m_gltfResourceReader; 75 | std::shared_ptr m_resourceSet; 76 | }; 77 | } // SceneLoader -------------------------------------------------------------------------------- /TestViewer/App.xaml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using Windows.ApplicationModel; 7 | using Windows.ApplicationModel.Activation; 8 | using Windows.UI.Xaml; 9 | using Windows.UI.Xaml.Controls; 10 | using Windows.UI.Xaml.Navigation; 11 | 12 | namespace TestViewer 13 | { 14 | /// 15 | /// Provides application-specific behavior to supplement the default Application class. 16 | /// 17 | sealed partial class App : Application 18 | { 19 | /// 20 | /// Initializes the singleton application object. This is the first line of authored code 21 | /// executed, and as such is the logical equivalent of main() or WinMain(). 22 | /// 23 | public App() 24 | { 25 | this.InitializeComponent(); 26 | this.Suspending += OnSuspending; 27 | } 28 | 29 | /// 30 | /// Invoked when the application is launched normally by the end user. Other entry points 31 | /// will be used such as when the application is launched to open a specific file. 32 | /// 33 | /// Details about the launch request and process. 34 | protected override void OnLaunched(LaunchActivatedEventArgs e) 35 | { 36 | Frame rootFrame = Window.Current.Content as Frame; 37 | 38 | // Do not repeat app initialization when the Window already has content, 39 | // just ensure that the window is active 40 | if (rootFrame == null) 41 | { 42 | // Create a Frame to act as the navigation context and navigate to the first page 43 | rootFrame = new Frame(); 44 | 45 | rootFrame.NavigationFailed += OnNavigationFailed; 46 | 47 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 48 | { 49 | //TODO: Load state from previously suspended application 50 | } 51 | 52 | // Place the frame in the current Window 53 | Window.Current.Content = rootFrame; 54 | } 55 | 56 | if (e.PrelaunchActivated == false) 57 | { 58 | if (rootFrame.Content == null) 59 | { 60 | // When the navigation stack isn't restored navigate to the first page, 61 | // configuring the new page by passing required information as a navigation 62 | // parameter 63 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 64 | } 65 | // Ensure the current window is active 66 | Window.Current.Activate(); 67 | } 68 | } 69 | 70 | /// 71 | /// Invoked when Navigation to a certain page fails 72 | /// 73 | /// The Frame which failed navigation 74 | /// Details about the navigation failure 75 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 76 | { 77 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 78 | } 79 | 80 | /// 81 | /// Invoked when application execution is being suspended. Application state is saved 82 | /// without knowing whether the application will be terminated or resumed with the contents 83 | /// of memory still intact. 84 | /// 85 | /// The source of the suspend request. 86 | /// Details about the suspend request. 87 | private void OnSuspending(object sender, SuspendingEventArgs e) 88 | { 89 | var deferral = e.SuspendingOperation.GetDeferral(); 90 | //TODO: Save application state and stop any background activity 91 | deferral.Complete(); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "UtilForIntermingledNamespaces.h" 8 | #include "GLTFVisitor.h" 9 | 10 | using namespace std; 11 | using namespace Microsoft::glTF; 12 | 13 | namespace winrt { 14 | using namespace Windows::UI::Composition; 15 | using namespace Windows::UI::Composition::Scenes; 16 | } 17 | using namespace winrt; 18 | 19 | extern std::wstringstream s_export; 20 | 21 | namespace SceneLoader 22 | { 23 | GLTFVisitor::GLTFVisitor(Compositor compositor, 24 | SceneNode rootSceneNode, 25 | shared_ptr resourceSet, 26 | shared_ptr gltfResourceReader, 27 | Document& gltfDocument, 28 | Scene& gltfScene) : 29 | m_compositor(compositor), 30 | m_rootSceneNode(rootSceneNode), 31 | m_sceneNodeMap(single_threaded_map()), 32 | m_resourceSet(resourceSet), 33 | m_gltfResourceReader(gltfResourceReader), 34 | m_gltfDocument(gltfDocument), 35 | m_gltfScene(gltfScene) 36 | { 37 | } 38 | 39 | HRESULT GLTFVisitor::EnsureGraphicsDevice() 40 | { 41 | HRESULT hr = S_OK; 42 | 43 | if (!m_graphicsDevice) 44 | { 45 | // Initialize DX 46 | winrt::com_ptr cpDevice; 47 | winrt::com_ptr cpContext; 48 | UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; 49 | D3D_FEATURE_LEVEL featureLevels[] = 50 | { 51 | D3D_FEATURE_LEVEL_11_1, 52 | D3D_FEATURE_LEVEL_11_0, 53 | D3D_FEATURE_LEVEL_10_1, 54 | D3D_FEATURE_LEVEL_10_0, 55 | D3D_FEATURE_LEVEL_9_3, 56 | D3D_FEATURE_LEVEL_9_2, 57 | D3D_FEATURE_LEVEL_9_1 58 | }; 59 | D3D_FEATURE_LEVEL usedFeatureLevel; 60 | 61 | hr = D3D11CreateDevice( 62 | nullptr, 63 | D3D_DRIVER_TYPE_HARDWARE, 64 | nullptr, 65 | creationFlags, 66 | featureLevels, 67 | ARRAYSIZE(featureLevels), 68 | D3D11_SDK_VERSION, 69 | cpDevice.put(), 70 | &usedFeatureLevel, 71 | cpContext.put()); 72 | 73 | winrt::com_ptr cpD2DFactory; 74 | winrt::com_ptr cpD2D1Device; 75 | winrt::com_ptr cpd3dDevice = cpDevice.as(); 76 | hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory1), cpD2DFactory.put_void()); 77 | winrt::com_ptr cpDxgiDevice = cpd3dDevice.as(); 78 | cpD2DFactory->CreateDevice(cpDxgiDevice.get(), cpD2D1Device.put()); 79 | 80 | winrt::com_ptr cpCompositorInterop = m_compositor.as< ABI::Windows::UI::Composition::ICompositorInterop>(); 81 | cpCompositorInterop->CreateGraphicsDevice(/*cpDevice*/cpD2D1Device.get(), m_graphicsDevice.put()); 82 | 83 | assert(m_graphicsDevice); 84 | } 85 | 86 | return hr; 87 | } 88 | 89 | winrt::Windows::UI::Composition::CompositionMipmapSurface 90 | GLTFVisitor::EnsureMipMapSurfaceId( 91 | const std::string id, 92 | winrt::Windows::Graphics::SizeInt32 sizePixels, 93 | winrt::Windows::Graphics::DirectX::DirectXPixelFormat pixelFormat, 94 | winrt::Windows::Graphics::DirectX::DirectXAlphaMode alphaMode) 95 | { 96 | EnsureGraphicsDevice(); 97 | 98 | winrt::Windows::UI::Composition::ICompositionGraphicsDevice3 cpGraphicsDevice3 = m_graphicsDevice.as< winrt::Windows::UI::Composition::ICompositionGraphicsDevice3>(); 99 | 100 | return m_resourceSet->EnsureMipMapSurfaceId( 101 | id, 102 | sizePixels, 103 | pixelFormat, 104 | alphaMode, 105 | cpGraphicsDevice3 106 | ); 107 | } 108 | 109 | 110 | } // SceneLoader 111 | -------------------------------------------------------------------------------- /SceneLoader/SceneLoader.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | #include "SceneLoader.h" 7 | 8 | #include "UtilForIntermingledNamespaces.h" 9 | #include "Bounds3D.h" 10 | #include "GLTFVisitor.h" 11 | 12 | using namespace std; 13 | using namespace Microsoft::glTF; 14 | using namespace SceneLoader; 15 | 16 | namespace winrt { 17 | using namespace Windows::ApplicationModel::Core; 18 | using namespace Windows::Foundation::Collections; 19 | using namespace Windows::UI::Core; 20 | using namespace Windows::UI::Composition; 21 | using namespace Windows::UI::Composition::Scenes; 22 | using namespace Windows::Storage; 23 | using namespace Windows::Storage::Streams; 24 | using namespace Windows::Storage::Pickers; 25 | using namespace Windows::Foundation::Numerics; 26 | using namespace Windows::Foundation; 27 | } 28 | using namespace winrt; 29 | 30 | namespace winrt::SceneLoaderComponent::implementation 31 | { 32 | struct MemBuf : std::streambuf 33 | { 34 | MemBuf(char* begin, char* end) { 35 | this->setg(begin, begin, end); 36 | } 37 | }; 38 | 39 | struct StreamReader : public IStreamReader 40 | { 41 | MemBuf m_membuf; 42 | 43 | StreamReader(BYTE* data, UINT32 capacity) : 44 | m_membuf((char*)data, (char*)(data + capacity)) 45 | { 46 | } 47 | 48 | virtual ~StreamReader() 49 | { 50 | 51 | } 52 | 53 | shared_ptr GetInputStream(const std::string&) const override 54 | { 55 | auto spIfStream = make_shared(const_cast(&m_membuf)); 56 | 57 | if (spIfStream->fail()) 58 | { 59 | throw exception("failed to open file"); 60 | } 61 | return spIfStream; 62 | } 63 | }; 64 | 65 | SceneNode SceneLoader::Load(IBuffer buffer, Compositor compositor) 66 | { 67 | auto memoryBuffer = winrt::Windows::Storage::Streams::Buffer::CreateMemoryBufferOverIBuffer(buffer); 68 | auto memoryBufferReference = memoryBuffer.CreateReference(); 69 | auto data = GetDataPointerFromMemoryBuffer(memoryBufferReference); 70 | 71 | SceneNode worldNode = SceneNode::Create(compositor); 72 | SceneNode rootNode = SceneNode::Create(compositor); 73 | worldNode.Children().Append(rootNode); 74 | 75 | // 76 | // Parses the GLTF file and creates the WUC Scenes objects 77 | // 78 | ParseGLTF(data.first, data.second, compositor, rootNode); 79 | 80 | Bounds3D bounds = ComputeTreeBounds( 81 | rootNode, 82 | float4x4::identity()); 83 | 84 | float lengthX = bounds.Max().x - bounds.Min().x; 85 | float lengthY = bounds.Max().y - bounds.Min().y; 86 | float lengthZ = bounds.Max().z - bounds.Min().z; 87 | 88 | float maxDimension = max(lengthX, max(lengthY, lengthZ)); 89 | 90 | if (maxDimension > 0.0f) 91 | { 92 | float scaleFactor = 300.0f / maxDimension; 93 | 94 | worldNode.Transform().Scale({ scaleFactor, scaleFactor, scaleFactor }); 95 | worldNode.Transform().Translation({ 0.0f, -(bounds.Min().y + bounds.Max().y) * scaleFactor / 2, 0.0f }); 96 | 97 | } 98 | 99 | return worldNode; 100 | } 101 | 102 | void SceneLoader::ParseGLTF(BYTE* data, UINT32 capacity, Compositor& compositor, SceneNode& rootNode) 103 | { 104 | auto streamReader = make_shared(data, capacity); 105 | auto spifstream = streamReader->GetInputStream(""); 106 | auto resourceReader = make_shared(streamReader); 107 | 108 | ////////////////////////////////////////////////////////////////////////////// 109 | // 110 | // Document 111 | // 112 | ////////////////////////////////////////////////////////////////////////////// 113 | Document gltfDoc = Deserialize(*spifstream); 114 | Validation::Validate(gltfDoc); 115 | 116 | DoIt(gltfDoc, resourceReader, compositor, rootNode); 117 | } 118 | 119 | void SceneLoader::DoIt(Document& gltfDoc, shared_ptr resourceReader, Compositor& compositor, SceneNode& rootNode) 120 | { 121 | ////////////////////////////////////////////////////////////////////////////// 122 | // 123 | // Scene 124 | // 125 | ////////////////////////////////////////////////////////////////////////////// 126 | auto scene = gltfDoc.GetDefaultScene(); 127 | 128 | shared_ptr resourceSet = make_shared(compositor); 129 | 130 | Visit(gltfDoc, DefaultSceneIndex, GLTFVisitor( 131 | compositor, 132 | rootNode, 133 | resourceSet, 134 | resourceReader, 135 | gltfDoc, 136 | scene)); 137 | 138 | resourceSet->CreateSceneMaterialObjects(); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/OrthographicProjection.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Numerics; 7 | using Windows.UI.Composition; 8 | 9 | namespace CameraComponent 10 | { 11 | /// 12 | /// A class that defines an orthographic projection with a distance to the near and far planes and a size. 13 | /// Implements the Projection and Animatable interfaces. 14 | /// 15 | public sealed class OrthographicProjection : Projection 16 | { 17 | private CompositionPropertySet _propertySet; 18 | private Compositor _compositor; 19 | 20 | /// 21 | /// Creates a OrthographicProjection with default properties. 22 | /// Size = 100 23 | /// Near = 1 24 | /// Far = 1000 25 | /// 26 | /// 27 | /// Thrown when constructor is passed a null value. 28 | public OrthographicProjection(Compositor compositor) 29 | { 30 | if (compositor == null) 31 | { 32 | throw new System.ArgumentException("Compositor cannot be null"); 33 | } 34 | 35 | _compositor = compositor; 36 | _propertySet = _compositor.CreatePropertySet(); 37 | 38 | // Create the properties for the projection 39 | _propertySet.InsertScalar("Size", 100f); 40 | _propertySet.InsertScalar("Near", 1f); 41 | _propertySet.InsertScalar("Far", 1000f); 42 | _propertySet.InsertMatrix4x4("ProjectionMatrix", Matrix4x4.Identity); 43 | 44 | StartAnimationsOnProjectionMatrix(); 45 | } 46 | 47 | /// 48 | /// Size of the square plane that the image is projected onto. 49 | /// 50 | public float Size 51 | { 52 | get 53 | { 54 | float curr; 55 | _propertySet.TryGetScalar("Size", out curr); 56 | return curr; 57 | } 58 | set 59 | { 60 | float epsilon = 0.0001f; 61 | _propertySet.InsertScalar("Size", MathF.Max(epsilon, value)); 62 | } 63 | } 64 | 65 | /// 66 | /// Distance from the eye to the near plane. 67 | /// 68 | public float Near 69 | { 70 | get 71 | { 72 | float curr; 73 | _propertySet.TryGetScalar("Near", out curr); 74 | return curr; 75 | } 76 | set 77 | { 78 | float epsilon = 0.0001f; 79 | _propertySet.InsertScalar("Near", MathF.Max(epsilon, value)); 80 | } 81 | } 82 | 83 | /// 84 | /// Distance from the eye to the far plane. 85 | /// 86 | public float Far 87 | { 88 | get 89 | { 90 | float curr; 91 | _propertySet.TryGetScalar("Far", out curr); 92 | return curr; 93 | } 94 | set 95 | { 96 | _propertySet.InsertScalar("Far", value); 97 | } 98 | } 99 | 100 | /// 101 | /// Returns the matrix created from the projection's Near, Far, and Size. 102 | /// 103 | /// A Matrix4x4 that normalizes the scene in the range (-1, -1, -1) to (1, 1, 1). 104 | public Matrix4x4 GetProjectionMatrix() 105 | { 106 | Matrix4x4 matProj = Matrix4x4.Identity; 107 | matProj.M11 = 1 / Size; 108 | matProj.M22 = 1 / Size; 109 | matProj.M33 = 1 / (Far - Near); 110 | 111 | return matProj; 112 | } 113 | 114 | private void StartAnimationsOnProjectionMatrix() 115 | { 116 | var matProj = 117 | "Matrix4x4(" + 118 | "1 / Max(epsilon, OrthoProj.Size), 0, 0, 0, " + 119 | "0, 1 / Max(epsilon, OrthoProj.Size), 0, 0, " + 120 | "0, 0, 1 / (OrthoProj.Far - OrthoProj.Near), 0, " + 121 | "0, 0, 0, 1)"; 122 | 123 | var projExpression = _compositor.CreateExpressionAnimation(); 124 | projExpression.Expression = matProj; 125 | projExpression.SetScalarParameter("epsilon", 0.0001f); 126 | projExpression.SetReferenceParameter("OrthoProj", _propertySet); 127 | 128 | _propertySet.StartAnimation("ProjectionMatrix", projExpression); 129 | } 130 | 131 | /// 132 | /// Returns the projection's set of animatable properties. 133 | /// 134 | /// A CompositionPropertySet holding the projection's properties. 135 | public CompositionPropertySet GetPropertySet() 136 | { 137 | return _propertySet; 138 | } 139 | 140 | /// 141 | /// Starts a given animation on the specified property. 142 | /// 143 | /// The name of the property to be animated. 144 | /// The animation being applied. 145 | public void StartAnimation(string propertyName, CompositionAnimation animation) 146 | { 147 | _propertySet.StartAnimation(propertyName, animation); 148 | } 149 | 150 | /// 151 | /// Stops any animations on the specified property. 152 | /// 153 | /// The name of the property whose animations we are stopping. 154 | public void StopAnimation(string propertyName) 155 | { 156 | _propertySet.StopAnimation(propertyName); 157 | } 158 | } 159 | } -------------------------------------------------------------------------------- /SceneLoader/Bounds3D.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "Bounds3D.h" 8 | 9 | using namespace std; 10 | 11 | namespace winrt { 12 | using namespace Windows::Foundation::Numerics; 13 | using namespace Windows::UI::Composition::Scenes; 14 | } 15 | using namespace winrt; 16 | 17 | namespace SceneLoader 18 | { 19 | Bounds3D::Bounds3D(SceneBoundingBox sceneBounds) 20 | { 21 | m_min = sceneBounds.Min(); 22 | m_max = sceneBounds.Max(); 23 | } 24 | 25 | Bounds3D::Bounds3D(float3 _min, float3 _max) 26 | { 27 | m_min = _min; 28 | m_max = _max; 29 | } 30 | 31 | Bounds3D 32 | Bounds3D::Union(const Bounds3D &lBounds, const Bounds3D &rBounds) 33 | { 34 | winrt::Windows::Foundation::Numerics::float3 newMin; 35 | winrt::Windows::Foundation::Numerics::float3 newMax; 36 | 37 | newMin.x = min(lBounds.Min().x, rBounds.Min().x); 38 | newMin.y = min(lBounds.Min().y, rBounds.Min().y); 39 | newMin.z = min(lBounds.Min().z, rBounds.Min().z); 40 | 41 | newMax.x = max(lBounds.Max().x, rBounds.Max().x); 42 | newMax.y = max(lBounds.Max().y, rBounds.Max().y); 43 | newMax.z = max(lBounds.Max().z, rBounds.Max().z); 44 | 45 | return Bounds3D(newMin, newMax); 46 | } 47 | 48 | Bounds3D 49 | Bounds3D::Transform(const Bounds3D &srcBounds, const winrt::Windows::Foundation::Numerics::float4x4 &srcToDestTransform) 50 | { 51 | float3 newMin(FLT_MAX, FLT_MAX, FLT_MAX); 52 | float3 newMax(-FLT_MAX, -FLT_MAX, -FLT_MAX); 53 | 54 | { 55 | float3 boxVertices[8]; 56 | 57 | // Setup a cube, first 4 verties will be min (z) plane, 2nd 4 vertices will be max (z) plane 58 | // First vertex in each plane will be at min (x,y) winding clockwise around to rest at (xMax, yMin) 59 | 60 | boxVertices[0] = srcBounds.Min(); 61 | boxVertices[6] = srcBounds.Max(); 62 | 63 | boxVertices[1] = boxVertices[0]; 64 | boxVertices[1].y = boxVertices[6].y; 65 | 66 | boxVertices[2] = boxVertices[1]; 67 | boxVertices[2].x = boxVertices[6].x; 68 | 69 | boxVertices[3] = boxVertices[2]; 70 | boxVertices[3].y = boxVertices[0].y; 71 | 72 | boxVertices[4] = boxVertices[0]; 73 | boxVertices[4].z = boxVertices[6].z; 74 | 75 | boxVertices[5] = boxVertices[4]; 76 | boxVertices[5].y = boxVertices[6].y; 77 | 78 | boxVertices[7] = boxVertices[6]; 79 | boxVertices[7].y = boxVertices[0].y; 80 | 81 | for (int i = 0; i < 8; i++) 82 | { 83 | boxVertices[i] = transform(boxVertices[i], srcToDestTransform); 84 | 85 | newMin.x = min(newMin.x, boxVertices[i].x); 86 | newMin.y = min(newMin.y, boxVertices[i].y); 87 | newMin.z = min(newMin.z, boxVertices[i].z); 88 | 89 | newMax.x = max(newMax.x, boxVertices[i].x); 90 | newMax.y = max(newMax.y, boxVertices[i].y); 91 | newMax.z = max(newMax.z, boxVertices[i].z); 92 | } 93 | } 94 | 95 | return Bounds3D(newMin, newMax); 96 | } 97 | 98 | 99 | float3 Bounds3D::Min() const 100 | { 101 | return m_min; 102 | } 103 | 104 | float3 Bounds3D::Max() const 105 | { 106 | return m_max; 107 | } 108 | 109 | 110 | Bounds3D ComputeTreeBounds(winrt::Windows::UI::Composition::Scenes::SceneNode root); 111 | 112 | void DecomposeMatrix( 113 | const std::array matrix, 114 | winrt::Windows::Foundation::Numerics::float3* pOutScale, 115 | winrt::Windows::Foundation::Numerics::quaternion* pOutRotation, 116 | winrt::Windows::Foundation::Numerics::float3* pOutTranslation 117 | ); 118 | 119 | Bounds3D ComputeTreeBounds( 120 | SceneNode root, 121 | float4x4 parentToWorldTransform 122 | ) 123 | { 124 | Bounds3D retBounds; 125 | 126 | float4x4 localToWorldTransform = parentToWorldTransform; 127 | 128 | localToWorldTransform *= make_float4x4_scale(root.Transform().Scale()); 129 | localToWorldTransform *= make_float4x4_from_quaternion(root.Transform().Orientation()); 130 | localToWorldTransform *= make_float4x4_translation(root.Transform().Translation()); 131 | 132 | // Check if we have a mesh attached 133 | auto firstComponent = root.Components().First(); 134 | 135 | if (firstComponent && firstComponent.HasCurrent()) 136 | { 137 | auto meshRenderer = firstComponent.Current().as(); 138 | 139 | if (meshRenderer) 140 | { 141 | auto mesh = meshRenderer.Mesh(); 142 | 143 | if (mesh) 144 | { 145 | Bounds3D localBounds = mesh.Bounds(); 146 | 147 | retBounds = Bounds3D::Transform(localBounds, localToWorldTransform); 148 | } 149 | } 150 | } 151 | 152 | for (UINT i = 0; i < root.Children().Size(); i++) 153 | { 154 | retBounds = Bounds3D::Union(retBounds, ComputeTreeBounds(root.Children().GetAt(i), localToWorldTransform)); 155 | } 156 | 157 | return retBounds; 158 | } 159 | 160 | void DecomposeMatrix( 161 | const std::array matrix, 162 | float3* pOutScale, 163 | quaternion* pOutRotation, 164 | float3* pOutTranslation) 165 | { 166 | float4x4 inputMatrix( 167 | matrix[0], matrix[1], matrix[2], matrix[3], 168 | matrix[4], matrix[5], matrix[6], matrix[7], 169 | matrix[8], matrix[9], matrix[10], matrix[11], 170 | matrix[12], matrix[13], matrix[14], matrix[15] 171 | ); 172 | 173 | bool fDecomposeResult = decompose( 174 | inputMatrix, 175 | pOutScale, 176 | pOutRotation, 177 | pOutTranslation); 178 | 179 | assert(fDecomposeResult); 180 | } 181 | } // namespace SceneLoader -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_MeshPrimitive.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "UtilForIntermingledNamespaces.h" 8 | #include "GLTFVisitor.h" 9 | 10 | using namespace std; 11 | using namespace Microsoft::glTF; 12 | 13 | namespace winrt { 14 | using namespace Windows::Foundation::Numerics; 15 | using namespace Windows::Graphics::DirectX; 16 | using namespace Windows::UI::Composition::Scenes; 17 | } 18 | using namespace winrt; 19 | 20 | extern vector s_binExportVector; 21 | 22 | namespace SceneLoader 23 | { 24 | // Mesh Primitive 25 | void GLTFVisitor::operator()(const MeshPrimitive& meshPrimitive, VisitState state, const VisitDefaultAction&) // FIXME: It is creating necessary mesh primitives (engine.gltf) 26 | { 27 | if (state == VisitState::New) 28 | { 29 | static uint16_t sCounter = 0; 30 | 31 | auto sceneNodeForTheGLTFMeshPrimitive = SceneNode::Create(m_compositor); 32 | 33 | // m_latestSceneNode is sceneNodeForTheGLTFMesh 34 | m_latestSceneNode.Children().Append(sceneNodeForTheGLTFMeshPrimitive); 35 | 36 | 37 | // We want all MeshPrimitives of a Mesh to be siblings. 38 | // That's why we don't define m_latestSceneNode as sceneNodeForTheGLTFMeshPrimitive. 39 | 40 | auto curMaterial = m_resourceSet->EnsureMaterialById(meshPrimitive.materialId); 41 | 42 | auto mesh = SceneMesh::Create(m_compositor); 43 | 44 | if (meshPrimitive.mode == MESH_TRIANGLES) 45 | { 46 | mesh.PrimitiveTopology(DirectXPrimitiveTopology::TriangleList); 47 | } 48 | else 49 | { 50 | SceneResourceSet::UnimplementedFeatureFound(); 51 | } 52 | 53 | for (auto value : meshPrimitive.attributes) 54 | { 55 | if (value.first == ACCESSOR_POSITION) 56 | { 57 | auto accessorId = meshPrimitive.GetAttributeAccessorId(value.first); 58 | auto& accessor = m_gltfDocument.accessors[accessorId]; 59 | 60 | auto data = MeshPrimitiveUtils::GetPositions(m_gltfDocument, *m_gltfResourceReader, accessor); 61 | 62 | mesh.FillMeshAttribute( 63 | SceneAttributeSemantic::Vertex, 64 | DirectXPixelFormat::R32G32B32Float, 65 | CopyArrayOfBytesToMemoryBuffer((BYTE*)data.data(), data.size() * sizeof(float))); 66 | } 67 | else if (value.first == ACCESSOR_NORMAL) 68 | { 69 | auto accessorId = meshPrimitive.GetAttributeAccessorId(value.first); 70 | auto& accessor = m_gltfDocument.accessors[accessorId]; 71 | auto data = MeshPrimitiveUtils::GetNormals(m_gltfDocument, *m_gltfResourceReader, accessor); 72 | 73 | mesh.FillMeshAttribute( 74 | SceneAttributeSemantic::Normal, 75 | DirectXPixelFormat::R32G32B32Float, 76 | CopyArrayOfBytesToMemoryBuffer((BYTE*)data.data(), data.size() * sizeof(float))); 77 | } 78 | else if (value.first == ACCESSOR_TANGENT) 79 | { 80 | auto accessorId = meshPrimitive.GetAttributeAccessorId(value.first); 81 | auto& accessor = m_gltfDocument.accessors[accessorId]; 82 | auto data = MeshPrimitiveUtils::GetTangents(m_gltfDocument, *m_gltfResourceReader, accessor); 83 | 84 | mesh.FillMeshAttribute( 85 | SceneAttributeSemantic::Tangent, 86 | DirectXPixelFormat::R32G32B32A32Float, 87 | CopyArrayOfBytesToMemoryBuffer((BYTE*)data.data(), data.size() * sizeof(float))); 88 | } 89 | else if ((value.first == ACCESSOR_TEXCOORD_0) || (value.first == ACCESSOR_TEXCOORD_1)) 90 | { 91 | auto accessorId = meshPrimitive.GetAttributeAccessorId(value.first); 92 | auto& accessor = m_gltfDocument.accessors[accessorId]; 93 | auto data = MeshPrimitiveUtils::GetTexCoords(m_gltfDocument, *m_gltfResourceReader, accessor); 94 | 95 | mesh.FillMeshAttribute( 96 | (value.first == ACCESSOR_TEXCOORD_0) ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1, 97 | DirectXPixelFormat::R32G32Float, 98 | CopyArrayOfBytesToMemoryBuffer((BYTE*)data.data(), data.size() * sizeof(float))); 99 | } 100 | else if (value.first == ACCESSOR_COLOR_0) 101 | { 102 | auto accessorId = meshPrimitive.GetAttributeAccessorId(value.first); 103 | auto& accessor = m_gltfDocument.accessors[accessorId]; 104 | auto data = MeshPrimitiveUtils::GetColors(m_gltfDocument, *m_gltfResourceReader, accessor); 105 | 106 | mesh.FillMeshAttribute( 107 | SceneAttributeSemantic::Color, 108 | DirectXPixelFormat::R32UInt, 109 | CopyArrayOfBytesToMemoryBuffer((BYTE*)data.data(), data.size() * sizeof(uint32_t))); 110 | } 111 | } // for attributes 112 | 113 | auto indices = MeshPrimitiveUtils::GetTriangulatedIndices16(m_gltfDocument, *m_gltfResourceReader, meshPrimitive); 114 | 115 | mesh.FillMeshAttribute( 116 | SceneAttributeSemantic::Index, 117 | DirectXPixelFormat::R16UInt, 118 | CopyArrayOfBytesToMemoryBuffer((BYTE*)indices.data(), indices.size() * sizeof(uint16_t))); 119 | 120 | // 121 | // Creates SceneRendererComponent, attaches MeshRenderer and add as component of the SceneNode 122 | // 123 | auto renderComponent = SceneMeshRendererComponent::Create(m_compositor); 124 | 125 | renderComponent.Mesh(mesh); 126 | 127 | renderComponent.Material(curMaterial); 128 | 129 | sceneNodeForTheGLTFMeshPrimitive.Components().Append(renderComponent); 130 | 131 | sCounter++; 132 | m_resourceSet->SetLatestMeshRendererComponent(renderComponent); 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /SceneLoader.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29123.88 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SceneLoaderComponent", "SceneLoader\SceneLoader.vcxproj", "{88C4D662-8669-433B-8A8B-47B3A17E3C6E}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestViewer", "TestViewer\TestViewer.csproj", "{5D504AFF-651A-4C27-BA19-550663227A85}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CameraComponent", "Experimental\CameraComponent\CameraComponent.csproj", "{239C87C3-1E17-4F01-8D93-9B21C1A53F3D}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|ARM = Debug|ARM 16 | Debug|ARM64 = Debug|ARM64 17 | Debug|x64 = Debug|x64 18 | Debug|x86 = Debug|x86 19 | Release|Any CPU = Release|Any CPU 20 | Release|ARM = Release|ARM 21 | Release|ARM64 = Release|ARM64 22 | Release|x64 = Release|x64 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|Any CPU.ActiveCfg = Debug|Win32 27 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|Any CPU.Build.0 = Debug|Win32 28 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|ARM.ActiveCfg = Debug|ARM 29 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|ARM.Build.0 = Debug|ARM 30 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|ARM64.ActiveCfg = Debug|ARM64 31 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|ARM64.Build.0 = Debug|ARM64 32 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|x64.ActiveCfg = Debug|x64 33 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|x64.Build.0 = Debug|x64 34 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|x86.ActiveCfg = Debug|Win32 35 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|x86.Build.0 = Debug|Win32 36 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|Any CPU.ActiveCfg = Release|Win32 37 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|Any CPU.Build.0 = Release|Win32 38 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|ARM.ActiveCfg = Release|ARM 39 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|ARM.Build.0 = Release|ARM 40 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|ARM64.ActiveCfg = Release|ARM64 41 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|ARM64.Build.0 = Release|ARM64 42 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|x64.ActiveCfg = Release|x64 43 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|x64.Build.0 = Release|x64 44 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|x86.ActiveCfg = Release|Win32 45 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|x86.Build.0 = Release|Win32 46 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|Any CPU.ActiveCfg = Debug|x86 47 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|Any CPU.Build.0 = Debug|x86 48 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|Any CPU.Deploy.0 = Debug|x86 49 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM.ActiveCfg = Debug|ARM 50 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM.Build.0 = Debug|ARM 51 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM.Deploy.0 = Debug|ARM 52 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM64.ActiveCfg = Debug|ARM64 53 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM64.Build.0 = Debug|ARM64 54 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM64.Deploy.0 = Debug|ARM64 55 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x64.ActiveCfg = Debug|x64 56 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x64.Build.0 = Debug|x64 57 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x64.Deploy.0 = Debug|x64 58 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x86.ActiveCfg = Debug|x86 59 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x86.Build.0 = Debug|x86 60 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x86.Deploy.0 = Debug|x86 61 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|Any CPU.ActiveCfg = Release|x86 62 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|Any CPU.Build.0 = Release|x86 63 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|Any CPU.Deploy.0 = Release|x86 64 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM.ActiveCfg = Release|ARM 65 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM.Build.0 = Release|ARM 66 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM.Deploy.0 = Release|ARM 67 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM64.ActiveCfg = Release|ARM64 68 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM64.Build.0 = Release|ARM64 69 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM64.Deploy.0 = Release|ARM64 70 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x64.ActiveCfg = Release|x64 71 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x64.Build.0 = Release|x64 72 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x64.Deploy.0 = Release|x64 73 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x86.ActiveCfg = Release|x86 74 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x86.Build.0 = Release|x86 75 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x86.Deploy.0 = Release|x86 76 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|Any CPU.ActiveCfg = Debug|x86 77 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|Any CPU.Build.0 = Debug|x86 78 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|ARM.ActiveCfg = Debug|ARM 79 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|ARM.Build.0 = Debug|ARM 80 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|ARM64.ActiveCfg = Debug|ARM64 81 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|ARM64.Build.0 = Debug|ARM64 82 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|x64.ActiveCfg = Debug|x64 83 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|x64.Build.0 = Debug|x64 84 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|x86.ActiveCfg = Debug|x86 85 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|x86.Build.0 = Debug|x86 86 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|Any CPU.ActiveCfg = Release|x86 87 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|Any CPU.Build.0 = Release|x86 88 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|ARM.ActiveCfg = Release|ARM 89 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|ARM.Build.0 = Release|ARM 90 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|ARM64.ActiveCfg = Release|ARM64 91 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|ARM64.Build.0 = Release|ARM64 92 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|x64.ActiveCfg = Release|x64 93 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|x64.Build.0 = Release|x64 94 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|x86.ActiveCfg = Release|x86 95 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|x86.Build.0 = Release|x86 96 | EndGlobalSection 97 | GlobalSection(SolutionProperties) = preSolution 98 | HideSolutionNode = FALSE 99 | EndGlobalSection 100 | GlobalSection(ExtensibilityGlobals) = postSolution 101 | SolutionGuid = {79558D4B-E776-4662-A741-BBDDC6C0556F} 102 | EndGlobalSection 103 | EndGlobal 104 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/ModelViewer.xaml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using Windows.UI.Xaml; 7 | using Windows.UI.Xaml.Controls; 8 | using Windows.UI.Xaml.Input; 9 | using SceneLoaderComponent; 10 | using Windows.UI.Composition; 11 | using Windows.UI.Composition.Scenes; 12 | using System.Numerics; 13 | using Windows.UI.Xaml.Hosting; 14 | using Windows.Storage; 15 | using System.Threading.Tasks; 16 | 17 | // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 18 | 19 | namespace CameraComponent 20 | { 21 | public sealed partial class ModelViewer : UserControl 22 | { 23 | private Compositor _compositor; 24 | private SceneVisual _sceneVisual; 25 | private Viewport _viewport; 26 | private OrbitalCamera _camera; 27 | 28 | private bool _mouseDowned; 29 | private Vector2 _mouseDownLocation; 30 | 31 | public ModelViewer() 32 | { 33 | this.InitializeComponent(); 34 | 35 | // Create a camera and a ContainerVisual 36 | _compositor = Window.Current.Compositor; 37 | var root = _compositor.CreateContainerVisual(); 38 | root.Size = new Vector2(1000, 1000); 39 | ElementCompositionPreview.SetElementChildVisual(this, root); 40 | 41 | // create a SceneVisual and insert it into the visual tree 42 | _sceneVisual = SceneVisual.Create(_compositor); 43 | root.Children.InsertAtTop(_sceneVisual); 44 | 45 | // instantiate viewport and assign it "good" default values 46 | _viewport = new Viewport(_compositor); 47 | _viewport.AttachToVisual(_sceneVisual); 48 | _viewport.Size = Target.ActualSize; 49 | _viewport.Offset = new Vector3(_viewport.Size / 2f, 0f); 50 | 51 | // instantiate camera and assign it "good" default values 52 | _camera = new OrbitalCamera(_compositor); 53 | _camera.Target = new Vector3(0f, 0f, 0f); 54 | _camera.Radius = 600f; 55 | _camera.Theta = 0f; 56 | _camera.Phi = MathF.PI / 4; 57 | 58 | // instantiate projection and assign it "good" default values 59 | PerspectiveProjection projection = new PerspectiveProjection(_compositor); 60 | projection.Fov = MathF.PI / 2; 61 | 62 | _camera.Projection = projection; 63 | _viewport.Camera = _camera; 64 | 65 | // add event handler for chaning target size 66 | Target.SizeChanged += Target_SizeChanged; 67 | 68 | // event handlers for pointer events 69 | Target.PointerWheelChanged += Target_PointerWheelChanged; 70 | Target.PointerPressed += Target_PointerPressed; 71 | Target.PointerReleased += Target_PointerReleased; 72 | Target.PointerMoved += Target_PointerMoved; 73 | 74 | Window.Current.CoreWindow.PointerReleased += CoreWindow_PointerReleased; 75 | } 76 | 77 | private void CoreWindow_PointerReleased(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.PointerEventArgs args) 78 | { 79 | _mouseDowned = false; 80 | } 81 | 82 | private void Target_SizeChanged(object sender, SizeChangedEventArgs e) 83 | { 84 | _viewport.Size = e.NewSize.ToVector2(); 85 | } 86 | 87 | private void Target_PointerWheelChanged(object sender, PointerRoutedEventArgs e) 88 | { 89 | // positive if scroll away from the user, negative if scroll toward the user 90 | int scrollSign = Math.Sign(e.GetCurrentPoint(Target).Properties.MouseWheelDelta); 91 | 92 | // determines how much to increase or decrease camera's radius by with each scroll 93 | // smaller numbers correspond to greater changes in radius 94 | float sensitivity = 0.95f; 95 | 96 | // scroll away from you 97 | if (scrollSign > 0) 98 | { 99 | _camera.Radius *= sensitivity; 100 | } 101 | // scroll towards you 102 | else if (scrollSign < 0) 103 | { 104 | _camera.Radius *= 1 + (1 - sensitivity); 105 | } 106 | } 107 | 108 | private void Target_PointerPressed(object sender, PointerRoutedEventArgs e) 109 | { 110 | // use to determine how much to rotate camera by, based on size of change in pointer position 111 | _mouseDownLocation = e.GetCurrentPoint(Target).Position.ToVector2(); 112 | 113 | _mouseDowned = true; 114 | } 115 | 116 | private void Target_PointerReleased(object sender, PointerRoutedEventArgs e) 117 | { 118 | // prohibit mouse from changing rotation if the mouse button isn't pressed 119 | _mouseDowned = false; 120 | } 121 | 122 | private void Target_PointerMoved(object sender, PointerRoutedEventArgs e) 123 | { 124 | if (_mouseDowned) 125 | { 126 | // rotate proportionately to the size of the mouse movement 127 | Vector2 newPos = e.GetCurrentPoint(Target).Position.ToVector2(); 128 | float thetaDelta = newPos.X - _mouseDownLocation.X; 129 | float phiDelta = newPos.Y - _mouseDownLocation.Y; 130 | 131 | _mouseDownLocation = newPos; 132 | 133 | // higher number corresponds to faster rotation 134 | float sensitivity = 0.005f; 135 | 136 | // changes camera's phi and theta based on the sensitivity and size of the mouse movement 137 | _camera.Theta -= sensitivity * thetaDelta; 138 | _camera.Phi -= sensitivity * phiDelta; 139 | } 140 | } 141 | 142 | public string GltfFile 143 | { 144 | get { return (string)GetValue(GltfFileProperty); } 145 | set 146 | { 147 | SetValue(GltfFileProperty, value); 148 | LoadGltfFile(); 149 | } 150 | } 151 | 152 | private static readonly DependencyProperty GltfFileProperty = 153 | DependencyProperty.Register("GltfFile", typeof(string), typeof(ModelViewer), null); 154 | 155 | private async void LoadGltfFile() 156 | { 157 | _sceneVisual.Root = await LoadGLTF(new Uri(GltfFile)); 158 | } 159 | 160 | async Task LoadGLTF(Uri uri) 161 | { 162 | var storageFile = await StorageFile.GetFileFromApplicationUriAsync(uri); 163 | var buffer = await FileIO.ReadBufferAsync(storageFile); 164 | 165 | var loader = new SceneLoader(); 166 | return loader.Load(buffer, _compositor); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/PerspectiveProjection.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Numerics; 7 | using Windows.UI.Composition; 8 | 9 | namespace CameraComponent 10 | { 11 | /// 12 | /// A class that defines a perspective projection with a distance to the near and far planes and a field of view. 13 | /// Implements the Projection and Animatable interfaces. 14 | /// 15 | public sealed class PerspectiveProjection : Projection 16 | { 17 | private Compositor _compositor; 18 | private CompositionPropertySet _propertySet; 19 | 20 | /// 21 | /// Creates a PerspectiveProjection with default properties. 22 | /// Fov = Pi / 2 23 | /// Near = 1 24 | /// Far = 1000 25 | /// 26 | /// 27 | /// Thrown when constructor is passed a null value. 28 | public PerspectiveProjection(Compositor compositor) 29 | { 30 | if (compositor == null) 31 | { 32 | throw new System.ArgumentException("Compositor cannot be null"); 33 | } 34 | 35 | _compositor = compositor; 36 | _propertySet = _compositor.CreatePropertySet(); 37 | 38 | // Create the properties for the projection 39 | _propertySet.InsertScalar("Fov", MathF.PI / 2); 40 | _propertySet.InsertScalar("Near", 1f); 41 | _propertySet.InsertScalar("Far", 1000f); 42 | _propertySet.InsertMatrix4x4("ProjectionMatrix", Matrix4x4.Identity); 43 | 44 | StartAnimationonProjectionMatrix(); 45 | } 46 | 47 | /// 48 | /// The field of view of the projection's frustum in radians. 49 | /// 50 | public float Fov 51 | { 52 | get 53 | { 54 | float curr; 55 | _propertySet.TryGetScalar("Fov", out curr); 56 | return curr; 57 | } 58 | set 59 | { 60 | float epsilon = 0.0001f; 61 | _propertySet.InsertScalar("Fov", MathF.Min(MathF.PI - epsilon, MathF.Max(epsilon, value))); 62 | } 63 | } 64 | 65 | /// 66 | /// The field of view of the projection's frustum in degrees. 67 | /// 68 | public float FovInDegrees { get => ConvertRadiansToDegrees(Fov); set => Fov = ConvertDegreesToRadians(value); } 69 | 70 | // Helper function that converts radians to degrees 71 | private float ConvertRadiansToDegrees(float rads) 72 | { 73 | return (180 / MathF.PI) * rads; 74 | } 75 | 76 | // Helper function that converts radians to degrees 77 | private float ConvertDegreesToRadians(float degs) 78 | { 79 | return (MathF.PI / 180) * degs; 80 | } 81 | 82 | /// 83 | /// Distance from the eye to the near plane. 84 | /// 85 | public float Near 86 | { 87 | get 88 | { 89 | float curr; 90 | _propertySet.TryGetScalar("Near", out curr); 91 | return curr; 92 | } 93 | set 94 | { 95 | float epsilon = 0.0001f; 96 | _propertySet.InsertScalar("Near", MathF.Max(epsilon, value)); 97 | } 98 | } 99 | 100 | /// 101 | /// Distance from the eye to the far plane. 102 | /// 103 | public float Far 104 | { 105 | get 106 | { 107 | float curr; 108 | _propertySet.TryGetScalar("Far", out curr); 109 | return curr; 110 | } 111 | set 112 | { 113 | _propertySet.InsertScalar("Far", value); 114 | } 115 | } 116 | 117 | /// 118 | /// Returns the matrix created from the projection's Near, Far, and Fov values. 119 | /// 120 | /// A Matrix4x4 that normalizes the scene in the range (-1, -1, -1) to (1, 1, 1). 121 | public Matrix4x4 GetProjectionMatrix() 122 | { 123 | Matrix4x4 matProj = Matrix4x4.Identity; 124 | matProj.M11 = 1 / MathF.Tan(Fov / 2); 125 | matProj.M22 = 1 / MathF.Tan(Fov / 2); 126 | matProj.M33 = (Far - Near) / -(Far + Near); 127 | matProj.M34 = -1; 128 | matProj.M43 = (-2 * Far * Near) / -(Far + Near); 129 | 130 | return matProj; 131 | } 132 | 133 | 134 | /// 135 | /// Returns the projection's set of animatable properties. 136 | /// 137 | /// A CompositionPropertySet holding the projection's properties. 138 | public CompositionPropertySet GetPropertySet() 139 | { 140 | return _propertySet; 141 | } 142 | 143 | private void StartAnimationonProjectionMatrix() 144 | { 145 | var matProj = 146 | "Matrix4x4(" + 147 | "1 / Tan(Clamp(PerspProj.Fov / 2, epsilon, Pi - epsilon)), 0, 0, 0, " + 148 | "0, 1 / Tan(Clamp(PerspProj.Fov / 2, epsilon, Pi - epsilon)), 0, 0, " + 149 | "0, 0, (PerspProj.Far - PerspProj.Near) / -(PerspProj.Far + PerspProj.Near), -1, " + 150 | "0, 0, (-2 * PerspProj.Far * PerspProj.Near) / -(PerspProj.Far + PerspProj.Near), 1)"; 151 | 152 | var projExpression = _compositor.CreateExpressionAnimation(); 153 | projExpression.Expression = matProj; 154 | projExpression.SetScalarParameter("epsilon", 0.0001f); 155 | projExpression.SetReferenceParameter("PerspProj", _propertySet); 156 | 157 | _propertySet.StartAnimation("ProjectionMatrix", projExpression); 158 | } 159 | 160 | /// 161 | /// Starts a given animation on the specified property. 162 | /// 163 | /// The name of the property to be animated. 164 | /// The animation being applied. 165 | public void StartAnimation(string propertyName, CompositionAnimation animation) 166 | { 167 | _propertySet.StartAnimation(propertyName, animation); 168 | } 169 | 170 | /// 171 | /// Stops any animations on the specified property. 172 | /// 173 | /// The name of the property whose animations we are stopping. 174 | public void StopAnimation(string propertyName) 175 | { 176 | _propertySet.StopAnimation(propertyName); 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | build/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | **/Properties/launchSettings.json 57 | 58 | # StyleCop 59 | StyleCopReport.xml 60 | 61 | # Files built by Visual Studio 62 | *_i.c 63 | *_p.c 64 | *_i.h 65 | *.ilk 66 | *.meta 67 | *.obj 68 | *.iobj 69 | *.pch 70 | *.pdb 71 | *.ipdb 72 | *.pgc 73 | *.pgd 74 | *.rsp 75 | *.sbr 76 | *.tlb 77 | *.tli 78 | *.tlh 79 | *.tmp 80 | *.tmp_proj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush 296 | .cr/ 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | 333 | # Nuget Packager 334 | */NugetPackager -------------------------------------------------------------------------------- /Experimental/CameraComponent/CameraComponent.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D} 8 | winmdobj 9 | Properties 10 | CameraComponent 11 | CameraComponent 12 | en-US 13 | UAP 14 | 10.0.18362.0 15 | 10.0.18362.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | false 20 | 21 | 22 | AnyCPU 23 | true 24 | full 25 | false 26 | bin\Debug\ 27 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 28 | prompt 29 | 4 30 | 31 | 32 | AnyCPU 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE;NETFX_CORE;WINDOWS_UWP 37 | prompt 38 | 4 39 | 40 | 41 | x86 42 | true 43 | bin\x86\Debug\ 44 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 45 | ;2008 46 | full 47 | false 48 | prompt 49 | false 50 | 51 | 52 | 53 | 54 | x86 55 | bin\x86\Release\ 56 | TRACE;NETFX_CORE;WINDOWS_UWP 57 | true 58 | ;2008 59 | pdbonly 60 | false 61 | prompt 62 | 63 | 64 | ARM 65 | true 66 | bin\ARM\Debug\ 67 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 68 | ;2008 69 | full 70 | false 71 | prompt 72 | 73 | 74 | ARM 75 | bin\ARM\Release\ 76 | TRACE;NETFX_CORE;WINDOWS_UWP 77 | true 78 | ;2008 79 | pdbonly 80 | false 81 | prompt 82 | 83 | 84 | ARM64 85 | true 86 | bin\ARM64\Debug\ 87 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 88 | ;2008 89 | full 90 | false 91 | prompt 92 | 93 | 94 | ARM64 95 | bin\ARM64\Release\ 96 | TRACE;NETFX_CORE;WINDOWS_UWP 97 | true 98 | ;2008 99 | pdbonly 100 | false 101 | prompt 102 | 103 | 104 | x64 105 | true 106 | bin\x64\Debug\ 107 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 108 | ;2008 109 | full 110 | false 111 | prompt 112 | 113 | 114 | x64 115 | bin\x64\Release\ 116 | TRACE;NETFX_CORE;WINDOWS_UWP 117 | true 118 | ;2008 119 | pdbonly 120 | false 121 | prompt 122 | 123 | 124 | PackageReference 125 | 126 | 127 | 128 | 129 | 130 | 131 | ModelViewer.xaml 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 6.2.8 143 | 144 | 145 | 146 | 147 | Designer 148 | MSBuild:Compile 149 | 150 | 151 | 152 | 153 | {88c4d662-8669-433b-8a8b-47b3a17e3c6e} 154 | SceneLoaderComponent 155 | 156 | 157 | 158 | 14.0 159 | 160 | 161 | 162 | 163 | 164 | 171 | -------------------------------------------------------------------------------- /TestViewer/TestViewer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x86 7 | {5D504AFF-651A-4C27-BA19-550663227A85} 8 | AppContainerExe 9 | Properties 10 | TestViewer 11 | TestViewer 12 | en-US 13 | UAP 14 | 10.0.18362.0 15 | 10.0.18362.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | true 20 | TestViewer_TemporaryKey.pfx 21 | 22 | 23 | true 24 | bin\x86\Debug\ 25 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 26 | ;2008 27 | full 28 | x86 29 | false 30 | prompt 31 | true 32 | MixedMinimumRules.ruleset 33 | 34 | 35 | bin\x86\Release\ 36 | TRACE;NETFX_CORE;WINDOWS_UWP 37 | true 38 | ;2008 39 | pdbonly 40 | x86 41 | false 42 | prompt 43 | true 44 | true 45 | 46 | 47 | true 48 | bin\ARM\Debug\ 49 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 50 | ;2008 51 | full 52 | ARM 53 | false 54 | prompt 55 | true 56 | 57 | 58 | bin\ARM\Release\ 59 | TRACE;NETFX_CORE;WINDOWS_UWP 60 | true 61 | ;2008 62 | pdbonly 63 | ARM 64 | false 65 | prompt 66 | true 67 | true 68 | 69 | 70 | true 71 | bin\ARM64\Debug\ 72 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 73 | ;2008 74 | full 75 | ARM64 76 | false 77 | prompt 78 | true 79 | true 80 | 81 | 82 | bin\ARM64\Release\ 83 | TRACE;NETFX_CORE;WINDOWS_UWP 84 | true 85 | ;2008 86 | pdbonly 87 | ARM64 88 | false 89 | prompt 90 | true 91 | true 92 | 93 | 94 | true 95 | bin\x64\Debug\ 96 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 97 | ;2008 98 | full 99 | x64 100 | false 101 | prompt 102 | true 103 | 104 | 105 | bin\x64\Release\ 106 | TRACE;NETFX_CORE;WINDOWS_UWP 107 | true 108 | ;2008 109 | pdbonly 110 | x64 111 | false 112 | prompt 113 | true 114 | true 115 | 116 | 117 | PackageReference 118 | 119 | 120 | 121 | App.xaml 122 | 123 | 124 | MainPage.xaml 125 | 126 | 127 | 128 | 129 | 130 | Designer 131 | 132 | 133 | PreserveNewest 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | MSBuild:Compile 151 | Designer 152 | 153 | 154 | MSBuild:Compile 155 | Designer 156 | 157 | 158 | 159 | 160 | 6.2.8 161 | 162 | 163 | 164 | 165 | {239c87c3-1e17-4f01-8d93-9b21c1a53f3d} 166 | CameraComponent 167 | 168 | 169 | {88c4d662-8669-433b-8a8b-47b3a17e3c6e} 170 | SceneLoaderComponent 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 14.0 181 | 182 | 183 | 190 | -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Image.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | #include "wincodec.h" 9 | 10 | using namespace std; 11 | using namespace Microsoft::glTF; 12 | 13 | namespace winrt { 14 | using namespace Windows::Graphics; 15 | using namespace Windows::Graphics::DirectX; 16 | using namespace Windows::UI::Composition; 17 | } 18 | using namespace winrt; 19 | 20 | namespace SceneLoader 21 | { 22 | // Image 23 | void GLTFVisitor::operator()(const Image& image, VisitState alreadyVisited, const VisitDefaultAction&) 24 | { 25 | if (alreadyVisited == VisitState::New) 26 | { 27 | std::vector imageData = m_gltfResourceReader->ReadBinaryData(m_gltfDocument, image); 28 | 29 | const void* pSource = static_cast(imageData.data()); 30 | 31 | // Create input stream for memory 32 | com_ptr cpWIC; 33 | winrt::check_hresult(CoCreateInstance( 34 | CLSID_WICImagingFactory, 35 | NULL, 36 | CLSCTX_INPROC_SERVER, 37 | __uuidof(cpWIC), 38 | (LPVOID*)&cpWIC)); 39 | 40 | com_ptr cpStream; 41 | winrt::check_hresult(cpWIC->CreateStream(cpStream.put())); 42 | winrt::check_hresult(cpStream->InitializeFromMemory(static_cast(const_cast(pSource)), 43 | static_cast(imageData.size()))); 44 | 45 | com_ptr cpDecoder; 46 | winrt::check_hresult(cpWIC->CreateDecoderFromStream(cpStream.get(), nullptr, WICDecodeMetadataCacheOnDemand, cpDecoder.put())); 47 | 48 | com_ptr cpSource; 49 | winrt::check_hresult(cpDecoder->GetFrame(0, cpSource.put())); 50 | 51 | UINT imageWidth = 0; 52 | UINT imageHeight = 0; 53 | winrt::check_hresult(cpSource->GetSize(&imageWidth, &imageHeight)); 54 | SizeInt32 size{ static_cast(imageWidth), static_cast(imageHeight) }; // FIXME: conversion from 'UINT' to 'int32_t' requires a narrowing conversion 55 | DirectXPixelFormat pixelFormat = DirectXPixelFormat::B8G8R8A8UIntNormalized; // Warning: SceneResourceSet::EnsureMipMapSurfaceId hard codes these values 56 | DirectXAlphaMode alphaMode = DirectXAlphaMode::Premultiplied; // Warning: SceneResourceSet::EnsureMipMapSurfaceId hard codes these values 57 | 58 | CompositionMipmapSurface mipmap = EnsureMipMapSurfaceId( 59 | image.id, 60 | size, 61 | pixelFormat, 62 | alphaMode 63 | ); 64 | 65 | com_ptr cpCurrentSourceBitmap; 66 | 67 | // Create highest resolution source bitmap 68 | { 69 | com_ptr cpD2DContext; 70 | 71 | // Create Scalar 72 | com_ptr cpScaler; 73 | winrt::check_hresult(cpWIC->CreateBitmapScaler(cpScaler.put())); 74 | 75 | winrt::check_hresult(cpScaler->Initialize( 76 | cpSource.get(), // Bitmap source to scale. 77 | imageWidth, // Scale width to half of original. 78 | imageHeight, // Scale height to half of original. 79 | WICBitmapInterpolationModeFant)); // Use Fant mode interpolation. 80 | 81 | com_ptr cpConverter; 82 | 83 | winrt::check_hresult(cpWIC->CreateFormatConverter(cpConverter.put())); 84 | winrt::check_hresult(cpConverter->Initialize( 85 | cpScaler.get(), 86 | /*WicPixelFormatFromDirectXPixelFormat(pixelFormat, alphaMode)*/GUID_WICPixelFormat32bppPBGRA, 87 | WICBitmapDitherTypeNone, 88 | nullptr, 89 | 0.0f, 90 | WICBitmapPaletteTypeMedianCut)); 91 | 92 | CompositionDrawingSurface cpDrawingSurface = mipmap.GetDrawingSurfaceForLevel(0); 93 | com_ptr cpDrawingSurfaceInterop = cpDrawingSurface.as(); 94 | 95 | POINT surfaceUpdateOffset; 96 | winrt::check_hresult(cpDrawingSurfaceInterop->BeginDraw( 97 | nullptr, 98 | IID_PPV_ARGS(cpD2DContext.put()), 99 | &surfaceUpdateOffset)); 100 | 101 | com_ptr cpCompatibleRenderTarget; 102 | winrt::check_hresult(cpD2DContext->CreateCompatibleRenderTarget(cpCompatibleRenderTarget.put())); 103 | 104 | winrt::check_hresult(cpCompatibleRenderTarget->CreateBitmapFromWicBitmap( 105 | cpConverter.get(), 106 | nullptr, 107 | cpCurrentSourceBitmap.put())); 108 | 109 | winrt::check_hresult(cpDrawingSurfaceInterop->EndDraw()); 110 | } 111 | 112 | float sourceBitmapDpiX, sourceBitmapDpiY; 113 | 114 | cpCurrentSourceBitmap->GetDpi(&sourceBitmapDpiX, &sourceBitmapDpiY); 115 | 116 | for (UINT i = 0; i < mipmap.LevelCount(); ++i) 117 | { 118 | CompositionDrawingSurface cpDrawingSurface = mipmap.GetDrawingSurfaceForLevel(i); 119 | com_ptr cpDrawingSurfaceInterop = cpDrawingSurface.as(); 120 | com_ptr cpD2DContext; 121 | 122 | #ifndef NDEBUG 123 | { 124 | D2D1_SIZE_U sourceSize2 = cpCurrentSourceBitmap->GetPixelSize(); 125 | 126 | assert(sourceSize2.width == imageWidth); 127 | assert(sourceSize2.height == imageHeight); 128 | } 129 | #endif 130 | 131 | POINT surfaceUpdateOffset; 132 | winrt::check_hresult(cpDrawingSurfaceInterop->BeginDraw( 133 | nullptr, 134 | IID_PPV_ARGS(cpD2DContext.put()), 135 | &surfaceUpdateOffset)); 136 | 137 | D2D1_RECT_F destRect; 138 | destRect.left = (float)surfaceUpdateOffset.x; 139 | destRect.top = (float)surfaceUpdateOffset.y; 140 | destRect.right = (float)(destRect.left + imageWidth); 141 | destRect.bottom = (float)(destRect.top + imageHeight); 142 | 143 | cpD2DContext->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY); 144 | 145 | cpD2DContext->DrawBitmap( 146 | cpCurrentSourceBitmap.get(), 147 | &destRect, 148 | 1.0f, 149 | D2D1_BITMAP_INTERPOLATION_MODE_LINEAR 150 | ); 151 | 152 | // For debugging, turn this on to clobber the contents with red 153 | #if 0 154 | com_ptr cpSolidColorBrush; 155 | winrt::check_hresult(cpD2DContext->CreateSolidColorBrush(D2D1::ColorF::ColorF(1.0f, 0.0f, 0.0f), cpSolidColorBrush.put())); 156 | 157 | cpD2DContext->FillRectangle( 158 | &destRect, 159 | cpSolidColorBrush.get() 160 | ); 161 | #endif 162 | 163 | winrt::check_hresult(cpD2DContext->Flush()); 164 | 165 | winrt::check_hresult(cpDrawingSurfaceInterop->EndDraw()); 166 | 167 | // Update image size 168 | #undef max 169 | imageWidth = std::max(imageWidth / 2, 1U); 170 | imageHeight = std::max(imageHeight / 2, 1U); 171 | 172 | // Now we need to generate the next level source bitmap that's going to be used for 173 | // the next imagewidth/height. Note that imageWidth/Height have already been divided 174 | // by 2. 175 | com_ptr cpNewD2DTarget; 176 | 177 | D2D1_SIZE_F newDesiredSizeF = D2D1::SizeF(static_cast(imageWidth) / sourceBitmapDpiX, static_cast(imageHeight) / sourceBitmapDpiY); 178 | 179 | // Compatible Target should match format 180 | winrt::check_hresult(cpD2DContext->CreateCompatibleRenderTarget( 181 | newDesiredSizeF, 182 | D2D1::SizeU(imageWidth, imageHeight), 183 | cpCurrentSourceBitmap->GetPixelFormat(), 184 | D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, 185 | cpNewD2DTarget.put() 186 | )); 187 | 188 | cpNewD2DTarget->BeginDraw(); 189 | 190 | cpNewD2DTarget->DrawBitmap( 191 | cpCurrentSourceBitmap.get(), 192 | D2D1::RectF(0.0f, 0.0f, newDesiredSizeF.width, newDesiredSizeF.height), 193 | 1.0f, 194 | D2D1_BITMAP_INTERPOLATION_MODE_LINEAR 195 | ); 196 | 197 | winrt::check_hresult(cpNewD2DTarget->Flush()); 198 | 199 | winrt::check_hresult(cpNewD2DTarget->EndDraw()); 200 | 201 | com_ptr cpNewBitmap; 202 | winrt::check_hresult(cpNewD2DTarget->GetBitmap(cpNewBitmap.put())); 203 | 204 | // Now that we've generated the next level of bitmap, replace our current one 205 | cpCurrentSourceBitmap = cpNewBitmap; 206 | } 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/FirstPersonCamera.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Numerics; 7 | using Windows.UI.Composition; 8 | 9 | namespace CameraComponent 10 | { 11 | /// 12 | /// A class that defines a FirstPersonCamera that has a position in 3D world space and rotates about the x,y, and z axes. 13 | /// Implements the Camera and Animatable interfaces. 14 | /// 15 | public sealed class FirstPersonCamera : Camera 16 | { 17 | private Compositor _compositor; 18 | private Projection _projection; 19 | private CompositionPropertySet _propertySet; 20 | 21 | /// 22 | /// Creates a FirstPersonCamera with default properties. 23 | /// Position = Vector3.Zero 24 | /// Yaw = 0 25 | /// Pitch = 0 26 | /// Roll = 0 27 | /// ModelViewProjectionMatrix = Matrix4x4.Identity 28 | /// 29 | /// 30 | /// Thrown when constructor is passed a null value. 31 | public FirstPersonCamera(Compositor compositor) 32 | { 33 | if (compositor == null) 34 | { 35 | throw new System.ArgumentException("Compositor cannot be null"); 36 | } 37 | 38 | _compositor = compositor; 39 | 40 | // Create the properties for the camera 41 | _propertySet = _compositor.CreatePropertySet(); 42 | _propertySet.InsertVector3("Position", Vector3.Zero); 43 | _propertySet.InsertScalar("Yaw", 0f); 44 | _propertySet.InsertScalar("Pitch", 0f); 45 | _propertySet.InsertScalar("Roll", 0f); 46 | _propertySet.InsertMatrix4x4("ModelViewProjectionMatrix", Matrix4x4.Identity); 47 | 48 | // Default is an orthographic projection 49 | Projection = new OrthographicProjection(_compositor); 50 | } 51 | 52 | /// 53 | /// Camera's rotation about the y-axis in radians. 54 | /// Rotates counterclockwise from 0 to 2Pi. 55 | /// 56 | public float Yaw 57 | { 58 | get 59 | { 60 | float curr; 61 | _propertySet.TryGetScalar("Yaw", out curr); 62 | return curr; 63 | } 64 | set 65 | { 66 | _propertySet.InsertScalar("Yaw", value); 67 | } 68 | } 69 | 70 | /// 71 | /// Camera's rotation about the x-axis in radians. 72 | /// Rotates counterclockwise from 0 to 2Pi. 73 | /// 74 | public float Pitch 75 | { 76 | get 77 | { 78 | float curr; 79 | _propertySet.TryGetScalar("Pitch", out curr); 80 | return curr; 81 | } 82 | set 83 | { 84 | _propertySet.InsertScalar("Pitch", value); 85 | } 86 | } 87 | 88 | /// 89 | /// Camera's rotation about the z-axis in radians. 90 | /// Rotates counterclockwise from 0 to 2Pi. 91 | /// 92 | public float Roll 93 | { 94 | get 95 | { 96 | float curr; 97 | _propertySet.TryGetScalar("Roll", out curr); 98 | return curr; 99 | } 100 | set 101 | { 102 | _propertySet.InsertScalar("Roll", value); 103 | } 104 | } 105 | 106 | /// 107 | /// Camera's position in 3D world space. 108 | /// 109 | public Vector3 Position 110 | { 111 | get 112 | { 113 | Vector3 curr; 114 | _propertySet.TryGetVector3("Position", out curr); 115 | return curr; 116 | } 117 | set 118 | { 119 | _propertySet.InsertVector3("Position", value); 120 | } 121 | } 122 | 123 | /// 124 | /// The camera's reference to an object that implements the Projection interace. 125 | /// When setting, this property starts animations on the camera's ModelViewProjectionMatrix property. 126 | /// 127 | /// When set to null, the ModelViewProjectionProperty is animated using an OrthographicProjection with the 128 | /// default values of: Height = 100, Width = 100, Near = 1, Far = 1000. 129 | public Projection Projection 130 | { 131 | get => _projection; 132 | set 133 | { 134 | _projection = value; 135 | 136 | // create view matrix based on the camera's rotation and position 137 | var matPos = "Matrix4x4.CreateTranslation(-FPCamera.Position)"; 138 | var matRoll = "Matrix4x4.CreateFromAxisAngle(Vector3(0, 0, 1), -FPCamera.Roll)"; 139 | var matPitch = "Matrix4x4.CreateFromAxisAngle(Vector3(1, 0, 0), -FPCamera.Pitch)"; 140 | var matYaw = "Matrix4x4.CreateFromAxisAngle(Vector3(0, 1, 0), -FPCamera.Yaw)"; 141 | var viewMat = matPos + "*" + matYaw + "*" + matPitch + "*" + matRoll; 142 | 143 | // create a matrix that is the product of the camera's view matrix and the projection's projection matrix 144 | var modelViewProjMatExpression = _compositor.CreateExpressionAnimation(); 145 | if (_projection == null) // if null then the default is an orthographic projection 146 | { 147 | OrthographicProjection defaultProj = new OrthographicProjection(_compositor); 148 | modelViewProjMatExpression.Expression = viewMat + "*" + "DefaultProjection.ProjectionMatrix"; 149 | modelViewProjMatExpression.SetReferenceParameter("FPCamera", _propertySet); 150 | modelViewProjMatExpression.SetReferenceParameter("DefaultProjection", Projection.GetPropertySet()); 151 | } 152 | else 153 | { 154 | modelViewProjMatExpression.Expression = viewMat + "*" + "Projection.ProjectionMatrix"; 155 | modelViewProjMatExpression.SetReferenceParameter("FPCamera", _propertySet); 156 | modelViewProjMatExpression.SetReferenceParameter("Projection", Projection.GetPropertySet()); 157 | } 158 | 159 | StartAnimation("ModelViewProjectionMatrix", modelViewProjMatExpression); 160 | } 161 | } 162 | 163 | /// 164 | /// Rotates the camera's yaw and pitch to look in the given direction. 165 | /// 166 | /// 167 | public void SetLookDirection(Vector3 direction) 168 | { 169 | if (direction != Vector3.Zero) 170 | { 171 | direction = Vector3.Normalize(direction); 172 | } 173 | 174 | direction.X *= -1; 175 | Yaw = (MathF.PI / 2f) + MathF.Atan2(direction.Z, direction.X); 176 | Pitch = MathF.Asin(direction.Y); 177 | } 178 | 179 | /// 180 | /// Returns the matrix created from the camera's translation and rotation transformations. 181 | /// 182 | /// A Matrix4x4 that is the product of the matrices created from the camera's position, yaw, pitch, and roll. 183 | public Matrix4x4 GetViewMatrix() 184 | { 185 | // create view matrix based on the camera's rotation and position 186 | Matrix4x4 matPos = Matrix4x4.CreateTranslation(-Position); 187 | Matrix4x4 matRoll = Matrix4x4.CreateFromAxisAngle(new Vector3(0, 0, 1), -Roll); 188 | Matrix4x4 matPitch = Matrix4x4.CreateFromAxisAngle(new Vector3(1, 0, 0), -Pitch); 189 | Matrix4x4 matYaw = Matrix4x4.CreateFromAxisAngle(new Vector3(0, 1, 0), -Yaw); 190 | 191 | return matPos * matYaw * matPitch * matRoll; 192 | } 193 | 194 | /// 195 | /// Returns that a matrix created from the camera's view matrix and it's Projection's projection matrix. 196 | /// 197 | /// A Matrix4x4 that is the product of matrices created from the Camera's position, yaw, pitch, and roll and its Projection's projection matrix. 198 | public Matrix4x4 GetModelViewProjectionMatrix() 199 | { 200 | return GetViewMatrix() * Projection.GetProjectionMatrix(); 201 | } 202 | 203 | /// 204 | /// Returns the camera's set of animatable properties. 205 | /// 206 | /// A CompositionPropertySet holding the camera's properties. 207 | public CompositionPropertySet GetPropertySet() 208 | { 209 | return _propertySet; 210 | } 211 | 212 | /// 213 | /// Starts a given animation on the specified property. 214 | /// 215 | /// The name of the property to be animated. 216 | /// The animation being applied. 217 | public void StartAnimation(string propertyName, CompositionAnimation animation) 218 | { 219 | _propertySet.StartAnimation(propertyName, animation); 220 | } 221 | 222 | /// 223 | /// Stops any animations on the specified property. 224 | /// 225 | /// The name of the property whose animations we are stopping. 226 | public void StopAnimation(string propertyName) 227 | { 228 | _propertySet.StopAnimation(propertyName); 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /SceneLoader/SceneResourceSet.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "UtilForIntermingledNamespaces.h" 8 | #include "SceneResourceSet.h" 9 | 10 | using namespace std; 11 | using namespace Microsoft::glTF; 12 | 13 | namespace winrt { 14 | using namespace Windows::UI::Composition; 15 | using namespace Windows::UI::Composition::Scenes; 16 | } 17 | using namespace winrt; 18 | 19 | namespace SceneLoader 20 | { 21 | // If you want to assert when we hit a feature we don't support yet, change this to true. 22 | bool SceneResourceSet::s_assertOnUnimplementedFeature = false; 23 | 24 | SceneWrappingMode 25 | GLTFWrapModeToSceneWrapMode(Microsoft::glTF::WrapMode gltfWrapMode) 26 | { 27 | switch (gltfWrapMode) 28 | { 29 | case Microsoft::glTF::WrapMode::Wrap_CLAMP_TO_EDGE: 30 | return SceneWrappingMode::ClampToEdge; 31 | 32 | case Microsoft::glTF::WrapMode::Wrap_MIRRORED_REPEAT: 33 | return SceneWrappingMode::MirroredRepeat; 34 | 35 | case Microsoft::glTF::WrapMode::Wrap_REPEAT: 36 | default: 37 | return SceneWrappingMode::Repeat; 38 | } 39 | } 40 | 41 | 42 | SceneResourceSet::SceneResourceSet(winrt::Windows::UI::Composition::Compositor compositor) : 43 | m_compositor(compositor), 44 | m_sceneMaterialMap(single_threaded_map()), 45 | m_sceneSurfaceMaterialInputMap(single_threaded_map()), 46 | m_sceneMipMapSurfaceMap(single_threaded_map()) 47 | { 48 | 49 | } 50 | 51 | 52 | SceneMetallicRoughnessMaterial 53 | SceneResourceSet::EnsureMaterialById(const std::string id) 54 | { 55 | // Should we trust that the GLTF SDK is traversing correctly the DOM? 56 | if (!m_sceneMaterialMap.HasKey(GetHSTRINGFromStdString(id))) 57 | { 58 | auto sceneMaterial = SceneMetallicRoughnessMaterial::Create(m_compositor); 59 | sceneMaterial.Comment(wstring(id.begin(), id.end())); 60 | 61 | m_sceneMaterialMap.Insert(GetHSTRINGFromStdString(id), sceneMaterial); 62 | } 63 | 64 | return m_sceneMaterialMap.Lookup(GetHSTRINGFromStdString(id)); 65 | } 66 | 67 | 68 | CompositionMipmapSurface 69 | SceneResourceSet::EnsureMipMapSurfaceId( 70 | const std::string id, 71 | winrt::Windows::Graphics::SizeInt32 sizePixels, 72 | winrt::Windows::Graphics::DirectX::DirectXPixelFormat pixelFormat, 73 | winrt::Windows::Graphics::DirectX::DirectXAlphaMode alphaMode, 74 | winrt::Windows::UI::Composition::ICompositionGraphicsDevice3 graphicsDevice) 75 | { 76 | // Should we trust that the GLTF SDK is traversing correctly the DOM? 77 | if (!m_sceneMipMapSurfaceMap.HasKey(GetHSTRINGFromStdString(id))) 78 | { 79 | auto mipmapSurface = graphicsDevice.CreateMipmapSurface( 80 | sizePixels, 81 | pixelFormat, 82 | alphaMode); 83 | wstring mipmapId{ id.begin(), id.end() }; 84 | mipmapSurface.Comment(mipmapId); 85 | 86 | m_sceneMipMapSurfaceMap.Insert(GetHSTRINGFromStdString(id), mipmapSurface); 87 | } 88 | 89 | return m_sceneMipMapSurfaceMap.Lookup(GetHSTRINGFromStdString(id)); 90 | } 91 | 92 | 93 | CompositionMipmapSurface 94 | SceneResourceSet::LookupMipMapSurfaceId(const std::string id) 95 | { 96 | return m_sceneMipMapSurfaceMap.Lookup(GetHSTRINGFromStdString(id)); 97 | } 98 | 99 | void 100 | SceneResourceSet::StoreGLTFSamplerById(const std::string id, Microsoft::glTF::Sampler sampler) 101 | { 102 | // Make sure we haven't stored this before 103 | assert(m_gltfSamplerMap.find(GetHSTRINGFromStdString(id)) == m_gltfSamplerMap.end()); 104 | 105 | m_gltfSamplerMap.insert(std::map::value_type(GetHSTRINGFromStdString(id), sampler)); 106 | } 107 | 108 | bool 109 | SceneResourceSet::GetGLTFSamplerById(const std::string id, Microsoft::glTF::Sampler* pSampler) 110 | { 111 | if (m_gltfSamplerMap.find(GetHSTRINGFromStdString(id)) == m_gltfSamplerMap.end()) 112 | { 113 | return false; 114 | } 115 | 116 | if (pSampler) 117 | { 118 | *pSampler = m_gltfSamplerMap.at(GetHSTRINGFromStdString(id)); 119 | } 120 | 121 | return true; 122 | } 123 | 124 | 125 | void 126 | SceneResourceSet::StoreGLTFMaterialById(const std::string id, Microsoft::glTF::Material material) 127 | { 128 | // Make sure we haven't stored this before 129 | assert(m_gltfMaterialMap.find(GetHSTRINGFromStdString(id)) == m_gltfMaterialMap.end()); 130 | 131 | m_gltfMaterialMap.insert(std::map::value_type(GetHSTRINGFromStdString(id), material)); 132 | } 133 | 134 | 135 | bool 136 | SceneResourceSet::GetGLTFMaterialById(const std::string id, Microsoft::glTF::Material* pMaterial) 137 | { 138 | if (m_gltfMaterialMap.find(GetHSTRINGFromStdString(id)) == m_gltfMaterialMap.end()) 139 | { 140 | return false; 141 | } 142 | 143 | if (pMaterial) 144 | { 145 | *pMaterial = m_gltfMaterialMap.at(GetHSTRINGFromStdString(id)); 146 | } 147 | 148 | return true; 149 | } 150 | 151 | 152 | void 153 | SceneResourceSet::StoreGLTFTextureById(const std::string id, Microsoft::glTF::Texture texture) 154 | { 155 | // Make sure we haven't stored this before 156 | assert(m_gltfTextureMap.find(GetHSTRINGFromStdString(id)) == m_gltfTextureMap.end()); 157 | 158 | m_gltfTextureMap.insert(std::map::value_type(GetHSTRINGFromStdString(id), texture)); 159 | } 160 | 161 | 162 | bool 163 | SceneResourceSet::GetGLTFTextureById(const std::string id, Microsoft::glTF::Texture* pTexture) 164 | { 165 | if (m_gltfTextureMap.find(GetHSTRINGFromStdString(id)) == m_gltfTextureMap.end()) 166 | { 167 | return false; 168 | } 169 | 170 | if (pTexture) 171 | { 172 | *pTexture = m_gltfTextureMap.at(GetHSTRINGFromStdString(id)); 173 | } 174 | 175 | return true; 176 | } 177 | 178 | 179 | void 180 | SceneResourceSet::CreateSceneMaterialObjects() 181 | { 182 | for (std::map::iterator materialIterator = m_gltfMaterialMap.begin(); materialIterator != m_gltfMaterialMap.end(); materialIterator++) 183 | { 184 | SceneMetallicRoughnessMaterial sceneMaterial = EnsureMaterialById(materialIterator->second.id); 185 | Microsoft::glTF::Material material = materialIterator->second; 186 | 187 | 188 | // BaseColor 189 | if (material.metallicRoughness.baseColorTexture.textureId != "") 190 | { 191 | auto materialInput = GetMaterialInputFromTextureId(material.metallicRoughness.baseColorTexture.textureId); 192 | sceneMaterial.BaseColorInput(materialInput); 193 | 194 | if (m_latestMeshRendererComponent) 195 | { 196 | m_latestMeshRendererComponent.UVMappings().Insert(L"BaseColorInput", 197 | material.metallicRoughness.baseColorTexture.texCoord == 0 ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1); 198 | } 199 | } 200 | 201 | sceneMaterial.BaseColorFactor({ material.metallicRoughness.baseColorFactor.r, material.metallicRoughness.baseColorFactor.g, material.metallicRoughness.baseColorFactor.b, material.metallicRoughness.baseColorFactor.a }); 202 | 203 | // MetallicRoughness 204 | if (material.metallicRoughness.metallicRoughnessTexture.textureId != "") 205 | { 206 | auto materialInput = GetMaterialInputFromTextureId(material.metallicRoughness.metallicRoughnessTexture.textureId); 207 | sceneMaterial.MetallicRoughnessInput(materialInput); 208 | 209 | if (m_latestMeshRendererComponent) 210 | { 211 | m_latestMeshRendererComponent.UVMappings().Insert(L"MetallicRoughnessInput", 212 | material.metallicRoughness.metallicRoughnessTexture.texCoord == 0 ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1); 213 | } 214 | } 215 | 216 | sceneMaterial.RoughnessFactor(material.metallicRoughness.roughnessFactor); 217 | 218 | sceneMaterial.MetallicFactor(material.metallicRoughness.metallicFactor); 219 | 220 | // Normal 221 | if (material.normalTexture.textureId != "") 222 | { 223 | auto materialInput = GetMaterialInputFromTextureId(material.normalTexture.textureId); 224 | sceneMaterial.NormalInput(materialInput); 225 | 226 | if (m_latestMeshRendererComponent) 227 | { 228 | m_latestMeshRendererComponent.UVMappings().Insert(L"NormalInput", 229 | material.normalTexture.texCoord == 0 ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1); 230 | } 231 | } 232 | 233 | sceneMaterial.NormalScale(material.normalTexture.scale); 234 | 235 | // Occlusion 236 | if (material.occlusionTexture.textureId != "") 237 | { 238 | auto materialInput = GetMaterialInputFromTextureId(material.occlusionTexture.textureId); 239 | sceneMaterial.OcclusionInput(materialInput); 240 | 241 | if (m_latestMeshRendererComponent) 242 | { 243 | m_latestMeshRendererComponent.UVMappings().Insert(L"OcclusionInput", 244 | material.occlusionTexture.texCoord == 0 ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1); 245 | } 246 | } 247 | 248 | sceneMaterial.OcclusionStrength(material.occlusionTexture.strength); 249 | 250 | // Emissive 251 | if (material.emissiveTexture.textureId != "") 252 | { 253 | auto materialInput = GetMaterialInputFromTextureId(material.emissiveTexture.textureId); 254 | sceneMaterial.EmissiveInput(materialInput); 255 | 256 | if (m_latestMeshRendererComponent) 257 | { 258 | m_latestMeshRendererComponent.UVMappings().Insert(L"EmissiveInput", 259 | material.emissiveTexture.texCoord == 0 ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1); 260 | } 261 | } 262 | 263 | sceneMaterial.EmissiveFactor({ material.emissiveFactor.r, material.emissiveFactor.g, material.emissiveFactor.b }); 264 | 265 | switch (material.alphaMode) { 266 | case AlphaMode::ALPHA_OPAQUE: 267 | { 268 | sceneMaterial.AlphaMode(SceneAlphaMode::Opaque); 269 | break; 270 | } 271 | case AlphaMode::ALPHA_BLEND: 272 | { 273 | sceneMaterial.AlphaMode(SceneAlphaMode::Blend); 274 | break; 275 | } 276 | case AlphaMode::ALPHA_MASK: 277 | { 278 | sceneMaterial.AlphaMode(SceneAlphaMode::AlphaTest); 279 | break; 280 | } 281 | case AlphaMode::ALPHA_UNKNOWN: 282 | default: 283 | { 284 | UnimplementedFeatureFound(); 285 | } 286 | } 287 | 288 | sceneMaterial.AlphaCutoff(material.alphaCutoff); 289 | sceneMaterial.IsDoubleSided(material.doubleSided); 290 | } 291 | } 292 | 293 | 294 | SceneSurfaceMaterialInput 295 | SceneResourceSet::GetMaterialInputFromTextureId(const std::string textureId) 296 | { 297 | static uint16_t sCount = 0; 298 | Microsoft::glTF::Sampler sampler; 299 | Microsoft::glTF::Texture texture; 300 | 301 | bool resultFound; 302 | 303 | resultFound = GetGLTFTextureById(textureId, &texture); 304 | assert(resultFound); 305 | 306 | resultFound = GetGLTFSamplerById(texture.samplerId, &sampler); 307 | assert(resultFound); 308 | 309 | CompositionMipmapSurface mipMapSurface = LookupMipMapSurfaceId(texture.imageId); 310 | 311 | SceneSurfaceMaterialInput sceneSurfaceMaterialInput = SceneSurfaceMaterialInput::Create(m_compositor); 312 | wstringstream ssitoa; ssitoa << sCount; 313 | sceneSurfaceMaterialInput.Comment(ssitoa.str()); 314 | 315 | SetSceneSampler(sceneSurfaceMaterialInput, sampler); 316 | 317 | sceneSurfaceMaterialInput.Surface(mipMapSurface); 318 | 319 | ++sCount; 320 | 321 | return sceneSurfaceMaterialInput; 322 | } 323 | 324 | 325 | void 326 | SceneResourceSet::SetSceneSampler(winrt::Windows::UI::Composition::Scenes::SceneSurfaceMaterialInput sceneSurfaceMaterialInput, Microsoft::glTF::Sampler sampler) 327 | { 328 | sceneSurfaceMaterialInput.BitmapInterpolationMode(CompositionBitmapInterpolationMode::MagLinearMinLinearMipLinear); 329 | 330 | sceneSurfaceMaterialInput.WrappingUMode(GLTFWrapModeToSceneWrapMode(sampler.wrapS)); 331 | 332 | sceneSurfaceMaterialInput.WrappingVMode(GLTFWrapModeToSceneWrapMode(sampler.wrapT)); 333 | } 334 | 335 | void 336 | SceneResourceSet::SetLatestMeshRendererComponent(SceneMeshRendererComponent& meshRendererComponent) 337 | { 338 | m_latestMeshRendererComponent = meshRendererComponent; 339 | } 340 | 341 | void 342 | SceneResourceSet::UnimplementedFeatureFound() 343 | { 344 | if (s_assertOnUnimplementedFeature) 345 | { 346 | assert(false); 347 | } 348 | } 349 | 350 | } // namespace SceneLoader -------------------------------------------------------------------------------- /Experimental/CameraComponent/OrbitalCamera.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Numerics; 7 | using Windows.UI.Composition; 8 | 9 | namespace CameraComponent 10 | { 11 | /// 12 | /// A class that defines an OrbitalCamera that orbits around a point in world space. 13 | /// Implements the Camera and Animatable interfaces. 14 | /// 15 | public sealed class OrbitalCamera : Camera 16 | { 17 | private Compositor _compositor; 18 | private FirstPersonCamera _fpCam; 19 | private CompositionPropertySet _propertySet; 20 | 21 | /// 22 | /// Creates an OrbitalCamera with default properties. 23 | /// Target = Vector3.Zero 24 | /// Phi = 0 25 | /// Theta = 0 26 | /// Radius = 300 27 | /// ModelViewProjectionMatrix = Matrix4x4.Identity 28 | /// 29 | /// 30 | /// Thrown when constructor is passed a null value. 31 | public OrbitalCamera(Compositor compositor) 32 | { 33 | if (compositor == null) 34 | { 35 | throw new System.ArgumentException("Compositor cannot be null"); 36 | } 37 | 38 | _compositor = compositor; 39 | _fpCam = new FirstPersonCamera(_compositor); 40 | _propertySet = _compositor.CreatePropertySet(); 41 | 42 | float epsilon = 0.0001f; 43 | 44 | // Create the properties for the camera 45 | _propertySet.InsertVector3("Target", Vector3.Zero); 46 | _propertySet.InsertScalar("Phi", epsilon); 47 | _propertySet.InsertScalar("Theta", 0f); 48 | _propertySet.InsertScalar("Radius", 300f); 49 | _propertySet.InsertMatrix4x4("ModelViewProjectionMatrix", Matrix4x4.Identity); 50 | 51 | // Connect orbital camera's properties to the _fpCam's properties 52 | StartAnimationsOnFPCamera(); 53 | } 54 | 55 | /// 56 | /// Point in 3D world space that the camera orbits about and centers it's view on. 57 | /// 58 | public Vector3 Target 59 | { 60 | get 61 | { 62 | Vector3 curr; 63 | _propertySet.TryGetVector3("Target", out curr); 64 | return curr; 65 | } 66 | set 67 | { 68 | _propertySet.InsertVector3("Target", value); 69 | } 70 | } 71 | 72 | /// 73 | /// Distance between the camera and its Target. 74 | /// 75 | public float Radius 76 | { 77 | get 78 | { 79 | float curr; 80 | _propertySet.TryGetScalar("Radius", out curr); 81 | return MathF.Max(200, curr); 82 | } 83 | set 84 | { 85 | _propertySet.InsertScalar("Radius", value); 86 | } 87 | } 88 | 89 | /// 90 | /// The camera's angle of separation from the positive y-axis in radians. 91 | /// From 0 to Pi. 92 | /// 93 | /// 94 | /// When Phi = 0 we are looking down on the "north pole" of the object we are orbiting 95 | /// When Phi = Pi / 2 we are looking at the equator of the object 96 | /// When Phi = Pi we are looking at the "south pole" of the object 97 | /// This mimics spherical coordinates a common spherical coordinate system with (radius, theta, phi) 98 | /// 99 | public float Phi 100 | { 101 | get 102 | { 103 | float epsilon = 0.0001f; 104 | float curr; 105 | 106 | _propertySet.TryGetScalar("Phi", out curr); 107 | return MathF.Min(MathF.PI - epsilon, MathF.Max(epsilon, curr)); 108 | } 109 | set 110 | { 111 | float epsilon = 0.0001f; 112 | _propertySet.InsertScalar("Phi", MathF.Min(MathF.PI - epsilon, MathF.Max(epsilon, value))); 113 | } 114 | } 115 | 116 | /// 117 | /// The camera's angle of separation from the positive y-axis in degrees 118 | /// From 0 to 180 119 | /// 120 | /// 121 | /// When PhiInDegrees = 0 we are looking down on the "north pole" of the object we are orbiting 122 | /// When PhiInDegrees = 90 we are looking at the equator of the object 123 | /// When PhiInDegrees = 180 we are looking at the "south pole" of the object 124 | /// This mimics spherical coordinates a common spherical coordinate system with (radius, theta, phi) 125 | /// 126 | public float PhiInDegrees { get => ConvertRadiansToDegrees(Phi); set => Phi = ConvertDegreesToRadians(value); } 127 | 128 | /// 129 | /// The angle of separation from the positive z-axis in radians. 130 | /// Rotates counterclockwise from 0 to 2Pi. 131 | /// 132 | /// 133 | /// When Theta = 0 we are looking at the front of the object we are orbiting 134 | /// When Theta = Pi we are looking at the back of the object 135 | /// When Theta = Pi/2 or 3*Pi/2 we are looking at either the object's left or right side 136 | /// 137 | public float Theta 138 | { 139 | get 140 | { 141 | float curr; 142 | _propertySet.TryGetScalar("Theta", out curr); 143 | return curr; 144 | } 145 | set 146 | { 147 | _propertySet.InsertScalar("Theta", value); 148 | } 149 | } 150 | 151 | /// 152 | /// The angle of separation from the positive z-axis in degrees. 153 | /// Rotates counterclockwise from 0 to 360. 154 | /// 155 | /// 156 | /// When ThetaInDegrees = 0 we are looking at the front of the object we are orbiting 157 | /// When ThetaInDegrees = 180 we are looking at the back of the object 158 | /// When ThetaInDegrees = 90 or 270 we are looking at either the object's left or right side 159 | /// 160 | public float ThetaInDegrees { get => ConvertRadiansToDegrees(Theta); set => Theta = ConvertDegreesToRadians(value); } 161 | 162 | // Helper function that converts radians to degrees 163 | private float ConvertRadiansToDegrees(float rads) 164 | { 165 | return (180 / MathF.PI) * rads; 166 | } 167 | 168 | // Helper function that converts radians to degrees 169 | private float ConvertDegreesToRadians(float degs) 170 | { 171 | return (MathF.PI / 180) * degs; 172 | } 173 | 174 | /// 175 | /// The camera's reference to an object that implements the Projection interace. 176 | /// When setting, this property starts animations on the camera's ModelViewProjectionMatrix property. 177 | /// 178 | /// When set to null, the ModelViewProjectionProperty is animated using an OrthographicProjection with the 179 | /// default values of: Height = 100, Width = 100, Near = 1, Far = 1000. 180 | public Projection Projection { get => _fpCam.Projection; set => _fpCam.Projection = value; } 181 | 182 | /// 183 | /// Returns the camera's position in 3D world space. 184 | /// 185 | /// A Vector3 that represents the camera's extrinsic position in 3D world space. 186 | public Vector3 GetAbsolutePosition() 187 | { 188 | float x = MathF.Sin(Phi) * MathF.Sin(Theta); 189 | float y = -MathF.Cos(Phi); 190 | float z = MathF.Sin(Phi) * MathF.Cos(Theta); 191 | 192 | return Target + (Radius * new Vector3(x, y, z)); 193 | } 194 | 195 | /// 196 | /// Returns the camera's position in 3D world space. 197 | /// 198 | /// 199 | public void SetAbsolutePosition(Vector3 value) 200 | { 201 | Radius = Vector3.Distance(Target, value); 202 | Theta = MathF.Atan2(value.X, value.Z); 203 | Phi = MathF.Atan2(value.Z, value.Y); 204 | } 205 | 206 | /// 207 | /// Returns the matrix created from the camera's translation and rotation transformations. 208 | /// 209 | /// A Matrix4x4 that is created from the camera's target, radius, phi, and theta. 210 | public Matrix4x4 GetViewMatrix() 211 | { 212 | Vector3 position = GetAbsolutePosition(); 213 | 214 | // use OrbitalCamera's properties to calculate rotaation in terms of yaw, pitch, and roll 215 | Matrix4x4 matPos = Matrix4x4.CreateTranslation(-position); 216 | Matrix4x4 matRoll = Matrix4x4.CreateFromAxisAngle(new Vector3(0, 0, 1), 0); 217 | Matrix4x4 matPitch = Matrix4x4.CreateFromAxisAngle(new Vector3(1, 0, 0), -MathF.Asin(Vector3.Normalize(Target - position).Y)); 218 | Matrix4x4 matYaw = Matrix4x4.CreateFromAxisAngle(new Vector3(0, 1, 0), -Theta); 219 | 220 | return matPos * matYaw * matPitch * matRoll; 221 | } 222 | 223 | /// 224 | /// Returns that a matrix created from the camera's view matrix and it's Projection's projection matrix. 225 | /// 226 | /// A Matrix4x4 that is the product of matrices created from the Camera's target, radius, phi, and theta and its Projection's projection matrix. 227 | public Matrix4x4 GetModelViewProjectionMatrix() 228 | { 229 | return GetViewMatrix() * Projection.GetProjectionMatrix(); 230 | } 231 | 232 | // Creates expression animations to drive an FPCamera's position and rotation through the OrbitalCamera's phi, theta, and radius 233 | private void StartAnimationsOnFPCamera() 234 | { 235 | CompositionPropertySet fpCamera = _fpCam.GetPropertySet(); 236 | 237 | // Drives FPCamera's position based on the following formula 238 | // FPCamera.Position = Radius*( Sin(Phi)*Sin(Theta), -Cos(Phi), Sin(Phi)*Cos(Theta) ) 239 | // Sums with Target in the case where Target is not the origin 240 | var positionExpression = _compositor.CreateExpressionAnimation(); 241 | positionExpression.Expression = 242 | "OrbitalCamera.Target + OrbitalCamera.Radius * " + 243 | "Vector3(" + 244 | "Sin(Clamp(OrbitalCamera.Phi, epsilon, Pi - epsilon)) * Sin(OrbitalCamera.Theta), " + 245 | "-Cos(Clamp(OrbitalCamera.Phi, epsilon, Pi - epsilon)), " + 246 | "Sin(Clamp(OrbitalCamera.Phi, epsilon, Pi - epsilon)) * Cos(OrbitalCamera.Theta))"; 247 | positionExpression.SetExpressionReferenceParameter("OrbitalCamera", _propertySet); 248 | positionExpression.SetScalarParameter("epsilon", 0.0001f); 249 | fpCamera.StartAnimation("Position", positionExpression); 250 | 251 | // Drives FPCamera's yaw by equating it with Theta 252 | var yawExpression = _compositor.CreateExpressionAnimation(); 253 | yawExpression.Expression = "OrbitalCamera.Theta"; 254 | yawExpression.SetExpressionReferenceParameter("OrbitalCamera", _propertySet); 255 | fpCamera.StartAnimation("Yaw", yawExpression); 256 | 257 | // Drives FPCamera's yaw using the vector eminating from the camera's position to its target 258 | var pitchExpression = _compositor.CreateExpressionAnimation(); 259 | pitchExpression.Expression = "Asin(Normalize(OrbitalCamera.Target - FPCamera.Position).Y)"; 260 | pitchExpression.SetExpressionReferenceParameter("OrbitalCamera", _propertySet); 261 | pitchExpression.SetExpressionReferenceParameter("FPCamera", fpCamera); 262 | fpCamera.StartAnimation("Pitch", pitchExpression); 263 | 264 | // Links OrbitalCamera's ModelViewProjectionMatrix to the ModelViewProjectionMatrix that's computed in FPCamera 265 | var modelViewProjExpression = _compositor.CreateExpressionAnimation(); 266 | modelViewProjExpression.Expression = "FPCamera.ModelViewProjectionMatrix"; 267 | modelViewProjExpression.SetReferenceParameter("FPCamera", fpCamera); 268 | _propertySet.StartAnimation("ModelViewProjectionMatrix", modelViewProjExpression); 269 | } 270 | 271 | /// 272 | /// Returns the camera's set of animatable properties. 273 | /// 274 | /// A CompositionPropertySet holding the camera's properties. 275 | public CompositionPropertySet GetPropertySet() 276 | { 277 | return _propertySet; 278 | } 279 | 280 | /// 281 | /// Starts a given animation on the specified property. 282 | /// 283 | /// The name of the property to be animated. 284 | /// The animation being applied. 285 | public void StartAnimation(string propertyName, CompositionAnimation animation) 286 | { 287 | _propertySet.StartAnimation(propertyName, animation); 288 | } 289 | 290 | /// 291 | /// Stops any animations on the specified property. 292 | /// 293 | /// The name of the property whose animations we are stopping. 294 | public void StopAnimation(string propertyName) 295 | { 296 | _propertySet.StopAnimation(propertyName); 297 | } 298 | } 299 | } -------------------------------------------------------------------------------- /Experimental/CameraComponent/Viewport.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Numerics; 6 | using Windows.UI.Composition; 7 | 8 | namespace CameraComponent 9 | { 10 | /// 11 | /// Determines how the image is stretched to the viewport. 12 | /// 13 | /// 14 | /// Fill: Stretch the image to the size of the viewport so the same amount of the image is always shown. 15 | /// FixX: Stretch the image to the width of the screen so the same amount of horizontal space in the scene is always shown. 16 | /// FixY: Stretch the image to the height of the screen so the same amount of vertical space in the scene is always shown. 17 | /// Uniform: If the screen is wide stretch to the height of the screen, if the screen is tall stretch to the width of the screen. 18 | /// UniformToFill: If the screen is tall stretch to the height of the screen, if the screen is wide stretch to the width of the screen. 19 | /// 20 | public enum Stretch { Fill, FixX, FixY, Uniform, UniformToFill}; 21 | 22 | /// 23 | /// Manages how a the content that is in view of a 3D camera is placed and stretched on the screen. 24 | /// Implements the Animatable interface. 25 | /// 26 | public sealed class Viewport : Animatable 27 | { 28 | private Visual _visual; 29 | private Compositor _compositor; 30 | private Camera _camera; 31 | private CompositionPropertySet _propertySet; 32 | 33 | /// 34 | /// Creates a Viewport with default properties. 35 | /// Offset = Vector3.Zero 36 | /// Size = Vector2(100, 100) 37 | /// Stretch = Uniform 38 | /// StretchMatrix = Matrix4x4.Identity 39 | /// 40 | /// 41 | /// Thrown when constructor is passed a null value. 42 | public Viewport(Compositor compositor) 43 | { 44 | if(compositor == null) 45 | { 46 | throw new System.ArgumentException("Compositor cannot be null"); 47 | } 48 | 49 | _compositor = compositor; 50 | _propertySet = _compositor.CreatePropertySet(); 51 | 52 | // Create properties of viewport 53 | _propertySet.InsertVector3("Offset", Vector3.Zero); 54 | _propertySet.InsertVector2("Size", new Vector2(100, 100)); 55 | _propertySet.InsertScalar("Stretch", (int)Stretch.Uniform); 56 | _propertySet.InsertMatrix4x4("StretchMatrix", Matrix4x4.Identity); 57 | 58 | Camera = new OrbitalCamera(_compositor); 59 | 60 | StartAnimationsOnStretchMatrix(); 61 | } 62 | 63 | /// 64 | /// The Visual whose TransformMatrix we are using to apply our Viewport's, Camera's, and Projection's transformations. 65 | /// Starts and stops animations on the Visual's TransformMatrix based on the value it is set to and the value of the camera. 66 | /// 67 | public Visual Visual 68 | { 69 | get => _visual; 70 | set 71 | { 72 | // if camera is null then we cannot start animations so we just assign _visual to value 73 | if(_camera == null) 74 | { 75 | _visual = value; 76 | } 77 | // if _camera is not null... 78 | else 79 | { 80 | if(_visual == null) 81 | { 82 | // if _visual is null and we are assigning it to a non-null value then we start the animations 83 | if(value != null) 84 | { 85 | _visual = value; 86 | StartAnimationsOnTransformMatrix(); 87 | } 88 | } 89 | else 90 | { 91 | // if _visual is not null then we have to stop animating its Transform Matrix regardless of what it is being assigned to 92 | _visual.StopAnimation("TransformMatrix"); 93 | _visual = value; 94 | 95 | // if we are swapping out _visual then we restart animations on the _visual's Transform Matrix 96 | if(value != null) 97 | { 98 | StartAnimationsOnTransformMatrix(); 99 | } 100 | } 101 | } 102 | } 103 | } 104 | 105 | /// 106 | /// The size of the viewport in the form Vector2(width, height). 107 | /// 108 | public Vector2 Size 109 | { 110 | get 111 | { 112 | Vector2 curr; 113 | _propertySet.TryGetVector2("Size", out curr); 114 | return curr; 115 | } 116 | set 117 | { 118 | _propertySet.InsertVector2("Size", value); 119 | } 120 | } 121 | 122 | /// 123 | /// The coordinate of the top left corner of the viewport. 124 | /// 125 | public Vector3 Offset 126 | { 127 | get 128 | { 129 | Vector3 curr; 130 | _propertySet.TryGetVector3("Offset", out curr); 131 | return curr; 132 | } 133 | set 134 | { 135 | _propertySet.InsertVector3("Offset", value); 136 | } 137 | } 138 | 139 | /// 140 | /// The viewport's stretch enum that governs how the image is stretched to the viewport. 141 | /// 142 | public Stretch Stretch 143 | { 144 | get 145 | { 146 | float curr; 147 | _propertySet.TryGetScalar("Stretch", out curr); 148 | return (Stretch)curr; 149 | } 150 | set 151 | { 152 | _propertySet.InsertScalar("Stretch", (int)value); 153 | } 154 | } 155 | 156 | /// 157 | /// The viewport's reference to an object implementing the Camera interface. 158 | /// When setting, this property starts or stops animations when the Visual is not null and based on the value it is being set to. 159 | /// 160 | public Camera Camera 161 | { 162 | get => _camera; 163 | set 164 | { 165 | _camera = value; 166 | 167 | if(_visual != null) 168 | { 169 | // if null, nothing should be displayed 170 | if (_camera == null) 171 | { 172 | _visual.StopAnimation("TransfromMatrix"); 173 | } 174 | else 175 | { 176 | StartAnimationsOnTransformMatrix(); 177 | } 178 | } 179 | } 180 | } 181 | 182 | /// 183 | /// Co-opts the given Visual's TransformMatrix to be used to apply the viewport's, camera's, and projection's transformations to. 184 | /// 185 | /// The Visual whose TransformMatrix we are co-opting. 186 | public void AttachToVisual(Visual visual) 187 | { 188 | Visual = visual; 189 | } 190 | 191 | /// 192 | /// Returns the matrix being used to apply a stretch transformation to the image. 193 | /// 194 | /// A Matrix4x4 that is generated based on the value of the viewport's Stretch property. 195 | public Matrix4x4 GetStretchMatrix() 196 | { 197 | Matrix4x4 matStretch = Matrix4x4.Identity; 198 | 199 | if(Stretch == Stretch.Fill) 200 | { 201 | matStretch.M11 = Size.X; 202 | matStretch.M22 = Size.Y; 203 | matStretch.M33 = (Size.X + Size.Y) / 2f; 204 | } 205 | else if(Stretch == Stretch.FixX) 206 | { 207 | matStretch.M11 = Size.X; 208 | matStretch.M22 = Size.X; 209 | matStretch.M33 = Size.X; 210 | } 211 | else if(Stretch == Stretch.FixY) 212 | { 213 | matStretch.M11 = Size.Y; 214 | matStretch.M22 = Size.Y; 215 | matStretch.M33 = Size.Y; 216 | } 217 | else if(Stretch == Stretch.Uniform) 218 | { 219 | if(Size.X >= Size.Y) 220 | { 221 | matStretch.M11 = Size.Y; 222 | matStretch.M22 = Size.Y; 223 | matStretch.M33 = Size.Y; 224 | } 225 | else 226 | { 227 | matStretch.M11 = Size.X; 228 | matStretch.M22 = Size.X; 229 | matStretch.M33 = Size.X; 230 | } 231 | } 232 | else if(Stretch == Stretch.UniformToFill) 233 | { 234 | if (Size.X < Size.Y) 235 | { 236 | matStretch.M11 = Size.Y; 237 | matStretch.M22 = Size.Y; 238 | matStretch.M33 = Size.Y; 239 | } 240 | else 241 | { 242 | matStretch.M11 = Size.X; 243 | matStretch.M22 = Size.X; 244 | matStretch.M33 = Size.X; 245 | } 246 | } 247 | 248 | return matStretch; 249 | } 250 | 251 | /// 252 | /// Returns the matrix that is being applied to the viewport's Visual's TransformMatrix property. 253 | /// 254 | /// The product of the viewport's camera's model view projection matrix, the viewport's stretch matrix, 255 | /// and the matrix that transforms the content to the center of the viewport. 256 | public Matrix4x4 GetTransformMatrix() 257 | { 258 | if(_visual == null) 259 | { 260 | return Matrix4x4.Identity; 261 | } 262 | 263 | return Camera.GetModelViewProjectionMatrix() * GetStretchMatrix() * Matrix4x4.CreateTranslation(new Vector3(Offset.X + Size.X / 2f, Offset.Y + Size.Y / 2f, Offset.Z)); 264 | } 265 | 266 | // Starts animations on _visual's TransformMatrix property 267 | private void StartAnimationsOnTransformMatrix() 268 | { 269 | // Creates an expression that is represents the product of all our transformations 270 | var cameraMatExpression = _compositor.CreateExpressionAnimation(); 271 | cameraMatExpression.Expression = "Camera.ModelViewProjectionMatrix * Viewport.StretchMatrix " + 272 | "* Matrix4x4.CreateTranslation(Vector3(Viewport.Offset.X + Viewport.Size.X / 2f, Viewport.Offset.Y + Viewport.Size.Y / 2f, Viewport.Offset.Z))"; 273 | cameraMatExpression.SetReferenceParameter("Camera", Camera.GetPropertySet()); 274 | cameraMatExpression.SetReferenceParameter("Viewport", _propertySet); 275 | 276 | // Links our product of matrices expression to _visual's TransformMatrix 277 | _visual.StartAnimation("TransformMatrix", cameraMatExpression); 278 | } 279 | 280 | // Starts an expression animation on StretchMatrix property based on the Stretch 281 | private void StartAnimationsOnStretchMatrix() 282 | { 283 | // Expression that creates a matrix based on the value of the viewport's stretch property 284 | string stretchMat = 285 | // if (Stretch == Fill) 286 | "(Viewport.Stretch == 0f)?" + 287 | "Matrix4x4(" + 288 | "Viewport.Size.X, 0, 0, 0, " + 289 | "0, Viewport.Size.Y, 0, 0, " + 290 | "0, 0, (Viewport.Size.X + Viewport.Size.Y) / 2f, 0, " + 291 | "0, 0, 0, 1) " + 292 | ":" + 293 | // else if (Stretch == FixX) 294 | "(Viewport.Stretch == 1f)? " + 295 | "Matrix4x4(" + 296 | "Viewport.Size.X, 0, 0, 0, " + 297 | "0, Viewport.Size.X, 0, 0, " + 298 | "0, 0, Viewport.Size.X, 0, " + 299 | "0, 0, 0, 1)" + 300 | ":" + 301 | // else if (Stretch == FixY) 302 | "(Viewport.Stretch == 2f)? " + 303 | "Matrix4x4(" + 304 | "Viewport.Size.Y, 0, 0, 0, " + 305 | "0, Viewport.Size.Y, 0, 0, " + 306 | "0, 0, Viewport.Size.Y, 0, " + 307 | "0, 0, 0, 1)" + 308 | ":" + 309 | // else if (Stretch == Uniform) 310 | "(Viewport.Stretch == 3f)? " + 311 | // if (Size.X >= Size.Y) 312 | "(Viewport.Size.X >= Viewport.Size.Y)? " + 313 | "Matrix4x4(" + 314 | "Viewport.Size.Y, 0, 0, 0, " + 315 | "0, Viewport.Size.Y, 0, 0, " + 316 | "0, 0, Viewport.Size.Y, 0, " + 317 | "0, 0, 0, 1) " + 318 | ":" + 319 | // else 320 | "Matrix4x4(" + 321 | "Viewport.Size.X, 0, 0, 0, " + 322 | "0, Viewport.Size.X, 0, 0, " + 323 | "0, 0, Viewport.Size.X, 0, " + 324 | "0, 0, 0, 1)" + 325 | ":" + 326 | // else if (Stretch == UniformToFill) 327 | // if (Size.X < Size.Y) 328 | "(Viewport.Size.X < Viewport.Size.Y)? " + 329 | "Matrix4x4(" + 330 | "Viewport.Size.Y, 0, 0, 0, " + 331 | "0, Viewport.Size.Y, 0, 0, " + 332 | "0, 0, Viewport.Size.Y, 0, " + 333 | "0, 0, 0, 1) " + 334 | ":" + 335 | // else 336 | "Matrix4x4(" + 337 | "Viewport.Size.X, 0, 0, 0, " + 338 | "0, Viewport.Size.X, 0, 0, " + 339 | "0, 0, Viewport.Size.X, 0, " + 340 | "0, 0, 0, 1)"; 341 | 342 | var stretchExpression = _compositor.CreateExpressionAnimation(); 343 | stretchExpression.Expression = stretchMat; 344 | stretchExpression.SetReferenceParameter("Viewport", _propertySet); 345 | 346 | _propertySet.StartAnimation("StretchMatrix", stretchExpression); 347 | } 348 | 349 | /// 350 | /// Starts a given animation on the specified property. 351 | /// 352 | /// The name of the property to be animated. 353 | /// The animation being applied. 354 | public void StartAnimation(string propertyName, CompositionAnimation animation) 355 | { 356 | _propertySet.StartAnimation(propertyName, animation); 357 | } 358 | 359 | /// 360 | /// Stops any animations on the specified property. 361 | /// 362 | /// The name of the property whose animations we are stopping. 363 | public void StopAnimation(string propertyName) 364 | { 365 | _propertySet.StopAnimation(propertyName); 366 | } 367 | 368 | /// 369 | /// Returns the viewport's set of animatable properties. 370 | /// 371 | /// A CompositionPropertySet holding the viewport's properties. 372 | public CompositionPropertySet GetPropertySet() 373 | { 374 | return _propertySet; 375 | } 376 | } 377 | } 378 | -------------------------------------------------------------------------------- /SceneLoader/SceneLoader.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | ARM 8 | 9 | 10 | Debug 11 | ARM64 12 | 13 | 14 | Debug 15 | Win32 16 | 17 | 18 | Debug 19 | x64 20 | 21 | 22 | Release 23 | ARM 24 | 25 | 26 | Release 27 | ARM64 28 | 29 | 30 | Release 31 | Win32 32 | 33 | 34 | Release 35 | x64 36 | 37 | 38 | 39 | true 40 | true 41 | {88c4d662-8669-433b-8a8b-47b3a17e3c6e} 42 | SceneLoaderComponent 43 | SceneLoaderComponent 44 | en-US 45 | 14.0 46 | true 47 | Windows Store 48 | 10.0 49 | 10.0.18362.0 50 | 10.0.17763.0 51 | 52 | 53 | 54 | DynamicLibrary 55 | true 56 | 57 | 58 | DynamicLibrary 59 | true 60 | 61 | 62 | DynamicLibrary 63 | true 64 | 65 | 66 | DynamicLibrary 67 | true 68 | 69 | 70 | DynamicLibrary 71 | false 72 | true 73 | 74 | 75 | DynamicLibrary 76 | false 77 | true 78 | 79 | 80 | DynamicLibrary 81 | false 82 | true 83 | 84 | 85 | DynamicLibrary 86 | false 87 | true 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | false 122 | 123 | 124 | false 125 | false 126 | 127 | 128 | false 129 | 130 | 131 | false 132 | false 133 | 134 | 135 | false 136 | 137 | 138 | false 139 | 140 | 141 | false 142 | 143 | 144 | false 145 | false 146 | 147 | 148 | 149 | Use 150 | _WINRT_DLL;%(PreprocessorDefinitions) 151 | pch.h 152 | $(IntDir)pch.pch 153 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 154 | /bigobj %(AdditionalOptions) 155 | 28204 156 | 157 | 158 | Console 159 | 160 | 161 | SceneLoaderComponent.def 162 | 163 | 164 | 165 | 166 | Use 167 | _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 168 | pch.h 169 | $(IntDir)pch.pch 170 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 171 | /bigobj %(AdditionalOptions) 172 | 28204 173 | true 174 | 175 | 176 | Console 177 | false 178 | SceneLoaderComponent.def 179 | 180 | 181 | 182 | 183 | Use 184 | _WINRT_DLL;%(PreprocessorDefinitions) 185 | pch.h 186 | $(IntDir)pch.pch 187 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 188 | /bigobj %(AdditionalOptions) 189 | 28204 190 | true 191 | 192 | 193 | Console 194 | 195 | 196 | SceneLoaderComponent.def 197 | 198 | 199 | 200 | 201 | Use 202 | _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 203 | pch.h 204 | $(IntDir)pch.pch 205 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 206 | /bigobj %(AdditionalOptions) 207 | 28204 208 | true 209 | 210 | 211 | Console 212 | false 213 | SceneLoaderComponent.def 214 | 215 | 216 | 217 | 218 | Use 219 | _WINRT_DLL;%(PreprocessorDefinitions) 220 | pch.h 221 | $(IntDir)pch.pch 222 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 223 | /bigobj %(AdditionalOptions) 224 | 28204 225 | 226 | 227 | Console 228 | 229 | 230 | SceneLoaderComponent.def 231 | 232 | 233 | 234 | 235 | Use 236 | _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 237 | pch.h 238 | $(IntDir)pch.pch 239 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 240 | /bigobj %(AdditionalOptions) 241 | 28204 242 | true 243 | 244 | 245 | Console 246 | false 247 | SceneLoaderComponent.def 248 | 249 | 250 | 251 | 252 | Use 253 | _WINRT_DLL;%(PreprocessorDefinitions) 254 | pch.h 255 | $(IntDir)pch.pch 256 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 257 | /bigobj %(AdditionalOptions) 258 | 28204 259 | 260 | 261 | Console 262 | 263 | 264 | SceneLoaderComponent.def 265 | 266 | 267 | 268 | 269 | Use 270 | _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 271 | pch.h 272 | $(IntDir)pch.pch 273 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 274 | /bigobj %(AdditionalOptions) 275 | 28204 276 | true 277 | 278 | 279 | Console 280 | false 281 | SceneLoaderComponent.def 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | Create 309 | Create 310 | Create 311 | Create 312 | Create 313 | Create 314 | Create 315 | Create 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 339 | 340 | 341 | 342 | 343 | 344 | 345 | --------------------------------------------------------------------------------