예제 #1
0
    private static void ResetMaterialId(EffectBinding materialBinding)
    {
      Debug.Assert(
        materialBinding.MaterialBinding == null,
        "The specified binding needs to be a material binding, not a material instance binding.");

      materialBinding.Id = 0;
    }
    private static bool UpdateAndApplyParameter<T>(EffectBinding effectBinding, string name, T value, RenderContext context)
    {
      var parameterBinding = effectBinding.ParameterBindings[name] as ConstParameterBinding<T>;
      if (parameterBinding != null)
      {
        parameterBinding.Value = value;
        parameterBinding.Update(context);
        parameterBinding.Apply(context);
        return true;
      }

      return false;
    }
예제 #3
0
    private static uint GetMaterialId(EffectBinding materialInstanceBinding)
    {
      Debug.Assert(
        materialInstanceBinding.MaterialBinding != null,
        "The specified binding is not a material instance binding.");

      var materialBinding = materialInstanceBinding.MaterialBinding;
      if (materialBinding.Id == 0)
      {
        var effectEx = materialBinding.EffectEx;
        effectEx.BindingCount++;
        materialBinding.Id = effectEx.BindingCount;
      }

      return materialBinding.Id;
    }
예제 #4
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);
        }
예제 #5
0
    /// <summary>
    /// Gets the material key for sorting draw jobs.
    /// </summary>
    /// <param name="materialInstanceBinding">The effect binding of a material instance.</param>
    /// <returns>The material key.</returns>
    private uint GetMaterialKey(EffectBinding materialInstanceBinding)
    {
      Debug.Assert(
        materialInstanceBinding.MaterialBinding != null,
        "The specified binding is not a material instance binding.");

      // ----------------------------------------------------
      // |   effect ID   |   material ID   |  technique ID  |
      // |    12 bit     |    12 bit       |   8 bit        |
      // ----------------------------------------------------

      uint effectId = GetEffectId(materialInstanceBinding.EffectEx);
      uint materialId = GetMaterialId(materialInstanceBinding);
      byte techniqueId = materialInstanceBinding.TechniqueBinding.Id;

      Debug.Assert(effectId <= 0xfff, "Max number of effect per render call exceeded.");
      Debug.Assert(materialId <= 0xfff, "Max number of materials per render call exceeded.");
      Debug.Assert(techniqueId <= 0xff, "Max number of techniques per render call exceeded.");

      return (effectId & 0xfff) << 20
             | (materialId & 0xfff) << 8
             | techniqueId;
    }
