protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { var viewport = context.GraphicsDevice.Viewport; for (int i = fromIndex; i <= toIndex; i++) { var skybox = (SkyboxComponent)renderItems[i].DrawContext; // Setup the intensity skyboxEffect.Parameters.Set(SkyboxKeys.Intensity, skybox.Intensity); // Setup the rotation skyboxEffect.Parameters.Set(SkyboxKeys.SkyMatrix, Matrix.RotationQuaternion(skybox.Entity.Transform.Rotation)); skyboxEffect.SetOutput(CurrentRenderFrame.RenderTargets); skyboxEffect.SetViewport(viewport); skyboxEffect.Draw(); } // Make sure to fully restore the current render frame CurrentRenderFrame.Activate(context); // Restore the viewport: TODO: We should add a method to Push/Pop Target/Depth/Stencil/Viewport on the GraphicsDevice context.GraphicsDevice.SetViewport(viewport); }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { var graphicsDevice = context.GraphicsDevice; var destination = new RectangleF(0, 0, 1, 1); spriteBatch.Begin(SpriteSortMode.FrontToBack, graphicsDevice.BlendStates.Opaque, graphicsDevice.SamplerStates.LinearClamp, graphicsDevice.DepthStencilStates.None); for(var i = fromIndex; i <= toIndex; ++i) { var background = (BackgroundComponent)renderItems[i].DrawContext; var texture = background.Texture; if (texture == null) continue; 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.Draw(texture, destination, source, Color.White, 0, Vector2.Zero); } spriteBatch.End(); }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { if (lightComponentForwardRenderer != null) { lightComponentForwardRenderer.Draw(context); } }
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(); }
public ShadowMapRenderer(string effectName) { if (effectName == null) { throw new ArgumentNullException("effectName"); } this.effectName = effectName; atlases = new FastListStruct <ShadowMapAtlasTexture>(16); shadowMapTextures = new PoolListStruct <LightShadowMapTexture>(16, CreateLightShadowMapTexture); LightComponentsWithShadows = new Dictionary <LightComponent, LightShadowMapTexture>(16); opaqueRenderItems = new RenderItemCollection(512, false); transparentRenderItems = new RenderItemCollection(512, true); renderers = new Dictionary <Type, ILightShadowMapRenderer>(); ShadowCamera = new CameraComponent { UseCustomViewMatrix = true, UseCustomProjectionMatrix = true }; // Creates a model renderer for the shadows casters shadowModelComponentRenderer = new ModelComponentRenderer(effectName + ".ShadowMapCaster") { CullingMode = CullingMode.None, Callbacks = { UpdateMeshes = FilterCasters, } }; shadowCasterParameters = new ParameterCollection(); shadowCasterParameters.Set(ParadoxEffectBaseKeys.ExtensionPostVertexStageShader, ShadowMapCasterExtension); }
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 PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { var cameraState = context.GetCurrentCamera(); if (cameraState == null) return; UpdateParameters(context, cameraState); }
public void Draw(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { if (Enabled) { PreDrawCoreInternal(context); DrawCore(context, renderItems, fromIndex, toIndex); PostDrawCoreInternal(context); } }
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)); }
public void Prepare(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { if (Context == null) { Initialize(context); } else if (Context != context) { throw new InvalidOperationException("Cannot use a different context between Load and Draw"); } PrepareCore(context, opaqueList, transparentList); }
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 void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { var viewParameters = context.Parameters; var device = context.GraphicsDevice; // var viewProjection = viewParameters.Get(TransformationKeys.ViewProjection); var viewMat = viewParameters.Get(TransformationKeys.View); var projMat = viewParameters.Get(TransformationKeys.Projection); Matrix viewInv; Matrix.Invert(ref viewMat, out viewInv); for (var i = fromIndex; i <= toIndex; i++) { var renderItem = renderItems[i]; var particleSystemState = (ParticleSystemProcessor.ParticleSystemComponentState)renderItem.DrawContext; var particleSystemComponent = particleSystemState.ParticleSystemComponent; particleSystemComponent.ParticleSystem.Draw(device, context, ref viewMat, ref projMat, ref viewInv, particleSystemComponent.Color); } // TODO Part of the renderer code is not thread safe - need to split the buffer building and the rendering to speed up the process /* * var itemCount = toIndex - fromIndex + 1; // Inclusive * var renderItemList = renderItems.GetRange(fromIndex, itemCount); * * TaskList.Dispatch( * renderItemList, * 8, * 8, * (i, renderItem) => * { * var particleSystemState = (ParticleSystemProcessor.ParticleSystemComponentState)renderItem.DrawContext; * var particleSystemComponent = particleSystemState.ParticleSystemComponent; * * particleSystemComponent.ParticleSystem.Draw(device, context, ref viewMat, ref projMat, ref viewInv, particleSystemComponent.Color); * } * ); * //*/ }
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) { // 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 PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { // Early out if particle system processor doesn't exist particleSystemProcessor = SceneInstance.GetProcessor <ParticleSystemProcessor>(); if (particleSystemProcessor == null) { return; } // Early out if camera doesn't exist var camera = context.GetCurrentCamera(); if (camera == null) { return; } var viewProjectionMatrix = camera.ViewProjectionMatrix; foreach (var particleSystemState in particleSystemProcessor.ParticleSystems) { // Perform culling on group and accept // TODO Should culling be performed on a per-sprite basis or batched? if (!CurrentCullingMask.Contains(particleSystemState.ParticleSystemComponent.Entity.Group)) { continue; } // Project the position to find depth for sorting var worldPosition = new Vector4(particleSystemState.TransformComponent.WorldMatrix.TranslationVector, 1.0f); Vector4 projectedPosition; Vector4.Transform(ref worldPosition, ref viewProjectionMatrix, out projectedPosition); var projectedZ = projectedPosition.Z / projectedPosition.W; //var list = true ? transparentList : opaqueList; //list.Add(new RenderItem(this, particleSystemState, projectedZ)); transparentList.Add(new RenderItem(this, particleSystemState, 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)); } }
public void Prepare(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { if (!Enabled) { return; } if (Context == null) { Initialize(context); } else if (Context != context) { throw new InvalidOperationException("Cannot use a different context between Load and Draw"); } if (SceneCameraRenderer != null) { CurrentCullingMask = SceneCameraRenderer.CullingMask; } PrepareCore(context, opaqueList, transparentList); }
protected abstract void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex);
protected abstract void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList);
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { // TODO: Check how to integrate sprites in a Camera renderer instead of this var viewParameters = context.Parameters; var device = context.GraphicsDevice; var cullMode = device.RasterizerStates.CullNone; var viewInverse = Matrix.Invert(viewParameters.Get(TransformationKeys.View)); var viewProjection = viewParameters.Get(TransformationKeys.ViewProjection); BlendState previousBlendState = 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 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 && spriteComp.Tags.Get(IsEntitySelected)) ? GetOrCreateSelectedSpriteEffect(): null; // TODO remove this code when material are available if (previousEffect != currentEffect || blendState != previousBlendState) { if (hasBegin) { sprite3DBatch.End(); } sprite3DBatch.Begin(viewProjection, SpriteSortMode.Deferred, blendState, null, context.GraphicsDevice.DepthStencilStates.None, cullMode, currentEffect); hasBegin = true; } previousEffect = currentEffect; previousBlendState = blendState; 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. { texture = device.GetSharedWhiteTexture(); color = (Color)new Color4(spriteComp.Id); } // skip the sprite if no texture is set. if (texture == null) continue; // determine the size of the element depending on the extrusion method. var elementSize = Vector2.One; if (spriteComp.ExtrusionMethod == SpriteExtrusionMethod.UnitHeightSpriteRatio) { elementSize.X = sourceRegion.Width / sourceRegion.Height; } else if (spriteComp.ExtrusionMethod == SpriteExtrusionMethod.UnitWidthSpriteRatio) { elementSize.Y = sourceRegion.Height / sourceRegion.Width; } // 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; } // draw the sprite sprite3DBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref elementSize, ref color, sprite.Orientation, SwizzleMode.None, renderItem.Depth); } sprite3DBatch.End(); }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { var viewParameters = context.Parameters; var device = context.GraphicsDevice; 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 = (SpriteStudioProcessor.Data)renderItem.DrawContext; var transfoComp = spriteState.TransformComponent; var depthStencilState = device.DepthStencilStates.None; foreach (var node in spriteState.SpriteStudioComponent.SortedNodes) { if (node.Sprite?.Texture == null || node.Sprite.Region.Width <= 0 || node.Sprite.Region.Height <= 0f || node.Hide) continue; // Update the sprite batch BlendState spriteBlending; switch (node.BaseNode.AlphaBlending) { case SpriteStudioBlending.Mix: spriteBlending = device.BlendStates.AlphaBlend; break; case SpriteStudioBlending.Multiplication: spriteBlending = MultBlendState; break; case SpriteStudioBlending.Addition: spriteBlending = device.BlendStates.Additive; break; case SpriteStudioBlending.Subtraction: spriteBlending = SubBlendState; break; default: throw new ArgumentOutOfRangeException(); } var blendState = isPicking ? device.BlendStates.Opaque : renderItems.HasTransparency ? spriteBlending : device.BlendStates.Opaque; var currentEffect = isPicking ? GetOrCreatePickingSpriteEffect() : spriteState.SpriteStudioComponent.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 = node.Sprite.Region; var texture = node.Sprite.Texture; // skip the sprite if no texture is set. if (texture == null) continue; var color4 = Color4.White; if (isPicking) { // TODO move this code corresponding to picking out of the runtime code. color4 = new Color4(spriteState.SpriteStudioComponent.Id); } else { if (node.BlendFactor > 0.0f) { switch (node.BlendType) //todo this should be done in a shader { case SpriteStudioBlending.Mix: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; case SpriteStudioBlending.Multiplication: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; case SpriteStudioBlending.Addition: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; case SpriteStudioBlending.Subtraction: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; default: throw new ArgumentOutOfRangeException(); } } else { color4 *= node.FinalTransparency; } } var worldMatrix = node.ModelTransform*transfoComp.WorldMatrix; // calculate normalized position of the center of the sprite (takes into account the possible rotation of the image) var normalizedCenter = new Vector2(node.Sprite.Center.X/sourceRegion.Width - 0.5f, 0.5f - node.Sprite.Center.Y/sourceRegion.Height); if (node.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 size = node.Sprite.Size; var centerOffset = Vector2.Modulate(normalizedCenter, size); worldMatrix.M41 -= centerOffset.X*worldMatrix.M11 + centerOffset.Y*worldMatrix.M21; worldMatrix.M42 -= centerOffset.X*worldMatrix.M12 + centerOffset.Y*worldMatrix.M22; // draw the sprite sprite3DBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref size, ref color4, node.Sprite.Orientation, SwizzleMode.None, renderItem.Depth); } } sprite3DBatch.End(); }
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(); }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { modelRenderer.Draw(context, renderItems, fromIndex, toIndex); }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { // build the list of the UI elements to render uiElementStates.Clear(); for (var i = fromIndex; i <= toIndex; ++i) { var renderItem = renderItems[i]; uiElementStates.Add((UIComponentProcessor.UIComponentState)renderItem.DrawContext); } // evaluate the current draw time (game instance is null for thumbnails) var drawTime = game != null ? game.DrawTime : new GameTime(); // update the rendering context renderingContext.Time = drawTime; renderingContext.RenderTarget = CurrentRenderFrame.RenderTargets[0]; // TODO: avoid hardcoded index 0 // cache the ratio between viewport and target. var viewportSize = context.GraphicsDevice.Viewport.Size; viewportTargetRatio = new Vector2(viewportSize.X / renderingContext.RenderTarget.Width, viewportSize.Y / renderingContext.RenderTarget.Height); // compact all the pointer events that happened since last frame to avoid performing useless hit tests. CompactPointerEvents(); // allocate temporary graphics resources if needed Texture scopedDepthBuffer = null; foreach (var uiElement in uiElementStates) { if (uiElement.UIComponent.IsFullScreen) { var renderTarget = renderingContext.RenderTarget; var description = TextureDescription.New2D(renderTarget.Width, renderTarget.Height, PixelFormat.D24_UNorm_S8_UInt, TextureFlags.DepthStencil); scopedDepthBuffer = PushScopedResource(context.Allocator.GetTemporaryTexture(description)); break; } } // render the UI elements of all the entities foreach (var uiElementState in uiElementStates) { var uiComponent = uiElementState.UIComponent; var rootElement = uiComponent.RootElement; if (rootElement == null) continue; var updatableRootElement = (IUIElementUpdate)rootElement; // calculate the size of the virtual resolution depending on target size (UI canvas) var virtualResolution = uiComponent.VirtualResolution; var targetSize = new Vector2(renderingContext.RenderTarget.Width, renderingContext.RenderTarget.Height); if (uiComponent.IsFullScreen) { // update the virtual resolution of the renderer if (uiComponent.VirtualResolutionMode == VirtualResolutionMode.FixedWidthAdaptableHeight) virtualResolution.Y = virtualResolution.X * targetSize.Y / targetSize.X; if (uiComponent.VirtualResolutionMode == VirtualResolutionMode.FixedHeightAdaptableWidth) virtualResolution.X = virtualResolution.Y * targetSize.X / targetSize.Y; } // Update the view parameters if (uiComponent.IsFullScreen) { viewParameters.Update(uiComponent.Entity, virtualResolution); } else { var cameraComponent = context.Tags.Get(CameraComponentRenderer.Current); viewParameters.Update(uiComponent.Entity, cameraComponent); } // Analyze the input and trigger the UI element touch and key events // Note: this is done before measuring/arranging/drawing the element in order to avoid one frame latency on clicks. // But by doing so the world matrices taken for hit test are the ones calculated during last frame. using (Profiler.Begin(UIProfilerKeys.TouchEventsUpdate)) { foreach (var uiState in uiElementStates) { if (uiState.UIComponent.RootElement == null) continue; UpdateMouseOver(uiState); UpdateTouchEvents(uiState, drawTime); } } // update the rendering context values specific to this element renderingContext.Resolution = virtualResolution; renderingContext.ViewMatrix = viewParameters.ViewMatrix; renderingContext.ProjectionMatrix = viewParameters.ProjectionMatrix; renderingContext.ViewProjectionMatrix = viewParameters.ViewProjectionMatrix; renderingContext.DepthStencilBuffer = uiComponent.IsFullScreen ? scopedDepthBuffer : CurrentRenderFrame.DepthStencil; renderingContext.ShouldSnapText = uiComponent.SnapText; // calculate an estimate of the UI real size by projecting the element virtual resolution on the screen var virtualOrigin = viewParameters.ViewProjectionMatrix.Row4; var virtualWidth = new Vector4(virtualResolution.X/2, 0, 0, 1); var virtualHeight = new Vector4(0, virtualResolution.Y / 2, 0, 1); var transformedVirtualWidth = Vector4.Zero; var transformedVirtualHeight = Vector4.Zero; for (int i = 0; i < 4; i++) { transformedVirtualWidth[i] = virtualWidth[0] * viewParameters.ViewProjectionMatrix[0 + i] + viewParameters.ViewProjectionMatrix[12 + i]; transformedVirtualHeight[i] = virtualHeight[1] * viewParameters.ViewProjectionMatrix[4 + i] + viewParameters.ViewProjectionMatrix[12 + i]; } var projectedOrigin = virtualOrigin.XY() / virtualOrigin.W; var projectedVirtualWidth = viewportSize * (transformedVirtualWidth.XY() / transformedVirtualWidth.W - projectedOrigin); var projectedVirtualHeight = viewportSize * (transformedVirtualHeight.XY() / transformedVirtualHeight.W - projectedOrigin); // update layouting context. layoutingContext.VirtualResolution = virtualResolution; layoutingContext.RealResolution = viewportSize; layoutingContext.RealVirtualResolutionRatio = new Vector2(projectedVirtualWidth.Length() / virtualResolution.X, projectedVirtualHeight.Length() / virtualResolution.Y); rootElement.LayoutingContext = layoutingContext; // perform the time-based updates of the UI element updatableRootElement.Update(drawTime); // update the UI element disposition rootElement.Measure(virtualResolution); rootElement.Arrange(virtualResolution, false); // update the UI element hierarchical properties var rootMatrix = Matrix.Translation(-virtualResolution / 2); // UI world is rotated of 180degrees along Ox updatableRootElement.UpdateWorldMatrix(ref rootMatrix, rootMatrix != uiElementState.LastRootMatrix); updatableRootElement.UpdateElementState(0); uiElementState.LastRootMatrix = rootMatrix; // clear and set the Depth buffer as required if (uiComponent.IsFullScreen) { context.GraphicsDevice.Clear(renderingContext.DepthStencilBuffer, DepthStencilClearOptions.DepthBuffer | DepthStencilClearOptions.Stencil); } context.GraphicsDevice.SetDepthAndRenderTarget(renderingContext.DepthStencilBuffer, renderingContext.RenderTarget); // start the image draw session renderingContext.StencilTestReferenceValue = 0; batch.Begin(ref viewParameters.ViewProjectionMatrix, context.GraphicsDevice.BlendStates.AlphaBlend, uiSystem.KeepStencilValueState, renderingContext.StencilTestReferenceValue); // Render the UI elements in the final render target ReccursiveDrawWithClipping(context, rootElement); // end the image draw session batch.End(); } // clear the list of compacted pointer events of time frame ClearPointerEvents(); // revert the depth stencil buffer to the default value context.GraphicsDevice.SetDepthAndRenderTargets(CurrentRenderFrame.DepthStencil, CurrentRenderFrame.RenderTargets); }
private void PrepareRenderMeshes(RenderModel renderModel, List<Mesh> meshes, ref FastListStruct<RenderMesh> renderMeshes, RenderItemCollection opaqueList, RenderItemCollection transparentList) { // Add new render meshes for (int i = renderMeshes.Count; i < meshes.Count; i++) { var renderMesh = new RenderMesh(renderModel, meshes[i]); renderMeshes.Add(renderMesh); } // Create the bounding frustum locally on the stack, so that frustum.Contains is performed with boundingBox that is also on the stack var frustum = new BoundingFrustum(ref ViewProjectionMatrix); for (int i = 0; i < renderMeshes.Count; i++) { var renderMesh = renderMeshes[i]; // Update the model hierarchy var modelViewHierarchy = renderModel.ModelComponent.ModelViewHierarchy; modelViewHierarchy.UpdateRenderMesh(renderMesh); if (!renderMesh.Enabled) { continue; } // Upload skinning blend matrices BoundingBoxExt boundingBox; skinningUpdater.Update(modelViewHierarchy, renderMesh, out boundingBox); // Fast AABB transform: http://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/ // Compute transformed AABB (by world) // TODO: CullingMode should be pluggable // TODO: This should not be necessary. Add proper bounding boxes to gizmos etc. if (CullingMode == CullingMode.Frustum && boundingBox.Extent != Vector3.Zero && !frustum.Contains(ref boundingBox)) { 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(renderMesh.WorldMatrix.TranslationVector, 1.0f); Vector4 projectedPosition; Vector4.Transform(ref worldPosition, ref ViewProjectionMatrix, out projectedPosition); var projectedZ = projectedPosition.Z / projectedPosition.W; renderMesh.RasterizerState = renderMesh.IsGeometryInverted ? RasterizerStateForInvertedGeometry : RasterizerState; renderMesh.UpdateMaterial(); var list = renderMesh.HasTransparency ? transparentList : opaqueList; list.Add(new RenderItem(this, renderMesh, projectedZ)); } }
private void PrepareModels(RenderContext context, List<RenderModel> renderModels, RenderItemCollection opaqueList, RenderItemCollection transparentList) { var preRenderModel = Callbacks.PreRenderModel; foreach (var renderModel in renderModels) { var modelComponent = renderModel.ModelComponent; var meshes = modelComponent.Model.Meshes; int meshCount = meshes.Count; if (meshCount == 0) { continue; } if (preRenderModel != null && !preRenderModel(context, renderModel)) { continue; } // Always prepare the slot for the render meshes even if they are not used. for (int i = renderModel.RenderMeshesPerEffectSlot.Count; i <= modelRenderSlot; i++) { renderModel.RenderMeshesPerEffectSlot.Add(new FastListStruct<RenderMesh>(meshCount)); } PrepareRenderMeshes(renderModel, meshes, ref renderModel.RenderMeshesPerEffectSlot.Items[modelRenderSlot], opaqueList, transparentList); } }
public RenderBucket() { RenderItems = new RenderItemCollection(); }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { spriteProcessor = SceneInstance.GetProcessor <SpriteStudioProcessor>(); 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 worldMatrix = spriteState.TransformComponent.WorldMatrix; var worldPosition = new Vector4(worldMatrix.TranslationVector, 1.0f); Vector4 projectedPosition; Vector4.Transform(ref worldPosition, ref viewProjectionMatrix, out projectedPosition); var projectedZ = projectedPosition.Z / projectedPosition.W; transparentList.Add(new RenderItem(this, spriteState, projectedZ)); //for (var index = 0; index < ssSheet.Sheet.NodesInfo.Count; index++) //{ // var node = ssSheet.Sheet.NodesInfo[index]; // var sprite = ssSheet.Sheet.SpriteSheet.Sprites[index]; // if (sprite?.Texture == null || sprite.Region.Width <= 0 || sprite.Region.Height <= 0f) // continue; // // Perform culling on group and accept // if (!CurrentCullingMask.Contains(spriteState.SpriteStudioComponent.Entity.Group)) // continue; // var worldMatrix = node.WorldTransform * spriteState.TransformComponent.WorldMatrix; // // 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(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, new SpriteItem // { // Sprite = sprite, // Data = spriteState, // Node = node // }, projectedZ)); //} } }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { spriteProcessor = SceneInstance.GetProcessor<SpriteStudioProcessor>(); 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 worldMatrix = spriteState.TransformComponent.WorldMatrix; var worldPosition = new Vector4(worldMatrix.TranslationVector, 1.0f); Vector4 projectedPosition; Vector4.Transform(ref worldPosition, ref viewProjectionMatrix, out projectedPosition); var projectedZ = projectedPosition.Z / projectedPosition.W; transparentList.Add(new RenderItem(this, spriteState, projectedZ)); //for (var index = 0; index < ssSheet.Sheet.NodesInfo.Count; index++) //{ // var node = ssSheet.Sheet.NodesInfo[index]; // var sprite = ssSheet.Sheet.SpriteSheet.Sprites[index]; // if (sprite?.Texture == null || sprite.Region.Width <= 0 || sprite.Region.Height <= 0f) // continue; // // Perform culling on group and accept // if (!CurrentCullingMask.Contains(spriteState.SpriteStudioComponent.Entity.Group)) // continue; // var worldMatrix = node.WorldTransform * spriteState.TransformComponent.WorldMatrix; // // 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(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, new SpriteItem // { // Sprite = sprite, // Data = spriteState, // Node = node // }, projectedZ)); //} } }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { modelRenderer.Prepare(context, opaqueList, transparentList); }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { // Nothing to draw for this camera }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { var viewParameters = context.Parameters; var device = context.GraphicsDevice; 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 = (SpriteStudioProcessor.Data)renderItem.DrawContext; var transfoComp = spriteState.TransformComponent; var depthStencilState = device.DepthStencilStates.None; foreach (var node in spriteState.SpriteStudioComponent.SortedNodes) { if (node.Sprite?.Texture == null || node.Sprite.Region.Width <= 0 || node.Sprite.Region.Height <= 0f || node.Hide) { continue; } // Update the sprite batch BlendState spriteBlending; switch (node.BaseNode.AlphaBlending) { case SpriteStudioBlending.Mix: spriteBlending = device.BlendStates.AlphaBlend; break; case SpriteStudioBlending.Multiplication: spriteBlending = MultBlendState; break; case SpriteStudioBlending.Addition: spriteBlending = device.BlendStates.Additive; break; case SpriteStudioBlending.Subtraction: spriteBlending = SubBlendState; break; default: throw new ArgumentOutOfRangeException(); } var blendState = isPicking ? device.BlendStates.Opaque : renderItems.HasTransparency ? spriteBlending : device.BlendStates.Opaque; var currentEffect = isPicking ? GetOrCreatePickingSpriteEffect() : spriteState.SpriteStudioComponent.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 = node.Sprite.Region; var texture = node.Sprite.Texture; // skip the sprite if no texture is set. if (texture == null) { continue; } var color4 = Color4.White; if (isPicking) { // TODO move this code corresponding to picking out of the runtime code. color4 = new Color4(spriteState.SpriteStudioComponent.Id); } else { if (node.BlendFactor > 0.0f) { switch (node.BlendType) //todo this should be done in a shader { case SpriteStudioBlending.Mix: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; case SpriteStudioBlending.Multiplication: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; case SpriteStudioBlending.Addition: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; case SpriteStudioBlending.Subtraction: color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency; break; default: throw new ArgumentOutOfRangeException(); } } else { color4 *= node.FinalTransparency; } } var worldMatrix = node.ModelTransform * transfoComp.WorldMatrix; // calculate normalized position of the center of the sprite (takes into account the possible rotation of the image) var normalizedCenter = new Vector2(node.Sprite.Center.X / sourceRegion.Width - 0.5f, 0.5f - node.Sprite.Center.Y / sourceRegion.Height); if (node.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 size = node.Sprite.Size; var centerOffset = Vector2.Modulate(normalizedCenter, size); worldMatrix.M41 -= centerOffset.X * worldMatrix.M11 + centerOffset.Y * worldMatrix.M21; worldMatrix.M42 -= centerOffset.X * worldMatrix.M12 + centerOffset.Y * worldMatrix.M22; // draw the sprite sprite3DBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref size, ref color4, node.Sprite.Orientation, SwizzleMode.None, renderItem.Depth); } } sprite3DBatch.End(); }
public RenderBucket(string name) { RenderItemName = name; RenderItems = new RenderItemCollection(); }
protected override void PrepareCore(RenderContext context, RenderItemCollection opaqueList, RenderItemCollection transparentList) { // If there is a list of models to render, use this list directly if (RenderModels != null) { PrepareModels(context, RenderModels, opaqueList, transparentList); } else { // Otherwise, use the models from the ModelProcessor var modelProcessor = SceneInstance.GetProcessor<ModelProcessor>(); renderModelCollections.Clear(); modelProcessor.QueryModelGroupsByMask(CurrentCullingMask, renderModelCollections); foreach (var renderModelGroup in renderModelCollections) { PrepareModels(context, renderModelGroup, opaqueList, transparentList); } } }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItemList, int fromIndex, int toIndex) { if (dynamicEffectCompiler == null) { throw new InvalidOperationException("This instance is not correctly initialized (no EffectName)"); } // Get all meshes from render models meshesToRender.Clear(); for(int i = fromIndex; i <= toIndex; i++) { meshesToRender.Add((RenderMesh)renderItemList[i].DrawContext); } // Slow path there is a callback if (Callbacks.UpdateMeshes != null) { Callbacks.UpdateMeshes(context, ref meshesToRender); } // Fetch callback on PreRenderGroup var preRenderMesh = Callbacks.PreRenderMesh; for (int i = 0; i < meshesToRender.Count; i++) { var renderMesh = meshesToRender[i]; // If the EntityGroup is changing, call the callback to allow to plug specific parameters for this group if (preRenderMesh != null) { preRenderMesh(context, renderMesh); } // Update Effect and mesh UpdateEffect(context, renderMesh, context.Parameters); // Draw the mesh renderMesh.Draw(context); } }