I was working on this idea of drawing a cone rotating on the y axis with a parametric equation, using a compute shader with a function like:
CS(SV_GroupID, uint3 nDTid : SV_DispatchThreadID, SV_GroupThreadID).
To avoid multiple rendering, I was using a test on nDTid to draw only in a given nDTid.xy interval.
I found this tricky and finally I decided to use Dispatch(1,1,1) and numthreads[1,1,1], which remove the requirement for the nDTid interval test and the cone is drawn only once.
What I have noticed is an erratic framerate that I guess depends on the number of pixel drawn.
This becomes more an exercise than something applicable to my regular project, but is it of interest to limit Dispatch and numthread as I did with compute shaders? How can I reduce this erratic framerate?
Below is a code example and the rendered result.
Preparing constant shader
void UpdateShaderConstantCone()
{
FLOAT R = 10.0f;//radius at cone base
FLOAT H = 30.0f;//height of Cone
XMVECTOR U = XMVectorSet(R, 0, 0, 1);//vector for plane of base cone
XMVECTOR DirC = XMVectorSet(0, 0, H, 360);//initial direction of cone along Z axis
XMMATRIX M = XMMatrixRotationY(RotCone);
M.r[3] = XMVectorSet(20, 50, 0, 1);//position of the cone top = purple ball center
gCBCone.mWorld = XMMatrixTranspose(M*gVP);//set World.View.Perspective mat
XMStoreFloat4(&gCBCone.DirC, DirC);
XMStoreFloat4(&gCBCone.U, U);
FLOAT C = 0.5f * 255.0f;
gCBCone.Color = XMFLOAT4(0 * C, C * 255 , C * 255 * 255, 1.0f);
gpDC11->UpdateSubresource(gpCBBufferCone, 0, NULL, &gCBCone, 0, 0);
gpDC11->CSSetConstantBuffers(dwSlotCone, 1, &gpCBBufferCone);
}
Setting the compute shader. Instead of progressing along the cone axis and drawing a circle at each step, which required one transform / lighting calculation per circle pixel drawn, I loop first for each pixel of the circle at the base and draw a line from top cone to this pixel. This requires only one transform / lighting calculation per line drawn. It is not really efficient may I say, as top pixels can be drawn several times. This shader does not draw the base of the cone and did not z-test. For some reasons, the lighting makes the cone reddish instead of going grey, which I have not solved yet.
#define SM_SCREENX 1920.0
#define SM_SCREENY 1080.0
RWTexture2D<uint> UAVDiffuse0 : register( u0 );
cbuffer cbCone: register(b6)
{
matrix WVP;
float4 DirC;//direction of cone, w=Height
float4 U;//vector plane of circle w=radius / Height
//Note the plane requires two vectors UP(R,0,0) and VP(0,R,0).
//so U is used as U.xyy is UP and U.yxy is VP
float4 C;//color precalculated half
};
#define CPInc 2*3.14159265359f
static const float3 f3_u3 = float3(255,255*255,255*255*255);
static const float3 LDir = normalize(float3(-1,-1, 1));//Light dir
static const float3 LCol = float3(0.5f,0.5f,0.5f)*f3_u3;//ambient color 0.5f,0.5f,0.5f
static const float2 Sd2a = float2(SM_SCREENX, SM_SCREENY)*0.5f;
static const float2 Sd2m = float2(SM_SCREENX, -SM_SCREENY)*0.5f;
[numthreads(1,1,1)]
void CS_PostDeferred( uint3 nGid : SV_GroupID, uint3 nDTid : SV_DispatchThreadID, uint3 nGTid : SV_GroupThreadID )
{
float4 P = mul(float4(0,0,0,1),WVP);
P/=P.w;
P.xy=P.xy*Sd2m+Sd2a;
float4 E = float4(0,0,0,1);
float k=CPInc/DirC.w;//angle increment to draw the circle
float Angle = 0;
float2 sd2aP = Sd2a-P.xy;//precalculate delta for line tracing
for ( int a = 0; a < DirC.w; a++ )//make a circle at height h
{
float3 D = U.xyy*cos(Angle)+U.yxy*sin(Angle);//calculate circle pixel pos
E.xyz = DirC.xyz+D;//add base position from top eg 0,0,Height
Angle+=k;
E = mul(E,WVP);//convert to screen space
E/=E.w;
E.xy=mad(E.xy,Sd2m,sd2aP);//convert pixel position E to distance in pixel from top cone
float2 dXY = abs(E.xy);//calculate longest screen pixel path
int L = (dXY.x>dXY.y)?dXY.x:dXY.y;//determine number of step
float3 CL = C*dot(normalize(D),LDir)+LCol;//calculate ambient lighting
//we assume the normal D along the line is constant
E.xy/=L;//convert E to pixel path step
float2 XY = P.xy;
for (int l=0;l<L;l++)
{
UAVDiffuse0[int2(XY)]= (uint(CL.r)&0xFF) | (uint(CL.g)&0xFF00) | (uint(CL.b)&0xFF0000);
XY+=E.xy;
}
}
}
Screen shot
An alternative solution is to use a geometry shader to output a triangle from the top to two successive pixel circles.