예제 #6
0
    private void ProcessJobs(RenderContext context, RenderOrder order)
    {
      Effect currentEffect = null;
      EffectEx currentEffectEx = null;
      EffectBinding currentMaterialBinding = null;

      // Set render states for drawing decals.
      var graphicsDevice = context.GraphicsService.GraphicsDevice;
      var savedRenderState = new RenderStateSnapshot(graphicsDevice);

      graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
      graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;

      if (!ClipAtNearPlane)
      {
        // Cache some info for near plane intersection tests.

        var cameraNode = context.CameraNode;
        var cameraPose = cameraNode.PoseWorld;
        var projection = cameraNode.Camera.Projection;

        // Get min and max of near plane AABB in view space.
        var min = new Vector3(projection.Left, projection.Bottom, -projection.Near);
        var max = new Vector3(projection.Right, projection.Top, -projection.Near);

        // Convert min and max to world space.
        min = cameraPose.ToWorldPosition(min);
        max = cameraPose.ToWorldPosition(max);

        // Get world space aabb
        _cameraNearPlaneAabbWorld = new Aabb(Vector3.Min(min, max), Vector3.Max(min, max));
      }

      // The BlendState is set below.
      bool isGBufferPass = string.Equals(context.RenderPass, "GBuffer", StringComparison.OrdinalIgnoreCase);  // InvariantCultureIgnoreCase would be better but is not available in WindowsStore.
      var blendState = isGBufferPass ? GBufferBlendState : BlendState.AlphaBlend;

      int index = 0;
      var jobs = _jobs.Array;
      int jobCount = _jobs.Count;
      while (index < jobCount)
      {
        // Update BlendState. (Needs to be done for each batch because decals can
        // change the blend mode in the material. For example, alpha-tested decals 
        // can disable alpha blending.)
        graphicsDevice.BlendState = blendState;

        uint materialKey = jobs[index].MaterialKey;
        var materialInstanceBinding = jobs[index].MaterialInstanceBinding;
        var materialBinding = materialInstanceBinding.MaterialBinding;
        var effectEx = materialBinding.EffectEx;

        Debug.Assert(effectEx != null, "EffectEx must not be null.");

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

        if (currentEffectEx != effectEx)
        {
          // ----- Next effect.
          currentEffectEx = effectEx;
          currentEffect = effectEx.Resource;

          // Reset ID. (Only used during state sorting.)
          ResetEffectId(effectEx);

          // Update and apply global bindings.
          foreach (var binding in currentEffectEx.ParameterBindings)
          {
            if (binding.Description.Hint == EffectParameterHint.Global)
            {
              binding.Update(context);
              binding.Apply(context);
            }
          }
        }

        if (currentMaterialBinding != materialBinding)
        {
          // ----- Next material.
          currentMaterialBinding = materialBinding;

          // Reset ID. (Only used during state sorting.)
          ResetMaterialId(materialBinding);

          // Update and apply material bindings.
          foreach (var binding in currentMaterialBinding.ParameterBindings)
          {
            binding.Update(context);
            binding.Apply(context);

            // In "GBuffer" pass the specular power is written to the alpha channel.
            // The specular power needs to be set as the BlendFactor. (See GBufferBlendState.)
            if (isGBufferPass && binding.Description.Semantic == DefaultEffectParameterSemantics.SpecularPower)
            {
              var specularPowerBinding = binding as EffectParameterBinding<float>;
              if (specularPowerBinding != null)
              {
                // Note: Specular power is currently encoded using log2 - see Deferred.fxh.
                // (Blending encoded values is mathematically not correct, but there are no
                // rules for blending specular powers anyway.)
                float specularPower = specularPowerBinding.Value;
                int encodedSpecularPower = (byte)((float)Math.Log(specularPower + 0.0001f, 2) / 17.6f * 255.0f);
                graphicsDevice.BlendFactor = new Color(255, 255, 255, encodedSpecularPower);
              }
            }
          }
        }

        // Note: EffectTechniqueBinding only returns the EffectTechnique, but does 
        // not set it as the current technique.
        var techniqueBinding = materialInstanceBinding.TechniqueBinding;
        var technique = techniqueBinding.GetTechnique(currentEffect, context);

        // See if there is an associated technique that supports hardware instancing.
        //var instancingTechnique = (EffectTechnique)null;
        //var techniqueDescription = currentEffectEx.TechniqueDescriptions[technique];
        //if (techniqueDescription != null)
        //  instancingTechnique = techniqueDescription.InstancingTechnique;

        //if (EnableInstancing && instancingTechnique != null)
        //{
        //  // ----- Instancing
        //  // Render all decals that share the same effect/material and batch instances 
        //  // into a single draw call.
        //  int count = 1;
        //  while (index + count < jobCount && jobs[index + count].MaterialKey == materialKey)
        //    count++;

        //  if (count >= InstancingThreshold)
        //  {
        //    // Draw decals using instancing.
        //    currentEffect.CurrentTechnique = instancingTechnique;
        //    var passBinding = techniqueBinding.GetPassBinding(instancingTechnique, context);
        //    DrawInstanced(ref passBinding, context, index, count);
        //    index += count;
        //  }
        //  else
        //  {
        //    // Draw decals without instancing.
        //    currentEffect.CurrentTechnique = technique;
        //    var passBinding = techniqueBinding.GetPassBinding(technique, context);
        //    Draw(ref passBinding, context, index, count, order);
        //    index += count;
        //  }
        //}
        //else
        {
          // ----- No instancing

          // Render all decals that share the same effect/material.
          int count = 1;
          while (index + count < jobCount && jobs[index + count].MaterialKey == materialKey)
            count++;

          currentEffect.CurrentTechnique = technique;
          var passBinding = techniqueBinding.GetPassBinding(technique, context);
          Draw(ref passBinding, context, index, count, order);
          index += count;
        }
      }

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

      savedRenderState.Restore();
    }
