1
votes

I am attempting to use alpha blending with SharpDX. If I set my blend state on my output merger, nothing renders at all, and I have absolutely no idea why. When never setting the blend state, everything works fine. Even if I set a blend state with the default blend description, nothing renders. I figure there's some step I'm missing or I am doing something in the wrong order, so I'll just paste what I've got and hope somebody can point something out...

I have a BlendState set up using the following code:

bs = new BlendState(Devices.Device11, new BlendStateDescription());

var blendDesc = new RenderTargetBlendDescription(
    true,
    BlendOption.SourceAlpha,
    BlendOption.InverseSourceAlpha,
    BlendOperation.Add,
    BlendOption.One,
    BlendOption.Zero,
    BlendOperation.Add,
    ColorWriteMaskFlags.All);

bs.Description.RenderTarget[0] = blendDesc;

...and here are the contents of my render loop. If all I do is comment out context.OutputMerger.SetBlendState(bs), my meshes render fine (without any blending, that is):

var context = Devices.Device11.ImmediateContext;

context.ClearDepthStencilView(DepthStencilView, DepthStencilClearFlags.Depth, 1.0f, 0);
context.ClearRenderTargetView(RenderTargetView, new Color4());

context.OutputMerger.SetTargets(DepthStencilView, RenderTargetView);
context.OutputMerger.SetBlendState(bs);
context.Rasterizer.State = rs;
context.Rasterizer.SetViewport(Viewport);

context.VertexShader.SetConstantBuffer(0, viewProjBuffer);
context.UpdateSubresource(Camera.ViewProjection.ToFloatArray(), viewProjBuffer);

Dictionary<Mesh, Buffer> vBuffers = VertexBuffers.ToDictionary(k => k.Key, v => v.Value);
Dictionary<Mesh, Buffer> iBuffers = IndexBuffers.ToDictionary(k => k.Key, v => v.Value);

foreach (var mesh in vBuffers.Keys)
{
    if (mesh.MeshType == MeshType.LineStrip)
    {
        context.InputAssembler.PrimitiveTopology = PrimitiveTopology.LineStrip;
        context.InputAssembler.InputLayout = Effects.LineEffect.InputLayout;
        context.VertexShader.Set(Effects.LineEffect.VertexShader);
        context.PixelShader.Set(Effects.LineEffect.PixelShader);
    }
    else
    {
        context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
        context.InputAssembler.InputLayout = Effects.FaceEffect.InputLayout;
        context.VertexShader.Set(Effects.FaceEffect.VertexShader);
        context.PixelShader.Set(Effects.FaceEffect.PixelShader);
    }

    context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vBuffers[mesh], GetMeshStride(mesh) * 4, 0));
    context.InputAssembler.SetIndexBuffer(iBuffers[mesh], Format.R32_UInt, 0);

    context.DrawIndexed(mesh.IndexUsage, 0, 0);
}

context.ResolveSubresource(RenderTarget, 0, SharedTexture, 0, Format.B8G8R8A8_UNorm);
context.Flush();

I am rendering to a texture, which is initialized using the following texture description:

Texture2DDescription colorDesc = new Texture2DDescription
{
    BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
    Format = Format.B8G8R8A8_UNorm,
    Width = width,
    Height = height,
    MipLevels = 1,
    SampleDescription = new SampleDescription(8, 32),
    Usage = ResourceUsage.Default,
    OptionFlags = ResourceOptionFlags.Shared,
    CpuAccessFlags = CpuAccessFlags.None,
    ArraySize = 1
};

It is important for me to render to a texture and for me to use that format. I thought that maybe blending worked with particular formats, but I could not find any info suggesting anything of that sort.

I am also multisampling, which is why I call ResolveSubresource(...) at the end of my render method. The texture I am copying to has an identical description to RenderTarget, except with a different SampleDescription.

Speaking of multisampling, here's the RasterizerState I am using:

rs = new RasterizerState(Devices.Device11, new RasterizerStateDescription()
{
    FillMode = FillMode.Solid,
    CullMode = CullMode.Back,
    IsFrontCounterClockwise = true,
    DepthBias = 0,
    DepthBiasClamp = 0,
    SlopeScaledDepthBias = 0,
    IsDepthClipEnabled = true,
    IsScissorEnabled = false,
    IsMultisampleEnabled = true,
    IsAntialiasedLineEnabled = true
});

I am rendering with a shader, which is basically a "Hello World" shader plus a camera matrix and basic normal direction lighting. I've verified that my vertex alpha values are what they're supposed to be just as they're being populated into their vertex buffers... and even if I hardcode their alpha to 1 at the end of the pixel shader, I still get nothing, so long as I use that BlendState. Without using BlendState, everything renders opaque as expected, regardless of alpha values. I've even tried implementing the blend state in the shader itself, but that seems to have no effect whatsoever. Everything appears to render as if no blending was defined at all.

If it matters, I'm using FeatureLevel.Level.Level_11_0 with my Device.

Unfortunately this is about as much as I have to go on. Like I said this problem is a total mystery to me at this point.

1
Looks like a duplicate of this "SharpDX: Enabling blend state"xoofx
Ah I see. Thanks Alexandre!Nasai
I guess the appropriate thing to do here is to have my question marked as a duplicate, but I haven't found a way to do that. I've read that normally it's done by others, who have enough reputation or are moderators... Is there any special way I can do this for my own question without meeting those requirements?Nasai

1 Answers

1
votes

Just wanted to update this for anyone who comes here in the future. Something that worked for me was quite simply:

            BlendStateDescription blendStateDescription = new BlendStateDescription
            {
                AlphaToCoverageEnable = false,
            };

            blendStateDescription.RenderTarget[0].IsBlendEnabled = true;
            blendStateDescription.RenderTarget[0].SourceBlend = BlendOption.SourceAlpha;
            blendStateDescription.RenderTarget[0].DestinationBlend = BlendOption.InverseSourceAlpha;
            blendStateDescription.RenderTarget[0].BlendOperation = BlendOperation.Add;
            blendStateDescription.RenderTarget[0].SourceAlphaBlend = BlendOption.Zero;
            blendStateDescription.RenderTarget[0].DestinationAlphaBlend = BlendOption.Zero;
            blendStateDescription.RenderTarget[0].AlphaBlendOperation = BlendOperation.Add;
            blendStateDescription.RenderTarget[0].RenderTargetWriteMask = ColorWriteMaskFlags.All;

            this._context.OutputMerger.BlendState = new BlendState(_device,blendStateDescription);

I also handled the alpha component in my shader, as well, in case you want to manually add transparency to a model, pseudo code:

float4 PixelShaderMain( PixelShaderArgs pixelShaderArgs ) 
    : SV_Target
{
    float u = pixelShaderArgs.col.x;
    float v = pixelShaderArgs.col.y;
    float4 color = ShaderTexture.Load(int3(convertUVToPixel(u,v),0));
    return float4(color.r,color.g,color.b,0.5); // 50% transparency
}

Hope this helps someone instead of getting a dead page that basically points nowhere. Happy coding everyone!