protected override void DrawCore(RenderContext context, RenderFrame output) { var input = Input.GetSafeRenderFrame(context); // If RenderFrame input or output are null, we can't do anything if (input == null) { return; } // If an effect is set, we are using it if (Effect != null) { Effect.SetInput(0, input); if (input.DepthStencil != null) { Effect.SetInput(1, input.DepthStencil); } Effect.SetOutput(output); Effect.Draw(context); } else if (input != output) { // Else only use a scaler if input and output don't match // TODO: Is this something we want by default or we just don't output anything? var effect = context.GetSharedEffect<ImageScaler>(); effect.SetInput(0, input); effect.SetOutput(output); effect.Draw(context); } }
protected override void DrawCore(RenderContext context, RenderFrame output) { var graphicsDevice = context.GraphicsDevice; // clear the targets if (output.DepthStencil != null && (ClearFlags == ClearRenderFrameFlags.ColorAndDepth || ClearFlags == ClearRenderFrameFlags.DepthOnly)) { const DepthStencilClearOptions ClearOptions = DepthStencilClearOptions.DepthBuffer | DepthStencilClearOptions.Stencil; graphicsDevice.Clear(output.DepthStencil, ClearOptions, Depth, Stencil); } if (ClearFlags == ClearRenderFrameFlags.ColorAndDepth || ClearFlags == ClearRenderFrameFlags.ColorOnly) { foreach (var renderTarget in output.RenderTargets) { if (renderTarget != null) { // If color is in GammeSpace and rendertarget is either SRgb or HDR, use a linear value to clear the buffer. // TODO: We will need to move this color transform code to a shareable component var color = Color.ToColorSpace(ColorSpace, (renderTarget.Format.IsSRgb() || renderTarget.Format.IsHDR()) ? ColorSpace.Linear : graphicsDevice.ColorSpace); graphicsDevice.Clear(renderTarget, color); } } } }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { var graphicsDevice = context.GraphicsDevice; var destination = new RectangleF(0, 0, 1, 1); // find the last background to display with valid texture BackgroundComponent background = null; for (var i = toIndex; i >= fromIndex; --i) { background = (BackgroundComponent)renderItems[i].DrawContext; if (background.Texture != null) break; } // Abort if not valid background component if (background == null || background.Texture == null) return; var texture = background.Texture; var target = CurrentRenderFrame; var imageBufferMinRatio = Math.Min(texture.ViewWidth / (float)target.Width, texture.ViewHeight / (float)target.Height); var sourceSize = new Vector2(target.Width * imageBufferMinRatio, target.Height * imageBufferMinRatio); var source = new RectangleF((texture.ViewWidth - sourceSize.X) / 2, (texture.ViewHeight - sourceSize.Y) / 2, sourceSize.X, sourceSize.Y); spriteBatch.Parameters.Add(BackgroundEffectKeys.Intensity, background.Intensity); spriteBatch.Begin(SpriteSortMode.FrontToBack, graphicsDevice.BlendStates.Opaque, graphicsDevice.SamplerStates.LinearClamp, graphicsDevice.DepthStencilStates.None, null, backgroundEffect); spriteBatch.Draw(texture, destination, source, Color.White, 0, Vector2.Zero); spriteBatch.End(); }
protected override void LoadContent() { var assetManager = Services.GetSafeServiceAs<ContentManager>(); var graphicsContext = Services.GetSafeServiceAs<GraphicsContext>(); // Preload the scene if it exists if (InitialSceneUrl != null && assetManager.Exists(InitialSceneUrl)) { SceneInstance = new SceneInstance(Services, assetManager.Load<Scene>(InitialSceneUrl)); } if (MainRenderFrame == null) { // TODO GRAPHICS REFACTOR Check if this is a good idea to use Presenter targets MainRenderFrame = RenderFrame.FromTexture(GraphicsDevice.Presenter?.BackBuffer, GraphicsDevice.Presenter?.DepthStencilBuffer); if (MainRenderFrame != null) { previousWidth = MainRenderFrame.Width; previousHeight = MainRenderFrame.Height; } } // Create the drawing context renderContext = RenderContext.GetShared(Services); renderDrawContext = new RenderDrawContext(Services, renderContext, graphicsContext); }
public static void UpdateParameters(RenderContext context, CameraComponent camera) { if (camera == null) throw new ArgumentNullException("camera"); // Setup viewport size var currentViewport = context.GraphicsDevice.Viewport; var aspectRatio = currentViewport.AspectRatio; // Update the aspect ratio if (camera.UseCustomAspectRatio) { aspectRatio = camera.AspectRatio; } // If the aspect ratio is calculated automatically from the current viewport, update matrices here camera.Update(aspectRatio); // Store the current view/projection matrix in the context var viewParameters = context.Parameters; viewParameters.Set(TransformationKeys.View, camera.ViewMatrix); viewParameters.Set(TransformationKeys.Projection, camera.ProjectionMatrix); viewParameters.Set(TransformationKeys.ViewProjection, camera.ViewProjectionMatrix); viewParameters.Set(CameraKeys.NearClipPlane, camera.NearClipPlane); viewParameters.Set(CameraKeys.FarClipPlane, camera.FarClipPlane); viewParameters.Set(CameraKeys.VerticalFieldOfView, camera.VerticalFieldOfView); viewParameters.Set(CameraKeys.OrthoSize, camera.OrthographicSize); viewParameters.Set(CameraKeys.ViewSize, new Vector2(currentViewport.Width, currentViewport.Height)); viewParameters.Set(CameraKeys.AspectRatio, aspectRatio); //viewParameters.Set(CameraKeys.FocusDistance, camera.FocusDistance); }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { if (lightComponentForwardRenderer != null) { lightComponentForwardRenderer.Draw(context); } }
public static void UpdateCameraToRenderView(RenderContext context, RenderView renderView) { var camera = context.Tags.Get(CameraComponentRendererExtensions.Current); var sceneCameraRenderer = context.Tags.Get(SceneCameraRenderer.Current); if (camera == null || sceneCameraRenderer == null) return; // Setup viewport size var currentViewport = sceneCameraRenderer.ComputedViewport; var aspectRatio = currentViewport.AspectRatio; // Update the aspect ratio if (camera.UseCustomAspectRatio) { aspectRatio = camera.AspectRatio; } // If the aspect ratio is calculated automatically from the current viewport, update matrices here camera.Update(aspectRatio); // Copy camera data renderView.View = camera.ViewMatrix; renderView.Projection = camera.ProjectionMatrix; renderView.NearClipPlane = camera.NearClipPlane; renderView.FarClipPlane = camera.FarClipPlane; renderView.Frustum = camera.Frustum; // Copy scene camera renderer data renderView.CullingMask = sceneCameraRenderer.CullingMask; renderView.CullingMode = sceneCameraRenderer.CullingMode; renderView.ViewSize = new Vector2(sceneCameraRenderer.ComputedViewport.Width, sceneCameraRenderer.ComputedViewport.Height); Matrix.Multiply(ref renderView.View, ref renderView.Projection, out renderView.ViewProjection); }
public void ClearRenderTarget(RenderContext context) { if (!IsRenderTargetCleared) { context.GraphicsDevice.Clear(Texture, DepthStencilClearOptions.DepthBuffer); IsRenderTargetCleared = true; } }
/// <summary> /// Setups the current material using the graphics device. /// </summary> /// <param name="graphicsDevice">Graphics device to setup</param> /// <param name="viewMatrix">The camera's View matrix</param> /// <param name="projMatrix">The camera's Projection matrix</param> public virtual void Setup(RenderContext context) { if (!IsInitialized) { InitializeCore(context); IsInitialized = true; } }
/// <summary> /// Activates the output to the current <see cref="GraphicsDevice"/>. /// </summary> /// <param name="context">The context.</param> /// <param name="disableDepth">if set to <c>true</c> [disable depth].</param> public void ActivateOutput(RenderContext context, bool disableDepth = false) { var output = GetOutput(context); if (output != null) { ActivateOutputCore(context, output, disableDepth); } }
public void Draw(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { if (Enabled) { PreDrawCoreInternal(context); DrawCore(context, renderItems, fromIndex, toIndex); PostDrawCoreInternal(context); } }
/// <summary> /// Draws this renderer with the specified context. /// </summary> /// <param name="context">The context.</param> /// <exception cref="System.ArgumentNullException">context</exception> /// <exception cref="System.InvalidOperationException">Cannot use a different context between Load and Draw</exception> public void Draw(RenderContext context) { if (Enabled) { PreDrawCoreInternal(context); DrawCore(context); PostDrawCoreInternal(context); } }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { var cameraState = context.GetCurrentCamera(); if (cameraState == null) return; UpdateParameters(context, cameraState); }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { skyboxProcessor = SceneInstance.GetProcessor<SkyboxProcessor>(); if (skyboxProcessor == null) { return; } var skybox = skyboxProcessor.ActiveSkyboxBackground; // do not draw if no active skybox or the skybox is not included in the current entity group if (skybox == null || !CurrentCullingMask.Contains(skybox.Entity.Group)) return; // Copy camera/pass parameters context.Parameters.CopySharedTo(skyboxEffect.Parameters); // Show irradiance in the background if (skybox.Background == SkyboxBackground.Irradiance) { foreach (var parameterKeyValue in skybox.Skybox.DiffuseLightingParameters) { if (parameterKeyValue.Key == SkyboxKeys.Shader) { skyboxEffect.Parameters.Set(SkyboxKeys.Shader, (ShaderSource)parameterKeyValue.Value); } else { skyboxEffect.Parameters.SetObject(parameterKeyValue.Key.ComposeWith("skyboxColor"), parameterKeyValue.Value); } } } else { // TODO: Should we better use composition on "skyboxColor" for parameters? // Copy Skybox parameters if (skybox.Skybox != null) { foreach (var parameterKeyValue in skybox.Skybox.Parameters) { if (parameterKeyValue.Key == SkyboxKeys.Shader) { skyboxEffect.Parameters.Set(SkyboxKeys.Shader, (ShaderSource)parameterKeyValue.Value); } else { skyboxEffect.Parameters.SetObject(parameterKeyValue.Key, parameterKeyValue.Value); } } } } // Fake as the skybox was in front of all others (as opaque are rendered back to front) opaqueList.Add(new RenderItem(this, skybox, float.NegativeInfinity)); }
protected override void DrawCore(RenderContext context) { // TODO: Find a better extensibility point for PixelStageSurfaceFilter var currentFilter = context.Parameters.Get(MaterialKeys.PixelStageSurfaceFilter); if (!ReferenceEquals(currentFilter, MaterialFilter)) { context.Parameters.Set(MaterialKeys.PixelStageSurfaceFilter, MaterialFilter); } base.DrawCore(context); }
public override void Collect(RenderContext context) { base.Collect(context); // Update view parameters UpdateCameraToRenderView(context, MainRenderView); // Collect render objects var visibilityGroup = context.Tags.Get(SceneInstance.CurrentVisibilityGroup); visibilityGroup.Collect(MainRenderView); }
protected override async Task LoadContent() { await base.LoadContent(); hdrTexture = Content.Load<Texture>("HdrTexture"); hdrRenderTexture = Texture.New2D(GraphicsDevice, hdrTexture.Width, hdrTexture.Height, 1, hdrTexture.Description.Format, TextureFlags.ShaderResource | TextureFlags.RenderTarget); drawEffectContext = RenderContext.GetShared(Services); postProcessingEffects = new PostProcessingEffects(drawEffectContext); postProcessingEffects.BrightFilter.Threshold = 100.0f; postProcessingEffects.Bloom.DownScale = 2; postProcessingEffects.Bloom.Enabled = true; postProcessingEffects.Bloom.ShowOnlyBloom = true; }
protected override async Task LoadContent() { await base.LoadContent(); spriteBatch = new SpriteBatch(GraphicsDevice); inputTexture = Asset.Load<Texture>("uv"); var groupCounts = new Int3(inputTexture.Width / ReductionRatio, inputTexture.Height / ReductionRatio, 1); outputTexture = Texture.New2D(GraphicsDevice, groupCounts.X, groupCounts.Y, 1, PixelFormat.R8G8B8A8_UNorm, TextureFlags.UnorderedAccess | TextureFlags.ShaderResource); displayedTexture = outputTexture; drawEffectContext = RenderContext.GetShared(Services); computeShaderEffect = new ComputeEffectShader(drawEffectContext) { ShaderSourceName = "ComputeShaderTestEffect", ThreadGroupCounts = groupCounts }; }
protected override async Task LoadContent() { await base.LoadContent(); cubemapSpriteEffect = EffectSystem.LoadEffect("CubemapSprite").WaitForResult(); drawEffectContext = RenderContext.GetShared(Services); lamberFilter = new LambertianPrefilteringSH(drawEffectContext); renderSHEffect = new SphericalHarmonicsRendererEffect(); renderSHEffect.Initialize(drawEffectContext); spriteBatch = new SpriteBatch(GraphicsDevice); inputCubemap = Asset.Load<Texture>("CubeMap"); outputCubemap = Texture.NewCube(GraphicsDevice, 256, 1, PixelFormat.R8G8B8A8_UNorm, TextureFlags.RenderTarget | TextureFlags.ShaderResource).DisposeBy(this); displayedCubemap = outputCubemap; }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { var backgroundProcessor = SceneInstance.GetProcessor<BackgroundComponentProcessor>(); if (backgroundProcessor == null) return; foreach (var backgroundComponent in backgroundProcessor.Backgrounds) { // Perform culling on group and accept if (!CurrentCullingMask.Contains(backgroundComponent.Entity.Group)) continue; opaqueList.Add(new RenderItem(this, backgroundComponent, float.NegativeInfinity)); // render background first so that it can replace a clear frame return; // draw only one background by group } }
protected override async Task LoadContent() { await base.LoadContent(); drawEffectContext = RenderContext.GetShared(Services); radianceFilter = new RadiancePrefilteringGGX(drawEffectContext); skipHighestLevel = radianceFilter.DoNotFilterHighestLevel; spriteBatch = new SpriteBatch(GraphicsDevice); inputCubemap = Asset.Load<Texture>("CubeMap"); outputCubemap = Texture.New2D(GraphicsDevice, outputSize, outputSize, MathUtil.Log2(outputSize), PixelFormat.R16G16B16A16_Float, TextureFlags.ShaderResource | TextureFlags.UnorderedAccess, 6).DisposeBy(this); CreateViewsFor(outputCubemap); //RenderSystem.Pipeline.Renderers.Add(new DelegateRenderer(Services) { Render = PrefilterCubeMap }); //RenderSystem.Pipeline.Renderers.Add(new RenderTargetSetter(Services) { ClearColor = Color.Zero }); //RenderSystem.Pipeline.Renderers.Add(new DelegateRenderer(Services) { Render = RenderCubeMap }); }
public override void Collect(RenderContext context) { base.Collect(context); var rect = Viewport; var output = GetOutput(context); // Setup the viewport if (!ForceAspectRatio) { if (IsViewportInPercentage) { var width = output.Width; var height = output.Height; ComputedViewport = new Viewport((int)(rect.X*width/100.0f), (int)(rect.Y*height/100.0f), (int)(rect.Width*width/100.0f), (int)(rect.Height*height/100.0f)); } else { ComputedViewport = new Viewport((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height); } } else { var currentAr = output.Width / (float)output.Height; var requiredAr = FixedAspectRatio; var arDiff = currentAr - requiredAr; // Pillarbox if (arDiff > 0.0f) { var newWidth = (float)Math.Max(1.0f, Math.Round(output.Height * requiredAr)); var adjX = (float)Math.Round(0.5f * (output.Width - newWidth)); ComputedViewport = new Viewport((int)adjX, 0, (int)newWidth, output.Height); } // Letterbox else { var newHeight = (float)Math.Max(1.0f, Math.Round(output.Width / requiredAr)); var adjY = (float)Math.Round(0.5f * (output.Height - newHeight)); ComputedViewport = new Viewport(0, (int)adjY, output.Width, (int)newHeight); } } }
public override RenderFrame GetRenderFrame(RenderContext context) { // Get the relative frame var relativeFrame = context.Tags.Get(RelativeSizeSource == RenderFrameRelativeMode.Current ? RenderFrame.Current : SceneGraphicsLayer.Master); // Check if we need to resize it if (currentFrame != null && (currentFrame.Descriptor != Descriptor || currentFrame.CheckIfResizeRequired(relativeFrame) || Descriptor.Format == RenderFrameFormat.LDR && colorSpace != context.GraphicsDevice.ColorSpace)) { Dispose(); } // Store the colorSpace colorSpace = context.GraphicsDevice.ColorSpace; // Allocate the render frame if necessary // TODO: Should we use allocated shared textures from RenderContext? return currentFrame ?? (currentFrame = RenderFrame.New(context.GraphicsDevice, Descriptor, relativeFrame)); }
public void Initialize(RenderContext context) { if (context == null) throw new ArgumentNullException("context"); if (Context != null) { Unload(); } Context = context; InitializeCore(); Initialized = true; // Notify that a particular renderer has been initialized. context.OnRendererInitialized(this); }
protected override void ActivateOutputCore(RenderContext context, RenderFrame output, bool disableDepth) { base.ActivateOutputCore(context, output, disableDepth); Viewport viewport; var rect = Viewport; // Setup the viewport if (IsViewportInPercentage) { var width = output.Width; var height = output.Height; viewport = new Viewport((int)(rect.X * width / 100.0f), (int)(rect.Y * height / 100.0f), (int)(rect.Width * width / 100.0f), (int)(rect.Height * height / 100.0f)); } else { viewport = new Viewport((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height); } context.GraphicsDevice.SetViewport(viewport); }
protected override void DrawCore(RenderContext context, RenderFrame output) { if (ChildScene == null || !ChildScene.Enabled) { return; } currentSceneInstance = SceneInstance.GetCurrent(Context); childSceneProcessor = childSceneProcessor ?? currentSceneInstance.GetProcessor<ChildSceneProcessor>(); if (childSceneProcessor == null) { return; } SceneInstance sceneInstance = childSceneProcessor.GetSceneInstance(ChildScene); if (sceneInstance != null) { sceneInstance.Draw(context, output, GraphicsCompositorOverride); } }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { var uiProcessor = SceneInstance.GetProcessor<UIComponentProcessor>(); if (uiProcessor == null) return; foreach (var uiRoot in uiProcessor.UIRoots) { // Perform culling on group and accept if (!CurrentCullingMask.Contains(uiRoot.UIComponent.Entity.Group)) continue; // skips empty UI elements if(uiRoot.UIComponent.RootElement == null) continue; // Project the position // TODO: This code is duplicated from SpriteComponent -> unify it at higher level? var worldPosition = new Vector4(uiRoot.TransformComponent.WorldMatrix.TranslationVector, 1.0f); float projectedZ; if (uiRoot.UIComponent.IsFullScreen) { projectedZ = -uiRoot.TransformComponent.WorldMatrix.M43; } else { Vector4 projectedPosition; var cameraComponent = context.Tags.Get(CameraComponentRenderer.Current); if (cameraComponent == null) continue; Vector4.Transform(ref worldPosition, ref cameraComponent.ViewProjectionMatrix, out projectedPosition); projectedZ = projectedPosition.Z / projectedPosition.W; } transparentList.Add(new RenderItem(this, uiRoot, projectedZ)); } }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { spriteProcessor = SceneInstance.GetProcessor<SpriteProcessor>(); if (spriteProcessor == null) { return; } // If no camera, early exit var camera = context.GetCurrentCamera(); if (camera == null) { return; } var viewProjectionMatrix = camera.ViewProjectionMatrix; foreach (var spriteState in spriteProcessor.Sprites) { var sprite = spriteState.SpriteComponent.CurrentSprite; if(sprite == null || sprite.Texture == null || sprite.Region.Width <= 0 || sprite.Region.Height <= 0f) continue; // Perform culling on group and accept if (!CurrentCullingMask.Contains(spriteState.SpriteComponent.Entity.Group)) continue; // Project the position // TODO: This could be done in a SIMD batch, but we need to figure-out how to plugin in with RenderMesh object var worldPosition = new Vector4(spriteState.TransformComponent.WorldMatrix.TranslationVector, 1.0f); Vector4 projectedPosition; Vector4.Transform(ref worldPosition, ref viewProjectionMatrix, out projectedPosition); var projectedZ = projectedPosition.Z / projectedPosition.W; var list = sprite.IsTransparent ? transparentList : opaqueList; list.Add(new RenderItem(this, spriteState, projectedZ)); } }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { // If no camera, early exit var camera = context.GetCurrentCamera(); if (camera == null) { return; } // Copy the ViewProjectionMatrix from the camera as it is not automatically picked up by the ModelComponentRenderer modelRenderer.ViewProjectionMatrix = camera.ViewProjectionMatrix; var sceneCameraRenderer = context.Tags.Get(SceneCameraRenderer.Current); var cameraRenderMode = sceneCameraRenderer != null ? sceneCameraRenderer.Mode : null; if (cameraRenderMode != null) { modelRenderer.RasterizerState = cameraRenderMode.GetDefaultRasterizerState(false); modelRenderer.RasterizerStateForInvertedGeometry = cameraRenderMode.GetDefaultRasterizerState(true); } modelRenderer.Prepare(context, opaqueList, transparentList); }
protected override void LoadContent() { var assetManager = Services.GetSafeServiceAs<AssetManager>(); // Preload the scene if it exists if (InitialSceneUrl != null && assetManager.Exists(InitialSceneUrl)) { SceneInstance = new SceneInstance(Services, assetManager.Load<Scene>(InitialSceneUrl)); } if (MainRenderFrame == null) { MainRenderFrame = RenderFrame.FromTexture(GraphicsDevice.BackBuffer, GraphicsDevice.DepthStencilBuffer); if (MainRenderFrame != null) { previousWidth = MainRenderFrame.Width; previousHeight = MainRenderFrame.Height; } } // Create the drawing context renderContext = RenderContext.GetShared(Services); }
/// <param name="context"></param> /// <inheritdoc/> public virtual void Collect(RenderContext context) { EnsureContext(context); }
/// <summary> /// Gets the current output <see cref="RenderFrame"/> output. /// </summary> /// <param name="context">The context.</param> /// <returns>RenderFrame.</returns> public RenderFrame GetOutput(RenderContext context) { return(Output.GetSafeRenderFrame(context)); }
protected abstract void DrawCore(RenderContext context, RenderFrame output);
/// <summary> /// Activates the output to the current <see cref="GraphicsDevice" />. /// </summary> /// <param name="context">The context.</param> /// <param name="output">The output.</param> /// <param name="disableDepth">if set to <c>true</c> [disable depth].</param> protected virtual void ActivateOutputCore(RenderContext context, RenderFrame output, bool disableDepth) { // Setup the render target context.GraphicsDevice.SetDepthAndRenderTargets(disableDepth ? null : output.DepthStencil, output.RenderTargets); }
/// <summary> /// Extract data from entities, should be as fast as possible to not block simulation loop. It should be mostly copies, and the actual processing should be part of Prepare(). /// </summary> public void Extract(RenderContext context) { // Prepare views for (int index = 0; index < Views.Count; index++) { // Update indices var view = Views[index]; view.Index = index; // Create missing RenderViewFeature while (view.Features.Count < RenderFeatures.Count) { view.Features.Add(new RenderViewFeature()); } for (int i = 0; i < RenderFeatures.Count; i++) { var renderViewFeature = view.Features[i]; renderViewFeature.RootFeature = RenderFeatures[i]; } } foreach (var view in Views) { for (int index = 0; index < view.RenderStages.Count; index++) { var renderViewStage = view.RenderStages[index]; renderViewStage.RenderNodes = renderNodePool.Acquire(); renderViewStage.SortedRenderNodes = sortedRenderNodePool.Acquire(); view.RenderStages[index] = renderViewStage; } } // Create nodes for objects to render Dispatcher.ForEach(Views, view => { // Sort per render feature (used for later sorting) // We'll be able to process data more efficiently for the next steps Dispatcher.Sort(view.RenderObjects, RenderObjectFeatureComparer.Default); Dispatcher.ForEach(view.RenderObjects, () => extractThreadLocals.Value, (renderObject, batch) => { var renderFeature = renderObject.RenderFeature; var viewFeature = view.Features[renderFeature.Index]; // Create object node renderFeature.GetOrCreateObjectNode(renderObject); // Let's create the view object node var renderViewNode = renderFeature.CreateViewObjectNode(view, renderObject); viewFeature.ViewObjectNodes.Add(renderViewNode, batch.ViewFeatureObjectNodeCache); // Collect object // TODO: Check which stage it belongs to (and skip everything if it doesn't belong to any stage) // TODO: For now, we build list and then copy. Another way would be to count and then fill (might be worse, need to check) var activeRenderStages = renderObject.ActiveRenderStages; foreach (var renderViewStage in view.RenderStages) { // Check if this RenderObject wants to be rendered for this render stage var renderStageIndex = renderViewStage.Index; if (!activeRenderStages[renderStageIndex].Active) { continue; } var renderStage = RenderStages[renderStageIndex]; if (renderStage.Filter != null && !renderStage.Filter.IsVisible(renderObject, view, renderViewStage)) { continue; } var renderNode = renderFeature.CreateRenderNode(renderObject, view, renderViewNode, renderStage); // Note: Used mostly during updating viewFeature.RenderNodes.Add(renderNode, batch.ViewFeatureRenderNodeCache); // Note: Used mostly during rendering renderViewStage.RenderNodes.Add(new RenderNodeFeatureReference(renderFeature, renderNode, renderObject), batch.ViewStageRenderNodeCache); } }, batch => batch.Flush()); // Finish collectin of view feature nodes foreach (var viewFeature in view.Features) { viewFeature.ViewObjectNodes.Close(); viewFeature.RenderNodes.Close(); } // Also sort view|stage per render feature foreach (var renderViewStage in view.RenderStages) { renderViewStage.RenderNodes.Close(); Dispatcher.Sort(renderViewStage.RenderNodes, RenderNodeFeatureReferenceComparer.Default); } }); // Finish collection of render feature nodes foreach (var renderFeature in RenderFeatures) { renderFeature.CloseNodeCollectors(); } // Ensure size of data arrays per objects PrepareDataArrays(); // Generate and execute extract jobs foreach (var renderFeature in RenderFeatures) // We might be able to parallelize too as long as we resepect render feature dependency graph (probably very few dependencies in practice) { // Divide into task chunks for parallelism renderFeature.Extract(); } // Ensure size of all other data arrays PrepareDataArrays(); }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { var viewParameters = context.Parameters; var device = context.GraphicsDevice; var viewInverse = Matrix.Invert(viewParameters.Get(TransformationKeys.View)); var viewProjection = viewParameters.Get(TransformationKeys.ViewProjection); BlendState previousBlendState = null; DepthStencilState previousDepthStencilState = null; Effect previousEffect = null; var isPicking = context.IsPicking(); bool hasBegin = false; for (var i = fromIndex; i <= toIndex; i++) { var renderItem = renderItems[i]; var spriteState = (SpriteProcessor.SpriteComponentState)renderItem.DrawContext; var spriteComp = spriteState.SpriteComponent; var transfoComp = spriteState.TransformComponent; var depthStencilState = spriteState.SpriteComponent.IgnoreDepth ? device.DepthStencilStates.None : device.DepthStencilStates.Default; var sprite = spriteComp.CurrentSprite; if (sprite == null) { continue; } // Update the sprite batch var blendState = isPicking ? device.BlendStates.Opaque : renderItems.HasTransparency ? (spriteComp.PremultipliedAlpha ? device.BlendStates.AlphaBlend : device.BlendStates.NonPremultiplied) : device.BlendStates.Opaque; var currentEffect = isPicking? GetOrCreatePickingSpriteEffect(): spriteComp.Tags.Get(IsEntitySelected)? GetOrCreateSelectedSpriteEffect(): null; // TODO remove this code when material are available if (previousEffect != currentEffect || blendState != previousBlendState || depthStencilState != previousDepthStencilState) { if (hasBegin) { sprite3DBatch.End(); } sprite3DBatch.Begin(viewProjection, SpriteSortMode.Deferred, blendState, null, depthStencilState, device.RasterizerStates.CullNone, currentEffect); hasBegin = true; } previousEffect = currentEffect; previousBlendState = blendState; previousDepthStencilState = depthStencilState; var sourceRegion = sprite.Region; var texture = sprite.Texture; var color = spriteComp.Color; if (isPicking) // TODO move this code corresponding to picking out of the runtime code. { color = new Color4(RuntimeIdHelper.ToRuntimeId(spriteComp)); } // skip the sprite if no texture is set. if (texture == null) { continue; } // determine the element world matrix depending on the type of sprite var worldMatrix = transfoComp.WorldMatrix; if (spriteComp.SpriteType == SpriteType.Billboard) { worldMatrix = viewInverse; // remove scale of the camera worldMatrix.Row1 /= ((Vector3)viewInverse.Row1).Length(); worldMatrix.Row2 /= ((Vector3)viewInverse.Row2).Length(); // set the scale of the object worldMatrix.Row1 *= ((Vector3)transfoComp.WorldMatrix.Row1).Length(); worldMatrix.Row2 *= ((Vector3)transfoComp.WorldMatrix.Row2).Length(); // set the position worldMatrix.TranslationVector = transfoComp.WorldMatrix.TranslationVector; } // calculate normalized position of the center of the sprite (takes into account the possible rotation of the image) var normalizedCenter = new Vector2(sprite.Center.X / sourceRegion.Width - 0.5f, 0.5f - sprite.Center.Y / sourceRegion.Height); if (sprite.Orientation == ImageOrientation.Rotated90) { var oldCenterX = normalizedCenter.X; normalizedCenter.X = -normalizedCenter.Y; normalizedCenter.Y = oldCenterX; } // apply the offset due to the center of the sprite var centerOffset = Vector2.Modulate(normalizedCenter, sprite.SizeInternal); worldMatrix.M41 -= centerOffset.X * worldMatrix.M11 + centerOffset.Y * worldMatrix.M21; worldMatrix.M42 -= centerOffset.X * worldMatrix.M12 + centerOffset.Y * worldMatrix.M22; worldMatrix.M43 -= centerOffset.X * worldMatrix.M13 + centerOffset.Y * worldMatrix.M23; // draw the sprite sprite3DBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref sprite.SizeInternal, ref color, sprite.Orientation, SwizzleMode.None, renderItem.Depth); } sprite3DBatch.End(); }
/// <summary> /// Main drawing method for this renderer that must be implemented. /// </summary> /// <param name="context">The context.</param> protected abstract void DrawCore(RenderContext context);
/// <summary> /// Initializes a new instance of the <see cref="DrawEffect" /> class. /// </summary> /// <param name="context">The context.</param> /// <param name="name">The name.</param> protected DrawEffect(RenderContext context, string name = null) : this(name) { Initialize(context); }