使用directx 11中的实例渲染渲染粗线

时间:2017-02-28 13:50:53

标签: directx-11

我想在directx11中实现粗线。 我想,我可以使用实例渲染技术来渲染高质量的#34;每张线的几何图形如下图所示:

enter image description here

P1和P2表示非等距线的顶点,它们以" D3D11_PRIMITIVE_TOPOLOGY_LINELIST"给出。线条粗细存储在常量缓冲区中。每条线都有相同的厚度。 实例几何体还有一个索引缓冲区,其中包含有关如何将顶点连接到三角形的信息(在图片中,顶点是I0 - I11)。

我应该将P1和P2位置和SV_VertexID放到一个顶点着色线程中,我可以计算I0 - I11顶点的每个位置。所以这不是问题。

问题是:是否可以使用实例化渲染技术来实现这一目标?

如果是这样的话:这样使用它是个好主意吗?或者有更多的性能方法来实现粗圆线?例如,使用geometryshader或只使用该几何体制作1000个drawcall ...

1 个答案:

答案 0 :(得分:3)

我尝试了很多使用实例化渲染的想法,但现在我将想法改为geometryshader并且它非常容易实现。 作为输入,它变成一条线(2个顶点),输出是30个三角形。

这里是pixelshader输入结构

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
};

此处为几何着色器:

#include <psiPosition.hlsli>

//#pragma warning (disable:3206)
//#pragma warning (disable:3554)

static const float PI = 3.1415926f;
static const float fRatio = 2.0f;
static float fThickness = 0.01f;

void addHalfCircle(inout TriangleStream<PS_INPUT> triangleStream, int nCountTriangles, float4 linePointToConnect, float fPointWComponent, float fAngle)
{
    PS_INPUT output = (PS_INPUT)0;
    for (int nI = 0; nI < nCountTriangles; ++nI)
    {
        output.Pos.x = cos(fAngle + (PI / nCountTriangles * nI)) * fThickness / fRatio;
        output.Pos.y = sin(fAngle + (PI / nCountTriangles * nI)) * fThickness;
        output.Pos.z = 0.0f;
        output.Pos.w = 0.0f;
        output.Pos += linePointToConnect;
        output.Pos *= fPointWComponent;
        triangleStream.Append(output);

        output.Pos = linePointToConnect * fPointWComponent;
        triangleStream.Append(output);

        output.Pos.x = cos(fAngle + (PI / nCountTriangles * (nI + 1))) * fThickness / fRatio;
        output.Pos.y = sin(fAngle + (PI / nCountTriangles * (nI + 1))) * fThickness;
        output.Pos.z = 0.0f;
        output.Pos.w = 0.0f;
        output.Pos += linePointToConnect;
        output.Pos *= fPointWComponent;
        triangleStream.Append(output);

        triangleStream.RestartStrip();
    }
}

[maxvertexcount(42)]
void main(line PS_INPUT input[2], inout TriangleStream<PS_INPUT> triangleStream)
{
    PS_INPUT output= (PS_INPUT)0;

    int nCountTriangles =6;

    float4 positionPoint0Transformed = input[0].Pos;
    float4 positionPoint1Transformed = input[1].Pos;

    float fPoint0w = positionPoint0Transformed.w;
    float fPoint1w = positionPoint1Transformed.w;

    //calculate out the W parameter, because of usage of perspective rendering
    positionPoint0Transformed.xyz = positionPoint0Transformed.xyz / positionPoint0Transformed.w;
    positionPoint0Transformed.w = 1.0f;
    positionPoint1Transformed.xyz = positionPoint1Transformed.xyz / positionPoint1Transformed.w;
    positionPoint1Transformed.w = 1.0f;

    //calculate the angle between the 2 points on the screen
    float3 positionDifference = positionPoint0Transformed.xyz - positionPoint1Transformed.xyz;
    float3 coordinateSysten = float3(1.0f, 0.0f, 0.0f);

    positionDifference.z = 0.0f;
    coordinateSysten.z = 0.0f;

    float fAngle = acos(dot(positionDifference.xy, coordinateSysten.xy) / (length(positionDifference.xy) * length(coordinateSysten.xy)));

    if (cross(positionDifference, coordinateSysten).z < 0.0f)
    {
        fAngle = 2.0f * PI - fAngle;
    }

    fAngle *= -1.0f;
    fAngle -= PI *0.5f;

    //first half circle of the line
    addHalfCircle(triangleStream, nCountTriangles, positionPoint0Transformed, fPoint0w, fAngle);
    addHalfCircle(triangleStream, nCountTriangles, positionPoint1Transformed, fPoint1w, fAngle + PI);

    //connection between the two circles
    //triangle1
    output.Pos.x = cos(fAngle) * fThickness / fRatio;
    output.Pos.y = sin(fAngle) * fThickness;
    output.Pos.z = 0.0f;
    output.Pos.w = 0.0f;
    output.Pos += positionPoint0Transformed;
    output.Pos *= fPoint0w; //undo calculate out the W parameter, because of usage of perspective rendering
    triangleStream.Append(output);

    output.Pos.x = cos(fAngle + (PI / nCountTriangles * (nCountTriangles))) * fThickness / fRatio;
    output.Pos.y = sin(fAngle + (PI / nCountTriangles * (nCountTriangles))) * fThickness;
    output.Pos.z = 0.0f;
    output.Pos.w = 0.0f;
    output.Pos += positionPoint0Transformed;
    output.Pos *= fPoint0w;
    triangleStream.Append(output);

    output.Pos.x = cos(fAngle + (PI / nCountTriangles * (nCountTriangles))) * fThickness / fRatio;
    output.Pos.y = sin(fAngle + (PI / nCountTriangles * (nCountTriangles))) * fThickness;
    output.Pos.z = 0.0f;
    output.Pos.w = 0.0f;
    output.Pos += positionPoint1Transformed;
    output.Pos *= fPoint1w;
    triangleStream.Append(output);

    //triangle2
    output.Pos.x = cos(fAngle) * fThickness / fRatio;
    output.Pos.y = sin(fAngle) * fThickness;
    output.Pos.z = 0.0f;
    output.Pos.w = 0.0f;
    output.Pos += positionPoint0Transformed;
    output.Pos *= fPoint0w;
    triangleStream.Append(output);

    output.Pos.x = cos(fAngle) * fThickness / fRatio;
    output.Pos.y = sin(fAngle) * fThickness;
    output.Pos.z = 0.0f;
    output.Pos.w = 0.0f;
    output.Pos += positionPoint1Transformed;
    output.Pos *= fPoint1w;
    triangleStream.Append(output);

    output.Pos.x = cos(fAngle + (PI / nCountTriangles * (nCountTriangles))) * fThickness / fRatio;
    output.Pos.y = sin(fAngle + (PI / nCountTriangles * (nCountTriangles))) * fThickness;
    output.Pos.z = 0.0f;
    output.Pos.w = 0.0f;
    output.Pos += positionPoint1Transformed;
    output.Pos *= fPoint1w;
    triangleStream.Append(output);
}

我知道它是非常硬编码的,但至少它有效;) 现在是一个具有较粗线条的立方体图片(第一个是透视投影,第二个是正投影) perspective projection orthographic projection

我希望我可以帮助这个人。如果有人更好地实施粗线,请发表评论。