0

I want to input control points through the tessellation stages and output them as bent lines. I expand the lines into billboarded quads in the geometry shader. Right now I input a bunch of random vertices with a control point number of 4. I assume the bending is done in the domain shader so I use one of the uv coordinates unique for that stage as a t value for a bezier function that takes in 4 world position coordinates.

However the lines remain straight. And I don't know what I am missing.

My code looks like this:

Domain Shader:

    float3 bezier( float3 p0, float3 p1, float3 p2, float3 p3, float u)
{
    float B0 = (1. - u) * (1. - u) * (1. - u);
    float B1 = 3. * u * (1. - u) * (1. - u);
    float B2 = 3. * u * u * (1. - u);
    float B3 = u * u * u;

    float3 p = B0 * p0 + B1 * p1 + B2 * p2 + B3 * p3;
    return p;

}

    float t = uv.x;
    float3 pos = bezier(inp[0].worldPos, inp[1].worldPos, inp[2].worldPos, inp[3].worldPos, t);

Could the problem be that the vertex points I input are not forming curves? Right now I just take a mesh such as a plane and take the vertices from there.

The detail factor in the hull shader is 16. Density factor varies by distance.

I don't know what else is relevant. If you need more information let me know. I hope I made the question clear, I have googled it but can't seem to find the error in my own code.

Progman
  • 16,827
  • 6
  • 33
  • 48
  • Can you show the code that draws the full curve, instead of just a single position on that curve? – Mike 'Pomax' Kamermans Jan 16 '22 at 19:16
  • What do you mean, the entire curve? – Emil Johansson Jan 17 '22 at 15:53
  • the code you're showing generates a single float3 `pos` based on a single time value (`uv.x`), so where is the code that _should_ draws the full curve, but instead draws lines, as you explained in text above the code you're showing. – Mike 'Pomax' Kamermans Jan 17 '22 at 15:59
  • This is the bezier related code from the domain shader. I was hoping it would be executed once per control point, but it seems to be executed once per line because the lines seem to form a bezier pattern in groups. The t value I use right now is not based on time ,its just a unique value for each time the domain shader is executed. – Emil Johansson Jan 19 '22 at 00:42
  • Clarification: that's what the variable `t` gets called in the context of Bezier curves. It's the "time" parameter for a Bezier curve, running from t=0 to t=1. It's not related to successive frames. – Mike 'Pomax' Kamermans Jan 19 '22 at 01:27
  • ok I didnt know that. – Emil Johansson Jan 19 '22 at 03:56

1 Answers1

0

See the SimpleBezier sample:

float4 BernsteinBasis(float t)
{
    float invT = 1.0f - t;

    return float4(invT * invT * invT,
        3.0f * t * invT * invT,
        3.0f * t * t * invT,
        t * t * t);
}

float4 dBernsteinBasis(float t)
{
    float invT = 1.0f - t;

    return float4(-3 * invT * invT,
        3 * invT * invT - 6 * t * invT,
        6 * t * invT - 3 * t * t,
        3 * t * t);
}

float3 EvaluateBezier(const OutputPatch< HS_OUTPUT, OUTPUT_PATCH_SIZE > BezPatch,
    float4 BasisU,
    float4 BasisV)
{
    float3 value = float3(0, 0, 0);
    value = BasisV.x * (BezPatch[0].pos * BasisU.x + BezPatch[1].pos * BasisU.y + BezPatch[2].pos * BasisU.z + BezPatch[3].pos * BasisU.w);
    value += BasisV.y * (BezPatch[4].pos * BasisU.x + BezPatch[5].pos * BasisU.y + BezPatch[6].pos * BasisU.z + BezPatch[7].pos * BasisU.w);
    value += BasisV.z * (BezPatch[8].pos * BasisU.x + BezPatch[9].pos * BasisU.y + BezPatch[10].pos * BasisU.z + BezPatch[11].pos * BasisU.w);
    value += BasisV.w * (BezPatch[12].pos * BasisU.x + BezPatch[13].pos * BasisU.y + BezPatch[14].pos * BasisU.z + BezPatch[15].pos * BasisU.w);

    return value;
}

[domain("quad")]
DS_OUTPUT BezierDS(HS_CONSTANT_DATA_OUTPUT input,
    float2 UV : SV_DomainLocation,
    const OutputPatch< HS_OUTPUT, OUTPUT_PATCH_SIZE > BezPatch)
{
    float4 BasisU = BernsteinBasis(UV.x);
    float4 BasisV = BernsteinBasis(UV.y);
    float4 dBasisU = dBernsteinBasis(UV.x);
    float4 dBasisV = dBernsteinBasis(UV.y);

    float3 worldPos = EvaluateBezier(BezPatch, BasisU, BasisV);
    float3 tangent = EvaluateBezier(BezPatch, dBasisU, BasisV);
    float3 biTangent = EvaluateBezier(BezPatch, BasisU, dBasisV);
    float3 normal = normalize(cross(tangent, biTangent));

    DS_OUTPUT output;
    output.pos = mul(float4(worldPos, 1), g_mViewProjection);
    output.worldPos = worldPos;
    output.normal = normal;

    return output;
}

https://github.com/microsoft/Xbox-ATG-Samples/tree/master/PCSamples/IntroGraphics/SimpleBezierPC

https://github.com/microsoft/Xbox-ATG-Samples/tree/master/PCSamples/IntroGraphics/SimpleBezierPC12


Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
  • Tried, but I get the same result, I don't know if the problem is I use a geometry shader after the domain shader, it only inputs 2 points? – Emil Johansson Jan 22 '22 at 11:15