Example #1
0
        /// <summary>
        /// Creates a new instance of the <see cref="EffectBinding"/> class for a material instance.
        /// </summary>
        internal EffectBinding CreateMaterialInstance()
        {
            Debug.Assert(Hints == EffectParameterHint.Material, "EffectBinding for material expected.");

            // Note: The EffectBinding used in a Material can be a special binding, such as
            // BasicEffectBinding. The EffectBinding used in the MaterialInstance is not a
            // clone of the BasicEffectBinding, instead it is a normal EffectBinding.

            // A material instance may contain all parameters, except global and material settings.
            const EffectParameterHint hints = EffectParameterHint.Local
                                              | EffectParameterHint.PerInstance
                                              | EffectParameterHint.PerPass;

            var effectBinding = new EffectBinding
            {
                EffectEx          = EffectEx,
                MaterialBinding   = this,
                TechniqueBinding  = TechniqueBinding.Clone(),
                ParameterBindings = new EffectParameterBindingCollection(hints),
                OpaqueData        = OpaqueData,
            };

            // Copy all local, per-instance and per-pass bindings.
            foreach (var binding in EffectEx.ParameterBindings)
            {
                if ((binding.Description.Hint & hints) != 0)
                {
                    effectBinding.ParameterBindings.Add(binding.Clone());
                }
            }

            return(effectBinding);
        }
        /// <inheritdoc/>
        protected override void CloneCore(EffectBinding source)
        {
            // Clone EffectBinding properties.
            base.CloneCore(source);

            // Clone DualTextureEffectBinding properties.
            var sourceTyped = (DualTextureEffectBinding)source;

            VertexColorEnabled = sourceTyped.VertexColorEnabled;
        }
Example #3
0
        /// <inheritdoc/>
        protected override void CloneCore(EffectBinding source)
        {
            // Clone EffectBinding properties.
            base.CloneCore(source);

            // Clone SkinnedEffectBinding properties.
            var sourceTyped = (SkinnedEffectBinding)source;

            PreferPerPixelLighting = sourceTyped.PreferPerPixelLighting;
            WeightsPerVertex       = sourceTyped.WeightsPerVertex;
        }
        /// <inheritdoc/>
        protected override void CloneCore(EffectBinding source)
        {
            // Clone EffectBinding properties.
            base.CloneCore(source);

            // Clone AlphaTestEffectBinding properties.
            var sourceTyped = (AlphaTestEffectBinding)source;

            AlphaFunction      = sourceTyped.AlphaFunction;
            ReferenceAlpha     = sourceTyped.ReferenceAlpha;
            VertexColorEnabled = sourceTyped.VertexColorEnabled;
        }
        /// <inheritdoc/>
        protected override void CloneCore(EffectBinding source)
        {
            // Clone EffectBinding properties.
            base.CloneCore(source);

            // Clone BasicEffectBinding properties.
            var sourceTyped = (BasicEffectBinding)source;

            LightingEnabled        = sourceTyped.LightingEnabled;
            PreferPerPixelLighting = sourceTyped.PreferPerPixelLighting;
            TextureEnabled         = sourceTyped.TextureEnabled;
            VertexColorEnabled     = sourceTyped.VertexColorEnabled;
        }
        protected virtual void CloneCore(EffectBinding source)
        {
            EffectEx = source.EffectEx;
              MaterialBinding = source.MaterialBinding;
              // Note: MorphWeights need to be set by MeshNode.
              TechniqueBinding = source.TechniqueBinding.Clone();
              OpaqueData = source.OpaqueData;
              UserData = source.UserData;

              // Clone parameter bindings (deep copy).
              ParameterBindings = new EffectParameterBindingCollection(source.Hints);
              foreach (var binding in source.ParameterBindings)
            ParameterBindings.Add(binding.Clone());
        }
