Attached a working example:
shader_worldsize.gh (46.2 KB)
The key was to move the calculation of the screen position from the Vertex Shader to Geometry shader:
Vertex Shader:
/*
vec4 clip = _worldToClip * vec4(world_vertex, 1);
// center points on pixels so they get drawn as 'clean' as possible
clip.x = (int(clip.x * _viewportSize.x) + 0.5) / _viewportSize.x;
clip.y = (int(clip.y * _viewportSize.y) + 0.5) / _viewportSize.y;
gl_Position = clip;
*/
gl_Position = vec4(world_vertex, 1.0);
Geometry Shader
void main()
{
Out.stroke_color = In[0].stroke_color;
Out.fill_color = In[0].fill_color;
Out.linewidth = In[0].linewidth;
Out.diameter = In[0].diameter;
Out.inner_diameter = In[0].inner_diameter;
Out.style = In[0].style;
Out.full_diameter = In[0].full_diameter;
if (world_size==1) {
vec4 center = _worldToCamera * gl_in[0].gl_Position;
if( In[0].style==PIN )
{
center.y += In[0].diameter * 0.5 + In[0].linewidth;
}
if( In[0].style==ARROW_TAIL )
{
center.x += In[0].diameter * 0.5;
center.x += In[0].inner_diameter;
}
if( In[0].style==ARROW_TIP )
{
center.x -= In[0].diameter * 0.5;
center.x -= In[0].inner_diameter;
}
Out.texture_coordinate = vec2(-0.5,0.5);
vec4 corner = _cameraToClip * vec4(center.x - radius, center.y - radius, center.z, 1);
Emit(corner);
Out.texture_coordinate = vec2(0.5,0.5);
corner = _cameraToClip * vec4(center.x + radius, center.y - radius, center.z, 1);
Emit(corner);
Out.texture_coordinate = vec2(-0.5,-0.5);
corner = _cameraToClip * vec4(center.x - radius, center.y + radius, center.z, 1);
Emit(corner);
Out.texture_coordinate = vec2(0.5,-0.5);
corner = _cameraToClip * vec4(center.x + radius, center.y + radius, center.z, 1);
Emit(corner);
}
else
{
vec4 clip = _worldToClip * gl_in[0].gl_Position;
// center points on pixels so they get drawn as 'clean' as possible
clip.x = (int(clip.x * _viewportSize.x) + 0.5) / _viewportSize.x;
clip.y = (int(clip.y * _viewportSize.y) + 0.5) / _viewportSize.y;
vec2 screen = ClipToScreen(clip, _viewportSize);
float radius = In[0].full_diameter * 0.5;
vec2 center = screen;
if( In[0].style==PIN )
{
screen.y += In[0].diameter * 0.5 + In[0].linewidth;
}
if( In[0].style==ARROW_TAIL )
{
screen.x += In[0].diameter * 0.5;
screen.x += In[0].inner_diameter;
}
if( In[0].style==ARROW_TIP )
{
screen.x -= In[0].diameter * 0.5;
screen.x -= In[0].inner_diameter;
}
Out.texture_coordinate = vec2(-0.5,0.5);
vec2 screen0 = screen + vec2(-radius, -radius);
screen0 = RotatePoint(screen0, In[0].rotation, center);
vec4 corner = ScreenToClip(screen0.xy,clip.z,clip.w, _viewportSize);
Emit(corner);
Out.texture_coordinate = vec2(0.5,0.5);
vec2 screen1 = screen + vec2(radius, -radius);
screen1 = RotatePoint(screen1, In[0].rotation, center);
corner = ScreenToClip(screen1.xy,clip.z,clip.w, _viewportSize);
Emit(corner);
Out.texture_coordinate = vec2(-0.5,-0.5);
vec2 screen2 = screen + vec2(-radius, radius);
screen2 = RotatePoint(screen2, In[0].rotation, center);
corner = ScreenToClip(screen2.xy,clip.z,clip.w, _viewportSize);
Emit(corner);
Out.texture_coordinate = vec2(0.5,-0.5);
vec2 screen3 = screen + vec2(radius, radius);
screen3 = RotatePoint(screen3, In[0].rotation, center);
corner = ScreenToClip(screen3.xy,clip.z,clip.w, _viewportSize);
Emit(corner);
}
EndPrimitive();
}
You’d need to rewrite the rotation part to work with world coordinates and vec4 as input but I’ll leave it up to you.