예제 #7
0
        /// <summary>
        /// Creates a graphics mesh with the triangle mesh data of the given shape and the given
        /// diffuse and specular material properties.
        /// </summary>
        /// <param name="contentManager">The contentManager manager.</param>
        /// <param name="graphicsService">The graphics service.</param>
        /// <param name="submesh">The submesh.</param>
        /// <param name="diffuse">The diffuse material color.</param>
        /// <param name="specular">The specular material color.</param>
        /// <param name="specularPower">The specular power of the material.</param>
        /// <returns>The graphics mesh.</returns>
        /// <remarks>
        /// This method does not set the bounding shape of the mesh. (The default is an infinite shape
        /// which is not optimal for performance.)
        /// </remarks>
        public static Mesh CreateMesh(ContentManager contentManager, IGraphicsService graphicsService, Submesh submesh,
                                      Vector3 diffuse, Vector3 specular, float specularPower)
        {
            Mesh mesh = new Mesh();

            mesh.Submeshes.Add(submesh);

            // Build material.
            // We could load a predefined material (*.drmat file)
            // with the content manager.
            //var material = contentManager.Load<Material>("MyMaterialName");

            // Alternatively, we can load some effects and build the material here:
            Material material = new Material();

            // We need an EffectBinding for each render pass.
            // The "Default" pass uses a BasicEffectBinding (which is an EffectBinding
            // for the XNA BasicEffect).
            // Note: The "Default" pass is not used by the DeferredLightingScreen, so
            // we could ignore this pass in this sample project.
            BasicEffectBinding defaultEffectBinding = new BasicEffectBinding(graphicsService, null)
            {
                LightingEnabled    = true,
                TextureEnabled     = true,
                VertexColorEnabled = false
            };

            defaultEffectBinding.Set("Texture", graphicsService.GetDefaultTexture2DWhite());
            defaultEffectBinding.Set("DiffuseColor", new Vector4((Vector3)diffuse, 1));
            defaultEffectBinding.Set("SpecularColor", (Vector3)specular);
            defaultEffectBinding.Set("SpecularPower", specularPower);
            material.Add("Default", defaultEffectBinding);

            // EffectBinding for the "ShadowMap" pass.
            // Note: EffectBindings which are used in a Material must be marked with
            // the EffectParameterHint Material.
            EffectBinding shadowMapEffectBinding = new EffectBinding(
                graphicsService,
                contentManager.Load <Effect>("DigitalRune\\Materials\\ShadowMap"),
                null,
                EffectParameterHint.Material);

            material.Add("ShadowMap", shadowMapEffectBinding);

            // EffectBinding for the "GBuffer" pass.
            EffectBinding gBufferEffectBinding = new EffectBinding(
                graphicsService,
                contentManager.Load <Effect>("DigitalRune\\Materials\\GBuffer"),
                null,
                EffectParameterHint.Material);

            gBufferEffectBinding.Set("SpecularPower", specularPower);
            material.Add("GBuffer", gBufferEffectBinding);

            // EffectBinding for the "Material" pass.
            EffectBinding materialEffectBinding = new EffectBinding(
                graphicsService,
                contentManager.Load <Effect>("DigitalRune\\Materials\\Material"),
                null,
                EffectParameterHint.Material);

            materialEffectBinding.Set("DiffuseTexture", graphicsService.GetDefaultTexture2DWhite());
            materialEffectBinding.Set("DiffuseColor", (Vector3)diffuse);
            materialEffectBinding.Set("SpecularColor", (Vector3)specular);
            material.Add("Material", materialEffectBinding);

            // Assign this material to the submesh.
            submesh.SetMaterial(material);

            return(mesh);
        }
 bool IDictionary <string, EffectBinding> .TryGetValue(string key, out EffectBinding value)
 {
     return(_bindingsPerPass.TryGetValue(key, out value));
 }
예제 #9
0
        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;



            // 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;


            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);
                        }
                    }
                }
            }
        }
예제 #10
0
        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 Vector3(-Terrain.TerrainLimit), new Vector3(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;
        }
예제 #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);
 }
예제 #12
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();
        }
 void IDictionary <string, EffectBinding> .Add(string key, EffectBinding value)
 {
     throw new NotSupportedException("The MaterialInstance is a read-only collection.");
 }
