Geometry Shader Blank Screen

Started by
10 comments, last by KieronH 9 years ago

Okay so I'm trying to do point to quad expansion on particle data that is being fed through the graphics pipeline. If I have a simple vertex and pixel shader everything works perfectly (rendered as points). However, when I add in the geometry shader stage everything disappears from the screen. I don't just mean the particles, even the text that is being rendered using spritebatch from the DirectXTK. Any ideas as to what might be causing this? I'll post my shader code.

It appears to happen more specifically when I use this line:

deviceContext->GSSetShader(geometryShader, 0, 0);

I've checked everything compiles correctly and that seems to be fine.

Here's the shader code I'm referring too:


//#pragma pack_matrix( row_major )

cbuffer ConstantBuffer : register(b0)
{
	matrix World;
	matrix View;
	matrix Projection;
}
cbuffer cbFixed
{
	//
	// Compute texture coordinates to stretch texture over quad.
	//

	float2 gTexC[4] =
	{
		float2(0.0f, 1.0f),
		float2(0.0f, 0.0f),
		float2(1.0f, 1.0f),
		float2(1.0f, 0.0f)
	};
};

struct particles
{
	float3 position : POSITION;
	float3 velocity;
	float life;
	float age;
	bool alive;
	float startSize;
	float endSize;
	float4 startColour;
	float4 endColour;
};

struct VS_INPUT
{
	uint id : SV_VERTEXID;
};

struct GS_INPUT
{
    float3 Pos : POSITION;
};

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float4 Col : COLOUR;
	float2 TexCoord : TEXCOORD;
};

struct GeoOut
{
	float4 PosH    : SV_POSITION;
	float2 Tex     : TEXCOORD;
	uint   PrimID  : SV_PrimitiveID;
};

static const float scale = 0.5f;

static const float4 g_positions[4] =
{
	float4(-scale, scale, 0, 0),
	float4(scale, scale, 0, 0),
	float4(-scale, -scale, 0, 0),
	float4(scale, -scale, 0, 0),
};

static const float2 g_texcoords[4] =
{
	float2(0, 1),
	float2(1, 1),
	float2(0, 0),
	float2(1, 0),
};


StructuredBuffer<particles>   particlesIn : register(t0);

GS_INPUT VS(VS_INPUT input)
{
	GS_INPUT output;

	output.Pos.xyz = particlesIn[input.id].position;

	return output;
}

[maxvertexcount(4)]
void GS(point GS_INPUT input[1], inout TriangleStream<PS_INPUT> SpriteStream)
{
	PS_INPUT output;

	float3 CameraLocation = float3(0.0f, 1.0f, -5.0f);

	float dist = saturate(length(input[0].Pos - CameraLocation.xyz) / 100.0f);
	//float4 color = float4( 0.2f, 1.0f, 0.2f, 0.0f ) * dist + float4( 1.0f, 0.1f, 0.1f, 0.0f ) * ( 1.0f - dist ); 
	//float4 color = float4( 0.2f, 1.0f, 1.0f, 0.0f ) * dist + float4( 1.0f, 0.1f, 0.1f, 0.0f ) * ( 1.0f - dist ); 
	float4 color = float4(0.2f, 0.2f, 1.0f, 0.0f) * dist + float4(1.0f, 0.1f, 0.1f, 0.0f) * (1.0f - dist);

		// Transform to view space
		float4 viewposition = mul(float4(input[0].Pos, 1.0f), World);

		// Emit two new triangles
		for (int i = 0; i < 4; i++)
		{
			float4 p = mul(input[0].Pos, World);
			p = mul(p, View);
			p = mul(p, Projection);
			output.Pos = p;
			output.TexCoord = g_texcoords[i];
			output.Col = color;

			SpriteStream.Append(output);
		}

	SpriteStream.RestartStrip();
}

//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS(PS_INPUT input) : SV_Target
{
	return float4(1.0f, 1.0f, 0.0f, 1.0f);
}
Advertisement
Do you unbind the geometry shader afterwards (setting to NULL) ?

Also, for your quad expansion you should use g_positions, too. Currently, you don't expand anything. wink.png

Edit: Watch out for compiler warnings:


float4 p = mul(input[0].Pos, World);

This is a float3 and a 4x4 matrix, you want


float4 p = mul(float4(input[0].Pos,1), World); 

Do you unbind the geometry shader afterwards (setting to NULL) ?

Also, for your quad expansion you should use g_positions, too. Currently, you don't expand anything. wink.png

Edit: Watch out for compiler warnings:


float4 p = mul(input[0].Pos, World);

This is a float3 and a 4x4 matrix, you want


float4 p = mul(float4(input[0].Pos,1), World); 

Ah, forgot to unbind it! Thank you!

That solves my problem of nothing showing up on screen, so the particle counter and fps counter are working now as intended. I just can't see any particles on the screen. This leads me to believe it's something to do with the positions and matrices. I've changed the line you said and there are still no particles on the screen.

