예제 #1
0
        private void SetRandomColorAndAlpha(ModelNode model)
        {
            var randomColor3F = RandomHelper.Random.NextVector3F(0, 4);

            // Desaturate random color to avoid eye cancer. ;-)
            float luminance   = Vector3F.Dot(randomColor3F, GraphicsHelper.LuminanceWeights);
            var   randomColor = (Vector3)InterpolationHelper.Lerp(new Vector3F(luminance), randomColor3F, 0.5f);

            var randomAlpha = MathHelper.Clamp(RandomHelper.Random.NextFloat(0, 5), 0, 1);

            // Change the values of all effect parameters "InstanceColor" and "InstanceAlpha":
            foreach (MeshNode meshNode in model.GetDescendants().OfType <MeshNode>())
            {
                foreach (MaterialInstance materialInstance in meshNode.MaterialInstances)
                {
                    foreach (EffectBinding effectBinding in materialInstance.EffectBindings)
                    {
                        if (effectBinding.ParameterBindings.Contains("InstanceColor"))
                        {
                            effectBinding.Set("InstanceColor", randomColor);
                        }
                        if (effectBinding.ParameterBindings.Contains("InstanceAlpha"))
                        {
                            effectBinding.Set("InstanceAlpha", randomAlpha);
                        }
                    }
                }
            }
        }
예제 #2
0
        public void PlayAnimation(string name)
        {
            if (CurrentAnimation == name)
            {
                return;
            }

            StopAnimation();

            CurrentAnimation = name;

            // Start selected animation.
            var meshNode         = ModelNode.GetDescendants().OfType <MeshNode>().First();
            var mesh             = meshNode.Mesh;
            var animation        = mesh.Animations[name];
            var loopingAnimation = new TimelineClip(animation)
            {
                Duration     = TimeSpan.MaxValue,
                LoopBehavior = LoopBehavior.Cycle,
            };

            _animationController = _animationService.StartAnimation(loopingAnimation, (IAnimatableProperty)meshNode.SkeletonPose);

            // Update view model IsPlaying flags.
            foreach (var animationPropertyViewModel in _animationPropertyViewModels)
            {
                if (animationPropertyViewModel.Name == CurrentAnimation)
                {
                    animationPropertyViewModel.IsPlaying = true;
                }
            }
        }
예제 #3
0
        // OnLoad() is called when the GameObject is added to the IGameObjectService.
        protected override void OnLoad()
        {
            var contentManager = _services.GetInstance <ContentManager>();

            // A rusty barrel with multiple levels of detail (LODs).
            _rigidBody  = new RigidBody(new CylinderShape(0.35f, 1));
            _modelNode0 = contentManager.Load <ModelNode>("Barrel/Barrel").Clone();
            SampleHelper.EnablePerPixelLighting(_modelNode0);

            // Mark the LOD nodes with UserFlags = 1.
            _modelNode0.GetDescendants()
            .OfType <LodGroupNode>()
            .SelectMany(lodGroupNode => lodGroupNode.Levels)
            .Select(level => level.Node)
            .ForEach(node =>
            {
                node.UserFlags = 1;
            });

            // Add a second model where each LOD has a different color.
            _modelNode1 = contentManager.Load <ModelNode>("Barrel/Barrel_Colored").Clone();
            SampleHelper.EnablePerPixelLighting(_modelNode1);

            // Mark the LOD nodes with UserFlags = 2.
            _modelNode1.GetDescendants()
            .OfType <LodGroupNode>()
            .SelectMany(lodGroupNode => lodGroupNode.Levels)
            .Select(level => level.Node)
            .ForEach(node =>
            {
                node.UserFlags = 2;
            });


            // Set a random pose.
            var randomPosition = new Vector3F(
                RandomHelper.Random.NextFloat(-10, 10),
                RandomHelper.Random.NextFloat(2, 5),
                RandomHelper.Random.NextFloat(-10, 0));

            _rigidBody.Pose       = new Pose(randomPosition, RandomHelper.Random.NextQuaternionF());
            _modelNode0.PoseWorld = _rigidBody.Pose;
            _modelNode1.PoseWorld = _rigidBody.Pose;

            // Add rigid body to physics simulation and models to scene.
            var simulation = _services.GetInstance <Simulation>();

            simulation.RigidBodies.Add(_rigidBody);

            var scene = _services.GetInstance <IScene>();

            scene.Children.Add(_modelNode0);
            scene.Children.Add(_modelNode1);
        }
예제 #4
0
        private void InitializeModel()
        {
            Debug.Assert(GraphicsScreens.Count != 0, "Initialize graphics screens before calling InitializeModel().");

            if (Document.ModelNode != null)
            {
                ModelNode = Document.ModelNode;

                // The first view model can use the original model node. All other view models
                // use clones because we cannot put one model node into several scenes.
                if (Document.ViewModels[0] != this)
                {
                    ModelNode = ModelNode.Clone();
                }

                if (Document.HasAnimations)
                {
                    // We want to animate all clones together. --> Make all clones use the skeleton
                    // pose instance of the original mesh node.
                    var originalMeshNode = Document.ModelNode.GetDescendants().OfType <MeshNode>().FirstOrDefault();
                    var clonedMeshNode   = ModelNode.GetDescendants().OfType <MeshNode>().FirstOrDefault();
                    if (originalMeshNode != null && clonedMeshNode != null)
                    {
                        clonedMeshNode.SkeletonPose = originalMeshNode.SkeletonPose;
                    }

                    HasSkeleton = true;
                }
                else
                {
                    HasSkeleton = false;
                }

                var scene = UseDeferredLighting
                            ? ((DeferredGraphicsScreen)GraphicsScreens[0]).Scene
                            : ((BasicGraphicsScreen)GraphicsScreens[0]).Scene;
                scene.Children.Add(ModelNode);
            }
            else if (Document.Model != null)
            {
                HasSkeleton = false;
                ((BasicGraphicsScreen)GraphicsScreens[0]).Model = Document.Model;
            }
        }
