I have this basic raymarch shader, which is applied to a fullscreen quad, that draws a variable amount of "lines" (basically capsules at really small widths so they appear like lines).
shader_type spatial;
render_mode unshaded;
uniform float min_draw_distance = 0.0001f;
uniform float max_draw_distance = 100.0f;
uniform int march_iterations = 512;
uniform int lines_amount = 0;
uniform vec3 lines_starts[ 100 ];
uniform vec3 lines_ends[ 100 ];
uniform float lines_widths[ 100 ];
uniform vec4 lines_colors[ 100 ];
struct CommonData
{
vec3 cam_pos;
float cam_fov;
vec3 ray_origin;
vec3 ray_dir;
};
void camera_ray( in vec2 screen_uv, in mat4 inv_view_matrix, in mat4 inv_proj_matrix, out vec3 position, out vec3 origin, out vec3 direction )
{
vec3 ndc = vec3( screen_uv, 0.0f ) * 2.0f - 1.0f;
vec4 view_coords = inv_proj_matrix * vec4( ndc, 1.0f );
view_coords.xyz /= view_coords.w;
position = ( inv_view_matrix * vec4( 0.0f, 0.0f, 0.0f, 1.0f ) ).xyz;
vec4 world_coords = inv_view_matrix * vec4( view_coords.xyz, 1.0f );
origin = world_coords.xyz;
direction = normalize( world_coords.xyz - position );
}
// RETURNS x: distance field value, y: color red channel, z: color green channel, w: color blue channel
vec4 sd_op_union( in vec4 d1, in vec4 d2 )
{
return ( d1.x < d2.x ) ? d1 : d2;
}
float sd_line_segment( in vec3 point, in vec3 start, in vec3 end, in float thickness )
{
vec3 pa = point - start, ba = end - start;
return length( pa - ba * clamp( dot( pa, ba ) / dot( ba, ba ), 0.0f, 1.0f ) ) - ( thickness / 2.0f );
}
// RETURNS x: distance field value, y: color red channel, z: color green channel, w: color blue channel
vec4 sd_lines( in vec3 p )
{
vec4 lines = vec4( max_draw_distance, vec3( 0.0f ) );
for ( int i = 0; i < lines_amount; i++ )
{
float sd = sd_line_segment( p, lines_starts[ i ], lines_ends[ i ], lines_widths[ i ] );
vec4 line = vec4( sd, lines_colors[ i ].rgb );
lines = sd_op_union( lines, line );
}
return lines;
}
// RETURNS x: distance field value, y: color red channel, z: color green channel, w: color blue channel
vec4 sd_map( in vec3 point )
{
vec4 lines = sd_lines( point );
return lines;
}
vec4 raymarch( in CommonData data )
{
vec4 result = vec4( 0.0f );
float t = 0.0f;
for ( int i = 0; i < march_iterations; i++ )
{
if ( t > max_draw_distance )
{
result = vec4( 0.0f );
break;
}
vec3 p = data.ray_origin + data.ray_dir * t;
vec4 d = sd_map( p, data );
if ( d.x < 0.001f )
{
result = vec4( d.yzw, 1.0f );
break;
}
t += d.x;
}
return result;
}
void vertex()
{
POSITION = vec4( VERTEX, 1.0f );
}
void fragment()
{
vec3 cam_pos, ray_origin, ray_dir;
camera_ray( SCREEN_UV, INV_VIEW_MATRIX, INV_PROJECTION_MATRIX, cam_pos, ray_origin, ray_dir );
float cam_fov = atan( -1.0f / PROJECTION_MATRIX[1][1] ) * 2.0f;
CommonData data = CommonData( cam_pos, cam_fov, ray_origin, ray_dir );
vec4 color = raymarch( data );
ALBEDO = color.rgb;
ALPHA = color.a;
DEPTH = 0.0f;
}
I was wondering how I can specify the thickness of the "lines" as screen pixel amounts (like, "1.0f" would mean 1 pixel), and have them stay at that size regardless of the distance of the camera. With the shader code as it is now the lines get smaller as the camera gets farther away and bigger as the camera gets closer (like it is with regular mesh geometry).
I've tried several things but none of them seem to work quite right.
I know I could draw the lines another way (without raymarch) and they would stay the same size automatically, but for my needs I need it to be raymarched.
Thank you!