Example #7
0
        /// <summary>
        /// Initializes a new instance of the <see cref="TerrainClearLayer"/> class.
        /// </summary>
        /// <param name="graphicService">The graphic service.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="graphicService"/> is <see langword="null"/>.
        /// </exception>
        public TerrainClearLayer(IGraphicsService graphicService)
        {
            if (graphicService == null)
            throw new ArgumentNullException("graphicService");

              var effect = graphicService.Content.Load<Effect>("DigitalRune/Terrain/TerrainClearLayer");
              var effectBinding = new EffectBinding(graphicService, effect, null, EffectParameterHint.Material);
              Material = new Material
              {
            { "Base", effectBinding },
            { "Detail", effectBinding }
              };
              MaterialInstance = new MaterialInstance(Material);
        }
Example #8
0
        protected virtual void CloneCore(EffectBinding source)
        {
            EffectEx        = source.EffectEx;
            MaterialBinding = source.MaterialBinding;
            // Note: MorphWeights need to be set by MeshNode.
            TechniqueBinding = source.TechniqueBinding.Clone();
            OpaqueData       = source.OpaqueData;
            UserData         = source.UserData;

            // Clone parameter bindings (deep copy).
            ParameterBindings = new EffectParameterBindingCollection(source.Hints);
            foreach (var binding in source.ParameterBindings)
            {
                ParameterBindings.Add(binding.Clone());
            }
        }
        private void ProcessLayer(GraphicsDevice graphicsDevice, RenderContext context, TerrainClipmap clipmap, bool isBaseClipmap, IInternalTerrainLayer layer, Aabb tileAabb)
        {
            // The material needs to have a "Base" or "Detail" render pass.
              if (!layer.Material.Contains(context.RenderPass))
            return;

              var layerAabb = layer.Aabb ?? tileAabb;
              //if (!HaveContactXZ(ref layerAabb, ref clipmap.Aabb))
              //  continue;

              bool isInInvalidRegion = false;
              for (int level = clipmap.NumberOfLevels - 1; level >= 0; level--)
              {
            for (int i = 0; i < clipmap.InvalidRegions[level].Count; i++)
            {
              var aabb = clipmap.InvalidRegions[level][i];
              if (HaveContactXZ(ref layerAabb, ref aabb))
              {
            isInInvalidRegion = true;
            break;
              }
            }
            if (isInInvalidRegion)
              break;
              }

              if (!isInInvalidRegion)
            return;

              // Reset render state for each layer because layers are allowed to change render state
              // without restoring it in a restore pass.
              // The base clipmap uses no blending. The detail clipmap uses alpha-blending (but only in
              // RGB, A is not changed, A is used e.g. for hole info).
              graphicsDevice.BlendState = isBaseClipmap ? BlendState.Opaque : BlendStateAlphaBlendRgb;
              graphicsDevice.RasterizerState = RasterizerStateCullNoneWithScissorTest;
              graphicsDevice.DepthStencilState = DepthStencilState.None;

              #region ----- Effect binding updates -----

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

              context.MaterialInstanceBinding = materialInstanceBinding;
              context.MaterialBinding = materialBinding;

              if (effectEx.Id == 0)
              {
            effectEx.Id = 1;

            // 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.
              // If this material is the same as in the last ProcessLayer() call, then we can skip this.
              if (_previousMaterialBinding != materialBinding)
              {
            _previousMaterialBinding = materialBinding;

            if (materialBinding.Id == 0)
            {
              materialBinding.Id = 1;
              foreach (var binding in materialBinding.ParameterBindings)
              {
            binding.Update(context);
            binding.Apply(context);
              }
            }
            else
            {
              // The material has already been updated in this frame.
              foreach (var binding in materialBinding.ParameterBindings)
            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;
              #endregion

              int border = isBaseClipmap ? 0 : Border;

              // Region covered by the layer.
              Vector2F layerStart = new Vector2F(layerAabb.Minimum.X, layerAabb.Minimum.Z);
              Vector2F layerEnd = new Vector2F(layerAabb.Maximum.X, layerAabb.Maximum.Z);

              // Clamp to tile AABB
              layerStart.X = Math.Max(layerStart.X, tileAabb.Minimum.X);
              layerStart.Y = Math.Max(layerStart.Y, tileAabb.Minimum.Z);
              layerEnd.X = Math.Min(layerEnd.X, tileAabb.Maximum.X);
              layerEnd.Y = Math.Min(layerEnd.Y, tileAabb.Maximum.Z);

              // Loop over clipmap levels.
              for (int level = 0; level < clipmap.NumberOfLevels; level++)
              {
            // If there are no invalid regions, the combined AABB is NaN.
            if (Numeric.IsNaN(clipmap.CombinedInvalidRegionsAabbs[level].Minimum.X))
              continue;

            if (layer.FadeInStart > level || layer.FadeOutEnd <= level)
              continue;

            if (!HaveContactXZ(ref layerAabb, ref clipmap.CombinedInvalidRegionsAabbs[level]))
              continue;

            Vector2F levelOrigin = clipmap.Origins[level];
            Vector2F levelSize = new Vector2F(clipmap.LevelSizes[level]); // without border!
            Vector2F levelEnd = levelOrigin + levelSize;

            float cellsPerLevelWithoutBorder = clipmap.CellsPerLevel - 2 * border;
            float cellSize = clipmap.ActualCellSizes[level];
            float texelsPerUnit = 1 / cellSize;

            // Following effect parameters change per clipmap level:
            UpdateAndApplyParameter(materialBinding, "TerrainClipmapLevel", (float)level, context);
            UpdateAndApplyParameter(materialBinding, "TerrainClipmapCellSize", cellSize, context);

            // The rectangle of the whole clipmap level (including border).
            var levelRect = GetScreenSpaceRectangle(clipmap, level);

            // The pixel position of the offset.
            int offsetX = levelRect.X + border + (int)(cellsPerLevelWithoutBorder * clipmap.Offsets[level].X + 0.5f);
            int offsetY = levelRect.Y + border + (int)(cellsPerLevelWithoutBorder * clipmap.Offsets[level].Y + 0.5f);

            // Handle the 4 rectangles of the toroidally wrapped clipmap.
            bool applyPass = true;
            for (int i = 0; i < 4; i++)
            {
              Rectangle quadrantRect;
              Vector2F offsetPosition;
              switch (i)
              {
            case 0:
              // Top left rectangle.
              quadrantRect = new Rectangle(levelRect.X, levelRect.Y, offsetX - levelRect.X, offsetY - levelRect.Y);
              offsetPosition = levelEnd;
              break;
            case 1:
              // Top right rectangle.
              quadrantRect = new Rectangle(offsetX, levelRect.Y, levelRect.Right - offsetX, offsetY - levelRect.Y);
              offsetPosition.X = levelOrigin.X;
              offsetPosition.Y = levelEnd.Y;
              break;
            case 2:
              // Bottom left rectangle.
              quadrantRect = new Rectangle(levelRect.X, offsetY, offsetX - levelRect.X, levelRect.Bottom - offsetY);
              offsetPosition.X = levelEnd.X;
              offsetPosition.Y = levelOrigin.Y;
              break;
            default:
              // Bottom right rectangle.
              quadrantRect = new Rectangle(offsetX, offsetY, levelRect.Right - offsetX, levelRect.Bottom - offsetY);
              offsetPosition = levelOrigin;
              break;
              }

              if (quadrantRect.Width == 0 || quadrantRect.Height == 0)
            continue;

              applyPass |= UpdateAndApplyParameter(materialBinding, "TerrainClipmapOffsetWorld", (Vector2)offsetPosition, context);
              applyPass |= UpdateAndApplyParameter(materialBinding, "TerrainClipmapOffsetScreen", new Vector2(offsetX, offsetY), context);

              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);
                applyPass = true;
              }
            }

            if (applyPass)
            {
              pass.Apply();
              applyPass = false;
            }

            foreach (var aabb in clipmap.InvalidRegions[level])
            {
              // Intersect layer AABB with invalid region AABB.
              Vector2F clippedLayerStart, clippedLayerEnd;
              clippedLayerStart.X = Math.Max(layerStart.X, aabb.Minimum.X);
              clippedLayerStart.Y = Math.Max(layerStart.Y, aabb.Minimum.Z);
              clippedLayerEnd.X = Math.Min(layerEnd.X, aabb.Maximum.X);
              clippedLayerEnd.Y = Math.Min(layerEnd.Y, aabb.Maximum.Z);

              // Nothing to do if layer AABB does not intersect invalid region.
              if (clippedLayerStart.X >= clippedLayerEnd.X || clippedLayerStart.Y >= clippedLayerEnd.Y)
                continue;

              // Compute screen space rectangle of intersection (relative to toroidal offset).
              var invalidRect = GetScissorRectangle(
                clippedLayerStart - offsetPosition,
                clippedLayerEnd - clippedLayerStart,
                texelsPerUnit);

              // Add toroidal offset screen position.
              invalidRect.X += offsetX;
              invalidRect.Y += offsetY;

              // Set a scissor rectangle to avoid drawing outside the current toroidal wrap
              // part and outside the invalid region.
              var scissorRect = Rectangle.Intersect(quadrantRect, invalidRect);
              if (scissorRect.Width <= 0 || scissorRect.Height <= 0)
                continue;

              graphicsDevice.ScissorRectangle = scissorRect;

              // Compute world space position of scissor rectangle corners.
              Vector2F start, end;
              start.X = offsetPosition.X + (scissorRect.X - offsetX) * cellSize;
              start.Y = offsetPosition.Y + (scissorRect.Y - offsetY) * cellSize;
              end.X = offsetPosition.X + (scissorRect.Right - offsetX) * cellSize;
              end.Y = offsetPosition.Y + (scissorRect.Bottom - offsetY) * cellSize;

              Debug.Assert(Numeric.IsLessOrEqual(start.X, end.X));
              Debug.Assert(Numeric.IsLessOrEqual(start.Y, end.Y));

              layer.OnDraw(graphicsDevice, scissorRect, start, end);
            }
              }
            }
              }
        }
        private void ProcessClipmap(TerrainNode node, TerrainClipmap clipmap, RenderContext context)
        {
            var graphicsDevice = context.GraphicsService.GraphicsDevice;
              var lodCameraNode = context.LodCameraNode ?? context.CameraNode;

              bool isBaseClipmap = (node.BaseClipmap == clipmap);

              // Update the clipmap render targets if necessary.
              InitializeClipmapTextures(graphicsDevice, clipmap);

              // Update other clipmap data (origins, offsets, ...). No rendering.
              // (Data is stored in TerrainClipmap class.)
              UpdateClipmapData(node, clipmap, lodCameraNode, isBaseClipmap);

              // Compute which rectangular regions need to be updated.
              // (Data is stored in TerrainClipmap class.)
              ComputeInvalidRegions(node, clipmap, isBaseClipmap);

              // Abort if there are no invalid regions.
              int numberOfInvalidRegions = 0;
              for (int level = 0; level < clipmap.NumberOfLevels; level++)
            numberOfInvalidRegions += clipmap.InvalidRegions[level].Count;

              Debug.Assert(numberOfInvalidRegions > 0 || clipmap.UseIncrementalUpdate,
            "If the clipmap update is not incremental, there must be at least one invalid region.");

              if (numberOfInvalidRegions == 0)
            return;

              // Set render target binding to render into all clipmap textures at once.
              int numberOfTextures = clipmap.Textures.Length;
              if (_renderTargetBindings[numberOfTextures] == null)
            _renderTargetBindings[numberOfTextures] = new RenderTargetBinding[numberOfTextures];

              for (int i = 0; i < numberOfTextures; i++)
            _renderTargetBindings[numberOfTextures][i] = new RenderTargetBinding((RenderTarget2D)clipmap.Textures[i]);

              switch (numberOfTextures)
              {
            case 1: context.Technique = "RenderTargets1"; break;
            case 2: context.Technique = "RenderTargets2"; break;
            case 3: context.Technique = "RenderTargets3"; break;
            case 4: context.Technique = "RenderTargets4"; break;
            default: context.Technique = null; break;
              }

              graphicsDevice.SetRenderTargets(_renderTargetBindings[numberOfTextures]);

              // The viewport covers the whole texture atlas.
              var viewport = graphicsDevice.Viewport;
              context.Viewport = viewport;

              Debug.Assert(_previousMaterialBinding == null);

              // Loop over all layers. Render each layer into all levels (if there is an invalid region).
              Aabb tileAabb = new Aabb(new Vector3F(-Terrain.TerrainLimit), new Vector3F(Terrain.TerrainLimit));
              ProcessLayer(graphicsDevice, context, clipmap, isBaseClipmap, _clearLayer, tileAabb);
              foreach (var tile in node.Terrain.Tiles)
              {
            tileAabb = tile.Aabb;
            context.Object = tile;
            ProcessLayer(graphicsDevice, context, clipmap, isBaseClipmap, tile, tileAabb);

            foreach (var layer in tile.Layers)
              ProcessLayer(graphicsDevice, context, clipmap, isBaseClipmap, layer, tileAabb);

            context.Object = null;
              }

              _previousMaterialBinding = null;

              ClearFlags(_clearLayer, context);
              foreach (var tile in node.Terrain.Tiles)
              {
            ClearFlags(tile, context);
            foreach (var layer in tile.Layers)
              ClearFlags(layer, context);
              }

              // All invalid regions handled.
              for (int i = 0; i < clipmap.NumberOfLevels; i++)
            clipmap.InvalidRegions[i].Clear();

              // The next time we can update incrementally.
              clipmap.UseIncrementalUpdate = true;
        }
