Pārlūkot izejas kodu

Improving scene API
Improving compatibility with some edge cases.

Vicente Penades 5 gadi atpakaļ
vecāks
revīzija
95395544c5

+ 5 - 0
src/Demo1/Game1.cs

@@ -17,6 +17,10 @@ namespace Demo1
 
         protected override void Initialize()
         {
+            this.Window.Title = "SharpGLTF - MonoGame Demo 1";
+            this.Window.AllowUserResizing = true;
+            this.Window.AllowAltF4 = true;
+
             base.Initialize();
         }
 
@@ -69,6 +73,7 @@ namespace Demo1
             var mdlX = Matrix.CreateRotationY(0.25f * (float)gameTime.TotalGameTime.TotalSeconds) * Matrix.CreateTranslation(mdlPos);
 
             var dc = new ModelDrawingContext(_Graphics.GraphicsDevice);
+            dc.NearPlane = 0.1f; // we need to make near plane small because the object is very very close.
             dc.SetCamera(camX);
             dc.DrawMesh(_LightsAndFog, _MeshCollection[0], mdlX);
 

+ 4 - 0
src/Demo2/Game1.cs

@@ -15,6 +15,10 @@ namespace Demo2
 
         protected override void Initialize()
         {
+            this.Window.Title = "SharpGLTF - MonoGame Demo 2";
+            this.Window.AllowUserResizing = true;
+            this.Window.AllowAltF4 = true;
+
             base.Initialize();
         }
 

+ 1 - 1
src/Demo3/Game1.cs

