GS shader tubes

Attached is the example from the particles workshop at node15, it does a constrain solver to generate some lines, I’d like to turn the lines into tubes, preferably with normals so they can be shaded.
I’ve attempted to hack this together but failed, I imagine its pretty straight forward, but haven’t managed to crack it yet.
The other question I have is whether you can perform a RestartStrip() at the end of each line rather than discarding in the ps
Any suggestions or links gratefully received!

From node15 particles workshop (281.9 kB)

void GSOutputPoint( float3x3 m, float3 inpos, int i, inout TriangleStream<PSInput> gsout )
{
    PSInput output;

    float fRad = Radius;
	
    float3 pos = mul(TubeRes[i](i),m ) * fRad;
	
    float3 norm = normalize(pos);
	norm = mul(float4(norm,0),tV).xyz;
	
    pos += inpos;
    output.pos = mul( float4(pos,1), tVP );
	output.norm = norm;

    gsout.Append(output);
}

[maxvertexcount(20)](maxvertexcount(20))
void GS(line GSInput input[2](2), inout TriangleStream<PSInput> gsout)
{
	/*Stuff to create rotation matrices for tube, 
	from ms samples and quite sucks, need replacement at some point,
	but for thin objects it's cool */
	
	float3 n1 = float3(0,0,1);
	float3 n2 = float3(0,0,1);
	float3 left0 = cross( input[0](0).dir, n1 );
    float3x3 m0 = float3x3( -left0, n1, input[0](0).dir );
    float3 left1 = cross( input[1](1).dir, n2);
    float3x3 m1 = float3x3( -left1, n2, input[1](1).dir );

    float3 pos0 = input[0](0).pos;
    float3 pos1 = input[1](1).pos;
       
	//Build a little tube from the segment above
    for(int i=0; i < TUBE_RES + 1; i++)
    {
    	GSOutputPoint( m1, pos1, i, gsout );
    	GSOutputPoint( m0, pos0, i, gsout );
    }
    gsout.RestartStrip();
}

the tube code i got

is TubeResi a predefined structure?
You got a working shader you could post that I could take apart?

float3x3 rotationAlign(float3 d, float3 z)
{
    float3  v = cross( z, d );
    float c = dot( z, d );
    float k = 1.0f/(1.0f+c);

    return float3x3( v.x*v.x*k + c,     v.y*v.x*k - v.z,    v.z*v.x*k + v.y,
                   v.x*v.y*k + v.z,   v.y*v.y*k + c,      v.z*v.y*k - v.x,
                   v.x*v.z*k - v.y,   v.y*v.z*k + v.x,    v.z*v.z*k + c    );
}

[maxvertexcount(64)](maxvertexcount(64))
void GS(line vs2ps gsInput[2](2), inout TriangleStream<vs2ps> outStream)
{
	vs2ps output = (vs2ps)0;
	
	float4 p1 = gsInput[0](0).PosWVP;
	float4 p2 = gsInput[1](1).PosWVP;
	float3 dir = normalize(p1-p2).xyz;

	float3x3 rot1 = rotationAlign( float3(1,0,0), dir);
	float3x3 rot2 = rotationAlign( float3(1,0,0), dir);

float4x4 tWVP = mul(tW,tVP);
	for (int i=0; i<res+1; i++)
	{
		float phi = (i/(float)res)*3.14*2;
		float3 up = (float3)0;
		sincos(phi,up.y,up.z);
		
		float3 bt1 = normalize(mul(normalize(up),rot1));
		output.PosWVP.xyz = p1.xyz + bt1*p1.w*radius*0.001;;
		output.PosWVP.w = 1;
	
		output.PosWVP = mul(output.PosWVP, tWVP);
	
		outStream.Append(output);
		
		float3 bt2 = normalize(mul(normalize(up),rot1));
		output.PosWVP.xyz = p2.xyz + bt2*p2.w*radius*0.001;;
		output.PosWVP.w = 1;
	
	   output.PosWVP = mul(output.PosWVP,tWVP);
	
		outStream.Append(output);
	}

    outStream.RestartStrip();
}

kind of makes the tubes work, but still need to find a way to not connect it all into 1 tube but split at a set length eg 10 in this case…

if ((gsInput[1](1).iv2%StrandLength) == 0) {p2=p1;} //dont connect strips

which seems to fix that, now I need shading/uv’s

With tubes and split into separate objects (275.1 kB)

- define TUBE_RES_3 3
- define TUBE_RES_4 4
- define TUBE_RES_6 6
 
- ifndef TUBE_RES
	#define TUBE_RES TUBE_RES_6
- endif



- if TUBE_RES == TUBE_RES_3
static const float3 TubeRes[4](4) : IMMUTABLE =
{
	float3(1.0000,0.0000,0.0000),
	float3(-0.5000,0.8660,0.0000),
	float3(-0.5000,-0.8660,0.0000),
	float3(1.0000,0.0000,0.0000),
};
- endif

- if TUBE_RES == TUBE_RES_4
static const float3 TubeRes[5](5) : IMMUTABLE =
{
	float3(1.0000,0.0000,0.0000),
	float3(0.0000,1.0000,0.0000),
	float3(-1.0000,0.0000,0.0000),
	float3(0.0000,-1.0000,0.0000),
	float3(1.0000,0.0000,0.0000),
};
- endif

- if TUBE_RES == TUBE_RES_6
static const float3 TubeRes[7](7) : IMMUTABLE =
{
    float3( 1.0f, 0.0f,    0 ),
    float3( 0.5f, 0.866f,  0 ),
    float3( -0.5f, 0.866f, 0 ),
    float3( -1.0f, 0.0f,   0 ),
    float3( -0.5, -0.866f, 0 ),
    float3( 0.5, -0.866f,  0 ),
	float3( 1.0f, 0.0f,    0 ),
};
- endif