コード例 #1
0
        /// <summary>
        /// Adds a new <see cref="TerrainRendererMesh"/>.
        /// </summary>
        /// <param name="mesh">The terrain mesh.</param>
        /// <remarks>
        /// <para>
        /// The <see cref="TerrainRenderer"/> takes ownership of the <see cref="TerrainRendererMesh"/>
        /// instance. When the <see cref="TerrainRenderer"/> is disposed of, all internally stored
        /// <see cref="TerrainRendererMesh"/>es are disposed of.
        /// </para>
        /// <para>
        /// If the terrain renderer already has a mesh with the same settings
        /// (<see cref="TerrainRendererMesh.NumberOfLevels"/> and
        /// <see cref="TerrainRendererMesh.CellsPerLevel"/>), the old mesh is disposed of and replaced.
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="mesh"/> is <see langword="null"/>.
        /// </exception>
        public void SetMesh(TerrainRendererMesh mesh)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }
            if (mesh.IsDisposed)
            {
                throw new ArgumentException("Mesh is disposed.", "mesh");
            }

            var key = new Pair <int, int>(mesh.NumberOfLevels, mesh.CellsPerLevel);

            TerrainRendererMesh oldMesh;

            if (_meshes.TryGetValue(key, out oldMesh) && mesh != oldMesh)
            {
                oldMesh.Dispose();
            }

            _meshes[key] = mesh;
        }
コード例 #2
0
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            context.ThrowIfCameraMissing();
            context.ThrowIfRenderPassMissing();

            var graphicsService = context.GraphicsService;
            var graphicsDevice  = graphicsService.GraphicsDevice;

            var cameraNode = context.CameraNode;

            // Update SceneNode.LastFrame for all visible nodes.
            int frame = context.Frame;

            cameraNode.LastFrame = frame;

            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            for (int i = 0; i < numberOfNodes; i++)
            {
                var node = nodes[i] as TerrainNode;
                if (node == null)
                {
                    continue;
                }

                // Node is visible in current frame.
                node.LastFrame = frame;

                if (!node.MaterialInstance.Contains(context.RenderPass))
                {
                    continue;
                }

                TerrainRendererMesh mesh;
                var  meshKey    = new Pair <int, int>(node.BaseClipmap.NumberOfLevels, node.BaseClipmap.CellsPerLevel);
                bool meshExists = _meshes.TryGetValue(meshKey, out mesh);
                if (!meshExists || mesh.IsDisposed)
                {
                    // Warning: This may take a few seconds!
                    mesh             = new TerrainRendererMesh(graphicsDevice, node.BaseClipmap.NumberOfLevels, node.BaseClipmap.CellsPerLevel);
                    _meshes[meshKey] = mesh;
                }

                // Get the EffectBindings and the Effect for the current render pass.
                EffectBinding materialInstanceBinding = node.MaterialInstance[context.RenderPass];
                EffectBinding materialBinding         = node.Material[context.RenderPass];
                Effect        effect = materialBinding.Effect;

                // Add this info to the render context. This info will be needed by parameter bindings.
                context.SceneNode = node;
                context.MaterialInstanceBinding = materialInstanceBinding;
                context.MaterialBinding         = materialBinding;

                // Update and apply global effect parameter bindings - these bindings set the
                // effect parameter values for "global" parameters. For example, if an effect uses
                // a "ViewProjection" parameter, then a binding will compute this matrix from the
                // current CameraInstance in the render context and update the effect parameter.
                foreach (var binding in effect.GetParameterBindings())
                {
                    if (binding.Description.Hint == EffectParameterHint.Global)
                    {
                        binding.Update(context);
                        binding.Apply(context);
                    }
                }

                // Update and apply material bindings - these are usually constant parameter values,
                // like textures or colors, that are defined in the fbx file or material description
                // (XML files).
                //SetHoleParameter(materialBinding, context);
                foreach (var binding in materialBinding.ParameterBindings)
                {
                    binding.Update(context);
                    binding.Apply(context);
                }

                // Update and apply local, per-instance, and per-pass bindings - these are bindings
                // for parameters, like the "World" matrix or lighting parameters.
                foreach (var binding in materialInstanceBinding.ParameterBindings)
                {
                    if (binding.Description.Hint != EffectParameterHint.PerPass)
                    {
                        binding.Update(context);
                        binding.Apply(context);
                    }
                }

                // Select and apply technique.
                var techniqueBinding = materialInstanceBinding.TechniqueBinding;
                techniqueBinding.Update(context);
                var technique = techniqueBinding.GetTechnique(effect, context);
                effect.CurrentTechnique = technique;

                var passBinding = techniqueBinding.GetPassBinding(technique, context);
                foreach (var pass in passBinding)
                {
                    // Update and apply per-pass bindings.
                    foreach (var binding in materialInstanceBinding.ParameterBindings)
                    {
                        if (binding.Description.Hint == EffectParameterHint.PerPass)
                        {
                            binding.Update(context);
                            binding.Apply(context);
                        }
                    }

                    pass.Apply();

                    // The WireFrame pass is only rendered if DrawWireFrame is set.
                    if ((!string.Equals(pass.Name, "WireFrame", StringComparison.OrdinalIgnoreCase) || DrawWireFrame) &&
                        !string.Equals(pass.Name, "Restore", StringComparison.OrdinalIgnoreCase))
                    {
                        mesh.Submesh.Draw();
                    }
                }

                // Reset texture effect parameter:
                // This seems to be necessary because the vertex textures are not automatically
                // removed from the texture stage which causes exceptions later.
                ResetParameter(effect, "TerrainBaseClipmap0");
                ResetParameter(effect, "TerrainBaseClipmap1");
                ResetParameter(effect, "TerrainBaseClipmap2");
                ResetParameter(effect, "TerrainBaseClipmap3");
                foreach (var pass in passBinding)
                {
                    pass.Apply();
                    break;
                }
            }

            context.SceneNode               = null;
            context.MaterialBinding         = null;
            context.MaterialInstanceBinding = null;

            savedRenderState.Restore();
        }