예제 #5
0
        public void StopAnimation()
        {
            if (CurrentAnimation == null)
            {
                return;
            }

            CurrentAnimation = null;

            // Stop currently running animation.
            _animationController.Stop();
            _animationController.Recycle();

            // Set bind pose.
            var meshNode = ModelNode.GetDescendants().OfType <MeshNode>().First();

            meshNode.SkeletonPose.ResetBoneTransforms();

            // Update view model IsPlaying flags.
            foreach (var animationPropertyViewModel in _animationPropertyViewModels)
            {
                animationPropertyViewModel.IsPlaying = false;
            }
        }
        private void UpdateProperties()
        {
            if (_modelPropertySource == null)
            {
                _modelPropertySource = new PropertySource();
            }

            _currentPropertySource = _modelPropertySource;

            _modelPropertySource.Name     = this.GetName();
            _modelPropertySource.TypeName = "3D Model";
            _modelPropertySource.Properties.Clear();

            if (State != ModelDocumentState.Loaded)
            {
                return;
            }

            // Try to load drmdl file.
            string drmdlFile = Path.ChangeExtension(Uri.LocalPath, "drmdl");

            if (UseDigitalRuneGraphics && File.Exists(drmdlFile))
            {
                _modelPropertySource.Properties.Add(new CustomProperty
                {
                    Category = "General",
                    Name     = "Model description",
                    Value    = drmdlFile,
                    //Description = ,
                    PropertyType    = typeof(string),
                    DataTemplateKey = OpenLinkKey,
                    CanReset        = false,
                    IsReadOnly      = true,
                });
            }

            int numberOfVertices   = 0;
            int numberOfPrimitives = 0;

            if (UseDigitalRuneGraphics)
            {
                foreach (var mesh in ModelNode.GetDescendants().OfType <MeshNode>().Select(mn => mn.Mesh))
                {
                    foreach (var submesh in mesh.Submeshes)
                    {
                        numberOfVertices   += submesh.VertexCount;
                        numberOfPrimitives += submesh.PrimitiveCount;
                    }
                }
            }
            else
            {
                foreach (var meshPart in Model.Meshes.SelectMany(m => m.MeshParts))
                {
                    numberOfVertices   += meshPart.NumVertices;
                    numberOfPrimitives += meshPart.PrimitiveCount;
                }
            }

            _modelPropertySource.Properties.Add(new CustomProperty
            {
                Category = "General",
                Name     = "Triangles",
                Value    = numberOfPrimitives,
                //Description = ,
                PropertyType    = typeof(int),
                DataTemplateKey = TextBlockKey,
                CanReset        = false,
                IsReadOnly      = true,
            });

            _modelPropertySource.Properties.Add(new CustomProperty
            {
                Category = "General",
                Name     = "Vertices",
                Value    = numberOfVertices,
                //Description = ,
                PropertyType    = typeof(int),
                DataTemplateKey = TextBlockKey,
                CanReset        = false,
                IsReadOnly      = true,
            });

            // Try to load drmat files.
            if (UseDigitalRuneGraphics)
            {
                string drmdlFolder = Path.GetDirectoryName(drmdlFile);
                var    drmatFiles  = new HashSet <string>();
                var    textures    = new HashSet <string>();
                var    xDocument   = XDocument.Load(drmdlFile);
                foreach (var submeshElement in xDocument.Descendants("Submesh"))
                {
                    var materialAttribute = submeshElement.Attributes("Material").FirstOrDefault();
                    if (materialAttribute == null)
                    {
                        continue;
                    }

                    string drmatFile = GetAbsolutePath(drmdlFolder, materialAttribute.Value);
                    if (!File.Exists(drmatFile))
                    {
                        continue;
                    }

                    drmatFiles.Add(drmatFile);
                    string drmatFolder = Path.GetDirectoryName(drmatFile);

                    // Collect all referenced texture filenames.
                    var drmatXDocument = XDocument.Load(drmatFile);
                    foreach (var textureElement in drmatXDocument.Descendants("Texture"))
                    {
                        var fileAttribute = textureElement.Attributes("File").FirstOrDefault();
                        if (fileAttribute == null)
                        {
                            continue;
                        }

                        string textureFile = GetAbsolutePath(drmatFolder, fileAttribute.Value);
                        textures.Add(textureFile);
                    }
                }

                int i = 0;
                foreach (var drmatFile in drmatFiles)
                {
                    _modelPropertySource.Properties.Add(new CustomProperty
                    {
                        Category = "Materials",
                        Name     = Invariant($"Material {i}"),
                        Value    = drmatFile,
                        //Description = ,
                        PropertyType    = typeof(string),
                        DataTemplateKey = OpenLinkKey,
                        CanReset        = false,
                        IsReadOnly      = true,
                    });
                    i++;
                }

                i = 0;
                foreach (var texture in textures)
                {
                    _modelPropertySource.Properties.Add(new CustomProperty
                    {
                        Category = "Textures",
                        Name     = Invariant($"Texture {i}"),
                        Value    = texture,
                        //Description = ,
                        PropertyType    = typeof(string),
                        DataTemplateKey = OpenLinkKey,
                        CanReset        = false,
                        IsReadOnly      = true,
                    });
                    i++;
                }

                _animationPropertyViewModels.Clear();
                if (HasAnimations)
                {
                    var mesh = ModelNode.GetDescendants().OfType <MeshNode>().First().Mesh;
                    foreach (var entry in mesh.Animations)
                    {
                        var animationPropertyViewModel = new AnimationPropertyViewModel(this)
                        {
                            Name      = entry.Key,
                            Animation = entry.Value,
                        };
                        _animationPropertyViewModels.Add(animationPropertyViewModel);

                        _modelPropertySource.Properties.Add(new CustomProperty
                        {
                            Category = "Animations",
                            Name     = "\"" + entry.Key + "\"",
                            Value    = animationPropertyViewModel,
                            //Description = ,
                            PropertyType = typeof(AnimationPropertyViewModel),
                            CanReset     = false,
                            IsReadOnly   = true,
                        });
                    }
                }
            }

            if (_documentService.ActiveDocument == this)
            {
                // This document is active and can control tool windows.
                if (_propertiesService != null)
                {
                    _propertiesService.PropertySource = _currentPropertySource;
                }
            }
        }