Example #11
0
 //--------------------------------------------------------------
 /// <summary>
 /// Initializes a new instance of the <see cref="EffectPostProcessor"/> class.
 /// </summary>
 /// <param name="graphicsService">The graphics service.</param>
 /// <param name="effect">The effect.</param>
 /// <exception cref="ArgumentNullException">
 /// <paramref name="graphicsService"/> or <paramref name="effect"/> is <see langword="null"/>.
 /// </exception>
 public EffectPostProcessor(IGraphicsService graphicsService, Effect effect)
     : base(graphicsService)
 {
     EffectBinding = new EffectBinding(graphicsService, effect);
 }
Example #12
0
        /// <summary>
        /// Creates a new instance of the <see cref="EffectBinding"/> class for a material instance.
        /// </summary>
        internal EffectBinding CreateMaterialInstance()
        {
            Debug.Assert(Hints == EffectParameterHint.Material, "EffectBinding for material expected.");

              // Note: The EffectBinding used in a Material can be a special binding, such as
              // BasicEffectBinding. The EffectBinding used in the MaterialInstance is not a
              // clone of the BasicEffectBinding, instead it is a normal EffectBinding.

              // A material instance may contain all parameters, except global and material settings.
              const EffectParameterHint hints = EffectParameterHint.Local
                                        | EffectParameterHint.PerInstance
                                        | EffectParameterHint.PerPass;

              var effectBinding = new EffectBinding
              {
            EffectEx = EffectEx,
            MaterialBinding = this,
            TechniqueBinding = TechniqueBinding.Clone(),
            ParameterBindings = new EffectParameterBindingCollection(hints),
            OpaqueData = OpaqueData,
              };

              // Copy all local, per-instance and per-pass bindings.
              foreach (var binding in EffectEx.ParameterBindings)
            if ((binding.Description.Hint & hints) != 0)
              effectBinding.ParameterBindings.Add(binding.Clone());

              return effectBinding;
        }