lines3D.glsl 3.5 KB
@export ecgl.lines3D.vertex

uniform mat4 worldViewProjection : WORLDVIEWPROJECTION;

attribute vec3 position: POSITION;
attribute vec4 a_Color : COLOR;
varying vec4 v_Color;

void main()
{
    gl_Position = worldViewProjection * vec4(position, 1.0);
    v_Color = a_Color;
}

@end

@export ecgl.lines3D.fragment

uniform vec4 color : [1.0, 1.0, 1.0, 1.0];

varying vec4 v_Color;

@import clay.util.srgb

void main()
{
#ifdef SRGB_DECODE
    gl_FragColor = sRGBToLinear(color * v_Color);
#else
    gl_FragColor = color * v_Color;
#endif
}
@end



@export ecgl.lines3D.clipNear

vec4 clipNear(vec4 p1, vec4 p2) {
    float n = (p1.w - near) / (p1.w - p2.w);
    // PENDING
    return vec4(mix(p1.xy, p2.xy, n), -near, near);
}

@end

@export ecgl.lines3D.expandLine
#ifdef VERTEX_ANIMATION
    vec4 prevProj = worldViewProjection * vec4(mix(prevPositionPrev, positionPrev, percent), 1.0);
    vec4 currProj = worldViewProjection * vec4(mix(prevPosition, position, percent), 1.0);
    vec4 nextProj = worldViewProjection * vec4(mix(prevPositionNext, positionNext, percent), 1.0);
#else
    vec4 prevProj = worldViewProjection * vec4(positionPrev, 1.0);
    vec4 currProj = worldViewProjection * vec4(position, 1.0);
    vec4 nextProj = worldViewProjection * vec4(positionNext, 1.0);
#endif

    if (currProj.w < 0.0) {
        if (nextProj.w > 0.0) {
            currProj = clipNear(currProj, nextProj);
        }
        else if (prevProj.w > 0.0) {
            currProj = clipNear(currProj, prevProj);
        }
    }

    vec2 prevScreen = (prevProj.xy / abs(prevProj.w) + 1.0) * 0.5 * viewport.zw;
    vec2 currScreen = (currProj.xy / abs(currProj.w) + 1.0) * 0.5 * viewport.zw;
    vec2 nextScreen = (nextProj.xy / abs(nextProj.w) + 1.0) * 0.5 * viewport.zw;

    vec2 dir;
    float len = offset;
    // Start point
    if (position == positionPrev) {
        dir = normalize(nextScreen - currScreen);
    }
    // End point
    else if (position == positionNext) {
        dir = normalize(currScreen - prevScreen);
    }
    else {
        vec2 dirA = normalize(currScreen - prevScreen);
        vec2 dirB = normalize(nextScreen - currScreen);

        vec2 tanget = normalize(dirA + dirB);

        // TODO, simple miterLimit
        float miter = 1.0 / max(dot(tanget, dirA), 0.5);
        len *= miter;
        dir = tanget;
    }

    dir = vec2(-dir.y, dir.x) * len;
    currScreen += dir;

    currProj.xy = (currScreen / viewport.zw - 0.5) * 2.0 * abs(currProj.w);
@end


@export ecgl.meshLines3D.vertex

// https://mattdesl.svbtle.com/drawing-lines-is-hard
attribute vec3 position: POSITION;
attribute vec3 positionPrev;
attribute vec3 positionNext;
attribute float offset;
attribute vec4 a_Color : COLOR;

#ifdef VERTEX_ANIMATION
attribute vec3 prevPosition;
attribute vec3 prevPositionPrev;
attribute vec3 prevPositionNext;
uniform float percent : 1.0;
#endif

uniform mat4 worldViewProjection : WORLDVIEWPROJECTION;
uniform vec4 viewport : VIEWPORT;
uniform float near : NEAR;

varying vec4 v_Color;

@import ecgl.common.wireframe.vertexHeader

@import ecgl.lines3D.clipNear

void main()
{
    @import ecgl.lines3D.expandLine

    gl_Position = currProj;

    v_Color = a_Color;

    @import ecgl.common.wireframe.vertexMain
}
@end


@export ecgl.meshLines3D.fragment

uniform vec4 color : [1.0, 1.0, 1.0, 1.0];

varying vec4 v_Color;

@import ecgl.common.wireframe.fragmentHeader

@import clay.util.srgb

void main()
{
#ifdef SRGB_DECODE
    gl_FragColor = sRGBToLinear(color * v_Color);
#else
    gl_FragColor = color * v_Color;
#endif

    @import ecgl.common.wireframe.fragmentMain
}

@end