Generate Billboards from Tesselation Shaders possible?
What we do in our engine is we billboard in the vertex shader using instancing. Basically your render N instances where N is the number of particles, with 4 vertices per instance. Then in the vertex shader you use the instance ID to get the particle center position (usually from a buffer), and then use the vertex ID to figure out which corner you're processing. Using that you can billboard from a single position, and then use the tessellation stages downstream to add additional interior vertices.
Oh I see, do you mean using a function like DrawInstancedIndirect to render the particles?
But how do I set the correct number of instances (particles) to render in the indirect argument buffer? if I'm correct if I use CopyStructureCount(g_pIndirectArg,0,bufferWithParticles), the function will copy the particle amount to the slot [0] which contains the VertexCountPerInstance instead of the desired InstanceCount.
http://msdn.microsoft.com/en-us/library/windows/hardware/ff556147(v=vs.85).aspx
Sorry if I am misunderstanding something and thank you so much for your help.
if I'm correct if I use CopyStructureCount(g_pIndirectArg,0,bufferWithParticles), the function will copy the particle amount to the slot [0] which contains the VertexCountPerInstance instead of the desired InstanceCount.
So change the second argument of CopyStructureCount, DstAlignedByteOffset (Offset from the start of pDstBuffer to write 32-bit UINT structure count), to 4 ( size of VertexCountPerInstance).
This way the number of particles will be copied to the correct location.
CopyStructureCount(g_pIndirectArg, 4,bufferWithParticles)
Hmm odd I can't seem to get the Hull and Domain shaders working. I tried the code without them and no there was no problem (the particles are rendered as 4 unconnected points, see IMG1). But once I bind the Hull and Domain shaders it stops working (the particles are only visible if you are too close to them).
static const float3 g_TessPositions[4] =
{
float3(-1, 1, 0),
float3(1, 1, 0),
float3(1, -1, 0),
float3(-1, -1, 0)
}
/* OLD, NOT WORKING static const float3 g_positions[4] =
{ float3(-1, 1, 0), float3(1, 1, 0), float3(-1, -1, 0), float3(1, -1, 0), };*/
struct VS_INPUT_TESSELATED
{
uint vertexid : SV_VertexID;
uint instanceid : SV_InstanceID;
};
struct VS_CONTROL_POINT_OUTPUT
{
float3 position : POSITION;
};
//-----------------------------------------------
struct HS_OUTPUT
{
float3 position : POSITION;
};
struct HS_CONSTANT_DATA_OUTPUT
{
float Edges[4] : SV_TessFactor;
float Inside[2] : SV_InsideTessFactor;
};
//-----------------------------------------------
struct PS_INPUT // All of this (Except position) is ignored since I'm just rendering white quads for debugging
{
float4 position : SV_POSITION;
float4 color : Color;
float2 texcoords : TEXCOORD0;
float3 basis_col0 : TEXCOORD1;
float3 basis_col1 : TEXCOORD2;
float3 basis_col2 : TEXCOORD3;
float3 normal : TEXCOORD4;
};
VS_CONTROL_POINT_OUTPUT VSMAIN_TESSELATED(in VS_INPUT_TESSELATED input)
{
VS_CONTROL_POINT_OUTPUT output;
// There is one particle per vertex, so use the vertex id as an index into the sorted list
uint particleIndex = input.instanceid;
// Get the global particle index
uint index = (uint)g_SortedIndexBuffer[CurrentParticles.x - particleIndex - 1].y;
// Get Particle's center Position
float3 center = SimulationState[index].position;
// Send the billboarded position
float3 position = g_positions[input.vertexid] * sizeAndCurvature.x;
output.position = mul(position, (float3x3)g_mInvView) + center;
//output.position = mul(float4(position, 1.0), g_mWorldViewProj); // Moved to Domain Shader
return output;
}
HS_CONSTANT_DATA_OUTPUT ConstantHS(InputPatch<VS_CONTROL_POINT_OUTPUT, 4> ip,
uint PatchID : SV_PrimitiveID)
{
HS_CONSTANT_DATA_OUTPUT Output;
float tess = 1.0;
Output.Edges[0] = tess;
Output.Edges[1] = tess;
Output.Edges[2] = tess;
Output.Edges[3] = tess;
Output.Inside[0] = tess;
Output.Inside[1] = tess;
return Output;
}
[domain("quad")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(4)]
[patchconstantfunc("ConstantHS")]
HS_OUTPUT HSMAIN(const InputPatch<VS_CONTROL_POINT_OUTPUT, 4> p,
uint i : SV_OutputControlPointID,
uint PatchID : SV_PrimitiveID)
{
HS_OUTPUT Output;
Output.position = p[i].position;
return Output;
}
[domain("quad")]
PS_INPUT DSMAIN(HS_CONSTANT_DATA_OUTPUT input,
float2 UV : SV_DomainLocation,
const OutputPatch<HS_OUTPUT, 4> quad)
{
PS_INPUT Output = (PS_INPUT) 0;
float3 verticalPos1 = lerp(quad[0].position, quad[1].position, UV.y);
float3 verticalPos2 = lerp(quad[3].position, quad[2].position, UV.y);
float3 finalPos = lerp(verticalPos1, verticalPos2, UV.x);
//Output.position = float4(finalPos,1); // I tried with hard wired values like float4(0,0,0,1) and still nothing shows
Output.position = mul(float4(finalPos, 1), g_mWorldViewProj); / New Version, it works (somehow)
return Output; }