Like I said, you don't expand anything. All quad vertices come from the same vertex, so they end up at the same pixel. Nothing gets rasterized in this case. Expand e.g. in view space

for (int i = 0; i < 4; i++)
{
    float4 p = mul(float4(input[0].Pos,1), World);
    p = mul(p, View);
    p += g_positions[i];
    p = mul(p, Projection);
    output.Pos = p;
    output.TexCoord = g_texcoords[i];
    output.Col = color;

    SpriteStream.Append(output);
}
Do you remember to set the primitive type back to triangles?

I am also using a geometry shader for particles and part of this is to set the primitive type to point lists.

Afterwards you must explicitly set it back to triangle lists.

You might not see particles if you forget to set it to point lists before sending vertices to the shader.

I've fixed it now, there were errors in how I was calculating positions in the shader. Thanks for your help!

Also, the primitive type is always point list as I'm only making a particle system, there isn't anything else to draw. I hope I've understood what you're trying to say? Thanks though.


I've fixed it now, there were errors ...

For the future benefit of those that may be looking for the solution to a similar problem, can you post your fix? Pay Forward! smile.png

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

I simply unbound the geometry shader after the draw call like so:

deviceContext->GSSetShader(NULL, 0, 0);

And this is the revised shader code that now works as intended. Not sure if it's a perfect fix but it works for me:


//#pragma pack_matrix( row_major )

cbuffer ConstantBuffer : register(b0)
{
	matrix World;
	matrix View;
	matrix Projection;
}

//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------

struct particles
{
	float3 position : POSITION;
	float3 velocity;
	float life;
	float age;
	bool alive;
	float startSize;
	float endSize;
	float4 startColour;
	float4 endColour;
};

struct VS_INPUT
{
	uint id : SV_VERTEXID;
};

struct GS_INPUT
{
    float3 Pos : POSITION;
	float4 Col : COLOUR;
};

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float4 Col : COLOUR;
	float2 TexCoord : TEXCOORD;
};


struct GeoOut
{
	float4 PosH    : SV_POSITION;
	float2 Tex     : TEXCOORD;
	uint   PrimID  : SV_PrimitiveID;
};

static const float scale = 0.001f;

static const float4 g_positions[4] =
{
	float4(-scale, scale, 0, 0),
	float4(scale, scale, 0, 0),
	float4(-scale, -scale, 0, 0),
	float4(scale, -scale, 0, 0),
};

static const float2 g_texcoords[4] =
{
	float2(0, 1),
	float2(1, 1),
	float2(0, 0),
	float2(1, 0),
};


StructuredBuffer<particles>   particlesIn : register(t0);

GS_INPUT VS(VS_INPUT input)
{
	GS_INPUT output;

	uint index = input.id;
	particles p = particlesIn[index];

	output.Pos = mul(p.position, World);
	output.Pos = mul(output.Pos, View);
	output.Pos = mul(output.Pos, Projection);

	output.Col = p.startColour;

	return output;
}

[maxvertexcount(4)]
void GS(point GS_INPUT input[1], inout TriangleStream<PS_INPUT> SpriteStream)
{
	PS_INPUT output;

	// Transform to view space
	float4 viewposition = mul(float4(input[0].Pos, 1.0f), World);

	// Emit two new triangles
	for (int i = 0; i < 4; i++)
	{
		output.Pos = viewposition + g_positions[i];
                 output.TexCoord = g_texcoords[i];
		output.Col = input[0].Col;

		SpriteStream.Append(output);
	}

	SpriteStream.RestartStrip();
}

//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS(GS_INPUT input) : SV_Target
{
	float4 pos;
	pos.xyz = input.Pos.xyz;

	return input.Col;
}

Any other thoughts on how this could be improved are always welcome! But this is now working as intended for my purposes. :)

I'm a bit surprised it works. I see two problems: You transform your points to homogenous clip space already in the vertex shader. Then you apply again the world transformation. This is wrong. Always be careful with your spaces. It helps to use explicitly named temp variables (or even semantics) to point out the difference.

Also, when expanding in clip space, you need to adjust that scale value for the correct aspect ratio. If you expand x and y by the same scale, your particles will get the aspect ratio of your rendertarget.

I'm a bit surprised it works. I see two problems: You transform your points to homogenous clip space already in the vertex shader. Then you apply again the world transformation. This is wrong. Always be careful with your spaces. It helps to use explicitly named temp variables (or even semantics) to point out the difference.

Also, when expanding in clip space, you need to adjust that scale value for the correct aspect ratio. If you expand x and y by the same scale, your particles will get the aspect ratio of your rendertarget.

Yeah so was I as well, but at this point I've got other things to work out, I'll come back to this later if I need to!

And that was the next problem, scaling takes the aspect ratio of the rendertarget but that's an easy enough fix! Thanks though!

This topic is closed to new replies.

Advertisement