Generate Billboards from Tesselation Shaders possible?

Started by
4 comments, last by neroziros 9 years, 6 months ago
Hi there! I was wondering if anyone know if it is possible to create billboards through hull and domain shaders? (akin the geometry shader method)
I ask this because I'd like to tessellate my billboard's to add better shadow reception quality by moving the calculations from GS to the DS, but I'm not sure if it is possible to create billboards using the tessellation stages and how to go about it.
Cheers and thanks for any info!
PS: I don´t create the billboards with the GS and then tessellate them because from what I understand, the GS is executed AFTER the tesselation stages
PS2: http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/OpacityMappingSDKWhitePaper.pdf I read this example´s source code, and though they do have tesselate billboards I didn´t understand how they did it as I didn´t see the vertex expansion into view aligned quads anywhere.
Advertisement

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)
Thanks it worked perfectly! by the way if anyone else is doing this, remember to change your
IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
for
IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST);
otherwise it won't work properly.
Again thanks for your help, now I will look for tesselation examples so I can tesselate the particles based on their screen size.
Cheers.

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).

Here is my Vertex, Hull, Domain and Pixel shaders. Any help is welcomed!
UPDATE: Now I can see the particles! but they are still looking weird (IMG2). To make them visible I moved the line:
output.position = mul(float4(position, 1.0), g_mWorldViewProj); from the vertex shader, to the domain shader.
Does anyone knows why that worked and how to fix the particles? I'm obviously missing something here
UPDATE 2: Nvm now they are looking perfectly, I had to swap the g_positions´s coordinates for some reason. Still if someone could explain me why I had to move the g_mWorldViewProj transformation from the VS to the DS I'd be very grateful!
Cheers
PARTICLE'S CORNERS

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), };*/
STRUCTS

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;
};
VERTEX SHADER

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;
}
HULL SHADER (CONST FUNCTION AND SHADER)

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 SHADER

[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; }

This topic is closed to new replies.

Advertisement