@@ -25,7 +25,7 @@ namespace Demo3
         {
             // TODO: Add your initialization logic here
 
-            this.Window.Title = "SharpGLTF - MonoGame Scene";
+            this.Window.Title = "SharpGLTF - MonoGame Demo 3";
             this.Window.AllowUserResizing = true;
             this.Window.AllowAltF4 = true;
 

+ 1 - 1
src/MonoGame.Framework.Graphics.GLTF/MonoGame.Framework.Pipeline.GLTF.csproj

@@ -12,7 +12,7 @@
 
   <ItemGroup>
     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1375-develop" PrivateAssets="all" />
-    <PackageReference Include="SharpGLTF.Core" Version="1.0.0-Preview-20200921-1654" />    
+    <PackageReference Include="SharpGLTF.Core" Version="1.0.0-Preview-20201001-0943" />    
   </ItemGroup>
 
 </Project>

+ 4 - 14
src/MonoGame.Framework.Graphics.PBR/Effects/AnimatedEffect.cs

@@ -27,10 +27,7 @@ namespace Microsoft.Xna.Framework.Graphics
         private Matrix _World = Matrix.Identity;
         private Matrix _View = Matrix.Identity;
         private Matrix _Proj = Matrix.Identity;
-
         
-        private bool _WorldIsMirror = false;
-
         private int _BoneCount;
         private readonly Matrix[] _Bones = new Matrix[128];
 
@@ -52,28 +49,21 @@ namespace Microsoft.Xna.Framework.Graphics
         public Matrix World
         {
             get => _World;
-            set
-            {
-                _World = value;
-                _WorldIsMirror = _World.Determinant() < 0;
-            }
+            set => _World = value;
         }
         
         public Matrix View
         {
             get => _View;
-            set { _View = value; }
+            set => _View = value;
         }
 
         public Matrix Projection
         {
             get => _Proj;
-            set { _Proj = value; }
+            set => _Proj = value;
         }
-
-        // True if world matrix is a mirror matrix and requires the RasterizerState to reverse face culling.
-        public bool WorldIsMirror => _WorldIsMirror;
-
+        
         #endregion        
 
         #region API

+ 41 - 62
src/MonoGame.Framework.Graphics.Scene3D/ModelDrawingContext.cs

@@ -7,7 +7,7 @@ namespace Microsoft.Xna.Framework.Graphics
     /// <summary>
     /// Helper class for rendering <see cref="ModelLayerInstance"/> models.
     /// </summary>
-    public struct ModelDrawingContext
+    public class ModelDrawingContext
     {
         #region lifecycle
 
@@ -17,31 +17,51 @@ namespace Microsoft.Xna.Framework.Graphics
 
             _Device.DepthStencilState = DepthStencilState.Default;            
 
-            float fieldOfView = MathHelper.PiOver4;
-            float nearClipPlane = 1f;
-                    
-            _Projection = CreatePerspectiveFieldOfView(fieldOfView, graphics.Viewport.AspectRatio, nearClipPlane, float.PositiveInfinity);
-
             _View = Matrix.Invert(Matrix.Identity);
             _DistanceComparer = ModelLayerInstance.GetDistanceComparer(-_View.Translation);
         }
-
+        
         #endregion
 
         #region data
 
         private GraphicsDevice _Device;
-        private Matrix _Projection;
+
+        private float _FieldOfView = MathHelper.PiOver4;
+        private float _NearPlane = 1f;
+        
         private Matrix _View;
         private IComparer<ModelLayerInstance> _DistanceComparer;
 
         private static readonly HashSet<Effect> _SceneEffects = new HashSet<Effect>();
         private static readonly List<ModelLayerInstance> _SceneInstances = new List<ModelLayerInstance>();
 
+        #endregion
+
+        #region properties
+
+        public float FieldOfView
+        {
+            get => _FieldOfView;
+            set => _FieldOfView = value;
+        }
+
+        public float NearPlane
+        {
+            get => _NearPlane;
+            set => _NearPlane = value;
+        }
+
+
         #endregion
 
         #region API
 
+        public Matrix GetProjectionMatrix()
+        {
+            return SceneUtils.CreatePerspectiveFieldOfView(_FieldOfView, _Device.Viewport.AspectRatio, _NearPlane);
+        }
+
         public void SetCamera(Matrix cameraMatrix)
         {
             _View = Matrix.Invert(cameraMatrix);
@@ -49,16 +69,15 @@ namespace Microsoft.Xna.Framework.Graphics
             _DistanceComparer = ModelLayerInstance.GetDistanceComparer(-_View.Translation);
         }
 
-        public void SetProjection(Matrix projectionMatrix)
-        {
-            _Projection = projectionMatrix;
-        }
+        
 
         public void DrawMesh(PBREnvironment environment, RuntimeModelMesh mesh, Matrix worldMatrix)
         {
+            var proj = GetProjectionMatrix();
+
             foreach (var e in mesh.OpaqueEffects)
             {               
-                ModelLayerInstance.UpdateProjViewTransforms(e, _Projection, _View);
+                ModelLayerInstance.UpdateProjViewTransforms(e, proj, _View);
                 ModelLayerInstance.UpdateWorldTransforms(e, worldMatrix);
                 environment.ApplyTo(e);
             }
@@ -67,7 +86,7 @@ namespace Microsoft.Xna.Framework.Graphics
 
             foreach (var e in mesh.TranslucidEffects)
             {                
-                ModelLayerInstance.UpdateProjViewTransforms(e, _Projection, _View);
+                ModelLayerInstance.UpdateProjViewTransforms(e, proj, _View);
                 ModelLayerInstance.UpdateWorldTransforms(e, worldMatrix);
                 environment.ApplyTo(e);
             }
@@ -86,13 +105,15 @@ namespace Microsoft.Xna.Framework.Graphics
         /// </remarks>
         public void DrawModelInstance(PBREnvironment environment, ModelLayerInstance modelInstance)
         {
+            var proj = GetProjectionMatrix();
+
             foreach (var e in modelInstance.Template.SharedEffects)
             {
                 environment.ApplyTo(e);
-                ModelLayerInstance.UpdateProjViewTransforms(e, _Projection, _View);
+                ModelLayerInstance.UpdateProjViewTransforms(e, proj, _View);
             }
 
-            modelInstance.DrawAllParts(_Projection, _View);
+            modelInstance.DrawAllParts(proj, _View);
         }
 
         /// <summary>
@@ -113,6 +134,8 @@ namespace Microsoft.Xna.Framework.Graphics
         {
             // todo: fustrum culling goes here
 
+            var proj = GetProjectionMatrix();
+
             _SceneInstances.Clear();
             _SceneInstances.AddRange(modelInstances);
             _SceneInstances.Sort(_DistanceComparer);
@@ -125,7 +148,7 @@ namespace Microsoft.Xna.Framework.Graphics
 
             foreach (var e in _SceneEffects)
             {
-                ModelLayerInstance.UpdateProjViewTransforms(e, _Projection, _View);
+                ModelLayerInstance.UpdateProjViewTransforms(e, proj, _View);
                 // todo: set env.Exposure
                 // todo: set env.AmbientLight
             }
@@ -151,50 +174,6 @@ namespace Microsoft.Xna.Framework.Graphics
             }
         }
 
-        #endregion
-
-        #region helpers
-
-        public static Matrix CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance)
-        {
-            CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, nearPlaneDistance, farPlaneDistance, out Matrix m);
-            return m;
-        }
-
-        // Microsoft recently updated this method in System.Numerics.Vectors to support farPlaneDistance infinity
-        // https://github.com/dotnet/runtime/blob/e64bc548c609455652fcd4107f1f4a2ac3084ff3/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs#L860
-        public static void CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance, out Matrix result)
-        {
-            if (fieldOfView <= 0.0f || fieldOfView >= MathHelper.Pi)
-                throw new ArgumentOutOfRangeException(nameof(fieldOfView));
-
-            if (nearPlaneDistance <= 0.0f)
-                throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
-
-            if (farPlaneDistance <= 0.0f)
-                throw new ArgumentOutOfRangeException(nameof(farPlaneDistance));
-
-            if (nearPlaneDistance >= farPlaneDistance)
-                throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
-
-            float yScale = 1.0f / (float)Math.Tan(fieldOfView * 0.5f);
-            float xScale = yScale / aspectRatio;            
-
-            result.M11 = xScale;
-            result.M12 = result.M13 = result.M14 = 0.0f;
-
-            result.M22 = yScale;
-            result.M21 = result.M23 = result.M24 = 0.0f;
-
-            result.M31 = result.M32 = 0.0f;
-            float negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance);
-            result.M33 = negFarRange;
-            result.M34 = -1.0f;
-
-            result.M41 = result.M42 = result.M44 = 0.0f;
-            result.M43 = nearPlaneDistance * negFarRange;            
-        }
-
-        #endregion
+        #endregion        
     }
 }