예제 #14
0
        // OnLoad() is called when the GameObject is added to the IGameObjectService.
        protected override void OnLoad()
        {
            var graphicsService   = _services.GetInstance <IGraphicsService>();
            var gameObjectService = _services.GetInstance <IGameObjectService>();

            // Check if the game object manager has another ProceduralObject instance.
            var otherProceduralObject = gameObjectService.Objects
                                        .OfType <ProceduralObject>()
                                        .FirstOrDefault(o => o != this);
            Mesh mesh;

            if (otherProceduralObject != null)
            {
                // This ProceduralObject is not the first. We re-use rigid body data and
                // the mesh from the existing instance.
                var otherBody = otherProceduralObject._rigidBody;
                _rigidBody = new RigidBody(otherBody.Shape, otherBody.MassFrame, otherBody.Material);
                mesh       = otherProceduralObject._meshNode.Mesh;
            }
            else
            {
                // This is the first ProceduralObject instance. We create a new rigid body
                // and a new mesh.
                var shape = new MinkowskiSumShape(new GeometricObject(new SphereShape(0.05f)), new GeometricObject(new BoxShape(0.5f, 0.5f, 0.5f)));
                _rigidBody = new RigidBody(shape);

                // Create a DigitalRune.Geometry.Meshes.TriangleMesh from the RigidBody's
                // shape and convert this to a DigitalRune.Graphics.Mesh.
                var triangleMesh = _rigidBody.Shape.GetMesh(0.01f, 4);
                mesh = new Mesh {
                    Name = "ProceduralObject"
                };
                var submesh = CreateSubmeshWithTexCoords(graphicsService.GraphicsDevice, triangleMesh, MathHelper.ToRadians(70));
                mesh.Submeshes.Add(submesh);

                // Next, we need a material. We can load a predefined material (*.drmat file)
                // with the content manager.
                //var material = content.Load<Material>("Default");

                // Alternatively, we can load some effects and build the material here:
                Material material = new Material();

                // We need an EffectBinding for each render pass.
                // The "Default" pass uses a BasicEffectBinding (which is an EffectBinding
                // for the XNA BasicEffect).
                // Note: The "Default" pass is not used by the DeferredLightingScreen, so
                // we could ignore this pass in this sample project.
                BasicEffectBinding defaultEffectBinding = new BasicEffectBinding(graphicsService, null)
                {
                    LightingEnabled    = true,
                    TextureEnabled     = true,
                    VertexColorEnabled = false
                };
                defaultEffectBinding.Set("Texture", graphicsService.GetDefaultTexture2DWhite());
                defaultEffectBinding.Set("DiffuseColor", new Vector3(1, 1, 1));
                defaultEffectBinding.Set("SpecularColor", new Vector3(1, 1, 1));
                defaultEffectBinding.Set("SpecularPower", 100f);
                material.Add("Default", defaultEffectBinding);

                // EffectBinding for the "ShadowMap" pass.
                // Note: EffectBindings which are used in a Material must be marked with
                // the EffectParameterHint Material.
                var           content = _services.GetInstance <ContentManager>();
                EffectBinding shadowMapEffectBinding = new EffectBinding(
                    graphicsService,
                    content.Load <Effect>("DigitalRune\\Materials\\ShadowMap"),
                    null,
                    EffectParameterHint.Material);
                material.Add("ShadowMap", shadowMapEffectBinding);

                // EffectBinding for the "GBuffer" pass.
                EffectBinding gBufferEffectBinding = new EffectBinding(
                    graphicsService,
                    content.Load <Effect>("DigitalRune\\Materials\\GBuffer"),
                    null,
                    EffectParameterHint.Material);
                gBufferEffectBinding.Set("SpecularPower", 100f);
                material.Add("GBuffer", gBufferEffectBinding);

                // EffectBinding for the "Material" pass.
                EffectBinding materialEffectBinding = new EffectBinding(
                    graphicsService,
                    content.Load <Effect>("DigitalRune\\Materials\\Material"),
                    null,
                    EffectParameterHint.Material);
                materialEffectBinding.Set("DiffuseTexture", graphicsService.GetDefaultTexture2DWhite());
                materialEffectBinding.Set("DiffuseColor", new Vector3(1, 1, 1));
                materialEffectBinding.Set("SpecularColor", new Vector3(1, 1, 1));
                material.Add("Material", materialEffectBinding);

                // Assign this material to the submesh.
                submesh.SetMaterial(material);
            }

            // Create a scene graph node for the mesh.
            _meshNode = new MeshNode(mesh);

            // 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());
            _meshNode.PoseWorld = _rigidBody.Pose;

            // Add mesh node to scene graph.
            var scene = _services.GetInstance <IScene>();

            scene.Children.Add(_meshNode);

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

            simulation.RigidBodies.Add(_rigidBody);
        }