我尝试了很多使用实例渲染的想法,但现在我已将想法更改为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);
}
我知道这是非常硬编码的,但至少它的工作原理;) 现在图片立方体的线条较粗(第一次是透视投影,第二次是正投影)
我希望我可以帮助这个人。如果有人有更好的实现粗线的想法,请发表评论。
你有没有考虑只使用Direct2D,它被设计来做这种矢量图形绘制? –
@ChuckWalbourn线条在3D中也不允许使用Direct2D ...我只允许使用Direct3D 11 – Thomas
您是否想过使用几何着色器将您的观点扩展到四边形和广告牌?基本上,您可以将顶点A和B位置存储在一个点中,然后展开它。您也可以从相机矩阵中导出摄像机的向上矢量,因此通过权限可以计算您的交叉乘积以从中生成四个顶点。 这只是问题的一部分,您仍然需要确保根据距相机的距离计算四边形的正确宽度以模拟线条粗细。我认为这是一个简单的线性距离关系。 – ErnieDingo