2017-02-28 5 views
0

Ich möchte dicke Linien in directx11 implementieren. Ich dachte, ich die instanzierten Rendering-Technik verwenden kann, wie dieses Bild eine „hohe Qualität“ Geometrie für jede Zeile zu machen zeige:Rendern dicke Linien mit instanzierten Rendering in DirectX 11

enter image description here

P1 und P2, die nicht Äquidistanzlinie verticies repräsentieren Weichen sind in als "D3D11_PRIMITIVE_TOPOLOGY_LINELIST". Die Liniendicke wird im Konstantpuffer gespeichert. Jede Linie hat dieselbe Dicke. Die Instanzgeometrie hat auch einen Indexpuffer mit der Information, wie die Scheitelpunkte mit Dreiecken verbunden werden (im Bild sind die Scheitelpunkte I0 - I11).

sollte ich die P1 und P2-Position und die SV_VertexID in einen Vertexshader-Thread bekommen, kann ich jede Position der I0 - I11-Vertices berechnen. Das ist also kein Problem.

Die Frage ist: Ist es möglich, die instanced Rendering-Technik zu verwenden, um dies zu erreichen?

Und wenn ja: Ist es eine gute Idee, es so zu benutzen? Oder gibt es mehr Möglichkeiten, dicke gerundete Linien zu implementieren? zum Beispiel mit einem geometryshader oder einfach 1000 drawcalls mit dieser Geometrie machen ...

+0

Haben Sie darüber nachgedacht, Direct2D zu verwenden, das für diese Art von Vektorgrafik entworfen wurde? –

+0

@ChuckWalbourn die Zeilen sind in 3D auch ich darf nicht Direct2D verwenden ... Ich darf nur Direct3D 11 verwenden – Thomas

+1

Haben Sie über die Verwendung von Geometry Shader gedacht, um Ihre Punkte auf Quads und Billboard zu erweitern. Grundsätzlich könnten Sie die Scheitelpunkte A und B in einem Punkt speichern und erweitern. Sie können den Aufwärtsvektor der Kamera auch von der Kameramatrix ableiten, also könnten Sie rechnerisch Ihr Kreuzprodukt berechnen, um daraus Ihre Quad-Vertices zu generieren. Das ist nur ein Teil des Problems, Sie müssen immer noch sicherstellen, dass abhängig von der Entfernung von der Kamera, die Sie die richtige Breite des Quad zu berechnen, um Ihre Linienstärke zu emulieren. Ich denke, das ist eine einfache lineare Distanzbeziehung. – ErnieDingo

Antwort

1

Ich habe viel versucht, die instanced rendering Idee zu verwenden, aber jetzt habe ich die Idee zu geometryshader geändert und es ist extrem einfach zu implementieren. Als Eingabe wird es eine Linie (2 Scheitelpunkte) und die Ausgabe sind 30 Dreiecke.

Hier wird die Pixelshader Eingang struct

struct PS_INPUT 
{ 
    float4 Pos : SV_POSITION; 
}; 

Hier ist die Geometrie-Shader:

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

Ich weiß, es extrem hartkodierte ist, aber zumindest funktioniert es;) nun ein Bild eines Würfels mit dickeren Linien (zuerst in perspektivischer Projektion, zweiter in orthographischer Projektion) perspective projection orthographic projection

Ich hoffe, ich kann jemandem damit helfen. Wenn jemand eine bessere Idee hat, dicke Linien zu implementieren, hinterlassen Sie bitte einen Kommentar.

Verwandte Themen