GS Output not being rasterized (Billboards)

Started by
2 comments, last by Steven Ford 8 years, 3 months ago

Hi all,

apologies in advance if this is completely obvious to people, but I've spent two days trying to understand what's going on with no luck. If anyone has any weblinks which'd help explain this, then that'd be very much appreciated.

I'm modelling a 2D grid (of water) as an array of 4-bit numbers (bits 0..3 for 1st droplet, bits 4..7 for the 2nd droplet) within an array of 8 bit numbers where the location in the array is defined as '(y * totalWidth) + x'. I was hoping to be able to:

1. pass this memory chunk across to the graphics card for rendering directly

2. use a pointlist and the SV_VERTEXID functionality inside an expanding vertex shader to take in 32bits and output 8 vertices each

3. Expand these by the geometry shader into 2 triangles per original point (if the appropriate bits are set in the input data, otherwise output nothing for that input part of the point)

The HLSL code that I've written is:




// The data structure used to define the water points
struct WaterDropletsInputType
{
    uint bitMask : BITMASK;
    uint vertexID : SV_VertexID;
};

// Data structure used to communicate between the vertex shader and the geometry shader
struct WaterDropletExpandedType
{
    int2 position : SV_POSITION;

    // The following 2 values are expanded out of the bit mask
    // arguably this bit is unnecessary as we could simply pass
    // it through in a single value, but it's not costing us much
    // to split here
    uint movement;
    uint colour;
};

// Data structure which is passed out from the vertex shader and into the geometry shader
// prior to expansion into the various billboards
struct WaterDropletsVertexOutputType
{
    float2 offset : OFFSET;
    WaterDropletExpandedType droplets[8] : DROPLETS;
};

// This is what will get passed into the pixel shader from the geometry shader
struct WaterDropletPixelInputType
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

WaterDropletExpandedType PixelDetailsFromMask(int vertexNumber, uint mask)
{
    WaterDropletExpandedType output;
    
    uint uVertexNumber = vertexNumber;
    output.position = int2(uVertexNumber % (30 * 8), uVertexNumber / (30 * 8));

    output.colour = mask & 3;
    output.movement = (mask >> 2) & 3;

    return output;
}

WaterDropletsVertexOutputType WaterVertexShader(WaterDropletsInputType input)
{
    uint scaledVertexCount = 8 * input.vertexID;
    
    WaterDropletsVertexOutputType output;
    output.offset.xy = 0;

    output.droplets[0] = PixelDetailsFromMask(scaledVertexCount + 0, input.bitMask % 16);
    output.droplets[1] = PixelDetailsFromMask(scaledVertexCount + 1, (input.bitMask >> 4) & 15);
    output.droplets[2] = PixelDetailsFromMask(scaledVertexCount + 2, (input.bitMask >> 8) & 15);
    output.droplets[3] = PixelDetailsFromMask(scaledVertexCount + 3, (input.bitMask >> 12) & 15);
    output.droplets[4] = PixelDetailsFromMask(scaledVertexCount + 4, (input.bitMask >> 16) & 15);
    output.droplets[5] = PixelDetailsFromMask(scaledVertexCount + 5, (input.bitMask >> 20) & 15);
    output.droplets[6] = PixelDetailsFromMask(scaledVertexCount + 6, (input.bitMask >> 24) & 15);
    output.droplets[7] = PixelDetailsFromMask(scaledVertexCount + 7, (input.bitMask >> 28) & 15);

    return output;
}

[maxvertexcount(8*2*3*2)]
void WaterGeometryShader(point WaterDropletsVertexOutputType inputArray [1], inout TriangleStream<WaterDropletPixelInputType> outputStream)
{
    WaterDropletsVertexOutputType input = inputArray[0];

    for (int i = 0; i < 8;i++)
    {
        // Do nothing here
        if (input.droplets[i].colour == 0)
            continue;

        // These values are in pixels
        float pixelsX = input.offset.x + (input.droplets[i].position.x * 8);
        float pixelsY = input.offset.y + (input.droplets[i].position.y * 4);

        float4 color;
        color.rgb = 0;
        color.a = 1;
        switch (input.droplets[i].colour)
        {
        case 1:
            color.r = 1;
            break;

        case 2:
            color.b = 1;
            break;

        case 3:
            color.rb = 1;
            break;
        }

        WaterDropletPixelInputType pTL, pTR, pBL, pBR;
        pTL.position.wz = 0;
        pTR.position.wz = 0;
        pBL.position.wz = 0;
        pBR.position.wz = 0;

        pTL.color = color;
        pTR.color = color;
        pBL.color = color;
        pBR.color = color;

        pTL.position.x = pixelsX;
        pTL.position.y = pixelsY;
        pTR.position.x = pixelsX + 8;
        pTR.position.y = pixelsY;
        pBL.position.x = pixelsX;
        pBL.position.y = pixelsY + 4;
        pBR.position.x = pixelsX + 8;
        pBR.position.y = pixelsY + 4;

        // this must be configurable (scale to -1,1)
        pTL.position.x /= 640.0;
        pTR.position.x /= 640.0;
        pBL.position.x /= 640.0;
        pBR.position.x /= 640.0;
        pTL.position.x -= 1.0;
        pTR.position.x -= 1.0;
        pBL.position.x -= 1.0;
        pBR.position.x -= 1.0;

        // e.g. pixelsY = 64 (on screen of 1024 high) should go to 0.875
        pTL.position.y /= 512.0;
        pTR.position.y /= 512.0;
        pBL.position.y /= 512.0;
        pBR.position.y /= 512.0;
        pTL.position.y = 1.0 - pTL.position.y;
        pTR.position.y = 1.0 - pTR.position.y;
        pBL.position.y = 1.0 - pBL.position.y;
        pBR.position.y = 1.0 - pBR.position.y;

        // output the triangles (both ways round to avoid any culling issues)
        outputStream.Append(pTL);
        outputStream.Append(pBR);
        outputStream.Append(pTR);
        outputStream.RestartStrip();

        outputStream.Append(pTL);
        outputStream.Append(pBL);
        outputStream.Append(pBR);
        outputStream.RestartStrip();

        outputStream.Append(pTL);
        outputStream.Append(pTR);
        outputStream.Append(pBR);
        outputStream.RestartStrip();

        outputStream.Append(pTL);
        outputStream.Append(pBR);
        outputStream.Append(pBL);
        outputStream.RestartStrip();
    }
}