+ 53 - 0
src/MonoGame.Framework.Graphics.Scene3D/SceneUtils.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Microsoft.Xna.Framework.Graphics
+{
+    static class SceneUtils
+    {
+        #region helpers
+
+        public static Matrix CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance = float.PositiveInfinity)
+        {
+            CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, nearPlaneDistance, farPlaneDistance, out Matrix m);
+            return m;
+        }
+
+        // Microsoft recently updated this method in System.Numerics.Vectors to support farPlaneDistance infinity
+        // https://github.com/dotnet/runtime/blob/e64bc548c609455652fcd4107f1f4a2ac3084ff3/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs#L860
+        public static void CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance, out Matrix result)
+        {
+            if (fieldOfView <= 0.0f || fieldOfView >= MathHelper.Pi)
+                throw new ArgumentOutOfRangeException(nameof(fieldOfView));
+
+            if (nearPlaneDistance <= 0.0f)
+                throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
+
+            if (farPlaneDistance <= 0.0f)
+                throw new ArgumentOutOfRangeException(nameof(farPlaneDistance));
+
+            if (nearPlaneDistance >= farPlaneDistance)
+                throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
+
+            float yScale = 1.0f / (float)Math.Tan(fieldOfView * 0.5f);
+            float xScale = yScale / aspectRatio;
+
+            result.M11 = xScale;
+            result.M12 = result.M13 = result.M14 = 0.0f;
+
+            result.M22 = yScale;
+            result.M21 = result.M23 = result.M24 = 0.0f;
+
+            result.M31 = result.M32 = 0.0f;
+            float negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance);
+            result.M33 = negFarRange;
+            result.M34 = -1.0f;
+
+            result.M41 = result.M42 = result.M44 = 0.0f;
+            result.M43 = nearPlaneDistance * negFarRange;
+        }
+
+        #endregion
+    }
+}