예제 #7
0
        public ConstraintVehicleObject(IServiceLocator services)
        {
            Name = "Vehicle";

            _services     = services;
            _inputService = services.GetInstance <IInputService>();

            _simulation = services.GetInstance <Simulation>();

            // Load models for rendering.
            var contentManager = services.GetInstance <ContentManager>();

            _vehicleModelNode   = contentManager.Load <ModelNode>("Car/Car").Clone();
            _wheelModelNodes    = new ModelNode[4];
            _wheelModelNodes[0] = contentManager.Load <ModelNode>("Car/Wheel").Clone();
            _wheelModelNodes[1] = _wheelModelNodes[0].Clone();
            _wheelModelNodes[2] = _wheelModelNodes[0].Clone();
            _wheelModelNodes[3] = _wheelModelNodes[0].Clone();

            // Add wheels under the car model node.
            _vehicleModelNode.Children.Add(_wheelModelNodes[0]);
            _vehicleModelNode.Children.Add(_wheelModelNodes[1]);
            _vehicleModelNode.Children.Add(_wheelModelNodes[2]);
            _vehicleModelNode.Children.Add(_wheelModelNodes[3]);

            // ----- Create the chassis of the car.
            // The Vehicle needs a rigid body that represents the chassis. This can be any shape (e.g.
            // a simple BoxShape). In this example we will build a convex polyhedron from the car model.

            // 1. Extract the vertices from the car model.
            // The car model has ~10,000 vertices. It consists of a MeshNode for the glass
            // parts and a MeshNode "Car" for the chassis.
            var meshNode = _vehicleModelNode.GetDescendants()
                           .OfType <MeshNode>()
                           .First(mn => mn.Name == "Car");
            var mesh = MeshHelper.ToTriangleMesh(meshNode.Mesh);

            // Apply the transformation of the mesh node.
            mesh.Transform(meshNode.PoseWorld * Matrix.CreateScale(meshNode.ScaleWorld));

            // 2. (Optional) Create simplified convex hull from mesh.
            // We could also skip this step and directly create a convex polyhedron from the mesh using
            //    var chassisShape = new ConvexPolyhedron(mesh.Vertices);
            // However, the convex polyhedron would still have 500-600 vertices.
            // We can reduce the number of vertices by using the GeometryHelper.
            // Create a convex hull for mesh with max. 64 vertices. Additional, shrink the hull by 4 cm.
            var convexHull = GeometryHelper.CreateConvexHull(mesh.Vertices, 64, -0.04f);

            // 3. Create convex polyhedron shape using the vertices of the convex hull.
            var chassisShape = new ConvexPolyhedron(convexHull.Vertices.Select(v => v.Position));

            // (Note: Building convex hulls and convex polyhedra are time-consuming. To save loading time
            // we should build the shape in the XNA content pipeline. See other DigitalRune Physics
            // Samples.)

            // The mass properties of the car. We use a mass of 800 kg.
            var mass = MassFrame.FromShapeAndMass(chassisShape, Vector3.One, 800, 0.1f, 1);

            // Trick: We artificially modify the center of mass of the rigid body. Lowering the center
            // of mass makes the car more stable against rolling in tight curves.
            // We could also modify mass.Inertia for other effects.
            var pose = mass.Pose;

            pose.Position.Y -= 0.5f;  // Lower the center of mass.
            pose.Position.Z  = -0.5f; // The center should be below the driver.
            // (Note: The car model is not exactly centered.)
            mass.Pose = pose;

            // Material for the chassis.
            var material = new UniformMaterial
            {
                Restitution     = 0.1f,
                StaticFriction  = 0.2f,
                DynamicFriction = 0.2f
            };

            var chassis = new RigidBody(chassisShape, mass, material)
            {
                Pose     = new Pose(new Vector3(0, 2, 0)), // Start position
                UserData = "NoDraw",                       // (Remove this line to render the collision model.)
            };

            // ----- Create the vehicle.
            Vehicle = new ConstraintVehicle(_simulation, chassis);

            // Add 4 wheels.
            Vehicle.Wheels.Add(new ConstraintWheel {
                Offset = new Vector3(-0.9f, 0.6f, -2.0f), Radius = 0.36f, SuspensionRestLength = 0.55f, MinSuspensionLength = 0.25f, Friction = 2
            });                                                                                                                                                                       // Front left
            Vehicle.Wheels.Add(new ConstraintWheel {
                Offset = new Vector3(0.9f, 0.6f, -2.0f), Radius = 0.36f, SuspensionRestLength = 0.55f, MinSuspensionLength = 0.25f, Friction = 2
            });                                                                                                                                                                       // Front right
            Vehicle.Wheels.Add(new ConstraintWheel {
                Offset = new Vector3(-0.9f, 0.6f, 0.98f), Radius = 0.36f, SuspensionRestLength = 0.55f, MinSuspensionLength = 0.25f, Friction = 1.8f
            });                                                                                                                                                                        // Back left
            Vehicle.Wheels.Add(new ConstraintWheel {
                Offset = new Vector3(0.9f, 0.6f, 0.98f), Radius = 0.36f, SuspensionRestLength = 0.55f, MinSuspensionLength = 0.25f, Friction = 1.8f
            });                                                                                                                                                                        // Back right

            // Vehicles are disabled per default. This way we can create the vehicle and the simulation
            // objects are only added when needed.
            Vehicle.Enabled = false;
        }
