This site uses strictly necessary cookies. More Information

X- Home /

# Constant thickness line shader

Hi,

I'm working on a line rendering shader. The line is made of billboarded polygons.

The problem is that I would like the line to have a constant thickness wether the camera is far or close to the line. (screen space thickness)

Here is how the system works for now:

C# :

I have a script that generate a mesh following a list of points. For each vertex I store the position of the vertex that will be on the same line segment in the vertex data.

Vertex Shader :

```
v2f vert (appdata v)
{
v2f o;
//extrusion direction
float extrusionDir = v.nextPoint.w;
//clip space pos
float4 currentProjected = UnityObjectToClipPos(float4(v.vertex.xyz, 1.0));
float4 nextProjected = UnityObjectToClipPos(float4(v.nextPoint.xyz, 1.0));
//get 2D screen space with W divide
float2 currentScreen = currentProjected.xy / currentProjected.w;
float2 nextScreen = nextProjected.xy / nextProjected.w;
//compute extrusion dir and normal
float2 dir = normalize(nextScreen.xy - currentScreen.xy);
float2 normal = float2(-dir.y , dir.x);
float perspectiveCancel = currentProjected.w;
//apply extrusion
currentProjected += float4((normal * extrusionDir * _LineWidth), 0, 0) * perspectiveCancel ;
o.vertex = currentProjected;
return o;
}
```

I compute a direction vector in screen space in order to know which way to extrude the line. And I multiply this vector by currentProjected.w in order to "cancel" the perspective.

This solution is working fine until the camera is too close from the line:

Fine at distance:

Issue at close distance :

as you can see the line is distorted if some of the vertex are behind the camera. I think that is because the perspectiveCancel value becomes negative ?

What do you think I can do to correct this ?

Thanks !

Alas even if you get that edge behind the camera to the correct length, consider what happens to the shape as the line passes by the camera: Your formula assigns a line width based on the distance from the camera. So a line that start/ends X units in front/behind the camera, would have the same width on each end. However, since the center of the line is closer to the camera, due to perspective, it will appear wider than both endpoints.

I suggest computing the intersection of your line and the camera frustum, then use those intersection points, to compute the line width, rather than trying to account for "behind camera widths". (I think you can use clipspace to compute the frustum intersections, it might prove a bit easier/faster.)

Thanks for the answer.

If I undestand what you said well, when the line intersect with the camera frustrum the line width at the intersection should be 0.

I'm going to work on that tomorrow and I'll let you know if I managed to correct the issue.

No, not zero. It's thickness will depend on the distance from the camera, at the intersection point. Compute it just like you would any point in front of the camera, after clipping it to the frustum.

**Answer** by le_duke
·
Mar 07, 2017 at 03:18 PM

The answer of this question in the comments by **Glurth**, Thanks !

I was wrong trying to compute the width of the line based on the distance with the vertex when the vertex is behind the camera.

Has **Glurth** said the correct way to compute the camera width in this case is to compute the line intersection with the near clip plane,we can then use this intersection coordinates as new coordinates for the vertex, resulting in having the good width.

The final result for the vertex shader is :

```
v2f vert (appdata v)
{
v2f o;
//extrusion direction
float extrusionDir = v.nextPoint.w;
//clip space pos
float4 currentProjected = UnityObjectToClipPos(float4(v.vertex.xyz, 1.0));
float4 nextProjected = UnityObjectToClipPos(float4(v.nextPoint.xyz, 1.0));
//get 2D screen space with W divide
float2 currentScreen = currentProjected.xy / currentProjected.w;
float2 nextScreen = nextProjected.xy / nextProjected.w;
//compute extrusion dir and normal
float2 dir = normalize(nextScreen.xy - currentScreen.xy);
float2 normal = float2(-dir.y /*_ProjectionParams.x*/, dir.x);
float perspectiveCancel = currentProjected.w /100;
//special case where vertex is behind the camera clip plane
if (currentProjected.w <0)
{
float3 normalizedClipSpaceDir = normalize(currentProjected.xyw - nextProjected.xyw);
float coef = -currentProjected.w / normalizedClipSpaceDir.z;
float3 intersectionPos = currentProjected.xyw + (normalizedClipSpaceDir * coef);
float4 clippedPos = float4(intersectionPos.x, intersectionPos.y, 0, intersectionPos.z);
currentProjected = clippedPos;
}
else
{
//apply extrusion
currentProjected += float4((normal * extrusionDir * _LineWidth), 0, 0) * perspectiveCancel;
}
o.vertex = currentProjected;
return o;
}
```

cool! Especially like your intersection computation, efficient!

### Your answer

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.

### Follow this Question

### Related Questions

How to manipulate a shader's alpha channel while using a texture? 1 Answer

Combine Vertex / Fragment and Surface Shader 0 Answers

Vertex displacement shader not working 2 Answers

Vertex Offset Shader deforming verts but not the rendered mesh 0 Answers

Can I get the whitest point of an image within a shader, and use it for white balancing the image? 1 Answer