+ 4 - 4
src/MonoGame.Framework.Graphics.Toolkit3D/Graphics/Meshes/MeshPart.cs

@@ -62,7 +62,9 @@ namespace Microsoft.Xna.Framework.Graphics
 
         public void Draw(GraphicsDevice device)
         {
-            bool isMirrorTransform = _Effect is AnimatedEffect animEffect && animEffect.WorldIsMirror;
+            // check if world matrix is a mirror matrix and requires the face culling to be reversed.
+            bool isMirrorTransform = false;
+            if (_Effect is IEffectMatrices ematrices) isMirrorTransform = ematrices.World.Determinant() < 0;
 
             _Geometry.Bind(device, isMirrorTransform);            
 
@@ -77,7 +79,5 @@ namespace Microsoft.Xna.Framework.Graphics
         }
 
         #endregion
-    }
-
-    
+    }    
 }

+ 29 - 6
src/MonoGame.Framework.Graphics.Toolkit3D/Pipeline/MeshFactory.cs

@@ -25,8 +25,9 @@ namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
 
         #region data
 
-        private readonly GraphicsDevice _Device;        
+        private readonly GraphicsDevice _Device;
 
+        private MeshPrimitiveMaterial _DefaultMaterial;
         private readonly Dictionary<TMaterial, MeshPrimitiveMaterial> _Materials = new Dictionary<TMaterial, MeshPrimitiveMaterial>();
 
         /// <summary>
