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; }
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; }
/// <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); }
/// <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; }
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(); }
/// <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)); }
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); } } } } }
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; }
/// <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); }
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."); }
// 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); }