예제 #8
0
        private void UpdateDebugDrawing()
        {
            if (GraphicsScreens.Count == 0)
            {
                return;
            }

            var debugRenderer = UseDeferredLighting
                                ? ((DeferredGraphicsScreen)GraphicsScreens[0]).DebugRenderer
                                : ((BasicGraphicsScreen)GraphicsScreens[0]).DebugRenderer;

            debugRenderer.Clear();
            debugRenderer.DrawAxes(Pose.Identity, 1, true);

            // Draw status message.
            if (ModelNode == null && Document.Model == null)
            {
                string text = null;
                if (Document.State == ModelDocumentState.Loading)
                {
                    text = "Loading...";
                }
                else if (Document.State == ModelDocumentState.Error)
                {
                    text = "Error. See Output window and Errors window for more information.";
                }

                if (text != null)
                {
                    debugRenderer.DrawText(text, ModelCenter, new Vector2F(0.5f), Color.White, true);
                }

                return;
            }

            // Draw AABB.
            if (ShowBoundingShapes)
            {
                if (ModelNode != null)
                {
                    foreach (var meshNode in ModelNode.GetDescendants().OfType <MeshNode>())
                    {
                        debugRenderer.DrawObject(meshNode, Color.Orange, true, false);
                    }
                }
                else if (Document.Model != null)
                {
                    Matrix[] boneTransforms = new Matrix[Document.Model.Bones.Count];
                    Document.Model.CopyAbsoluteBoneTransformsTo(boneTransforms);
                    foreach (var mesh in Document.Model.Meshes)
                    {
                        var sphere = mesh.BoundingSphere;
                        sphere = sphere.Transform(boneTransforms[mesh.ParentBone.Index]);
                        debugRenderer.DrawSphere(sphere.Radius, new Pose((Vector3)sphere.Center), Color.Orange, true, false);
                    }
                }
            }

            // Draw skeleton.
            if (HasSkeleton && ShowSkeleton)
            {
                foreach (var meshNode in ModelNode.GetDescendants().OfType <MeshNode>())
                {
                    debugRenderer.DrawSkeleton(meshNode, meshNode.Aabb.Extent.Length / 20, Color.Orange, true);
                }
            }

            // Visualize intermediate render targets.
            if (Document.UseDigitalRuneGraphics && UseDeferredLighting)
            {
                ((DeferredGraphicsScreen)GraphicsScreens[0]).VisualizeIntermediateRenderTargets = ShowIntermediateRenderTargets;
            }

            // Draw selected outline items.
            Color highlightColor = Color.LightBlue;
            var   selectedItems  = Document.Outline?.SelectedItems;

            if (selectedItems?.Count > 0 &&
                Document.CurrentAnimation == null)    // DebugRenderer does not support animations.
            {
                foreach (var item in selectedItems)
                {
                    // Skip if any parent is selected.
                    var  parent = item.Parent;
                    bool skip   = false;
                    while (parent != null)
                    {
                        if (parent.IsSelected)
                        {
                            skip = true;
                            break;
                        }

                        parent = parent.Parent;
                    }

                    if (skip)
                    {
                        continue;
                    }

                    if (item.UserData is SceneNode)
                    {
                        var sceneNode = (SceneNode)item.UserData;
                        debugRenderer.DrawModel(sceneNode, highlightColor, true, true);
                    }
                    else if (item.UserData is Mesh)
                    {
                        var mesh      = (Mesh)item.UserData;
                        var sceneNode = (SceneNode)item.Parent.UserData;
                        debugRenderer.DrawMesh(mesh, sceneNode.PoseWorld, sceneNode.ScaleWorld, highlightColor, true, true);
                    }
                    else if (item.UserData is Submesh)
                    {
                        var submesh   = (Submesh)item.UserData;
                        var sceneNode = (SceneNode)item.Parent.Parent.UserData;
                        debugRenderer.DrawMesh(submesh, sceneNode.PoseWorld, sceneNode.ScaleWorld, highlightColor, true, true);
                    }
                    else if (item.UserData is Material)
                    {
                        var material      = (Material)item.UserData;
                        var mesh          = (Mesh)item.Parent.UserData;
                        var materialIndex = mesh.Materials.IndexOf(material);
                        var sceneNode     = (SceneNode)item.Parent.Parent.UserData;
                        foreach (var sm in mesh.Submeshes)
                        {
                            if (sm.MaterialIndex == materialIndex)
                            {
                                debugRenderer.DrawMesh(sm, sceneNode.PoseWorld, sceneNode.ScaleWorld, highlightColor, true, true);
                            }
                        }
                    }
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Checks the model for common mistakes and writes warnings.
        /// </summary>
        private void ValidateModelNode()
        {
            if (ModelNode == null)
            {
                return;
            }

            bool missingMesh               = true;
            bool tooSmall                  = false;
            bool tooBig                    = false;
            bool tooManyBones              = false;
            bool missingPositions          = false;
            bool missingTexture            = false;
            bool missingTextureCoordinates = false;
            bool missingNormals            = false;
            bool missingTangentFrames      = false;
            bool wrongAlpha                = false;
            bool missingBoneIndices        = false;
            bool missingBoneWeights        = false;

            foreach (var meshNode in ModelNode.GetDescendants().OfType <MeshNode>())
            {
                missingMesh = false;

                var size = meshNode.Aabb.Extent.Length;
                if (size < 0.01)
                {
                    tooSmall = true;
                }
                else if (size > 100)
                {
                    tooBig = true;
                }

                if (meshNode.SkeletonPose != null && meshNode.SkeletonPose.Skeleton.NumberOfBones > 72)
                {
                    tooManyBones = true;
                }

                foreach (var submesh in meshNode.Mesh.Submeshes)
                {
                    var vertexElements = submesh.VertexBuffer.VertexDeclaration.GetVertexElements();
                    if (!vertexElements.Any(ve => ve.VertexElementUsage == VertexElementUsage.Position))
                    {
                        missingPositions = true;
                    }
                    if (!vertexElements.Any(ve => ve.VertexElementUsage == VertexElementUsage.TextureCoordinate))
                    {
                        missingTextureCoordinates = true;
                    }
                    if (!vertexElements.Any(ve => ve.VertexElementUsage == VertexElementUsage.Normal))
                    {
                        missingNormals = true;
                    }
                    if (!vertexElements.Any(ve => ve.VertexElementUsage == VertexElementUsage.Tangent))
                    {
                        missingTangentFrames = true;
                    }
                    if (!vertexElements.Any(ve => ve.VertexElementUsage == VertexElementUsage.Binormal))
                    {
                        missingTangentFrames = true;
                    }
                    if (meshNode.SkeletonPose != null)
                    {
                        if (!vertexElements.Any(ve => ve.VertexElementUsage == VertexElementUsage.BlendIndices))
                        {
                            missingBoneIndices = true;
                        }
                        if (!vertexElements.Any(ve => ve.VertexElementUsage == VertexElementUsage.BlendWeight))
                        {
                            missingBoneWeights = true;
                        }
                    }
                }

                foreach (var material in meshNode.Mesh.Materials)
                {
                    foreach (var effectBinding in material.EffectBindings)
                    {
                        if (effectBinding.ParameterBindings.Contains("Diffuse"))
                        {
                            var alphaBinding = effectBinding.ParameterBindings["Diffuse"] as ConstParameterBinding <Vector4>;
                            if (alphaBinding != null && alphaBinding.Value.W < 0.001f)
                            {
                                wrongAlpha = true;
                            }
                        }
                        else if (effectBinding.ParameterBindings.Contains("DiffuseColor"))
                        {
                            var alphaBinding = effectBinding.ParameterBindings["DiffuseColor"] as ConstParameterBinding <Vector4>;
                            if (alphaBinding != null && alphaBinding.Value.W < 0.001f)
                            {
                                wrongAlpha = true;
                            }
                        }
                        else if (effectBinding.ParameterBindings.Contains("Alpha"))
                        {
                            var alphaBinding = effectBinding.ParameterBindings["Alpha"] as ConstParameterBinding <float>;
                            if (alphaBinding != null && alphaBinding.Value < 0.001f)
                            {
                                wrongAlpha = true;
                            }
                        }

                        if (effectBinding.ParameterBindings.Contains("Texture"))
                        {
                            var textureBinding = effectBinding.ParameterBindings["Texture"] as ConstParameterBinding <Texture>;
                            if (textureBinding != null && textureBinding.Value == null)
                            {
                                missingTexture = true;
                            }
                            var texture2DBinding = effectBinding.ParameterBindings["Texture"] as ConstParameterBinding <Texture2D>;
                            if (texture2DBinding != null && texture2DBinding.Value == null)
                            {
                                missingTexture = true;
                            }
                        }
                        if (effectBinding.ParameterBindings.Contains("DiffuseTexture"))
                        {
                            var textureBinding = effectBinding.ParameterBindings["DiffuseTexture"] as ConstParameterBinding <Texture>;
                            if (textureBinding != null && textureBinding.Value == null)
                            {
                                missingTexture = true;
                            }
                            var texture2DBinding = effectBinding.ParameterBindings["DiffuseTexture"] as ConstParameterBinding <Texture2D>;
                            if (texture2DBinding != null && texture2DBinding.Value == null)
                            {
                                missingTexture = true;
                            }
                        }
                    }
                }
            }

            if (missingMesh)
            {
                AddWarning("Model does not contain any meshes.");
            }

            if (tooSmall)
            {
                AddWarning("Model is very small. Scale it up in a 3D modeling tool or set a scale factor in DRMDL file!");
            }
            else if (tooBig)
            {
                AddWarning("Model is very big. Scale it down in a 3D modeling tool or set a scale factor in DRMDL file!");
            }

            if (tooManyBones)
            {
                AddWarning("Model uses too many bones for mesh skinning. Reduce number of bones to ≤ 72 in a 3D modeling tool!");
            }

            if (missingPositions)
            {
                AddWarning("Missing vertex positions. Correct the model in a 3D modeling tool!");
            }
            if (missingNormals)
            {
                AddWarning("Missing vertex normals. Correct the model in a 3D modeling tool!");
            }
            if (missingTexture)
            {
                AddWarning("Missing diffuse texture.");
            }
            if (missingTextureCoordinates)
            {
                AddWarning("Missing texture coordinates. Add texture coordinates in a 3D modeling tool!");
            }
            if (missingTangentFrames)
            {
                AddWarning("Missing tangent frames. Set GenerateTangentFrames in DRMDL file to true! (Optional for XNA BasicEffect. Required for advanced effects.)");
            }
            if (missingBoneIndices || missingBoneWeights)
            {
                AddWarning("Missing blend indices or blend weights for mesh skinning. Add blend indices and blend weights in a 3D modeling tool!");
            }
            if (wrongAlpha)
            {
                AddWarning("Alpha of mesh is 0 or almost 0.");
            }
        }
예제 #10
0
    public VegetationSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;

      _graphicsScreen = new DeferredGraphicsScreen(Services);
      _graphicsScreen.DrawReticle = true;
      GraphicsService.Screens.Insert(0, _graphicsScreen);
      GameObjectService.Objects.Add(new DeferredGraphicsOptionsObject(Services));

      Services.Register(typeof(DebugRenderer), null, _graphicsScreen.DebugRenderer);

      var scene = _graphicsScreen.Scene;
      Services.Register(typeof(IScene), null, scene);

      // Add gravity and damping to the physics simulation.
      Simulation.ForceEffects.Add(new Gravity());
      Simulation.ForceEffects.Add(new Damping());

      // Add a custom game object which controls the camera.
      var cameraGameObject = new CameraObject(Services);
      GameObjectService.Objects.Add(cameraGameObject);
      _graphicsScreen.ActiveCameraNode = cameraGameObject.CameraNode;

      // Add standard game objects.
      GameObjectService.Objects.Add(new GrabObject(Services));
      GameObjectService.Objects.Add(new DynamicSkyObject(Services, true, false, true));
      GameObjectService.Objects.Add(new GroundObject(Services));
      GameObjectService.Objects.Add(new ObjectCreatorObject(Services));
      GameObjectService.Objects.Add(new LavaBallsObject(Services));

      // Add a new game object which controls the wind velocity and "Wind" parameters in effects.
      GameObjectService.Objects.Add(new WindObject(Services));


      // The vegetation effects use an effect parameter named "LodDistances". By default all
      // effect parameters are shared per "Material". However, we want to change the parameter
      // per instance. Therefore, the effect declares the parameter like this:
      // float3 LodDistances < string Hint = "PerInstance"; >;
      // However, MonoGame does not yet support effect annotations. Therefore, we tell the
      // graphics service that the "LodDistances" parameter should be stored per instance by
      // adding a new entry to the default effect interpreter.
      var defaultEffectInterpreter = GraphicsService.EffectInterpreters.OfType<DefaultEffectInterpreter>().First();
      if (!defaultEffectInterpreter.ParameterDescriptions.ContainsKey("LodDistances"))
        defaultEffectInterpreter.ParameterDescriptions.Add(
          "LodDistances",
          (parameter, i) => new EffectParameterDescription(parameter, "LodDistances", i, EffectParameterHint.PerInstance));


      // Load three different plant models.
      // The palm tree consists of a single mesh. It uses the *Vegetation.fx effects.
      ModelNode palmModelNode = ContentManager.Load<ModelNode>("Vegetation/PalmTree/palm_tree");
      Mesh palmMesh = ((MeshNode)palmModelNode.Children[0]).Mesh;

      // The bird's nest plant consists of 2 LODs. It uses the *Vegetation.fx effects.
      ModelNode plantModelNode = ContentManager.Load<ModelNode>("Vegetation/BirdnestPlant/BirdnestPlant");
      LodGroupNode plantLodGroupNode = plantModelNode.GetDescendants().OfType<LodGroupNode>().First().Clone();

      // The grass model consists of one mesh. It uses the *Grass.fx effects.
      ModelNode grassModelNode = ContentManager.Load<ModelNode>("Vegetation/Grass/grass");
      Mesh grassMesh = ((MeshNode)grassModelNode.Children[0]).Mesh;

      // Store all used meshes in a list for use in UpdateMaterialEffectParameters.
      _meshes.Add(palmMesh);
      foreach (var meshNode in plantLodGroupNode.Levels.Select(lodEntry => lodEntry.Node).OfType<MeshNode>())
        _meshes.Add(meshNode.Mesh);
      _meshes.Add(grassMesh);

      // We can add individual plant instances to the scene like this:
      // (However, this is inefficient for large amounts of plants.)
      _graphicsScreen.Scene.Children.Add(new MeshNode(palmMesh)
      {
        PoseLocal = new Pose(new Vector3(-2, 0, 0))
      });
      plantLodGroupNode.PoseLocal = Pose.Identity;
      _graphicsScreen.Scene.Children.Add(plantLodGroupNode);
      _graphicsScreen.Scene.Children.Add(new MeshNode(grassMesh)
      {
        PoseLocal = new Pose(new Vector3(2, 0, 0))
      });


      int numberOfInstancesPerCell = 100;
#else
      int numberOfInstancesPerCell = 10;


      // It is more efficient to group instances in batches and render them using mesh instancing.
      // This is handled by the VegetationObject class.
      GameObjectService.Objects.Add(new VegetationObject(Services, palmMesh, numberOfInstancesPerCell, 20, 10, 10, 1)
      {
        Name = "PalmTrees"
      });

      // The bird's nest plant has 2 LODs. We create two VegetationObjects. One displays the
      // detailed meshes near the camera. The second displays the low-poly meshes in the distance.
      var plantMeshLod0 = ((MeshNode)plantLodGroupNode.Levels[0].Node).Mesh;
      _meshes.Add(plantMeshLod0);
      GameObjectService.Objects.Add(new VegetationObject(Services, plantMeshLod0, numberOfInstancesPerCell, 20, 10, 10, 2)
      {
        Name = "PlantLOD0",
        MaxDistance = plantLodGroupNode.Levels[1].Distance,
      });

      var plantMeshLod1 = ((MeshNode)plantLodGroupNode.Levels[1].Node).Mesh;
      _meshes.Add(plantMeshLod1);
      GameObjectService.Objects.Add(new VegetationObject(Services, plantMeshLod1, numberOfInstancesPerCell, 20, 10, 10, 2)
      {
        Name = "PlantLOD1",
        MinDistance = plantLodGroupNode.Levels[1].Distance,
        MaxDistance = plantLodGroupNode.MaxDistance,
        CastsShadows = false,  // No shadows in the distance.
      });

      // Grass, lots of it...
      GameObjectService.Objects.Add(new VegetationObject(Services, grassMesh, numberOfInstancesPerCell * 10, 10, 20, 20, 3)
      {
        Name = "Grass",
        MaxDistance = 30,
        CastsShadows = false,
      });

      CreateGuiControls();
    }
예제 #11
0
        private async Task LoadAsync(string fileName, bool recreateModelAndMaterialFiles)
        {
            Debug.Assert(_tempDirectoryHelper == null);
            Debug.Assert(_monoGameContent == null);
            Debug.Assert(ModelNode == null);
            Debug.Assert(Model == null);
            Debug.Assert(_assimpScene == null);
            Debug.Assert(State == ModelDocumentState.Loading);

            string extension = Path.GetExtension(fileName);

            IsXnb = string.Compare(extension, ".XNB", StringComparison.OrdinalIgnoreCase) == 0;

            // ----- Build XNB
            string directoryName;

            try
            {
                if (IsXnb)
                {
                    // Get the folder that contains the XNB.
                    directoryName = Path.GetDirectoryName(fileName);
                }
                else if (GameContentBuilder.IsSupportedModelFileExtension(extension))
                {
                    // Build the XNB and get the output folder.
                    var buildResult = await Task.Run(() => BuildXnb(Editor.Services, Editor.ApplicationName, fileName, UseDigitalRuneGraphics, recreateModelAndMaterialFiles));

                    directoryName        = buildResult.Item1;
                    _tempDirectoryHelper = buildResult.Item2;
                }
                else
                {
                    throw new EditorException(Invariant($"Unsupported 3D model file format (file extension \"{extension}\")."));
                }
            }
            catch (Exception)
            {
                if (IsDisposed)
                {
                    // Document was closed during loading.
                    Reset();
                    return;
                }

                State = ModelDocumentState.Error;
                UpdateProperties();
                UpdateOutline();

                // The GameContentBuilder logs to the output service.
                _outputService.Show();

                throw;
            }

            if (IsDisposed)
            {
                // Document was closed during loading.
                Reset();
                return;
            }

            Debug.Assert(directoryName != null);

            // ----- Load XNB
            try
            {
                // Get asset name for use with ContentManager. XNBs and unprocessed models
                // use different folder hierarchies.
                string assetFileName;
                if (IsXnb)
                {
                    // Use absolute path.
                    assetFileName = fileName;
                }
                else
                {
                    // The asset is built relative to the root folder (e.g. "C:\"). The folder
                    // hierarchy (from root to asset) is rebuilt in the temporary output folder.

                    // Make file name relative to root.
                    assetFileName = DRPath.GetRelativePath(Path.GetPathRoot(fileName), fileName);

                    // Get absolute file name relative to temporary output folder.
                    assetFileName = Path.Combine(directoryName, assetFileName);

                    // Change extension. .fbx --> .xnb
                    assetFileName = Path.ChangeExtension(assetFileName, "xnb");
                }

                _monoGameContent = await Task.Run(() => _monoGameService.LoadXnb(directoryName, assetFileName, cacheResult: false));

                if (_monoGameContent.Asset is ModelNode)
                {
                    ModelNode = (ModelNode)_monoGameContent.Asset;
                    UseDigitalRuneGraphics = true;
                    HasAnimations          = ModelNode.GetDescendants()
                                             .OfType <MeshNode>()
                                             .FirstOrDefault()?
                                             .Mesh?
                                             .Animations?
                                             .Count > 0;
                }
                else if (_monoGameContent.Asset is Model)
                {
                    Model = (Model)_monoGameContent.Asset;
                    UseDigitalRuneGraphics = false;
                    HasAnimations          = false;

                    // Enable default lighting.
                    var effects = Model.Meshes
                                  .SelectMany(m => m.Effects)
                                  .OfType <IEffectLights>();
                    foreach (var effect in effects)
                    {
                        effect.EnableDefaultLighting();
                    }
                }
                else
                {
                    throw new EditorException("XNB does not contain ModelNode or Model.");
                }
            }
            catch (Exception exception)
            {
                Reset();

                if (IsDisposed)
                {
                    return;
                }

                State = ModelDocumentState.Error;
                Logger.Error(exception, "XNB could not be loaded.");

                // Let LoadAsync return and fail, then show message box.
                WindowsHelper.BeginInvokeOnUI(() =>
                {
                    var message = Invariant($"XNB could not be loaded:\n\n\"{exception.Message}\"");
                    MessageBox.Show(message, Editor.ApplicationName, MessageBoxButton.OK, MessageBoxImage.Error);
                });

                throw;
            }

            if (IsDisposed)
            {
                // Document was closed during loading.
                Reset();
                return;
            }

            // ----- Load Assimp scene
            try
            {
                if (!IsXnb)
                {
                    _assimpScene = await Task.Run(() => LoadAssimp(fileName));
                }
            }
            catch (Exception exception)
            {
                Logger.Warn(exception, "Assimp could not read model file.");
            }

            if (IsDisposed)
            {
                // Document was closed during loading.
                Reset();
                return;
            }

            State = ModelDocumentState.Loaded;

            // ----- Validate model
            ValidateModelNode();
            // TODO: Validate MonoGame Model.

            // If there are errors or warnings, show Output and Errors window.
            // (Drawback: This steals focus from the document.)
            //if (_errors.Count > 0)
            //{
            //    _outputService?.Show();
            //    _errorService?.Show();
            //}

            // ----- Update outline and properties
            UpdateOutline();
            UpdateProperties();
        }
예제 #12
0
        // OnLoad() is called when the GameObject is added to the IGameObjectService.
        protected override void OnLoad()
        {
            var contentManager = _services.GetInstance <ContentManager>();

            if (_type == 1)
            {
                // A simple cube.
                _rigidBody = new RigidBody(new BoxShape(1, 1, 1));
                _modelNode = contentManager.Load <ModelNode>("RustyCube/RustyCube").Clone();
            }
            else if (_type == 2)
            {
                // Another simple cube.
                _rigidBody = new RigidBody(new BoxShape(1, 1, 1));
                _modelNode = contentManager.Load <ModelNode>("MetalGrateBox/MetalGrateBox").Clone();
            }
            else if (_type == 3)
            {
                // A TV-like box.
                _rigidBody = new RigidBody(new BoxShape(1, 0.6f, 0.8f))
                {
                    UserData = "TV"
                };
                _modelNode = contentManager.Load <ModelNode>("TVBox/TVBox");

                if (_modelNode.Children.OfType <LightNode>().Count() == 0)
                {
                    // This is the first time the "TVBox" is loaded.

                    // Add a projector light to the model that projects the TV screen. The
                    // TV screen is the emissive part of the TV mesh.
                    var meshNode = _modelNode.Children.OfType <MeshNode>().First();
                    var material = meshNode.Mesh.Materials.First(m => m.Name == "TestCard");

                    // Get texture from material.
                    // Note: In XNA the effect parameter type is Texture. In MonoGame it is Texture2D.
                    Texture2D texture;
                    EffectParameterBinding parameterBinding = material["Material"].ParameterBindings["EmissiveTexture"];
                    if (parameterBinding is EffectParameterBinding <Texture> )
                    {
                        texture = (Texture2D)((EffectParameterBinding <Texture>)parameterBinding).Value;
                    }
                    else
                    {
                        texture = ((EffectParameterBinding <Texture2D>)parameterBinding).Value;
                    }

                    var projection = new PerspectiveProjection();
                    projection.Near = 0.55f;
                    projection.Far  = 3.0f;
                    projection.SetFieldOfView(MathHelper.ToRadians(60), 0.76f / 0.56f);

                    var projectorLight = new ProjectorLight(texture, projection);
                    projectorLight.Attenuation = 4;
                    var projectorLightNode = new LightNode(projectorLight);
                    projectorLightNode.LookAt(new Vector3F(0, 0.2f, 0), Vector3F.Zero, Vector3F.UnitZ);

                    // Attach the projector light to the model.
                    _modelNode.Children.Add(projectorLightNode);
                }

                _modelNode = _modelNode.Clone();
            }
            else if (_type == 4)
            {
                // A "magic" sphere with a colored point light.
                _rigidBody = new RigidBody(new SphereShape(0.25f));
                _modelNode = contentManager.Load <ModelNode>("MagicSphere/MagicSphere");

                if (_modelNode.Children.OfType <LightNode>().Count() == 0)
                {
                    // This is the first time the "MagicSphere" is loaded.

                    // Change the size of the sphere.
                    var meshNode = _modelNode.Children.OfType <MeshNode>().First();
                    meshNode.ScaleLocal = new Vector3F(0.5f);

                    // Disable shadows. (The sphere acts as a light source.)
                    meshNode.CastsShadows = false;

                    // Add a point light.
                    var pointLight = new PointLight
                    {
                        Color             = new Vector3F(1, 1, 1),
                        DiffuseIntensity  = 4,
                        SpecularIntensity = 4,
                        Range             = 3,
                        Attenuation       = 1,
                        Texture           = contentManager.Load <TextureCube>("MagicSphere/ColorCube"),
                    };
                    var pointLightNode = new LightNode(pointLight)
                    {
                        // The point light uses shadow mapping to cast an omnidirectional shadow.
                        Shadow = new CubeMapShadow
                        {
                            PreferredSize   = 64,
                            DepthBiasScale  = 0.9f,
                            DepthBiasOffset = -0.01f,
                        }
                    };

                    _modelNode.Children.Add(pointLightNode);
                }

                _modelNode = _modelNode.Clone();
            }
            else if (_type == 5)
            {
                // A sphere of glass (or "bubble").
                _rigidBody = new RigidBody(new SphereShape(0.3f));
                _modelNode = contentManager.Load <ModelNode>("Bubble/Bubble").Clone();
                _modelNode.GetDescendants().OfType <MeshNode>().First().ScaleLocal = new Vector3F(0.3f);
            }
            else if (_type == 6)
            {
                // A rusty barrel with multiple levels of detail (LODs).
                _rigidBody = new RigidBody(new CylinderShape(0.35f, 1));
                _modelNode = contentManager.Load <ModelNode>("Barrel/Barrel").Clone();
            }
            else
            {
                // A cube consisting of a frame and transparent sides.
                _rigidBody = new RigidBody(new BoxShape(1, 1, 1));
                _modelNode = contentManager.Load <ModelNode>("GlassBox/GlassBox").Clone();
            }

            SampleHelper.EnablePerPixelLighting(_modelNode);

            // Set a random pose.
            var randomPosition = new Vector3F(
                RandomHelper.Random.NextFloat(-10, 10),
                RandomHelper.Random.NextFloat(2, 5),
                RandomHelper.Random.NextFloat(-20, 0));

            _rigidBody.Pose      = new Pose(randomPosition, RandomHelper.Random.NextQuaternionF());
            _modelNode.PoseWorld = _rigidBody.Pose;

            // Add rigid body to physics simulation and model to scene.
            var simulation = _services.GetInstance <Simulation>();

            simulation.RigidBodies.Add(_rigidBody);

            var scene = _services.GetInstance <IScene>();

            scene.Children.Add(_modelNode);
        }