@@ -51,6 +52,8 @@ namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
 
         public MeshCollection CreateMeshCollection(IEnumerable<IMeshDecoder<TMaterial>> srcMeshes)
         {
+            if (srcMeshes == null) throw new ArgumentNullException(nameof(srcMeshes));
+            
             _Disposables = new GraphicsResourceTracker();            
 
             int meshIndex = 0;
@@ -63,14 +66,34 @@ namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
             {
                 foreach (var srcPrim in srcMesh.Primitives)
                 {
+                    if (!srcPrim.TriangleIndices.Any()) continue;
+
                     Type vertexType = GetPreferredVertexType(srcPrim);
 
-                    if (!_Materials.TryGetValue(srcPrim.Material, out MeshPrimitiveMaterial material))
+                    MeshPrimitiveMaterial material = null;
+
+                    // we cannot set a Null Key for a dictionary, so we need to handle null (default) materials separately
+                    if (srcPrim.Material == null) 
+                    {
+                        if (_DefaultMaterial != null) material = _DefaultMaterial;
+                        else
+                        {
+                            material = ConvertMaterial(null, srcPrim.JointsWeightsCount > 0);
+                            if (material == null) throw new NullReferenceException("NULL Material conversion failed");
+                            _DefaultMaterial = material;
+                        }
+                    }
+
+                    // for all other defined materials we follow the dictionary path
+                    else
                     {
-                        material = ConvertMaterial(srcPrim.Material, srcPrim.JointsWeightsCount > 0);
-                        if (material == null) throw new NullReferenceException("Material conversion failed");
-                        _Materials[srcPrim.Material] = material;
-                    }                    
+                        if (!_Materials.TryGetValue(srcPrim.Material, out material))
+                        {
+                            material = ConvertMaterial(srcPrim.Material, srcPrim.JointsWeightsCount > 0);
+                            if (material == null) throw new NullReferenceException("Material conversion failed");
+                            _Materials[srcPrim.Material] = material;
+                        }
+                    }
 
                     meshPrimitiveBuilder.AppendMeshPrimitive(meshIndex, vertexType, srcPrim, material.Effect, material.Blend, material.DoubleSided);
                 }

+ 6 - 6
src/MonoGameScene/Game1.cs

@@ -137,22 +137,22 @@ namespace MonoGameScene
             _HauntedHouse.WorldMatrix = Matrix.CreateScale(20) * Matrix.CreateRotationY(1);
 
             _BrainStem.WorldMatrix = Matrix.CreateTranslation(0, 0.5f, 8);
-            _BrainStem.Controller.SetAnimationFrame(0, 0.7f* animTime);
+            _BrainStem.Controller.Armature.SetAnimationFrame(0, 0.7f* animTime);
 
             _CesiumMan1.WorldMatrix = Matrix.CreateTranslation(-3, 0, 5);
-            _CesiumMan1.Controller.SetAnimationFrame(0, 0.3f);
+            _CesiumMan1.Controller.Armature.SetAnimationFrame(0, 0.3f);
 
             _CesiumMan2.WorldMatrix = Matrix.CreateTranslation(-2, 0, 5);
-            _CesiumMan2.Controller.SetAnimationFrame(0, 0.5f * animTime);
+            _CesiumMan2.Controller.Armature.SetAnimationFrame(0, 0.5f * animTime);
 
             _CesiumMan3.WorldMatrix = Matrix.CreateTranslation(2, 0, 5);
-            _CesiumMan3.Controller.SetAnimationFrame(0, 1.0f * animTime);
+            _CesiumMan3.Controller.Armature.SetAnimationFrame(0, 1.0f * animTime);
 
             _CesiumMan4.WorldMatrix = Matrix.CreateTranslation(3, 0, 5);
-            _CesiumMan4.Controller.SetAnimationFrame(0, 1.5f * animTime);
+            _CesiumMan4.Controller.Armature.SetAnimationFrame(0, 1.5f * animTime);
 
             _Shark.WorldMatrix = Matrix.CreateTranslation(5, 3, -6);
-            _Shark.Controller.SetAnimationFrame(0, 1.0f * animTime);
+            _Shark.Controller.Armature.SetAnimationFrame(0, 1.0f * animTime);
 
             base.Update(gameTime);
         }        

+ 17 - 5
src/MonoGameViewer/MainScene.cs

@@ -6,6 +6,7 @@ using System.Windows.Controls;
 
 using Microsoft.Xna.Framework;
 using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
 
 using MonoGame.WpfCore.MonoGameControls;
 
