Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

code error in chapter 9 linestrip #63

Open
nyfpos opened this issue Jan 13, 2022 · 5 comments
Open

code error in chapter 9 linestrip #63

nyfpos opened this issue Jan 13, 2022 · 5 comments

Comments

@nyfpos
Copy link

nyfpos commented Jan 13, 2022

It seems to draw nothing if points at [[10., 4.], [20., 4.], [15., 4.]]

The code is in below.

uniform vec2 resolution;
uniform float antialias, thickness, linelength;
attribute vec4 prev, curr, next;
varying vec2 v_uv;

void main() {
    float w = thickness/2.0 + antialias;
    vec2 p;
    vec2 t0 = normalize(curr.xy - prev.xy);
    vec2 t1 = normalize(next.xy - curr.xy);
    vec2 n0 = vec2(-t0.y, t0.x);
    vec2 n1 = vec2(-t1.y, t1.x);

    // Cap at start
    if (prev.xy == curr.xy) {
        v_uv = vec2(-w, curr.z*w);
        p = curr.xy - w*t1 + curr.z*w*n1;
    // Cap at end
    } else if (curr.xy == next.xy) {
        v_uv = vec2(linelength+w, curr.z*w);
        p = curr.xy + w*t0 + curr.z*w*n0;
    // Body
    } else {
        vec2 miter = normalize(n0 + n1);
        float dy = w / dot(miter, n1);
        v_uv = vec2(curr.w, curr.z*w);
        p = curr.xy + dy*curr.z*miter;
    }
    gl_Position = vec4(2.0*p/resolution-1.0, 0.0, 1.0);
}

I guess it happened when points previous, current, next are collinear and the next point's x or y less than current point.

Another case: The drawing of points [[453, 138], [647, 137], [453, 139]] is weird. And points [[453, 138], [647, 137], [453, 138]] draw nothing.

@rougier
Copy link
Owner

rougier commented Jan 17, 2022

If you change the three 4. into 4.1 4.2 and 4.3 it works?

@nyfpos
Copy link
Author

nyfpos commented Jan 23, 2022

I figure out what happened. In the fragment shader, we are using v_uv.x to decide which points are cap.

It would be wrong if the end of point is 'before' it's previous point or 'before' the first point. But I still no idea how to fix it.

@rougier
Copy link
Owner

rougier commented Jan 31, 2022

where is this test exactly?

@nyfpos
Copy link
Author

nyfpos commented Feb 9, 2022

The whole code is bellow:

import sys
import ctypes
import numpy as np
from glumpy import app, gloo, gl

vertex = """
uniform vec2 resolution;
uniform float antialias;
uniform float thickness;
uniform float linelength;
attribute vec4 prev, curr, next;
varying vec2 v_uv;
void main() {
    float w = thickness/2.0 + antialias;
    vec2 p;
    if (prev.xy == curr.xy) {
        vec2 t1 = normalize(next.xy - curr.xy);
        vec2 n1 = vec2(-t1.y, t1.x);
        v_uv = vec2(-w, curr.z*w);
        p = curr.xy - w*t1 + curr.z*w*n1;
    } else if (curr.xy == next.xy) {
        vec2 t0 = normalize(curr.xy - prev.xy);
        vec2 n0 = vec2(-t0.y, t0.x);
        v_uv = vec2(linelength+w, curr.z*w);
        p = curr.xy + w*t0 + curr.z*w*n0;
    } else {
        vec2 t0 = normalize(curr.xy - prev.xy);
        vec2 t1 = normalize(next.xy - curr.xy);
        vec2 n0 = vec2(-t0.y, t0.x);
        vec2 n1 = vec2(-t1.y, t1.x);
        vec2 miter = normalize(n0 + n1);
        float dy = w / dot(miter, n1);
        v_uv = vec2(curr.w, curr.z*w);
        p = curr.xy + dy*curr.z*miter;
    }
    gl_Position = vec4(2.0*p/resolution-1.0, 0.0, 1.0);
} """

fragment = """
uniform float antialias;
uniform float thickness;
uniform float linelength;
varying vec2 v_uv;

void main() {
    float d = 0;
    float w = thickness/2.0 - antialias;

    // Cap at start
    if (v_uv.x < 0)
        d = length(v_uv) - w;

    // Cap at end
    else if (v_uv.x >= linelength)
        d = length(v_uv - vec2(linelength,0)) - w;

    // Body
    else
        d = abs(v_uv.y) - w;

    if( d < 0) {
        gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
    } else {
        d /= antialias;
        gl_FragColor = vec4(0.0, 0.0, 0.0, exp(-d*d));
    }
} """

window = app.Window(2*512, 512, color=(1,1,1,1))

@window.event
def on_resize(width, height):
    #spiral["resolution"] = width, height
    shape["resolution"] = width, height

@window.event
def on_draw(dt):
    window.clear()    
    shape.draw(gl.GL_TRIANGLE_STRIP)

def bake(P, closed=False):
    epsilon = 1e-10
    n = len(P)
    if closed and ((P[0]-P[-1])**2).sum() > epsilon:
        P = np.append(P, P[0])
        P = P.reshape(n+1,2)
        n = n+1
    #print("n=", n)
    V = np.zeros(((1+n+1),2,4), dtype=np.float32)
    V_prev, V_curr, V_next = V[:-2], V[1:-1], V[2:]
    V_curr[...,0] = P[:,np.newaxis,0]
    V_curr[...,1] = P[:,np.newaxis,1]
    V_curr[...,2] = 1,-1

    L = np.cumsum(np.sqrt(((P[1:]-P[:-1])**2).sum(axis=-1))).reshape(n-1,1)
    V_curr[1:,:,3] = L
    if closed:
        V[0], V[-1] = V[-3], V[2]
    else:
        V[0], V[-1] = V[1], V[-2]
    print(V_curr)
    return V_prev, V_curr, V_next, L[-1]

P = np.array([[4, 1], [4, 12], [4, 24]]).astype(np.float32)
V_prev, V_curr, V_next, length = bake(P, False)
shape = gloo.Program(vertex, fragment)
shape["prev"], shape["curr"], shape["next"]  = V_prev, V_curr, V_next
shape["thickness"] = 1.0
shape["antialias"] = 1.5
shape["linelength"] = length

app.run()

It works fine when the P is [[4, 1], [4, 12], [4, 24]], but shows nothing when P is [[4, 1], [4, 12], [4, 6]]

@rougier
Copy link
Owner

rougier commented Feb 15, 2022

v_uv.x is supposed to be the curvilinear coordinate along the line. For the actual line, it goes from 0 to linelength. Negativr means starting cap end > linemenght means ending cap. If the calculation of this curvilnear coordnate is wrong, then it might be problelatic. If all the point are aligned, there might be a division by 0 somewhere but the shader will not raise any kind of exception and will simply silently fails. This might be the explanation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants