protected override void InitializeCore() { base.InitializeCore(); _skyViewLutTexture = Texture.New2D(Context.GraphicsDevice, SkyViewLutSettings.Width, SkyViewLutSettings.Height, SkyViewLutSettings.Format, TextureFlags.RenderTarget | TextureFlags.ShaderResource); _atmosphereCameraScatteringVolumeTexture = Texture.New3D(Context.GraphicsDevice, AtmosphereCameraScatteringVolumeSettings.Size, AtmosphereCameraScatteringVolumeSettings.Size, AtmosphereCameraScatteringVolumeSettings.Slices, AtmosphereCameraScatteringVolumeSettings.Format, TextureFlags.RenderTarget | TextureFlags.ShaderResource); _multiScatteringTexture = Texture.New2D(Context.GraphicsDevice, MultiScatteringTextureSettings.Size, MultiScatteringTextureSettings.Size, MultiScatteringTextureSettings.Format, TextureFlags.UnorderedAccess | TextureFlags.ShaderResource); TransmittanceLutTexture = Texture.New2D(Context.GraphicsDevice, TransmittanceLutSettings.Width, TransmittanceLutSettings.Height, TransmittanceLutSettings.Format, TextureFlags.UnorderedAccess | TextureFlags.RenderTarget | TextureFlags.ShaderResource); _atmosphereCubeMapRenderTarget = Texture.New2D(Context.GraphicsDevice, 64, 64, PixelFormat.R16G16B16A16_Float, TextureFlags.RenderTarget | TextureFlags.ShaderResource); _atmosphereCubeMap = Texture.NewCube(Context.GraphicsDevice, 64, PixelFormat.R16G16B16A16_Float, TextureFlags.ShaderResource); _atmosphereCubeMapSpecular = Texture.NewCube(Context.GraphicsDevice, 64, MipMapCount.Auto, PixelFormat.R16G16B16A16_Float, TextureFlags.ShaderResource | TextureFlags.UnorderedAccess); _transmittanceLutEffect = new ImageEffectShader("AtmosphereRenderTransmittanceLutEffect"); _skyViewLutEffect = new ImageEffectShader("AtmosphereRenderSkyViewLutEffect"); _renderMultipleScatteringTextureEffect = new ComputeEffectShader(Context) { ShaderSourceName = "AtmosphereMultipleScatteringTextureEffect" }; _renderAtmosphereScatteringVolumeEffect = new DynamicEffectInstance("AtmosphereRenderScatteringCameraVolumeEffect"); _renderAtmosphereScatteringVolumeEffect.Initialize(Context.Services); _renderAtmosphereScatteringVolumePipelineState = new MutablePipelineState(Context.GraphicsDevice); _renderAtmosphereScatteringVolumePipelineState.State.SetDefaults(); _renderAtmosphereScatteringVolumePipelineState.State.PrimitiveType = PrimitiveType.TriangleList; _atmosphereLogicalGroupKey = CreateDrawLogicalGroup("Atmosphere"); _spriteBatch = new SpriteBatch(Context.GraphicsDevice); }
public override Task DisposeAsync() { EnsureNotDestroyed(nameof(EditorGameCameraPreviewService)); // Unregister events var selectionService = Services.Get <IEditorGameEntitySelectionService>(); if (selectionService != null) { selectionService.SelectionUpdated -= UpdateModifiedEntitiesList; } // Remove renderers var gameTopLevel = game.SceneSystem.GraphicsCompositor.Game as EditorTopLevelCompositor; var editorTopLevel = game.EditorSceneSystem.GraphicsCompositor.Game as EditorTopLevelCompositor; if (gameTopLevel != null && editorTopLevel != null) { gameTopLevel.PostGizmoCompositors.Remove(generateIncrustRenderer); editorTopLevel.PostGizmoCompositors.Remove(renderIncrustRenderer); } defaultFont?.Dispose(); defaultFont = null; spriteEffect?.Dispose(); spriteEffect = null; borderPipelineState = null; borderVertexBuffer?.Dispose(); borderVertexBuffer = null; return(base.DisposeAsync()); }
//private Matrix viewprojection = new Matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); protected override void InitializeCore() { base.InitializeCore(); myCustomShader = new DynamicEffectInstance("test_shader1"); myCustomShader.Initialize(Context.Services); pipelineState = new MutablePipelineState(Context.GraphicsDevice); pipelineState.State.SetDefaults(); pipelineState.State.InputElements = VertexDeclaration.CreateInputElements(); pipelineState.State.PrimitiveType = PrimitiveType.TriangleStrip; pipelineState.State.BlendState = BlendStates.Default; pipelineState.State.RasterizerState.CullMode = CullMode.None; }
protected override Task <bool> Initialize(EditorServiceGame editorGame) { game = (EntityHierarchyEditorGame)editorGame; // create the default font var fontItem = OfflineRasterizedSpriteFontFactory.Create(); fontItem.FontType.Size = 8; defaultFont = OfflineRasterizedFontCompiler.Compile(game.Services.GetService <IFontFactory>(), fontItem, game.GraphicsDevice.ColorSpace == ColorSpace.Linear); incrustBatch = new SpriteBatch(game.GraphicsDevice); // SpriteEffect will be used to draw camera incrust border spriteEffect = new EffectInstance(new Graphics.Effect(game.GraphicsDevice, SpriteEffect.Bytecode)); spriteEffect.Parameters.Set(TexturingKeys.Texture0, game.GraphicsDevice.GetSharedWhiteTexture()); spriteEffect.UpdateEffect(game.GraphicsDevice); borderPipelineState = new MutablePipelineState(game.GraphicsDevice); borderPipelineState.State.RootSignature = spriteEffect.RootSignature; borderPipelineState.State.EffectBytecode = spriteEffect.Effect.Bytecode; borderPipelineState.State.InputElements = VertexPositionTexture.Layout.CreateInputElements(); borderPipelineState.State.PrimitiveType = PrimitiveType.LineStrip; borderPipelineState.State.RasterizerState = RasterizerStates.CullNone; unsafe { var borderVertices = new[] { new VertexPositionTexture(new Vector3(0.0f, 0.0f, 0.0f), Vector2.Zero), new VertexPositionTexture(new Vector3(0.0f, 1.0f, 0.0f), Vector2.Zero), new VertexPositionTexture(new Vector3(1.0f, 1.0f, 0.0f), Vector2.Zero), new VertexPositionTexture(new Vector3(1.0f, 0.0f, 0.0f), Vector2.Zero), new VertexPositionTexture(new Vector3(0.0f, 0.0f, 0.0f), Vector2.Zero), new VertexPositionTexture(new Vector3(0.0f, 1.0f, 0.0f), Vector2.Zero), // extra vertex so that left-top corner is not missing (likely due to rasterization rule) }; fixed(VertexPositionTexture *borderVerticesPtr = borderVertices) borderVertexBuffer = Graphics.Buffer.Vertex.New(game.GraphicsDevice, new DataPointer(borderVerticesPtr, VertexPositionTexture.Size * borderVertices.Length)); } var editorTopLevel = game.EditorSceneSystem.GraphicsCompositor.Game as EditorTopLevelCompositor; if (editorTopLevel != null) { // Display it as incrust editorTopLevel.PostGizmoCompositors.Add(renderIncrustRenderer = new RenderIncrustRenderer(this)); } Services.Get <IEditorGameEntitySelectionService>().SelectionUpdated += UpdateModifiedEntitiesList; return(Task.FromResult(true)); }
protected override void InitializeCore() { base.InitializeCore(); // Light accumulation shader lightShaftsEffectShader = ToLoadAndUnload(new ImageEffectShader("LightShaftsEffect")); // Additive blending shader applyLightEffectShader = ToLoadAndUnload(new ImageEffectShader("AdditiveLightEffect")); applyLightEffectShader.BlendState = new BlendStateDescription(Blend.One, Blend.One); minmaxVolumeEffectShader = new DynamicEffectInstance("VolumeMinMaxShader"); minmaxVolumeEffectShader.Initialize(Context.Services); blur = ToLoadAndUnload(new GaussianBlur()); // Need the shadow map renderer in order to render light shafts var meshRenderFeature = Context.RenderSystem.RenderFeatures.OfType <MeshRenderFeature>().FirstOrDefault(); if (meshRenderFeature == null) { throw new InvalidOperationException("Missing mesh render feature"); } var forwardLightingFeature = meshRenderFeature.RenderFeatures.OfType <ForwardLightingRenderFeature>().FirstOrDefault(); if (forwardLightingFeature == null) { throw new InvalidOperationException("Missing forward lighting render feature"); } shadowMapRenderer = forwardLightingFeature.ShadowMapRenderer; for (int i = 0; i < 2; ++i) { var minmaxPipelineState = new MutablePipelineState(Context.GraphicsDevice); minmaxPipelineState.State.SetDefaults(); minmaxPipelineState.State.BlendState.RenderTarget0.BlendEnable = true; minmaxPipelineState.State.BlendState.RenderTarget0.ColorSourceBlend = Blend.One; minmaxPipelineState.State.BlendState.RenderTarget0.ColorDestinationBlend = Blend.One; minmaxPipelineState.State.BlendState.RenderTarget0.ColorBlendFunction = i == 0 ? BlendFunction.Min : BlendFunction.Max; minmaxPipelineState.State.BlendState.RenderTarget0.ColorWriteChannels = i == 0 ? ColorWriteChannels.Red : ColorWriteChannels.Green; minmaxPipelineState.State.DepthStencilState.DepthBufferEnable = false; minmaxPipelineState.State.DepthStencilState.DepthBufferWriteEnable = false; minmaxPipelineState.State.RasterizerState.DepthClipEnable = true; minmaxPipelineState.State.RasterizerState.CullMode = i == 0 ? CullMode.Back : CullMode.Front; minmaxPipelineStates[i] = minmaxPipelineState; } }
public TileMeshRenderer(GraphicsDevice graphicsDevice) { if (graphicsDevice == null) { throw new ArgumentNullException(nameof(graphicsDevice)); } GraphicsDevice = graphicsDevice; MutablePipeline = new MutablePipelineState(graphicsDevice); DefaultEffect = new EffectInstance(new Effect(GraphicsDevice, TileMeshRendererShader.Bytecode) { Name = "BatchDefaultEffect" }); }
protected override async Task LoadContent() { await base.LoadContent(); pipelineState = new MutablePipelineState(GraphicsDevice); var vertices = new Vertex[4]; vertices[0] = new Vertex { Position = new Vector3(-1, -1, 0.5f), TexCoords = new Vector2(0, 0) }; vertices[1] = new Vertex { Position = new Vector3(-1, 1, 0.5f), TexCoords = new Vector2(3, 0) }; vertices[2] = new Vertex { Position = new Vector3(1, 1, 0.5f), TexCoords = new Vector2(3, 3) }; vertices[3] = new Vertex { Position = new Vector3(1, -1, 0.5f), TexCoords = new Vector2(0, 3) }; var indices = new short[] { 0, 1, 2, 0, 2, 3 }; var vertexBuffer = Buffer.Vertex.New(GraphicsDevice, vertices, GraphicsResourceUsage.Default); var indexBuffer = Buffer.Index.New(GraphicsDevice, indices, GraphicsResourceUsage.Default); var meshDraw = new MeshDraw { DrawCount = 4, PrimitiveType = PrimitiveType.TriangleList, VertexBuffers = new[] { new VertexBufferBinding(vertexBuffer, new VertexDeclaration(VertexElement.Position<Vector3>(), VertexElement.TextureCoordinate<Vector2>()), 4) }, IndexBuffer = new IndexBufferBinding(indexBuffer, false, indices.Length), }; mesh = new Mesh { Draw = meshDraw, }; simpleEffect = new EffectInstance(new Effect(GraphicsDevice, SpriteEffect.Bytecode)); simpleEffect.Parameters.Set(TexturingKeys.Texture0, UVTexture); simpleEffect.UpdateEffect(GraphicsDevice); // TODO GRAPHICS REFACTOR //vao = VertexArrayObject.New(GraphicsDevice, mesh.Draw.IndexBuffer, mesh.Draw.VertexBuffers); myDraws = new DrawOptions[3]; myDraws[0] = new DrawOptions { Sampler = GraphicsDevice.SamplerStates.LinearClamp, Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(-0.5f, 0.5f, 0f)) }; myDraws[1] = new DrawOptions { Sampler = GraphicsDevice.SamplerStates.LinearWrap, Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(0.5f, 0.5f, 0f)) }; myDraws[2] = new DrawOptions { Sampler = SamplerState.New(GraphicsDevice, new SamplerStateDescription(TextureFilter.Linear, TextureAddressMode.Mirror)), Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(0.5f, -0.5f, 0f)) }; //var borderDescription = new SamplerStateDescription(TextureFilter.Linear, TextureAddressMode.Border) { BorderColor = Color.Purple }; //var border = SamplerState.New(GraphicsDevice, borderDescription); //myDraws[3] = new DrawOptions { Sampler = border, Transform = Matrix.Multiply(Matrix.Scale(0.3f), Matrix.Translation(-0.5f, -0.5f, 0f)) }; }
protected override void InitializeCore() { // Initalize the shader myCustomShader = new DynamicEffectInstance("MyCustomShader"); myCustomShader.Initialize(Context.Services); // Create the pipeline state and set properties that won't change pipelineState = new MutablePipelineState(Context.GraphicsDevice); pipelineState.State.SetDefaults(); pipelineState.State.InputElements = MyRenderObject.VertexDeclaration.CreateInputElements(); pipelineState.State.PrimitiveType = MyRenderObject.PrimitiveType; pipelineState.State.BlendState = BlendStates.Default; pipelineState.State.RasterizerState.CullMode = CullMode.None; }
public ComputeEffectShader(RenderContext context) : base(context, null) { pipelineState = new MutablePipelineState(context.GraphicsDevice); // Setup the effect compiler EffectInstance = new DynamicEffectInstance("ComputeEffectShader", Parameters); EffectInstance.Initialize(context.Services); ThreadNumbers = new Int3(1); ThreadGroupCounts = new Int3(1); SetDefaultParameters(); }
protected override void InitializeCore() { base.InitializeCore(); // initialize shader shader = new DynamicEffectInstance("SinglePassWireframeShader"); shader.Initialize(Context.Services); // create the pipeline state and set properties that won't change pipelineState = new MutablePipelineState(Context.GraphicsDevice); pipelineState.State.SetDefaults(); pipelineState.State.InputElements = VertexPositionNormalTexture.Layout.CreateInputElements(); pipelineState.State.BlendState = BlendStates.AlphaBlend; pipelineState.State.RasterizerState.CullMode = CullMode.None; }
/// <inheritdoc/> protected override void InitializeCore() { base.InitializeCore(); pipelineState = new MutablePipelineState(Context.GraphicsDevice); if (EffectName == null) { throw new ArgumentNullException("No EffectName specified"); } // Setup the effect compiler EffectInstance.Initialize(Context.Services); SetDefaultParameters(); }
//public static public static MutablePipelineState ReApplyGeometryStreamOutShader(this MutablePipelineState mutablePipelineState, GraphicsDevice graphicsDevice, EffectInstance geometryEffectInstance, string semanticName) { var bytecode = geometryEffectInstance.Effect.Bytecode; var reflection = bytecode.Reflection; var geometryBytecode = bytecode.Stages.First(s => s.Stage == ShaderStage.Geometry); // Calculate the strides var soStrides = new List <int>(); foreach (var streamOutputElement in reflection.ShaderStreamOutputDeclarations) { for (int i = soStrides.Count; i < (streamOutputElement.Stream + 1); i++) { soStrides.Add(0); } soStrides[streamOutputElement.Stream] += streamOutputElement.ComponentCount * sizeof(float); } SharpDX.Direct3D11.StreamOutputElement[] soElements; var soElems = new List <SharpDX.Direct3D11.StreamOutputElement>(); foreach (var streamOutputElement in reflection.ShaderStreamOutputDeclarations) { var soElem = new SharpDX.Direct3D11.StreamOutputElement() { Stream = streamOutputElement.Stream, SemanticIndex = streamOutputElement.SemanticIndex, SemanticName = streamOutputElement.SemanticName, StartComponent = streamOutputElement.StartComponent, ComponentCount = streamOutputElement.ComponentCount, OutputSlot = streamOutputElement.OutputSlot }; soElems.Add(soElem); } var nativeDevice = graphicsDevice.GetNativeDevice(); //var oldGeomShader = (SharpDX.Direct3D11.GeometryShader)geometryShaderFi.GetValue(mutablePipelineState.CurrentState); //oldGeomShader.Dispose(); needed? var geometryShader = new SharpDX.Direct3D11.GeometryShader(nativeDevice, geometryBytecode, soElems.ToArray(), reflection.StreamOutputStrides, reflection.StreamOutputRasterizedStream); geometryShaderFi.SetValue(mutablePipelineState.CurrentState, geometryShader); return(mutablePipelineState); }
public ComputeEffectShader(RenderContext context) : base(context, null) { pipelineState = new MutablePipelineState(context.GraphicsDevice); // Setup the effect compiler EffectInstance = new DynamicEffectInstance("ComputeEffectShader", Parameters); EffectInstance.Initialize(context.Services); // We give ComputeEffectShader a higher priority, since they are usually executed serially and blocking EffectInstance.EffectCompilerParameters.TaskPriority = -1; ThreadNumbers = new Int3(1); ThreadGroupCounts = new Int3(1); SetDefaultParameters(); }
private void Init() { _tribuf = Buffer.New(GraphicsDevice, new[] { new Vector4(-0.5f, 0.5f, 0, 1), new Vector4(0.5f, 0.5f, 0, 1), new Vector4(0, -0.5f, 0, 1) }, BufferFlags.VertexBuffer, GraphicsResourceUsage.Immutable); simpleEffect = new EffectInstance(new Effect(GraphicsDevice, SpriteEffect.Bytecode)); simpleEffect.Parameters.Set(SpriteBaseKeys.MatrixTransform, Matrix.Identity); simpleEffect.UpdateEffect(GraphicsDevice); pipelineState = new MutablePipelineState(GraphicsDevice); pipelineState.State.SetDefaults(); pipelineState.State.InputElements = VertexDeclaration.CreateInputElements(); pipelineState.State.PrimitiveType = PrimitiveType; }
/// <summary> /// Initializes a new instance of the <see cref="XenkoRenderer"/> class. /// </summary> /// <param name="graphicsDeviceManager">The graphics device manager.</param> public XenkoRenderer(GraphicsDeviceManager graphicsDeviceManager, EffectSystem effectSystem) : base() { manager = graphicsDeviceManager; this.effectSystem = effectSystem; spriteBatch = new SpriteBatch(manager.GraphicsDevice); clipRectanges = new Stack <Rectangle>(); activeEffects = new Stack <EffectInstance>(); scissorRasterizerStateDescription = RasterizerStates.CullNone; scissorRasterizerStateDescription.ScissorTestEnable = true; // enables the scissor test geometryRasterizerStateDescription = RasterizerStates.CullNone; //geometryRasterizerStateDescription.FillMode = FillMode.Wireframe; geometryPipelineState = new MutablePipelineState(manager.GraphicsDevice); geometryPipelineState.State.DepthStencilState = DepthStencilStates.None; clipArray = new Rectangle[1]; }
/// <inheritdoc/> protected override void InitializeCore() { base.InitializeCore(); pipelineState = new MutablePipelineState(Context.GraphicsDevice); pipelineState.State.SetDefaults(); pipelineState.State.InputElements = PrimitiveQuad.VertexDeclaration.CreateInputElements(); pipelineState.State.PrimitiveType = PrimitiveQuad.PrimitiveType; if (EffectName == null) { throw new ArgumentNullException("No EffectName specified"); } // Setup the effect compiler EffectInstance.Initialize(Context.Services); SetDefaultParameters(); }
/// <summary> /// Initializes a new instance of the <see cref="GeometricPrimitive{T}"/> class. /// </summary> /// <param name="graphicsDevice">The graphics device.</param> /// <param name="geometryMesh">The geometry mesh.</param> /// <exception cref="System.InvalidOperationException">Cannot generate more than 65535 indices on feature level HW <= 9.3</exception> public GeometricPrimitive(GraphicsDevice graphicsDevice, GeometricMeshData <T> geometryMesh) { GraphicsDevice = graphicsDevice; PipelineState = new MutablePipelineState(graphicsDevice); var vertices = geometryMesh.Vertices; var indices = geometryMesh.Indices; if (geometryMesh.IsLeftHanded) { ReverseWinding(vertices, indices); } if (indices.Length < 0xFFFF) { var indicesShort = new ushort[indices.Length]; for (int i = 0; i < indicesShort.Length; i++) { indicesShort[i] = (ushort)indices[i]; } IndexBuffer = Buffer.Index.New(graphicsDevice, indicesShort).RecreateWith(indicesShort).DisposeBy(this); } else { if (graphicsDevice.Features.CurrentProfile <= GraphicsProfile.Level_9_3) { throw new InvalidOperationException("Cannot generate more than 65535 indices on feature level HW <= 9.3"); } IndexBuffer = Buffer.Index.New(graphicsDevice, indices).RecreateWith(indices).DisposeBy(this); IsIndex32Bits = true; } // For now it will keep buffers for recreation. // TODO: A better alternative would be to store recreation parameters so that we can reuse procedural code. VertexBuffer = Buffer.Vertex.New(graphicsDevice, vertices).RecreateWith(vertices).DisposeBy(this); VertexBufferBinding = new VertexBufferBinding(VertexBuffer, new T().GetLayout(), vertices.Length); PipelineState.State.SetDefaults(); PipelineState.State.InputElements = VertexBufferBinding.Declaration.CreateInputElements(); PipelineState.State.PrimitiveType = PrimitiveQuad.PrimitiveType; }
/// <inheritdoc/> protected override void InitializeCore() { base.InitializeCore(); pipelineState = new MutablePipelineState(Context.GraphicsDevice); pipelineState.State.SetDefaults(); pipelineState.State.InputElements = PrimitiveQuad.VertexDeclaration.CreateInputElements(); pipelineState.State.PrimitiveType = PrimitiveQuad.PrimitiveType; if (EffectName == null) { throw new ArgumentNullException("No EffectName specified"); } // Setup the effect compiler EffectInstance.Initialize(Context.Services); // We give ImageEffectShader a higher priority, since they are usually executed serially and blocking EffectInstance.EffectCompilerParameters.TaskPriority = -1; SetDefaultParameters(); }
/// <inheritdoc/> protected override void InitializeCore() { base.InitializeCore(); MutablePipeline = new MutablePipelineState(Context.GraphicsDevice); // Create RenderEffectKey RenderEffectKey = RenderData.CreateStaticObjectKey <RenderEffect>(null, EffectPermutationSlotCount); // TODO: Assign weights so that PerDraw is always last? (we usually most custom user ones to be between PerView and PerDraw) perFrameDescriptorSetSlot = GetOrCreateEffectDescriptorSetSlot("PerFrame"); perViewDescriptorSetSlot = GetOrCreateEffectDescriptorSetSlot("PerView"); perDrawDescriptorSetSlot = GetOrCreateEffectDescriptorSetSlot("PerDraw"); RenderSystem.RenderStages.CollectionChanged += RenderStages_CollectionChanged; // Create effect slots Array.Resize(ref effectSlots, RenderSystem.RenderStages.Count); for (int index = 0; index < RenderSystem.RenderStages.Count; index++) { var renderStage = RenderSystem.RenderStages[index]; effectSlots[index] = CreateEffectPermutationSlot(renderStage.EffectSlotName); } }
public PrepareThreadContext(RenderContext renderContext) { MutablePipelineState = new MutablePipelineState(renderContext.GraphicsDevice); Context = renderContext.GetThreadContext(); }
void ILowLevelAPIRender.Draw(RenderContext renderContext, RenderDrawContext drawContext, RenderView renderView, RenderViewStage renderViewStage, CommandList commandList) { if (!enabledPin.Value) { return; } try { var pipelineState = this.pipelineState ?? (this.pipelineState = new MutablePipelineState(renderContext.GraphicsDevice)); // TODO1: PerFrame could be done in Update if we'd have access to frame time // TODO2: This code can be optimized by using parameter accessors and not parameter keys parameters.SetPerFrameParameters(perFrameParams, drawContext.RenderContext); parameters.SetPerViewParameters(perViewParams, renderView); if (worldPin != null) { var world = worldPin.ShaderValue; parameters.SetPerDrawParameters(perDrawParams, renderView, ref world); } // Set permutation parameters before updating the effect (needed by compiler) parameters.Set(ComputeEffectShaderKeys.ThreadNumbers, threadNumbersPin.Value); // Give user chance to override parameterSetterPin?.Value.Invoke(parameters, renderView, drawContext); if (instance.UpdateEffect(renderContext.GraphicsDevice) || pipelineStateDirty) { threadGroupCountAccessor = parameters.GetAccessor(ComputeShaderBaseKeys.ThreadGroupCountGlobal); foreach (var p in Inputs.OfType <ParameterPin>()) { p.Update(parameters); } pipelineState.State.SetDefaults(); pipelineState.State.RootSignature = instance.RootSignature; pipelineState.State.EffectBytecode = instance.Effect.Bytecode; pipelineState.Update(); pipelineStateDirty = false; } // Apply pipeline state commandList.SetPipelineState(pipelineState.CurrentState); // Set thread group count as provided by input pin var threadGroupCount = dispatchCountPin.Value; parameters.Set(ComputeShaderBaseKeys.ThreadGroupCountGlobal, threadGroupCount); // TODO: This can be optimized by uploading only parameters from the PerDispatch groups - look in Xenkos RootEffectRenderFeature var iterationCount = Math.Max(iterationCountPin.Value, 1); for (int i = 0; i < iterationCount; i++) { // Give user chance to override iterationParameterSetterPin.Value?.Invoke(parameters, renderView, drawContext, i); // The thread group count can be set for each dispatch threadGroupCount = parameters.Get(threadGroupCountAccessor); // Upload the parameters instance.Apply(drawContext.GraphicsContext); // Draw a full screen quad commandList.Dispatch(threadGroupCount.X, threadGroupCount.Y, threadGroupCount.Z); } } catch (Exception e) { var re = new RuntimeException(e.InnermostException(), this); RuntimeGraph.ReportException(re); } }
/// <summary> /// Bake lightprobes into buffers compatible with <see cref="LightProbeRenderer"/> /// </summary> /// <param name="drawContext">The drawing context</param> private unsafe void BakeLightProbes(RenderContext context, RenderDrawContext drawContext) { Texture ibl = null; Buffer tetrahedronProbeIndices = null; Buffer tetrahedronMatrices = null; Buffer lightprobesCoefficients = null; var renderView = context.RenderView; var lightProbesData = context.VisibilityGroup.Tags.Get(LightProbeRenderer.CurrentLightProbes); if (lightProbesData == null || lightProbesData.Tetrahedra.Count == 0) { // No lightprobes, we still set GPU resources (otherwise rendering might fetch invalid data) goto SetGPUResources; } // First time initialization if (bakeLightProbes == null) { bakeLightProbes = new DynamicEffectInstance("XenkoBakeLightProbeEffect"); bakeLightProbes.Initialize(Services); bakeLightProbesPipeline = new MutablePipelineState(GraphicsDevice); bakeLightProbesPipeline.State.InputElements = LightProbeVertex.Layout.CreateInputElements(); bakeLightProbesPipeline.State.PrimitiveType = PrimitiveType.TriangleList; } // Render IBL tetrahedra ID so that we can assign them per pixel //ibl = PushScopedResource(Context.Allocator.GetTemporaryTexture2D(drawContext.CommandList.DepthStencilBuffer.Width, drawContext.CommandList.DepthStencilBuffer.Height, PixelFormat.R16_UInt)); ibl = PushScopedResource(Context.Allocator.GetTemporaryTexture2D(TextureDescription.New2D(drawContext.CommandList.DepthStencilBuffer.Width, drawContext.CommandList.DepthStencilBuffer.Height, 1, PixelFormat.R16_UInt, TextureFlags.ShaderResource | TextureFlags.RenderTarget, 1, GraphicsResourceUsage.Default, actualMultisampleCount))); using (drawContext.PushRenderTargetsAndRestore()) { drawContext.CommandList.Clear(ibl, Color4.Black); drawContext.CommandList.SetRenderTarget(drawContext.CommandList.DepthStencilBuffer, ibl); bakeLightProbes.UpdateEffect(GraphicsDevice); bakeLightProbesPipeline.State.RootSignature = bakeLightProbes.RootSignature; bakeLightProbesPipeline.State.EffectBytecode = bakeLightProbes.Effect.Bytecode; bakeLightProbesPipeline.State.RasterizerState.DepthClipEnable = false; bakeLightProbesPipeline.State.DepthStencilState = new DepthStencilStateDescription(true, false) { StencilEnable = true, FrontFace = new DepthStencilStencilOpDescription { StencilDepthBufferFail = StencilOperation.Keep, StencilFail = StencilOperation.Keep, StencilPass = StencilOperation.Increment, StencilFunction = CompareFunction.Equal, }, }; //bakeLightProbesPipeline.State.RasterizerState.DepthClipEnable = false; bakeLightProbesPipeline.State.Output.CaptureState(drawContext.CommandList); bakeLightProbesPipeline.Update(); drawContext.CommandList.SetPipelineState(bakeLightProbesPipeline.CurrentState); drawContext.CommandList.SetStencilReference(0); // Apply the effect bakeLightProbes.Parameters.Set(BakeLightProbeShaderKeys.MatrixTransform, ref renderView.ViewProjection); bakeLightProbes.Apply(drawContext.GraphicsContext); /*int tetrahedrawGridSize = 5; * Vector3 tetrahedraMin = new Vector3(-12.0f); * Vector3 tetrahedraMax = new Vector3(12.0f); * var lightprobePositions = new Vector3[tetrahedrawGridSize*tetrahedrawGridSize*tetrahedrawGridSize]; * * for (int i = 0; i < lightprobePositions.Length; ++i) * { * lightprobePositions[i] = new Vector3( * MathUtil.Lerp(tetrahedraMin.X, tetrahedraMax.X, (float)(i/(tetrahedrawGridSize*tetrahedrawGridSize))/(tetrahedrawGridSize - 1)), * MathUtil.Lerp(tetrahedraMin.Y, tetrahedraMax.Y, (float)((i/tetrahedrawGridSize)%tetrahedrawGridSize)/(tetrahedrawGridSize - 1)), * MathUtil.Lerp(tetrahedraMin.Z, tetrahedraMax.Z, (float)(i%tetrahedrawGridSize)/(tetrahedrawGridSize - 1))); * } * * var tetra = new BowyerWatsonTetrahedralization(); * var tetraResult = tetra.Compute(lightprobePositions);*/ Matrix.Invert(ref renderView.View, out var viewInverse); var eye = new Vector3(viewInverse.M41, viewInverse.M42, viewInverse.M43); var tetraResult = lightProbesData.Tetrahedra; var lightprobePositions = lightProbesData.Vertices; var lightprobeFaces = lightProbesData.Faces; // We build a graph of tetrahedron connectivity from back to front, then do a topological sort on top of it var tetraDepth = new TetrahedronSortKey[tetraResult.Count]; var faceDirection = new bool[lightprobeFaces.Count]; var incomingEdges = new byte[tetraResult.Count]; var processQueue = new Queue <int>(); int processedTetrahedra = 0; for (int i = 0; i < lightprobeFaces.Count; ++i) { var face = lightprobeFaces[i]; // Compute face orientations var vertex0 = lightprobePositions[face.Vertices[0]]; Vector3.Subtract(ref vertex0, ref eye, out vertex0); bool faceFrontFacing = Vector3.Dot(face.Normal, vertex0) >= 0.0f; faceDirection[i] = faceFrontFacing; // Only process edges that connect two tetrahedra (ignore boundaries for now) if (face.BackTetrahedron != -1) { // Build list of incoming edges (back to front) if (faceFrontFacing) { incomingEdges[face.FrontTetrahedron] |= (byte)(1 << face.FrontFace); } else { incomingEdges[face.BackTetrahedron] |= (byte)(1 << face.BackFace); } } } for (int i = 0; i < tetraResult.Count; ++i) { // Tetrahedron without any incoming edges means they should be drawn first (graph nodes with no incoming edges for our topological sort) if (incomingEdges[i] == 0) { processQueue.Enqueue(i); } } // Perform topological sort while (processQueue.Count > 0) { var tetrahedronIndex = processQueue.Dequeue(); tetraDepth[tetrahedronIndex] = new TetrahedronSortKey(tetrahedronIndex, processedTetrahedra++); var tetrahedron = tetraResult[tetrahedronIndex]; //var frontFacingFaces = frontFacing[tetrahedronIndex]; // Process each outgoing face (edges in the graph) for (int tetrahedronFace = 0; tetrahedronFace < 4; ++tetrahedronFace) { // Check if there is a neighbour if (tetrahedron.Neighbours[tetrahedronFace] == -1) { continue; } var faceIndex = tetrahedron.Faces[tetrahedronFace]; var realFaceIndex = faceIndex >= 0 ? faceIndex : ~faceIndex; // Only process faces going back to front (outgoing edges) if (faceDirection[realFaceIndex] == faceIndex >= 0) { continue; } var face = lightprobeFaces[realFaceIndex]; int tetrahedronNeighbourIndex; sbyte tetrahedronNeighbourFace; if (faceIndex >= 0) { tetrahedronNeighbourIndex = face.BackTetrahedron; tetrahedronNeighbourFace = face.BackFace; } else { tetrahedronNeighbourIndex = face.FrontTetrahedron; tetrahedronNeighbourFace = face.FrontFace; } var neighbourTraversedFaces = incomingEdges[tetrahedronNeighbourIndex]; var newNeighbourTraversedFaces = (byte)(neighbourTraversedFaces & ~(1 << tetrahedronNeighbourFace)); // Proceed only if something changed if (newNeighbourTraversedFaces != neighbourTraversedFaces) { incomingEdges[tetrahedronNeighbourIndex] = newNeighbourTraversedFaces; if (newNeighbourTraversedFaces == 0) // are all incoming edges already marked? If yes, go on { processQueue.Enqueue(tetrahedronNeighbourIndex); } } } } Array.Sort(tetraDepth); // Draw shape tetrahedronMatrices = PushScopedResource(Context.Allocator.GetTemporaryBuffer(new BufferDescription(tetraResult.Count * 3 * sizeof(Vector4), BufferFlags.ShaderResource, GraphicsResourceUsage.Default), PixelFormat.R32G32B32A32_Float)); tetrahedronProbeIndices = PushScopedResource(Context.Allocator.GetTemporaryBuffer(new BufferDescription(tetraResult.Count * 4 * sizeof(int), BufferFlags.ShaderResource, GraphicsResourceUsage.Default), PixelFormat.R32G32B32A32_UInt)); lightprobesCoefficients = PushScopedResource(Context.Allocator.GetTemporaryBuffer(new BufferDescription(lightProbesData.Coefficients.Length * sizeof(Color3), BufferFlags.ShaderResource, GraphicsResourceUsage.Default), PixelFormat.R32G32B32_Float)); var tetraInsideIndex = -1; fixed(Color3 *lightProbeCoefficients = lightProbesData.Coefficients) fixed(Vector4 * matrices = lightProbesData.Matrices) fixed(Int4 * probeIndices = lightProbesData.LightProbeIndices) { drawContext.CommandList.UpdateSubresource(lightprobesCoefficients, 0, new DataBox((IntPtr)lightProbeCoefficients, 0, 0)); drawContext.CommandList.UpdateSubresource(tetrahedronProbeIndices, 0, new DataBox((IntPtr)probeIndices, 0, 0)); drawContext.CommandList.UpdateSubresource(tetrahedronMatrices, 0, new DataBox((IntPtr)matrices, 0, 0)); // Find which probe we are currently in // TODO: Optimize (use previous coherency info?) for (int i = 0; i < tetraResult.Count; ++i) { // Get tetrahedra matrix var tetrahedraMatrix = Matrix.Identity; tetrahedraMatrix.Column1 = matrices[i * 3 + 0]; tetrahedraMatrix.Column2 = matrices[i * 3 + 1]; tetrahedraMatrix.Column3 = matrices[i * 3 + 2]; // Extract and zero-out position of 3rd vertex (we get the 3x3 matrix) var vertex3 = tetrahedraMatrix.TranslationVector; tetrahedraMatrix.TranslationVector = Vector3.Zero; Vector3 tetraFactors = Vector3.TransformCoordinate(eye - vertex3, tetrahedraMatrix); var tetraFactorW = 1.0f - tetraFactors.X - tetraFactors.Y - tetraFactors.Z; if (tetraFactors.X >= 0.0f && tetraFactors.X <= 1.0f && tetraFactors.Y >= 0.0f && tetraFactors.Y <= 1.0f && tetraFactors.Z >= 0.0f && tetraFactors.Z <= 1.0f && tetraFactorW >= 0.0f && tetraFactorW <= 1.0f) { tetraInsideIndex = i; break; } } } // Fill vertex/index buffers var vertexBuffer = PushScopedResource(Context.Allocator.GetTemporaryBuffer(new BufferDescription((tetraResult.Count * 4 + 3) * LightProbeVertex.Size, BufferFlags.VertexBuffer, GraphicsResourceUsage.Dynamic))); var indexBuffer = PushScopedResource(Context.Allocator.GetTemporaryBuffer(new BufferDescription(tetraResult.Count * 12 * sizeof(uint), BufferFlags.IndexBuffer, GraphicsResourceUsage.Dynamic))); var mappedVertexBuffer = drawContext.CommandList.MapSubresource(vertexBuffer, 0, MapMode.WriteDiscard); var vertices = (LightProbeVertex *)mappedVertexBuffer.DataBox.DataPointer; // Upload sorted tetrahedron indices for (int i = 0; i < tetraResult.Count; ++i) { var sortedIndex = tetraDepth[i].Index; var tetrahedra = tetraResult[sortedIndex]; for (int j = 0; j < 4; ++j) { vertices[i * 4 + j] = new LightProbeVertex(lightprobePositions[tetrahedra.Vertices[j]], (uint)sortedIndex); } } // Full screen pass if (tetraInsideIndex != -1) { vertices[tetraResult.Count * 4 + 0] = new LightProbeVertex(new Vector3(-1, 1, 0), (uint)tetraInsideIndex); vertices[tetraResult.Count * 4 + 1] = new LightProbeVertex(new Vector3(3, 1, 0), (uint)tetraInsideIndex); vertices[tetraResult.Count * 4 + 2] = new LightProbeVertex(new Vector3(-1, -3, 0), (uint)tetraInsideIndex); } drawContext.CommandList.UnmapSubresource(mappedVertexBuffer); var mappedIndexBuffer = drawContext.CommandList.MapSubresource(indexBuffer, 0, MapMode.WriteDiscard); var indices = (int *)mappedIndexBuffer.DataBox.DataPointer; for (int i = 0; i < tetraResult.Count; ++i) { indices[i * 12 + 0] = i * 4 + 0; indices[i * 12 + 1] = i * 4 + 2; indices[i * 12 + 2] = i * 4 + 1; indices[i * 12 + 3] = i * 4 + 1; indices[i * 12 + 4] = i * 4 + 2; indices[i * 12 + 5] = i * 4 + 3; indices[i * 12 + 6] = i * 4 + 3; indices[i * 12 + 7] = i * 4 + 2; indices[i * 12 + 8] = i * 4 + 0; indices[i * 12 + 9] = i * 4 + 3; indices[i * 12 + 10] = i * 4 + 0; indices[i * 12 + 11] = i * 4 + 1; } drawContext.CommandList.UnmapSubresource(mappedIndexBuffer); drawContext.CommandList.SetVertexBuffer(0, vertexBuffer, 0, LightProbeVertex.Size); drawContext.CommandList.SetIndexBuffer(indexBuffer, 0, true); // Draw until current tetrahedra drawContext.CommandList.DrawIndexed(tetraResult.Count * 12); // For now, drawing them one by one (easier to debug) //for (int i = 0; i < tetraResult.Count; ++i) //{ // context.CommandList.DrawIndexed(12, i * 12); //} // Draw current tetrahedron we are in as full screen (fill stencil holes) if (tetraInsideIndex != -1) { bakeLightProbesPipeline.State.DepthStencilState.DepthBufferEnable = false; bakeLightProbesPipeline.Update(); drawContext.CommandList.SetPipelineState(bakeLightProbesPipeline.CurrentState); // Apply the effect bakeLightProbes.Parameters.Set(BakeLightProbeShaderKeys.MatrixTransform, Matrix.Identity); bakeLightProbes.Apply(drawContext.GraphicsContext); drawContext.CommandList.Draw(3, tetraResult.Count * 4); } // TODO: Draw the tetrahedron we are in full screen // context.CommandList.Draw... } // Set LightProbes resources SetGPUResources: foreach (var renderFeature in context.RenderSystem.RenderFeatures) { if (!(renderFeature is RootEffectRenderFeature)) { continue; } var logicalKey = ((RootEffectRenderFeature)renderFeature).CreateViewLogicalGroup("LightProbes"); var viewFeature = renderView.Features[renderFeature.Index]; foreach (var viewLayout in viewFeature.Layouts) { var resourceGroup = viewLayout.Entries[renderView.Index].Resources; var logicalGroup = viewLayout.GetLogicalGroup(logicalKey); if (logicalGroup.Hash == ObjectId.Empty) { continue; } resourceGroup.DescriptorSet.SetShaderResourceView(logicalGroup.DescriptorSlotStart, ibl); resourceGroup.DescriptorSet.SetShaderResourceView(logicalGroup.DescriptorSlotStart + 1, tetrahedronProbeIndices); resourceGroup.DescriptorSet.SetShaderResourceView(logicalGroup.DescriptorSlotStart + 2, tetrahedronMatrices); resourceGroup.DescriptorSet.SetShaderResourceView(logicalGroup.DescriptorSlotStart + 3, lightprobesCoefficients); } } }
protected override async Task LoadContent() { await base.LoadContent(); pipelineState = new MutablePipelineState(GraphicsDevice); var vertices = new Vertex[4]; vertices[0] = new Vertex { Position = new Vector3(-1, -1, 0.5f), TexCoords = new Vector2(0, 0) }; vertices[1] = new Vertex { Position = new Vector3(-1, 1, 0.5f), TexCoords = new Vector2(3, 0) }; vertices[2] = new Vertex { Position = new Vector3(1, 1, 0.5f), TexCoords = new Vector2(3, 3) }; vertices[3] = new Vertex { Position = new Vector3(1, -1, 0.5f), TexCoords = new Vector2(0, 3) }; var indices = new short[] { 0, 1, 2, 0, 2, 3 }; var vertexBuffer = Buffer.Vertex.New(GraphicsDevice, vertices, GraphicsResourceUsage.Default); var indexBuffer = Buffer.Index.New(GraphicsDevice, indices, GraphicsResourceUsage.Default); var meshDraw = new MeshDraw { DrawCount = 4, PrimitiveType = PrimitiveType.TriangleList, VertexBuffers = new[] { new VertexBufferBinding(vertexBuffer, new VertexDeclaration(VertexElement.Position <Vector3>(), VertexElement.TextureCoordinate <Vector2>()), 4) }, IndexBuffer = new IndexBufferBinding(indexBuffer, false, indices.Length), }; mesh = new Mesh { Draw = meshDraw, }; simpleEffect = new EffectInstance(new Effect(GraphicsDevice, SpriteEffect.Bytecode)); simpleEffect.Parameters.Set(TexturingKeys.Texture0, UVTexture); simpleEffect.UpdateEffect(GraphicsDevice); // TODO GRAPHICS REFACTOR //vao = VertexArrayObject.New(GraphicsDevice, mesh.Draw.IndexBuffer, mesh.Draw.VertexBuffers); myDraws = new DrawOptions[3]; myDraws[0] = new DrawOptions { Sampler = GraphicsDevice.SamplerStates.LinearClamp, Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(-0.5f, 0.5f, 0f)) }; myDraws[1] = new DrawOptions { Sampler = GraphicsDevice.SamplerStates.LinearWrap, Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(0.5f, 0.5f, 0f)) }; myDraws[2] = new DrawOptions { Sampler = SamplerState.New(GraphicsDevice, new SamplerStateDescription(TextureFilter.Linear, TextureAddressMode.Mirror)), Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(0.5f, -0.5f, 0f)) }; //var borderDescription = new SamplerStateDescription(TextureFilter.Linear, TextureAddressMode.Border) { BorderColor = Color.Purple }; //var border = SamplerState.New(GraphicsDevice, borderDescription); //myDraws[3] = new DrawOptions { Sampler = border, Transform = Matrix.Multiply(Matrix.Scale(0.3f), Matrix.Translation(-0.5f, -0.5f, 0f)) }; }