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)
Ich hoffe, ich kann jemandem damit helfen. Wenn jemand eine bessere Idee hat, dicke Linien zu implementieren, hinterlassen Sie bitte einen Kommentar.
Haben Sie darüber nachgedacht, Direct2D zu verwenden, das für diese Art von Vektorgrafik entworfen wurde? –
@ChuckWalbourn die Zeilen sind in 3D auch ich darf nicht Direct2D verwenden ... Ich darf nur Direct3D 11 verwenden – Thomas
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