float4 WaterPixelShader(WaterDropletPixelInputType input) : SV_TARGET
{
    return input.color;
}

When I look in VS2015's graphics analyzer, it shows me the geometry shader's output, but no reference to the pixel shader (see attached screen shot):

[attachment=30124:screenShot1.png]

Looking at the rasterizer state, I have:

FillMode SOLID CullMode NONE FrontCounterClockwise FALSE DepthBias 0 DepthBiasClamp 0.000f SlopeScaleDepthBias 0.000f DepthClipEnable FALSE ScissorEnable FALSE MultisampleEnable FALSE AntialiasedLineEnable FALSE ForcedSampleCount 0
Device obj:1

So I'm utterly perplexed as to what's going on here.

I'm using the DX toolkit in the project as well, and that's working. I've removed the spritebatch calls as well to see if that is the issue, but no combination seems to work.

Can anyone give me some hints / tips on what might be the issue here? Or alternatively, suggest places to learn about the debugging tools available to solve this sort of problem.

Thanks in advance

Steve

PS Yes, the constants of 30, 50 and the screen size etc. will be moved to a constant buffer, but one step at a time :-)

Advertisement
If I understand your code correctly, it looks like you're setting the output vertex position to have z = 0.0 and w = 0.0, which is invalid. Try setting to w to 1.0 instead.

Hi MJP, thanks for taking the time to look at this, much appreciated!

When you say the output vertex, do you mean updating the GS so that it has:


		WaterDropletPixelInputType pTL, pTR, pBL, pBR;
		pTL.position.z = 0;
		pTR.position.z = 0;
		pBL.position.z = 0;
		pBR.position.z = 0;

		pTL.position.w = 1;
		pTR.position.w = 1;
		pBL.position.w = 1;
		pBR.position.w = 1;

Even after trying that, I'm still seeing nothing on screen and no Pixel Shader section in the debugger.

I've also updated the shader so that it always tries to output geometry at 128,128 pixels (-0.8, .0.75 in DX screen co-ordinates) and I again see the geometry in the debugger, but no PS step.

Is there something that I could be missing in terms of setting something else up in the pipeline? I'm doing the following:


	context->VSSetShader(_vertexShader->shader.Get(), nullptr, 0);
	context->GSSetShader(_geometryShader->shader.Get(), nullptr, 0);
	context->PSSetShader(_pixelShader->shader.Get(), nullptr, 0);

	context->IASetInputLayout(_inputLayout.Get());

	auto pointer = _vertexBuffer.Get();
	UINT vertexStride = sizeof(unsigned int);
	UINT vertexOffset = 0;
	context->IASetVertexBuffers(0, 1, &pointer, &vertexStride, &vertexOffset);
	context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY::D3D_PRIMITIVE_TOPOLOGY_POINTLIST);

	context->Draw(vertexCount, 0);

and optionally the following just to double check that there's nothing crazy in the rasterizer state that I'm using:


	context->IASetIndexBuffer(nullptr, DXGI_FORMAT::DXGI_FORMAT_R8_UINT, 0);
	Microsoft::WRL::ComPtr<ID3D11DepthStencilState> pDepthStencilState;
	D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
	ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
	depthStencilDesc.StencilEnable = TRUE;
	depthStencilDesc.DepthEnable = FALSE;
	this->_device->CreateDepthStencilState(&depthStencilDesc, &pDepthStencilState);

	Microsoft::WRL::ComPtr<ID3D11RasterizerState> pRasterizerState;
	D3D11_RASTERIZER_DESC rasterizerDesc;
	ZeroMemory(&rasterizerDesc, sizeof(rasterizerDesc));
	rasterizerDesc.CullMode = D3D11_CULL_MODE::D3D11_CULL_NONE;
	rasterizerDesc.FillMode = D3D11_FILL_MODE::D3D11_FILL_SOLID;
	rasterizerDesc.ScissorEnable = false;
	rasterizerDesc.DepthClipEnable = false;
	this->_device->CreateRasterizerState(&rasterizerDesc, &pRasterizerState);

	context->OMSetDepthStencilState(pDepthStencilState.Get(), 0);
	context->RSSetScissorRects(0, nullptr);
	context->RSSetState(pRasterizerState.Get());

Do you know if there's a way to see the actual values of the resultant vertices / primitives? I'm aware of the ShaderOut concept from the GS, but I'm a little wary of going further down that road until I know what I'm doing.

Thanks

Steve

Hi MJP,

I just reimplemented the change that you suggested and it's working now, I must have done something else stupid on the other machine (I blame trying to do it at midnight as I was hopeful of getting it all working! smile.png ).

Now I just need to get the rest of the water simulation to be realistic (see attached), or I could just say that you have to funnel the jelly or something like that, change the narrative to fit the coding ;-)

[attachment=30127:screenshot.png]

And yes, this is a definite work in progress!

Thanks again

Steve

This topic is closed to new replies.

Advertisement