Nice 3D line rendering in screen space

Hi, I've read through the line rendering discussions both here and on the following resources:


https://mattdesl.svbtle.com/drawing-lines-is-hard

http://codeflow.org/entries/2012/aug/05/webgl-rendering-of-solid-trails/

http://discourse.libcinder.org/t/smooth-efficient-perfect-curves/925


Based on that, I've implemented my screen space shader for 3D line rendering, which works nicely (with possible gaps at joins for now).


However I got stuck in understanding how to calculate the fragment distance from the center line in the fragment shader.

If I visualize the in.position in my fragment shader, all I get is a constant value for all pixels.

If I visualize the additional in.midPoint, I get a nicely interpolated, changing value.


Why is my in.position constant in my fragment, and thus, how would you calculate a distance from the center line?


struct LineVertexOut {
  float4 position [[position]];
  float4 midPoint;
  float4 color;
};

vertex LineVertexOut lineVertexShader(device LineLine* lines [[buffer(0)]],
  constant Uniforms& uniforms [[buffer(2)]],
  uint vertexId [[vertex_id]],
  uint instanceId [[instance_id]]) {

  float thickness = 2;

  LineLine line = lines[instanceId];

  LinePoint startPoint = line.start;
  LinePoint endPoint = line.end;

  float4 startProjected = uniforms.MVP * float4(startPoint.position, 1);
  float4 endProjected = uniforms.MVP * float4(endPoint.position, 1);

  float2 startScreen = startProjected.xy / startProjected.w;
  float2 endScreen = endProjected.xy / endProjected.w;

  float2 v = normalize(endScreen - startScreen);
  float2 normal = normalize(float2(-v.y, v.x));

  normal *= thickness / 2;
  normal.x /= uniforms.aspectRatio;

  LineVertexOut out;

  if (vertexId == 0) {
    out.position = startProjected + float4(normal, 0, 1);
    out.midPoint = startProjected;
    out.color = startPoint.color;
  }

  if (vertexId == 1) {
    out.position = startProjected + float4(-normal, 0, 1);
    out.midPoint = startProjected;
    out.color = startPoint.color;
  }

  if (vertexId == 2) {
    out.position = endProjected + float4(normal, 0, 1);
    out.midPoint = endProjected;
    out.color = endPoint.color;
  }

  if (vertexId == 3) {
    out.position = endProjected + float4(-normal, 0, 1);
    out.midPoint = endProjected;
    out.color = endPoint.color;
  }

  return out;
}

fragment float4 lineFragmentShader(LineVertexOut in [[stage_in]]) {
  // float2 color = in.position.xy; // position not changing
  float2 color = in.midPoint.xy; // position changing
  color = fract(color);
  return float4(color, 0, 1);
}


Here is how it looks: https://i.imgur.com/4zwvyVh.png

Replies

I don’t have access to device on which I could test it right now, so it is just a guess: in.position.xy does change, but it has [[position]] next to it and do between vertex and fragment shader it will get translated from NDC to fragment position. Now you’re taking fraction part of fragment position and this indeed will be constant, or at most (if multisampling) one of a few values. Of course midpoint doesn’t get translated and you’re seeing original NDC values which fractional part indeed changes “continuously” To verify if I’m right, just do something like: float2 color = fract(in.position.xy / 100.0); Michał