2017-02-28 153 views
0

我想在directx11中实现粗线。 我想,我可以使用实例化呈现技术来呈现“高品质”的几何形状为这样的图像的每一行示出了:在directx中渲染粗实线11

enter image description here

P1和P2表示不等距线verticies WICH在给定的作为“D3D11_PRIMITIVE_TOPOLOGY_LINELIST”。线条粗细存储在常量缓冲区中。每条线具有相同的厚度。 实例几何也有一个索引缓冲区,其中包含有关如何将顶点连接到三角形的信息(图中的顶点是I0-I11)。

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

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

如果是这样的话:像这样使用它是个好主意吗?还是有更多的性能方法来实现粗圆线?例如使用geometryshader,或者只是使用几何图形进行1000次绘图...

+0

你有没有考虑只使用Direct2D,它被设计来做这种矢量图形绘制? –

+0

@ChuckWalbourn线条在3D中也不允许使用Direct2D ...我只允许使用Direct3D 11 – Thomas

+1

您是否想过使用几何着色器将您的观点扩展到四边形和广告牌?基本上,您可以将顶点A和B位置存储在一个点中,然后展开它。您也可以从相机矩阵中导出摄像机的向上矢量,因此通过权限可以计算您的交叉乘积以从中生成四个顶点。 这只是问题的一部分,您仍然需要确保根据距相机的距离计算四边形的正确宽度以模拟线条粗细。我认为这是一个简单的线性距离关系。 – ErnieDingo

回答

1

我尝试了很多使用实例渲染的想法,但现在我已将想法更改为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

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