在DirectX 11中使用实例渲染渲染粗线 [英] Render thick lines with instanced rendering in directx 11

查看:291
本文介绍了在DirectX 11中使用实例渲染渲染粗线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Directx11中实现粗线。
我想,我可以使用实例渲染技术为每条线渲染一个高质量的几何图形,如下图所示:

I want to implement thick lines in directx11. I thought, I can use the instanced rendering technique to render a "high quality" geometry for each line like this picture shows:

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

P1 and P2 are representing the not equidistant line verticies wich are given in as a "D3D11_PRIMITIVE_TOPOLOGY_LINELIST". The line thickness is stored into the constantbuffer. each line has the same thickness. The instance geometry also has an indexbuffer with the information about how to connect the vertices to triangles (in the picture the verticies are I0 - I11).

应该我将P1和P2位置以及SV_VertexID放入一个vertexshader线程中,我可以计算I0-I11顶点的每个位置。因此,这不是问题。

should I get the P1 and P2 position and the SV_VertexID into one vertexshader thread, I can calculate each position of the I0 - I11 verticies. So that is not a problem.

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

The question is: Is it possible to use the instanced rendering technique to achieve this?

如果这样:像这样使用它是否是一个好主意?还是有更多的性能方法可以实现粗线?例如使用geometryshader或仅使用该几何进行1000次绘图调用...

And if so: Is it a good idea to use it like this? or are there more performance ways to implement thick rounded lines? for example with a geometryshader or just make 1000 drawcalls with that geometry...

推荐答案

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

I tried a lot to use the instanced rendering idea, but now I changed the idea to geometryshader and it is extremely easy to implement. As input it becomes a line (2 vertices) and the output are 30 triangles.

此处为pixelhader输入结构

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

我知道它是经过严格编码的,但至少可以使用;)
现在是具有较粗线条的立方体的图片(透视投影第一次,正投影投影第二次)

I know it is extremely hardcoded, but at least it works ;) Now a picture of a cube with thicker lines (first in perspective projection, second in orthographic projection)

我希望我可以帮助某人。如果有人对实现粗线有更好的想法,请发表评论。

I hope I can help someone with this. If someone has a better idea of implementing thick lines please leave a comment.

这篇关于在DirectX 11中使用实例渲染渲染粗线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