@@ -60,13 +61,21 @@ namespace MonoGameViewer
         {
             SharpGLTF.Schema2.ModelRoot model;
 
-            if (filePath.ToLower().EndsWith(".zip"))
+            try
             {
-                model = SharpGLTF.IO.ZipReader.LoadSchema2(filePath, ValidationMode.TryFix);
+                if (filePath.ToLower().EndsWith(".zip"))
+                {
+                    model = SharpGLTF.IO.ZipReader.LoadSchema2(filePath, ValidationMode.TryFix);
+                }
+                else
+                {
+                    model = SharpGLTF.Schema2.ModelRoot.Load(filePath, ValidationMode.TryFix);
+                }
             }
-            else
+            catch(Exception ex)
             {
-                model = SharpGLTF.Schema2.ModelRoot.Load(filePath, ValidationMode.TryFix);
+                System.Windows.MessageBox.Show(ex.Message, "Error", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
+                return;
             }
             
             _Model = model;            
@@ -114,7 +123,7 @@ namespace MonoGameViewer
             
 
             var lookAt = _ModelSphere.Center;
-            var camPos = _ModelSphere.Center + new Vector3(0, 0, _ModelSphere.Radius * 3);
+            var camPos = _ModelSphere.Center + new Vector3(0, 0, _ModelSphere.Radius * 2.5f);
 
             var camera = Matrix.CreateWorld(camPos, lookAt - camPos, Vector3.UnitY);
 
@@ -132,6 +141,9 @@ namespace MonoGameViewer
                 _ModelInstance.WorldMatrix = Matrix.CreateFromQuaternion(_Rotation);
 
                 var ctx = new ModelDrawingContext(this.GraphicsDevice);
+
+                ctx.NearPlane = Math.Min(1, _ModelSphere.Radius);
+
                 ctx.SetCamera(camera);                
                 ctx.DrawModelInstance(env, _ModelInstance);
             }

+ 1 - 1
src/MonoGameViewer/MonoGameViewer.csproj

@@ -9,7 +9,7 @@
   <ItemGroup>
       <PackageReference Include="MonoGame.Framework.WindowsDX" Version="3.8.0.1375-develop" />
       <PackageReference Include="PropertyTools.Wpf" Version="3.1.0-alpha0041" />
-      <PackageReference Include="SharpGLTF.Toolkit" Version="1.0.0-Preview-20200921-1654" />
+      <PackageReference Include="SharpGLTF.Toolkit" Version="1.0.0-Preview-20201001-0943" />
   </ItemGroup>
 
   <ItemGroup>

+ 4 - 4
src/SharpGLTF.Runtime.MonoGame/MonoGameModelInstance.cs

@@ -63,9 +63,9 @@ namespace SharpGLTF.Runtime
 
         public int IndexOfNode(string nodeName)
         {
-            for(int i=0; i < _Controller.LogicalNodes.Count; ++i)
+            for(int i=0; i < _Controller.Armature.LogicalNodes.Count; ++i)
             {
-                if (_Controller.LogicalNodes[i].Name == nodeName) return i;
+                if (_Controller.Armature.LogicalNodes[i].Name == nodeName) return i;
             }
 
             return -1;
@@ -78,7 +78,7 @@ namespace SharpGLTF.Runtime
         /// <returns>A matrix in model space.</returns>
         public Matrix GetModelMatrix(int nodeIndex)
         {
-            return _Controller.LogicalNodes[nodeIndex].WorldMatrix.ToXna();
+            return _Controller.Armature.LogicalNodes[nodeIndex].ModelMatrix.ToXna();
         }
 
         /// <summary>
@@ -88,7 +88,7 @@ namespace SharpGLTF.Runtime
         /// <returns>A matrix in world space.</returns>
         public Matrix GetWorldMatrix(int nodeIndex)
         {
-            return _Controller.LogicalNodes[nodeIndex].WorldMatrix.ToXna() * _WorldMatrix;
+            return _Controller.Armature.LogicalNodes[nodeIndex].ModelMatrix.ToXna() * _WorldMatrix;
         }
 
         /// <summary>

+ 3 - 1
src/SharpGLTF.Runtime.MonoGame/RuntimeModelMeshPart.cs

@@ -98,7 +98,9 @@ namespace SharpGLTF.Runtime
 
         public void Draw(GraphicsDevice device)
         {
-            bool isMirrorTransform = _Effect is AnimatedEffect animEffect && animEffect.WorldIsMirror;
+            // check if world matrix is a mirror matrix and requires the face culling to be reversed.
+            bool isMirrorTransform = false;
+            if (_Effect is IEffectMatrices ematrices) isMirrorTransform = ematrices.World.Determinant() < 0;
 
             if (_PrimitiveCount > 0)
             {

+ 1 - 1
src/SharpGLTF.Runtime.MonoGame/SharpGLTF.Runtime.MonoGame.csproj

@@ -9,7 +9,7 @@
 
   <ItemGroup>
     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1375-develop" PrivateAssets="all" />
-    <PackageReference Include="SharpGLTF.Core" Version="1.0.0-Preview-20200921-1654" />    
+    <PackageReference Include="SharpGLTF.Core" Version="1.0.0-Preview-20201001-0943" />    
   </ItemGroup>  
 
   <ItemGroup>